From bed03db758a84112e94e9257475992ab0be13dc6 Mon Sep 17 00:00:00 2001 From: Ben McCann <322311+benmccann@users.noreply.github.com> Date: Sun, 16 Oct 2022 21:54:45 -0700 Subject: [PATCH] fix: implement for preview as well --- packages/vite/src/node/preview.ts | 42 ++++++++++++------- .../src/node/server/middlewares/static.ts | 30 +++---------- packages/vite/src/node/utils.ts | 18 ++++++++ 3 files changed, 51 insertions(+), 39 deletions(-) diff --git a/packages/vite/src/node/preview.ts b/packages/vite/src/node/preview.ts index d17fc0845326dc..83ea15cb68f480 100644 --- a/packages/vite/src/node/preview.ts +++ b/packages/vite/src/node/preview.ts @@ -1,3 +1,4 @@ +import fs from 'node:fs' import path from 'node:path' import type * as http from 'node:http' import sirv from 'sirv' @@ -15,7 +16,7 @@ import { import { openBrowser } from './server/openBrowser' import compression from './server/middlewares/compression' import { proxyMiddleware } from './server/middlewares/proxy' -import { resolveHostname, resolveServerUrls } from './utils' +import { hasCorrectCase, resolveHostname, resolveServerUrls } from './utils' import { printServerUrls } from './logger' import { resolveConfig } from '.' import type { InlineConfig, ResolvedConfig } from '.' @@ -112,21 +113,34 @@ export async function preview( // static assets const distDir = path.resolve(config.root, config.build.outDir) const headers = config.preview.headers - app.use( - previewBase, - sirv(distDir, { - etag: true, - dev: true, - single: config.appType === 'spa', - setHeaders(res) { - if (headers) { - for (const name in headers) { - res.setHeader(name, headers[name]!) - } + const asset_server = sirv(distDir, { + etag: true, + dev: true, + single: config.appType === 'spa', + setHeaders(res) { + if (headers) { + for (const name in headers) { + res.setHeader(name, headers[name]!) } } - }) - ) + } + }) + app.use(previewBase, async (req, res, next) => { + // TODO: why is this necessary? what's screwing up the request URL? + const fixedUrl = req.url!.startsWith('//') + ? req.url!.substring(1) + : req.url! + const url = new URL(fixedUrl, 'http://example.com') + const pathname = decodeURIComponent(url.pathname) + const file = distDir + pathname + if ( + !fs.existsSync(file) || + (!fs.statSync(file).isDirectory() && !hasCorrectCase(file, distDir)) + ) { + return next() + } + asset_server(req, res, next) + }) // apply post server hooks from plugins postHooks.forEach((fn) => fn && fn()) diff --git a/packages/vite/src/node/server/middlewares/static.ts b/packages/vite/src/node/server/middlewares/static.ts index 37ce10cfd11da6..73b3b60d86ae7b 100644 --- a/packages/vite/src/node/server/middlewares/static.ts +++ b/packages/vite/src/node/server/middlewares/static.ts @@ -10,6 +10,7 @@ import { cleanUrl, fsPathFromId, fsPathFromUrl, + hasCorrectCase, isFileReadable, isImportRequest, isInternalRequest, @@ -49,19 +50,16 @@ export function servePublicMiddleware( // Keep the named function. The name is visible in debug logs via `DEBUG=connect:dispatcher ...` return function viteServePublicMiddleware(req, res, next) { - const url = req.url! // skip import request and internal requests `/@fs/ /@vite-client` etc... - if (isImportRequest(url) || isInternalRequest(url)) { + if (isImportRequest(req.url!) || isInternalRequest(req.url!)) { return next() } - const queryStringIdx = url.indexOf('?') - const pathname = - queryStringIdx >= 0 ? url.substring(0, queryStringIdx) : url + const url = new URL(req.url!, 'http://example.com') + const pathname = decodeURIComponent(url.pathname) const file = dir + pathname if ( !fs.existsSync(file) || - fs.statSync(file).isDirectory() || - !hasCorrectCase(file, dir) + (!fs.statSync(file).isDirectory() && !hasCorrectCase(file, dir)) ) { return next() } @@ -230,21 +228,3 @@ function renderRestrictedErrorHTML(msg: string): string { ` } - -/** - * Determine if a file is being requested with the correct case, to ensure - * consistent behaviour between dev and prod and across operating systems. - * Note that we can't use realpath here, because we don't want to follow - * symlinks. - */ -function hasCorrectCase(file: string, assets: string): boolean { - if (file === assets) return true - - const parent = path.dirname(file) - - if (fs.readdirSync(parent).includes(path.basename(file))) { - return hasCorrectCase(parent, assets) - } - - return false -} diff --git a/packages/vite/src/node/utils.ts b/packages/vite/src/node/utils.ts index 2711a29b7eb703..e4537c530c51fb 100644 --- a/packages/vite/src/node/utils.ts +++ b/packages/vite/src/node/utils.ts @@ -1190,3 +1190,21 @@ export const isNonDriveRelativeAbsolutePath = (p: string): boolean => { if (!isWindows) return p.startsWith('/') return windowsDrivePathPrefixRE.test(p) } + +/** + * Determine if a file is being requested with the correct case, to ensure + * consistent behaviour between dev and prod and across operating systems. + * Note that we can't use realpath here, because we don't want to follow + * symlinks. + */ +export function hasCorrectCase(file: string, assets: string): boolean { + if (file === assets) return true + + const parent = path.dirname(file) + + if (fs.readdirSync(parent).includes(path.basename(file))) { + return hasCorrectCase(parent, assets) + } + + return false +}