diff --git a/packages/vite/src/node/server/index.ts b/packages/vite/src/node/server/index.ts index c810c7889a59e8..adc892e99d6fa5 100644 --- a/packages/vite/src/node/server/index.ts +++ b/packages/vite/src/node/server/index.ts @@ -711,9 +711,7 @@ export async function _createServer( // this applies before the transform middleware so that these files are served // as-is without transforms. if (config.publicDir) { - middlewares.use( - servePublicMiddleware(config.publicDir, config.server.headers), - ) + middlewares.use(servePublicMiddleware(server)) } // main transform middleware @@ -721,7 +719,7 @@ export async function _createServer( // serve static files middlewares.use(serveRawFsMiddleware(server)) - middlewares.use(serveStaticMiddleware(root, server)) + middlewares.use(serveStaticMiddleware(server)) // html fallback if (config.appType === 'spa' || config.appType === 'mpa') { diff --git a/packages/vite/src/node/server/middlewares/static.ts b/packages/vite/src/node/server/middlewares/static.ts index 8acc9e681b4e37..74c487268d61a0 100644 --- a/packages/vite/src/node/server/middlewares/static.ts +++ b/packages/vite/src/node/server/middlewares/static.ts @@ -5,6 +5,7 @@ import sirv from 'sirv' import type { Connect } from 'dep-types/connect' import escapeHtml from 'escape-html' import type { ViteDevServer } from '../..' +import type { ResolvedConfig } from '../../config' import { FS_PREFIX } from '../../constants' import { cleanUrl, @@ -54,45 +55,50 @@ const sirvOptions = ({ } } -export function servePublicMiddleware( - dir: string, - headers?: OutgoingHttpHeaders, -): Connect.NextHandleFunction { - const serve = sirv( - dir, +const getServePublic = createSirvCache((config: ResolvedConfig) => { + const { + publicDir, + server: { headers }, + } = config + return sirv( + publicDir, sirvOptions({ headers, - shouldServe: (filePath) => shouldServeFile(filePath, dir), + shouldServe: (filePath) => shouldServeFile(filePath, publicDir), }), ) - +}) +export function servePublicMiddleware( + server: ViteDevServer, +): Connect.NextHandleFunction { // Keep the named function. The name is visible in debug logs via `DEBUG=connect:dispatcher ...` return function viteServePublicMiddleware(req, res, next) { // skip import request and internal requests `/@fs/ /@vite-client` etc... if (isImportRequest(req.url!) || isInternalRequest(req.url!)) { return next() } - serve(req, res, next) + getServePublic(server.config)(req, res, next) } } +const getServeStatic = createSirvCache((config: ResolvedConfig) => + sirv( + config.root, + sirvOptions({ + headers: config.server.headers, + }), + ), +) export function serveStaticMiddleware( - dir: string, server: ViteDevServer, ): Connect.NextHandleFunction { - const serve = sirv( - dir, - sirvOptions({ - headers: server.config.server.headers, - }), - ) - // Keep the named function. The name is visible in debug logs via `DEBUG=connect:dispatcher ...` return function viteServeStaticMiddleware(req, res, next) { // only serve the file if it's not an html request or ends with `/` // so that html requests can fallthrough to our html middleware for // special processing // also skip internal requests `/@fs/ /@vite-client` etc... + const dir = server.config.root const cleanedUrl = cleanUrl(req.url!) if ( cleanedUrl[cleanedUrl.length - 1] === '/' || @@ -141,7 +147,7 @@ export function serveStaticMiddleware( req.url = url.href.slice(url.origin.length) } - serve(req, res, next) + getServeStatic(server.config)(req, res, next) } } @@ -255,3 +261,20 @@ function renderRestrictedErrorHTML(msg: string): string { ` } + +function createSirvCache( + createSirv: (config: ResolvedConfig) => Connect.NextHandleFunction, +) { + const serveStaticCache = new WeakMap< + ResolvedConfig, + Connect.NextHandleFunction + >() + return function getServeStatic(config: ResolvedConfig) { + let serveStatic = serveStaticCache.get(config) + if (!serveStatic) { + ;(serveStatic = createSirv(config)), + serveStaticCache.set(config, serveStatic) + } + return serveStatic + } +}