Skip to content

Instantly share code, notes, and snippets.

@xfournet
Last active May 8, 2024 16:27
Show Gist options
  • Save xfournet/068592b3d1ddd488427b874b23f707bf to your computer and use it in GitHub Desktop.
Save xfournet/068592b3d1ddd488427b874b23f707bf to your computer and use it in GitHub Desktop.
Vite support for HTTP2 and proxy
import proxy from 'http2-proxy';
import type { Plugin, ProxyOptions } from 'vite';
export const pluginHttp2Proxy = (): Plugin => {
let routes: Record<string, string | ProxyOptions>;
return {
name: 'vite-plugin-http2-proxy',
config: (config) => {
const { server } = config;
routes = server?.proxy ?? {};
if (server) {
server.proxy = undefined;
}
return config;
},
configureServer: ({ config: { logger }, middlewares }) => {
Object.entries(routes).forEach(([route, target]) => {
if (typeof target !== 'string') {
throw new Error('ProxyOptions target are not supported yet, only string target are currently supported');
}
const { protocol, hostname, port } = new URL(target);
const options = {
protocol: protocol as 'http' | 'https',
hostname,
port: Number(port),
proxyTimeout: 60000,
};
middlewares.use(route, (req, res) => {
proxy.web(req, res, { ...options, path: req.originalUrl }, (err) => {
if (err) {
logger.error(`[http2-proxy] Error when proxying request on '${req.originalUrl}'`, { timestamp: true, error: err });
}
});
});
});
},
};
};
@xfournet
Copy link
Author

Tested with Vite 5 (should probably work with Vite 4 too ?)
ProxyOptions not implemented.

Configure the Vite proxy as usual and just add the plugin in the vite configuration eg:

export default defineConfig({
  plugins: [
    ....
    pluginHttp2Proxy(),
  ],
  ....
  server: {
    ....
    proxy: {
      '/api': 'https://localhost:8080/api',
    },
  },
});

@sebinsua
Copy link

Thank you for this! ❤️

@zybieku
Copy link

zybieku commented Mar 5, 2024

Thank you for this! ❤️

@A2E9
Copy link

A2E9 commented Apr 4, 2024

i get :
error when starting dev server:
Error: Not supported yet
/vite.config.js.timestamp-1712238134948-ef04cf446917a.mjs:114:17
at Array.forEach ()
with:
"http2-proxy": "^5.0.53",
"vite": "^5.2.0"

@xfournet
Copy link
Author

xfournet commented Apr 4, 2024

@A2E9 yes, ProxyOptions are not implemented. Can you share your proxy config ?

@nik-prostok
Copy link

nik-prostok commented May 7, 2024

@A2E9 yes, ProxyOptions are not implemented. Can you share your proxy config ?

here is my proxy config:

'/123': { target: '/456', secure: false, rewrite: (e) => e.replace(/\/123/, '/'), configure: (proxy) => proxy.on('proxyReq', (proxyReq) => { proxyReq.setHeader('Cookie', proxyReq.getHeader('auth') || ''); }), },

@c1aphas
Copy link

c1aphas commented May 8, 2024

Here is my version with rewrite and configure support.
Note that you should update your proxy config in configure() sections

proxy.on('proxyRes', (proxyRes) => {...} => proxy.onRes = async (req, res, proxyRes) => {...}

import type { Http2ServerRequest } from 'http2';
import type { Plugin, ProxyOptions } from 'vite';
import http2Proxy, { type http2WebOptions as Http2WebOptions } from 'http2-proxy';

const getOptions = (proxyOptions: string | ProxyOptions) => {
    if (typeof proxyOptions !== 'string') {
        const { protocol, hostname, port } = new URL(proxyOptions.target);
        const { proxyTimeout } = proxyOptions;

        return {
            protocol: protocol as 'https',
            hostname,
            port: Number(port),
            proxyTimeout,
            rejectUnauthorized: false,
        };
    }
    const { protocol, hostname, port } = new URL(proxyOptions);

    return {
        protocol: protocol as 'https',
        hostname,
        port: Number(port),
        proxyTimeout: 60000,
        rejectUnauthorized: false,
    };
};

export default (): Plugin => {
    let routes: Record<string, string | ProxyOptions>;

    return {
        name: 'vite-plugin-http2-proxy',
        config: (config) => {
            const { server } = config;
            routes = server?.proxy ?? {};

            if (server) {
                server.proxy = undefined;
            }

            return config;
        },
        configureServer: ({ config: { logger }, middlewares }) => {
            Object.entries(routes).forEach(([route, proxyOptions]) => {
                const options = getOptions(proxyOptions);
                middlewares.use(route, (req, res) => {
                    const http2Options: Http2WebOptions = { ...options };

                    if (typeof proxyOptions !== 'string') {
                        if (proxyOptions.rewrite) {
                            http2Options.path = proxyOptions.rewrite(req.originalUrl);
                        } else {
                            http2Options.path = req.originalUrl;
                        }

                        if (proxyOptions.configure) {
                            proxyOptions.configure(http2Options, proxyOptions);
                        }
                    }

                    http2Proxy.web(req as Http2ServerRequest, res, http2Options, (err) => {
                        if (err) {
                            logger.error(`[http2-proxy] Error when proxying request on '${req.originalUrl}'`, {
                                timestamp: true,
                                error: err,
                            });
                        }
                    });
                });
            });
        },
    };
};

@nik-prostok
Copy link

nik-prostok commented May 8, 2024

@c1aphas I didn’t quite understand what configure should look like...

[vite] Internal server error: proxy.on is not a function

@c1aphas
Copy link

c1aphas commented May 8, 2024

@nik-prostok

configure(proxy) {
  // before
  // proxy.on('proxyRes', (proxyRes) => {...} 

  // now
  proxy.onRes = async (req, res, proxyRes) => {...}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment