From 711dd807610b39538e9955970145d52e4ca1d8c0 Mon Sep 17 00:00:00 2001 From: divdavem Date: Thu, 15 Jun 2023 14:49:41 +0200 Subject: [PATCH] fix: allow using vite as a proxy for another vite server (#13218) Co-authored-by: sapphi-red --- .../vite/src/node/server/middlewares/proxy.ts | 8 +++--- packages/vite/src/node/server/ws.ts | 11 +++++++- .../proxy-hmr/__tests__/proxy-hmr.spec.ts | 15 +++++++++++ playground/proxy-hmr/__tests__/serve.ts | 27 +++++++++++++++++++ playground/proxy-hmr/index.html | 2 ++ playground/proxy-hmr/other-app/index.html | 1 + playground/proxy-hmr/other-app/package.json | 11 ++++++++ playground/proxy-hmr/other-app/vite.config.js | 9 +++++++ playground/proxy-hmr/package.json | 11 ++++++++ playground/proxy-hmr/vite.config.js | 13 +++++++++ playground/test-utils.ts | 2 ++ pnpm-lock.yaml | 4 +++ 12 files changed, 108 insertions(+), 6 deletions(-) create mode 100644 playground/proxy-hmr/__tests__/proxy-hmr.spec.ts create mode 100644 playground/proxy-hmr/__tests__/serve.ts create mode 100644 playground/proxy-hmr/index.html create mode 100644 playground/proxy-hmr/other-app/index.html create mode 100644 playground/proxy-hmr/other-app/package.json create mode 100644 playground/proxy-hmr/other-app/vite.config.js create mode 100644 playground/proxy-hmr/package.json create mode 100644 playground/proxy-hmr/vite.config.js diff --git a/packages/vite/src/node/server/middlewares/proxy.ts b/packages/vite/src/node/server/middlewares/proxy.ts index 66f99f94f0609d..ae289a8f8e9776 100644 --- a/packages/vite/src/node/server/middlewares/proxy.ts +++ b/packages/vite/src/node/server/middlewares/proxy.ts @@ -4,7 +4,6 @@ import httpProxy from 'http-proxy' import type { Connect } from 'dep-types/connect' import type { HttpProxy } from 'dep-types/http-proxy' import colors from 'picocolors' -import { HMR_HEADER } from '../ws' import { createDebugger } from '../../utils' import type { CommonServerOptions, ResolvedConfig } from '../..' @@ -103,10 +102,9 @@ export function proxyMiddleware( if (doesProxyContextMatchUrl(context, url)) { const [proxy, opts] = proxies[context] if ( - (opts.ws || - opts.target?.toString().startsWith('ws:') || - opts.target?.toString().startsWith('wss:')) && - req.headers['sec-websocket-protocol'] !== HMR_HEADER + opts.ws || + opts.target?.toString().startsWith('ws:') || + opts.target?.toString().startsWith('wss:') ) { if (opts.rewrite) { req.url = opts.rewrite(url) diff --git a/packages/vite/src/node/server/ws.ts b/packages/vite/src/node/server/ws.ts index 61d989080e7573..e1278959fedb27 100644 --- a/packages/vite/src/node/server/ws.ts +++ b/packages/vite/src/node/server/ws.ts @@ -1,3 +1,4 @@ +import path from 'node:path' import type { Server } from 'node:http' import { STATUS_CODES, createServer as createHttpServer } from 'node:http' import type { ServerOptions as HttpsServerOptions } from 'node:https' @@ -101,9 +102,17 @@ export function createWebSocketServer( const host = (hmr && hmr.host) || undefined if (wsServer) { + let hmrBase = config.base + const hmrPath = hmr ? hmr.path : undefined + if (hmrPath) { + hmrBase = path.posix.join(hmrBase, hmrPath) + } wss = new WebSocketServerRaw({ noServer: true }) wsServer.on('upgrade', (req, socket, head) => { - if (req.headers['sec-websocket-protocol'] === HMR_HEADER) { + if ( + req.headers['sec-websocket-protocol'] === HMR_HEADER && + req.url === hmrBase + ) { wss.handleUpgrade(req, socket as Socket, head, (ws) => { wss.emit('connection', ws, req) }) diff --git a/playground/proxy-hmr/__tests__/proxy-hmr.spec.ts b/playground/proxy-hmr/__tests__/proxy-hmr.spec.ts new file mode 100644 index 00000000000000..85fcde963cfc83 --- /dev/null +++ b/playground/proxy-hmr/__tests__/proxy-hmr.spec.ts @@ -0,0 +1,15 @@ +import { test } from 'vitest' +import { editFile, page, untilUpdated, viteTestUrl } from '~utils' + +test('proxy-hmr', async () => { + await page.goto(viteTestUrl) + const otherAppTextLocator = page.frameLocator('iframe').locator('.content') + await untilUpdated(() => otherAppTextLocator.textContent(), 'other app') + editFile('other-app/index.html', (code) => + code.replace('app', 'modified app'), + ) + await untilUpdated( + () => otherAppTextLocator.textContent(), + 'other modified app', + ) +}) diff --git a/playground/proxy-hmr/__tests__/serve.ts b/playground/proxy-hmr/__tests__/serve.ts new file mode 100644 index 00000000000000..9cbeef96edcbb2 --- /dev/null +++ b/playground/proxy-hmr/__tests__/serve.ts @@ -0,0 +1,27 @@ +// this is automatically detected by playground/vitestSetup.ts and will replace +// the default e2e test serve behavior + +import path from 'node:path' +import { rootDir, setViteUrl } from '~utils' + +export async function serve(): Promise<{ close(): Promise }> { + const vite = await import('vite') + const rootServer = await vite.createServer({ + root: rootDir, + logLevel: 'silent', + }) + const otherServer = await vite.createServer({ + root: path.join(rootDir, 'other-app'), + logLevel: 'silent', + }) + + await Promise.all([rootServer.listen(), otherServer.listen()]) + const viteUrl = rootServer.resolvedUrls.local[0] + setViteUrl(viteUrl) + + return { + async close() { + await Promise.all([rootServer.close(), otherServer.close()]) + }, + } +} diff --git a/playground/proxy-hmr/index.html b/playground/proxy-hmr/index.html new file mode 100644 index 00000000000000..f14fde8e428635 --- /dev/null +++ b/playground/proxy-hmr/index.html @@ -0,0 +1,2 @@ +root app
+ diff --git a/playground/proxy-hmr/other-app/index.html b/playground/proxy-hmr/other-app/index.html new file mode 100644 index 00000000000000..18f42b0b93d11c --- /dev/null +++ b/playground/proxy-hmr/other-app/index.html @@ -0,0 +1 @@ +other app diff --git a/playground/proxy-hmr/other-app/package.json b/playground/proxy-hmr/other-app/package.json new file mode 100644 index 00000000000000..4457d4da6ae217 --- /dev/null +++ b/playground/proxy-hmr/other-app/package.json @@ -0,0 +1,11 @@ +{ + "name": "@vitejs/test-other-app", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + } +} diff --git a/playground/proxy-hmr/other-app/vite.config.js b/playground/proxy-hmr/other-app/vite.config.js new file mode 100644 index 00000000000000..6e79541a31d806 --- /dev/null +++ b/playground/proxy-hmr/other-app/vite.config.js @@ -0,0 +1,9 @@ +import { defineConfig } from 'vite' + +export default defineConfig({ + base: '/anotherApp', + server: { + port: 9607, + strictPort: true, + }, +}) diff --git a/playground/proxy-hmr/package.json b/playground/proxy-hmr/package.json new file mode 100644 index 00000000000000..3aff8b1c8936fd --- /dev/null +++ b/playground/proxy-hmr/package.json @@ -0,0 +1,11 @@ +{ + "name": "@vitejs/test-proxy-hmr", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + } +} diff --git a/playground/proxy-hmr/vite.config.js b/playground/proxy-hmr/vite.config.js new file mode 100644 index 00000000000000..cd418eacdb5d35 --- /dev/null +++ b/playground/proxy-hmr/vite.config.js @@ -0,0 +1,13 @@ +import { defineConfig } from 'vite' + +export default defineConfig({ + server: { + port: 9606, + proxy: { + '/anotherApp': { + target: 'http://localhost:9607', + ws: true, + }, + }, + }, +}) diff --git a/playground/test-utils.ts b/playground/test-utils.ts index c7a2cf6c5dab4f..f780024547b180 100644 --- a/playground/test-utils.ts +++ b/playground/test-utils.ts @@ -30,6 +30,8 @@ export const ports = { 'ssr-noexternal': 9603, 'ssr-pug': 9604, 'ssr-webworker': 9605, + 'proxy-hmr': 9606, // not imported but used in `proxy-hmr/vite.config.js` + 'proxy-hmr/other-app': 9607, // not imported but used in `proxy-hmr/other-app/vite.config.js` 'css/postcss-caching': 5005, 'css/postcss-plugins-different-dir': 5006, 'css/dynamic-import': 5007, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ddadf91e4b2e5d..9bfeceae5e6aa9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -995,6 +995,10 @@ importers: playground/preserve-symlinks/module-a: {} + playground/proxy-hmr: {} + + playground/proxy-hmr/other-app: {} + playground/resolve: dependencies: '@babel/runtime':