export function transformMiddleware( server: ViteDevServer): Connect.NextHandleFunction { const { config: { root, logger, cacheDir }, moduleGraph } = server // determine the url prefix of files inside cache directory let cacheDirPrefix: string | undefined if (cacheDir) { const cacheDirRelative = normalizePath(path.relative(root, cacheDir)) if (cacheDirRelative.startsWith('../')) { // if the cache directory is outside root, the url prefix would be something // like '/@fs/absolute/path/to/node_modules/.vite' cacheDirPrefix = `/@fs/${normalizePath(cacheDir).replace(/^\//, '')}` } else { // if the cache directory is inside root, the url prefix would be something // like '/node_modules/.vite' cacheDirPrefix = `/${cacheDirRelative}` } } return async (req, res, next) => { // 如果不是 get 请求,获取资源的请求 // 或者是在已知的可以选择忽略的资源('/','/favicon.ico'),则直接跳过转换 if (req.method !== 'GET' || knownIgnoreList.has(req.url!)) { return next() } if ( server._pendingReload && // always allow vite client requests so that it can trigger page reload !req.url?.startsWith(CLIENT_PUBLIC_PATH) && !req.url?.includes('vite/dist/client') ) { // missing dep pending reload, hold request until reload happens server._pendingReload.then(() => // If the refresh has not happened after timeout, Vite considers // something unexpected has happened. In this case, Vite // returns an empty response that will error. setTimeout(() => { // status code request timeout res.statusCode = 408 res.end( `<h1>[vite] Something unexpected happened while optimizing "${req.url}"<h1>` + `<p>The current page should have reloaded by now</p>` ) }, NEW_DEPENDENCY_BUILD_TIMEOUT) ) return } let url try { url = removeTimestampQuery(req.url!).replace(NULL_BYTE_PLACEHOLDER, '\0') } catch (err) { // if it starts with %PUBLIC%, someone's migrating from something // like create-react-app let errorMessage if (req.url?.startsWith('/%PUBLIC')) { errorMessage = `index.html shouldn't include environment variables like %PUBLIC_URL%, see https://vitejs.dev/guide/#index-html-and-project-root for more information` } else { errorMessage = `Vite encountered a suspiciously malformed request ${req.url}` } next(new Error(errorMessage)) return } const withoutQuery = cleanUrl(url) try { const isSourceMap = withoutQuery.endsWith('.map') // since we generate source map references, handle those requests here if (isSourceMap) { const originalUrl = url.replace(/\.map($|\?)/, '$1') const map = (await moduleGraph.getModuleByUrl(originalUrl)) ?.transformResult?.map if (map) { return send(req, res, JSON.stringify(map), 'json') } else { return next() } } // warn explicit /public/ paths if (url.startsWith('/public/')) { logger.warn( chalk.yellow( `files in the public directory are served at the root path.\n` + `Instead of ${chalk.cyan(url)}, use ${chalk.cyan( url.replace(/^\/public\//, '/') )}.` ) ) } if ( isJSRequest(url) || isImportRequest(url) || isCSSRequest(url) || isHTMLProxy(url) ) { // strip ?import url = removeImportQuery(url) // Strip valid id prefix. This is prepended to resolved Ids that are // not valid browser import specifiers by the importAnalysis plugin. url = unwrapId(url) // for CSS, we need to differentiate between normal CSS requests and // imports if (isCSSRequest(url) && req.headers.accept?.includes('text/css')) { url = injectQuery(url, 'direct') } // check if we can return 304 early const ifNoneMatch = req.headers['if-none-match'] if ( ifNoneMatch && (await moduleGraph.getModuleByUrl(url))?.transformResult?.etag === ifNoneMatch ) { isDebug && debugCache(`[304] ${prettifyUrl(url, root)}`) res.statusCode = 304 return res.end() } // resolve, load and transform using the plugin container const result = await transformRequest(url, server, { html: req.headers.accept?.includes('text/html') }) if (result) { const type = isDirectCSSRequest(url) ? 'css' : 'js' const isDep = DEP_VERSION_RE.test(url) || (cacheDirPrefix && url.startsWith(cacheDirPrefix)) return send( req, res, result.code, type, result.etag, // allow browser to cache npm deps! isDep ? 'max-age=31536000,immutable' : 'no-cache', result.map ) } } } catch (e) { return next(e) } next() }}