From 69737f496cb888a459b6cb701e66610991393bc7 Mon Sep 17 00:00:00 2001 From: Bjorn Lu Date: Thu, 2 Nov 2023 22:57:01 +0800 Subject: [PATCH] refactor(preview)!: use base middleware (#14818) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 翠 / green --- docs/guide/migration.md | 3 ++ packages/vite/src/node/preview.ts | 39 ++++++++----------- packages/vite/src/node/server/index.ts | 2 +- .../vite/src/node/server/middlewares/base.ts | 28 +++++++------ .../node/server/middlewares/htmlFallback.ts | 22 ++--------- 5 files changed, 40 insertions(+), 54 deletions(-) diff --git a/docs/guide/migration.md b/docs/guide/migration.md index 2825ee65184231..44726ac0050310 100644 --- a/docs/guide/migration.md +++ b/docs/guide/migration.md @@ -201,6 +201,9 @@ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8')) There are some changes which only affect plugin/tool creators. - [[#14119] refactor!: merge `PreviewServerForHook` into `PreviewServer` type](https://github.com/vitejs/vite/pull/14119) + - The `configurePreviewServer` hook now accepts the `PreviewServer` type instead of `PreviewServerForHook` type. +- [[#14818] refactor(preview)!: use base middleware](https://github.com/vitejs/vite/pull/14818) + - Middlewares added from the returned function in `configurePreviewServer` now does not have access to the `base` when comparing the `req.url` value. This aligns the behaviour with the dev server. You can check the `base` from the `configResolved` hook if needed. Also there are other breaking changes which only affect few users. diff --git a/packages/vite/src/node/preview.ts b/packages/vite/src/node/preview.ts index 77b8b0687eea59..68a650438f32fa 100644 --- a/packages/vite/src/node/preview.ts +++ b/packages/vite/src/node/preview.ts @@ -18,6 +18,7 @@ import { } from './http' import { openBrowser } from './server/openBrowser' import compression from './server/middlewares/compression' +import { baseMiddleware } from './server/middlewares/base' import { htmlFallbackMiddleware } from './server/middlewares/htmlFallback' import { indexHtmlMiddleware } from './server/middlewares/indexHtml' import { notFoundMiddleware } from './server/middlewares/notFound' @@ -167,8 +168,10 @@ export async function preview( app.use(compression()) - const previewBase = - config.base === './' || config.base === '' ? '/' : config.base + // base + if (config.base !== '/') { + app.use(baseMiddleware(config.rawBase, false)) + } // static assets const headers = config.preview.headers @@ -190,18 +193,11 @@ export async function preview( }, })(...args) - app.use(previewBase, viteAssetMiddleware) + app.use(viteAssetMiddleware) // html fallback if (config.appType === 'spa' || config.appType === 'mpa') { - app.use( - previewBase, - htmlFallbackMiddleware( - distDir, - config.appType === 'spa', - previewBase !== '/', - ), - ) + app.use(htmlFallbackMiddleware(distDir, config.appType === 'spa')) } // apply post server hooks from plugins @@ -209,17 +205,16 @@ export async function preview( if (config.appType === 'spa' || config.appType === 'mpa') { // transform index.html - app.use(previewBase, indexHtmlMiddleware(distDir, server)) + app.use(indexHtmlMiddleware(distDir, server)) // handle 404s - app.use(previewBase, notFoundMiddleware()) + app.use(notFoundMiddleware()) } const hostname = await resolveHostname(options.host) const port = options.port ?? DEFAULT_PREVIEW_PORT - const protocol = options.https ? 'https' : 'http' - const serverPort = await httpServerStart(httpServer, { + await httpServerStart(httpServer, { port, strictPort: options.strictPort, host: hostname.host, @@ -233,14 +228,12 @@ export async function preview( ) if (options.open) { - const path = typeof options.open === 'string' ? options.open : previewBase - openBrowser( - path.startsWith('http') - ? path - : new URL(path, `${protocol}://${hostname.name}:${serverPort}`).href, - true, - logger, - ) + const url = server.resolvedUrls?.local[0] ?? server.resolvedUrls?.network[0] + if (url) { + const path = + typeof options.open === 'string' ? new URL(options.open, url).href : url + openBrowser(path, true, logger) + } } return server as PreviewServer diff --git a/packages/vite/src/node/server/index.ts b/packages/vite/src/node/server/index.ts index 9fb7c201a93633..13be3ad0d9561a 100644 --- a/packages/vite/src/node/server/index.ts +++ b/packages/vite/src/node/server/index.ts @@ -680,7 +680,7 @@ export async function _createServer( // base if (config.base !== '/') { - middlewares.use(baseMiddleware(server)) + middlewares.use(baseMiddleware(config.rawBase, middlewareMode)) } // open in editor support diff --git a/packages/vite/src/node/server/middlewares/base.ts b/packages/vite/src/node/server/middlewares/base.ts index 4d6da95a411f34..a6fab33b08219c 100644 --- a/packages/vite/src/node/server/middlewares/base.ts +++ b/packages/vite/src/node/server/middlewares/base.ts @@ -1,20 +1,24 @@ import type { Connect } from 'dep-types/connect' -import type { ViteDevServer } from '..' -import { joinUrlSegments, stripBase, withTrailingSlash } from '../../utils' +import { + cleanUrl, + joinUrlSegments, + stripBase, + withTrailingSlash, +} from '../../utils' // this middleware is only active when (base !== '/') -export function baseMiddleware({ - config, -}: ViteDevServer): Connect.NextHandleFunction { +export function baseMiddleware( + rawBase: string, + middlewareMode: boolean, +): Connect.NextHandleFunction { // Keep the named function. The name is visible in debug logs via `DEBUG=connect:dispatcher ...` return function viteBaseMiddleware(req, res, next) { const url = req.url! - const parsed = new URL(url, 'http://vitejs.dev') - const path = parsed.pathname || '/' - const base = config.rawBase + const pathname = cleanUrl(url) + const base = rawBase - if (path.startsWith(base)) { + if (pathname.startsWith(base)) { // rewrite url to remove base. this ensures that other middleware does // not need to consider base being prepended or not req.url = stripBase(url, base) @@ -22,14 +26,14 @@ export function baseMiddleware({ } // skip redirect and error fallback on middleware mode, #4057 - if (config.server.middlewareMode) { + if (middlewareMode) { return next() } - if (path === '/' || path === '/index.html') { + if (pathname === '/' || pathname === '/index.html') { // redirect root visit to based url with search and hash res.writeHead(302, { - Location: base + (parsed.search || '') + (parsed.hash || ''), + Location: base + url.slice(pathname.length), }) res.end() return diff --git a/packages/vite/src/node/server/middlewares/htmlFallback.ts b/packages/vite/src/node/server/middlewares/htmlFallback.ts index 85f5e396e54f8c..de29c54ec321eb 100644 --- a/packages/vite/src/node/server/middlewares/htmlFallback.ts +++ b/packages/vite/src/node/server/middlewares/htmlFallback.ts @@ -8,21 +8,7 @@ const debug = createDebugger('vite:html-fallback') export function htmlFallbackMiddleware( root: string, spaFallback: boolean, - mounted = false, ): Connect.NextHandleFunction { - // When this middleware is mounted on a route, we need to re-assign `req.url` with a - // leading `.` to signal a relative rewrite. Returning with a leading `/` returns a - // buggy `req.url`. e.g.: - // - // mount /foo/bar: - // req.url = /index.html - // final = /foo/barindex.html - // - // mount /foo/bar: - // req.url = ./index.html - // final = /foo/bar/index.html - const prepend = mounted ? '.' : '' - // Keep the named function. The name is visible in debug logs via `DEBUG=connect:dispatcher ...` return function viteHtmlFallbackMiddleware(req, res, next) { if ( @@ -51,7 +37,7 @@ export function htmlFallbackMiddleware( const filePath = path.join(root, pathname) if (fs.existsSync(filePath)) { debug?.(`Rewriting ${req.method} ${req.url} to ${url}`) - req.url = prepend + url + req.url = url return next() } } @@ -61,7 +47,7 @@ export function htmlFallbackMiddleware( if (fs.existsSync(filePath)) { const newUrl = url + 'index.html' debug?.(`Rewriting ${req.method} ${req.url} to ${newUrl}`) - req.url = prepend + newUrl + req.url = newUrl return next() } } @@ -71,14 +57,14 @@ export function htmlFallbackMiddleware( if (fs.existsSync(filePath)) { const newUrl = url + '.html' debug?.(`Rewriting ${req.method} ${req.url} to ${newUrl}`) - req.url = prepend + newUrl + req.url = newUrl return next() } } if (spaFallback) { debug?.(`Rewriting ${req.method} ${req.url} to /index.html`) - req.url = prepend + '/index.html' + req.url = '/index.html' } next()