From af47c86c8c5eb21639243a739d756e86fca841a1 Mon Sep 17 00:00:00 2001 From: bompus Date: Thu, 14 Jan 2021 17:37:20 -0700 Subject: [PATCH 01/15] Support base option during dev #833 todo: tests I did not check if this works for react, preact, jsx as I am not familiar with those --- packages/plugin-vue/src/template.ts | 4 ++- packages/vite/src/node/config.ts | 23 ++++++++++++++-- packages/vite/src/node/plugins/asset.ts | 20 ++++++++------ packages/vite/src/node/plugins/css.ts | 2 +- packages/vite/src/node/plugins/html.ts | 2 +- .../vite/src/node/plugins/importAnalysis.ts | 20 +++++++++++--- packages/vite/src/node/server/hmr.ts | 13 ++++++++-- packages/vite/src/node/server/index.ts | 26 +++++++++++++------ .../vite/src/node/server/middlewares/base.ts | 17 ++++++++++++ .../src/node/server/middlewares/indexHtml.ts | 15 ++++++++--- 10 files changed, 113 insertions(+), 29 deletions(-) create mode 100644 packages/vite/src/node/server/middlewares/base.ts diff --git a/packages/plugin-vue/src/template.ts b/packages/plugin-vue/src/template.ts index 4d5d98daef7d23..edd9d1bf8d4128 100644 --- a/packages/plugin-vue/src/template.ts +++ b/packages/plugin-vue/src/template.ts @@ -104,7 +104,9 @@ export function resolveTemplateCompilerOptions( // request if (filename.startsWith(options.root)) { assetUrlOptions = { - base: '/' + slash(path.relative(options.root, path.dirname(filename))) + base: + options.devServer.config.env.BASE_URL + + slash(path.relative(options.root, path.dirname(filename))) } } } else { diff --git a/packages/vite/src/node/config.ts b/packages/vite/src/node/config.ts index d1708d487a8492..46076d1671a676 100644 --- a/packages/vite/src/node/config.ts +++ b/packages/vite/src/node/config.ts @@ -214,6 +214,24 @@ export async function resolveConfig( ? createFilter(config.assetsInclude) : () => false + const serverBase = config.server?.base || '/' + const BASE_URL = command === 'build' ? resolvedBuildOptions.base : serverBase + const trailingSlashRE = /\/$/ + + let hmr = undefined + if (serverBase !== '/') { + hmr = config.server?.hmr === true ? {} : config.server?.hmr + hmr = { + ...hmr, + path: BASE_URL !== '/' ? BASE_URL.substr(1) : undefined + } + } + + const server = { + ...config.server, + hmr + } + const resolved = { ...config, configFile: configFile ? normalizePath(configFile) : undefined, @@ -225,11 +243,12 @@ export async function resolveConfig( optimizeCacheDir, alias: resolvedAlias, plugins: userPlugins, - server: config.server || {}, + server, build: resolvedBuildOptions, env: { ...userEnv, - BASE_URL: command === 'build' ? resolvedBuildOptions.base : '/', + BASE_URL, + BASE_URL_NOSLASH: BASE_URL.replace(trailingSlashRE, ''), MODE: mode, DEV: !isProduction, PROD: isProduction diff --git a/packages/vite/src/node/plugins/asset.ts b/packages/vite/src/node/plugins/asset.ts index 5192137f4e32a2..649eca1995b89d 100644 --- a/packages/vite/src/node/plugins/asset.ts +++ b/packages/vite/src/node/plugins/asset.ts @@ -104,18 +104,22 @@ export function fileToUrl( } } -function fileToDevUrl(id: string, { root }: ResolvedConfig) { +function fileToDevUrl(id: string, { root, env }: ResolvedConfig) { + let rtn: string + if (checkPublicFile(id, root)) { // in public dir, keep the url as-is - return id - } - if (id.startsWith(root)) { + rtn = id + } else if (id.startsWith(root)) { // in project root, infer short public path - return '/' + path.posix.relative(root, id) + rtn = '/' + path.posix.relative(root, id) + } else { + // outside of project root, use absolute fs path + // (this is special handled by the serve static middleware + rtn = FS_PREFIX + id } - // outside of project root, use absolute fs path - // (this is special handled by the serve static middleware - return FS_PREFIX + id + + return env.BASE_URL_NOSLASH + rtn } const assetCache = new WeakMap>() diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 53bb9ba1298a24..01bce2d31a1c1f 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -157,7 +157,7 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin { // server only return [ `import { updateStyle, removeStyle } from ${JSON.stringify( - CLIENT_PUBLIC_PATH + config.env.BASE_URL_NOSLASH + CLIENT_PUBLIC_PATH )}`, `const id = ${JSON.stringify(id)}`, `const css = ${JSON.stringify(css)}`, diff --git a/packages/vite/src/node/plugins/html.ts b/packages/vite/src/node/plugins/html.ts index bfb6377fdc4991..f428bfe751789b 100644 --- a/packages/vite/src/node/plugins/html.ts +++ b/packages/vite/src/node/plugins/html.ts @@ -335,7 +335,7 @@ export function buildHtmlPlugin(config: ResolvedConfig): Plugin { export interface HtmlTagDescriptor { tag: string - attrs?: Record + attrs?: Record children?: string | HtmlTagDescriptor[] /** * default: 'head-prepend' diff --git a/packages/vite/src/node/plugins/importAnalysis.ts b/packages/vite/src/node/plugins/importAnalysis.ts index 88e0202f255f65..7af01ead6bf9f3 100644 --- a/packages/vite/src/node/plugins/importAnalysis.ts +++ b/packages/vite/src/node/plugins/importAnalysis.ts @@ -159,6 +159,13 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin { url: string, pos: number ): Promise<[string, string]> => { + if ( + config.env.BASE_URL !== '/' && + url.startsWith(config.env.BASE_URL) + ) { + url = url.replace(config.env.BASE_URL, '/') + } + const resolved = await this.resolve(url, importer) if (!resolved) { @@ -197,6 +204,9 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin { // mark non-js/css imports with `?import` url = markExplicitImport(url) + // prepend base path without trailing slash ( default empty string ) + url = config.env.BASE_URL_NOSLASH + url + // for relative js/css imports, inherit importer's version query // do not do this for unknown type imports, otherwise the appended // query can break 3rd party plugin's extension checks. @@ -294,7 +304,7 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin { // If resolvable, let's resolve it if (dynamicIndex === -1 || isLiteralDynamicId) { // skip client - if (url === CLIENT_PUBLIC_PATH) { + if (url === config.env.BASE_URL_NOSLASH + CLIENT_PUBLIC_PATH) { continue } @@ -385,7 +395,9 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin { ) // inject hot context str().prepend( - `import { createHotContext as __vite__createHotContext } from "${CLIENT_PUBLIC_PATH}";` + + `import { createHotContext as __vite__createHotContext } from "${ + config.env.BASE_URL_NOSLASH + CLIENT_PUBLIC_PATH + }";` + `import.meta.hot = __vite__createHotContext(${JSON.stringify( importerModule.url )});` @@ -394,7 +406,9 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin { if (needQueryInjectHelper) { str().prepend( - `import { injectQuery as __vite__injectQuery } from "${CLIENT_PUBLIC_PATH}";` + `import { injectQuery as __vite__injectQuery } from "${ + config.env.BASE_URL_NOSLASH + CLIENT_PUBLIC_PATH + }";` ) } diff --git a/packages/vite/src/node/server/hmr.ts b/packages/vite/src/node/server/hmr.ts index d4a588cf3b94d4..ba9f928961f0be 100644 --- a/packages/vite/src/node/server/hmr.ts +++ b/packages/vite/src/node/server/hmr.ts @@ -48,8 +48,17 @@ export async function handleHMRUpdate( ) await server.close() ;(global as any).__vite_start_time = Date.now() - server = await createServer(config.inlineConfig) - await server.listen() + + try { + server = await createServer(config.inlineConfig) + await server.listen() + } catch (e) { + config.logger.error( + chalk.red(`error when starting dev server:\n${e.stack}`) + ) + process.exit(1) + } + return } diff --git a/packages/vite/src/node/server/index.ts b/packages/vite/src/node/server/index.ts index f57e19ad0a18d8..1f47989cfe6a20 100644 --- a/packages/vite/src/node/server/index.ts +++ b/packages/vite/src/node/server/index.ts @@ -17,6 +17,7 @@ import { import { FSWatcher, WatchOptions } from 'types/chokidar' import { resolveHttpsConfig } from '../server/https' import { createWebSocketServer, WebSocketServer } from '../server/ws' +import { baseMiddleware } from './middlewares/base' import { proxyMiddleware, ProxyOptions } from './middlewares/proxy' import { transformMiddleware } from './middlewares/transform' import { indexHtmlMiddleware } from './middlewares/indexHtml' @@ -105,6 +106,11 @@ export interface ServerOptions { * Create Vite dev server to be used as a middleware in an existing server */ middlewareMode?: boolean + /** + * Prepend this folder to http requests, for use when proxying vite as a subfolder + * Should start and end with the `/` character + */ + base?: string } /** @@ -291,6 +297,10 @@ export async function createServer( app.use(proxyMiddleware(server)) } + if (config.env.BASE_URL !== '/') { + app.use(baseMiddleware(server)) + } + // open in editor support app.use('/__open-in-editor', launchEditorMiddleware()) @@ -315,12 +325,7 @@ export async function createServer( { from: /\/$/, to({ parsedUrl }: any) { - const rewritten = parsedUrl.pathname + 'index.html' - if (fs.existsSync(path.join(root, rewritten))) { - return rewritten - } else { - return `/index.html` - } + return parsedUrl.pathname + 'index.html' } } ] @@ -414,8 +419,13 @@ async function startServer( let port = inlinePort || options.port || 3000 let hostname = options.host || 'localhost' const protocol = options.https ? 'https' : 'http' + const base = options.base || '/' const info = server.config.logger.info + if (!base.startsWith('/') || !base.endsWith('/')) { + throw new Error(`server.base must start and end with "/".`) + } + return new Promise((resolve, reject) => { const onError = (e: Error & { code?: string }) => { if (e.code === 'EADDRINUSE') { @@ -451,7 +461,7 @@ async function startServer( } }) .forEach(({ type, host }) => { - const url = `${protocol}://${host}:${chalk.bold(port)}/` + const url = `${protocol}://${host}:${chalk.bold(port)}${base}` info(` > ${type} ${chalk.cyan(url)}`) }) ) @@ -487,7 +497,7 @@ async function startServer( if (options.open) { openBrowser( - `${protocol}://${hostname}:${port}`, + `${protocol}://${hostname}:${port}${base}`, options.open, server.config.logger ) diff --git a/packages/vite/src/node/server/middlewares/base.ts b/packages/vite/src/node/server/middlewares/base.ts new file mode 100644 index 00000000000000..66879c806fa410 --- /dev/null +++ b/packages/vite/src/node/server/middlewares/base.ts @@ -0,0 +1,17 @@ +import { ViteDevServer } from '..' +import { Connect } from 'types/connect' + +export function baseMiddleware({ + config +}: ViteDevServer): Connect.NextHandleFunction { + const base = config.env.BASE_URL! + + return (req, res, next) => { + const url = req.url! + if (url.startsWith(base)) { + // rewrite url to remove base.. this ensures that other middleware does not need to consider base being prepended or not + req.url = url.replace(base, '/') + } + next() + } +} diff --git a/packages/vite/src/node/server/middlewares/indexHtml.ts b/packages/vite/src/node/server/middlewares/indexHtml.ts index ff76d6bdf886ac..8b04436a41dfda 100644 --- a/packages/vite/src/node/server/middlewares/indexHtml.ts +++ b/packages/vite/src/node/server/middlewares/indexHtml.ts @@ -14,9 +14,13 @@ import { send } from '../send' import { CLIENT_PUBLIC_PATH, FS_PREFIX } from '../../constants' import { cleanUrl } from '../../utils' -const devHtmlHook: IndexHtmlTransformHook = (html, { path }) => { +const devHtmlHook: IndexHtmlTransformHook = ( + html, + { path: filePath, server } +) => { let index = -1 const comments: string[] = [] + const base: string = server?.config.env.BASE_URL || '/' html = html .replace(htmlCommentRE, (m) => { @@ -27,7 +31,7 @@ const devHtmlHook: IndexHtmlTransformHook = (html, { path }) => { index++ if (script) { // convert inline ` + return `` } return _match }) @@ -36,9 +40,14 @@ const devHtmlHook: IndexHtmlTransformHook = (html, { path }) => { return { html, tags: [ + { + tag: 'base', + attrs: { href: path.join(base, path.dirname(filePath), '/') }, + injectTo: 'head-prepend' + }, { tag: 'script', - attrs: { type: 'module', src: CLIENT_PUBLIC_PATH }, + attrs: { type: 'module', src: path.join(base, CLIENT_PUBLIC_PATH) }, injectTo: 'head-prepend' } ] From d64a79c498205fbe10f88ab94434534fca2ed474 Mon Sep 17 00:00:00 2001 From: bompus Date: Thu, 14 Jan 2021 17:46:47 -0700 Subject: [PATCH 02/15] use relative paths for create-app templates --- packages/create-app/template-preact-ts/index.html | 2 +- packages/create-app/template-preact/index.html | 2 +- packages/create-app/template-react-ts/index.html | 2 +- packages/create-app/template-react/index.html | 2 +- packages/create-app/template-vanilla/index.html | 2 +- packages/create-app/template-vue-ts/index.html | 4 ++-- packages/create-app/template-vue/index.html | 4 ++-- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/create-app/template-preact-ts/index.html b/packages/create-app/template-preact-ts/index.html index 1c6e2a4173159b..2aa77f7d7bf9af 100644 --- a/packages/create-app/template-preact-ts/index.html +++ b/packages/create-app/template-preact-ts/index.html @@ -7,6 +7,6 @@
- + diff --git a/packages/create-app/template-preact/index.html b/packages/create-app/template-preact/index.html index 4afc194c17f59a..8ad43bfe491e7c 100644 --- a/packages/create-app/template-preact/index.html +++ b/packages/create-app/template-preact/index.html @@ -7,6 +7,6 @@
- + diff --git a/packages/create-app/template-react-ts/index.html b/packages/create-app/template-react-ts/index.html index f3cb3615318c9a..75c756235587d6 100644 --- a/packages/create-app/template-react-ts/index.html +++ b/packages/create-app/template-react-ts/index.html @@ -7,6 +7,6 @@
- + diff --git a/packages/create-app/template-react/index.html b/packages/create-app/template-react/index.html index a380e811bf0564..4ab2dc7dbd3545 100644 --- a/packages/create-app/template-react/index.html +++ b/packages/create-app/template-react/index.html @@ -7,6 +7,6 @@
- + diff --git a/packages/create-app/template-vanilla/index.html b/packages/create-app/template-vanilla/index.html index 60fd73fa5ae2d7..9d76af872457fa 100644 --- a/packages/create-app/template-vanilla/index.html +++ b/packages/create-app/template-vanilla/index.html @@ -7,6 +7,6 @@
- + diff --git a/packages/create-app/template-vue-ts/index.html b/packages/create-app/template-vue-ts/index.html index a508f2037dec8e..40b8a68c241d13 100644 --- a/packages/create-app/template-vue-ts/index.html +++ b/packages/create-app/template-vue-ts/index.html @@ -2,12 +2,12 @@ - + Vite App
- + diff --git a/packages/create-app/template-vue/index.html b/packages/create-app/template-vue/index.html index d49c18c6fb142f..54db60dd203b64 100644 --- a/packages/create-app/template-vue/index.html +++ b/packages/create-app/template-vue/index.html @@ -2,12 +2,12 @@ - + Vite App
- + From d65707d621c2ef574f0a40aaf191b696bae2503f Mon Sep 17 00:00:00 2001 From: bompus Date: Thu, 14 Jan 2021 23:28:01 -0700 Subject: [PATCH 03/15] hmr needs to know about config.server.base --- packages/vite/src/client/client.ts | 5 ++++- packages/vite/src/node/plugins/importAnalysis.ts | 2 +- packages/vite/src/node/server/hmr.ts | 1 + packages/vite/types/hmrPayload.d.ts | 1 + 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/vite/src/client/client.ts b/packages/vite/src/client/client.ts index 949145a2103d0b..c0c80fc09bf02b 100644 --- a/packages/vite/src/client/client.ts +++ b/packages/vite/src/client/client.ts @@ -258,7 +258,10 @@ export function removeStyle(id: string) { } } -async function fetchUpdate({ path, acceptedPath, timestamp }: Update) { +async function fetchUpdate({ base, path, acceptedPath, timestamp }: Update) { + path = base + path + acceptedPath = base + acceptedPath + const mod = hotModulesMap.get(path) if (!mod) { // In a code-splitting project, diff --git a/packages/vite/src/node/plugins/importAnalysis.ts b/packages/vite/src/node/plugins/importAnalysis.ts index 7af01ead6bf9f3..61cf0aeb98b8d0 100644 --- a/packages/vite/src/node/plugins/importAnalysis.ts +++ b/packages/vite/src/node/plugins/importAnalysis.ts @@ -399,7 +399,7 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin { config.env.BASE_URL_NOSLASH + CLIENT_PUBLIC_PATH }";` + `import.meta.hot = __vite__createHotContext(${JSON.stringify( - importerModule.url + config.env.BASE_URL_NOSLASH + importerModule.url )});` ) } diff --git a/packages/vite/src/node/server/hmr.ts b/packages/vite/src/node/server/hmr.ts index ba9f928961f0be..ca62a594ebfb70 100644 --- a/packages/vite/src/node/server/hmr.ts +++ b/packages/vite/src/node/server/hmr.ts @@ -135,6 +135,7 @@ export async function handleHMRUpdate( ...[...boundaries].map(({ boundary, acceptedVia }) => ({ type: `${boundary.type}-update` as Update['type'], timestamp, + base: config.env.BASE_URL_NOSLASH, path: boundary.url, acceptedPath: acceptedVia.url })) diff --git a/packages/vite/types/hmrPayload.d.ts b/packages/vite/types/hmrPayload.d.ts index 2fbed3a821466f..25790ba79a56b5 100644 --- a/packages/vite/types/hmrPayload.d.ts +++ b/packages/vite/types/hmrPayload.d.ts @@ -18,6 +18,7 @@ export interface UpdatePayload { export interface Update { type: 'js-update' | 'css-update' path: string + base: string acceptedPath: string timestamp: number } From d5f7adcbbf633b32620d681760f0f978e1922353 Mon Sep 17 00:00:00 2001 From: bompus Date: Thu, 14 Jan 2021 23:28:27 -0700 Subject: [PATCH 04/15] rewriteCssUrls needs to prepend based on config.server.base value --- packages/vite/src/node/plugins/css.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 01bce2d31a1c1f..90e10b6bf38df4 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -112,7 +112,7 @@ export function cssPlugin(config: ResolvedConfig): Plugin { thisModule.isSelfAccepting = isSelfAccepting } // rewrite urls using current module's url as base - css = await rewriteCssUrls(css, thisModule.url) + css = await rewriteCssUrls(css, thisModule.url, config.env.BASE_URL_NOSLASH) } else { // if build, analyze url() asset reference // account for comments https://github.com/vitejs/vite/issues/426 @@ -592,12 +592,13 @@ const cssUrlRE = /url\(\s*('[^']+'|"[^"]+"|[^'")]+)\s*\)/ function rewriteCssUrls( css: string, - replacerOrBase: string | Replacer + replacerOrBase: string | Replacer, + prependBase: string = '' ): Promise { let replacer: Replacer if (typeof replacerOrBase === 'string') { replacer = (rawUrl) => { - return path.posix.resolve(path.posix.dirname(replacerOrBase), rawUrl) + return prependBase + path.posix.resolve(path.posix.dirname(replacerOrBase), rawUrl) } } else { replacer = replacerOrBase From 59af59bc591b7b3995455a6d56064d112dddf0e1 Mon Sep 17 00:00:00 2001 From: bompus Date: Fri, 15 Jan 2021 23:44:57 +0000 Subject: [PATCH 05/15] feat: support base option during dev (#833) --- packages/create-app/template-preact-ts/index.html | 2 +- packages/create-app/template-preact/index.html | 2 +- packages/create-app/template-react-ts/index.html | 2 +- packages/create-app/template-react/index.html | 2 +- packages/create-app/template-vanilla/index.html | 2 +- packages/create-app/template-vue-ts/index.html | 4 ++-- packages/create-app/template-vue/index.html | 4 ++-- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/create-app/template-preact-ts/index.html b/packages/create-app/template-preact-ts/index.html index 2aa77f7d7bf9af..1c6e2a4173159b 100644 --- a/packages/create-app/template-preact-ts/index.html +++ b/packages/create-app/template-preact-ts/index.html @@ -7,6 +7,6 @@
- + diff --git a/packages/create-app/template-preact/index.html b/packages/create-app/template-preact/index.html index 8ad43bfe491e7c..4afc194c17f59a 100644 --- a/packages/create-app/template-preact/index.html +++ b/packages/create-app/template-preact/index.html @@ -7,6 +7,6 @@
- + diff --git a/packages/create-app/template-react-ts/index.html b/packages/create-app/template-react-ts/index.html index 75c756235587d6..f3cb3615318c9a 100644 --- a/packages/create-app/template-react-ts/index.html +++ b/packages/create-app/template-react-ts/index.html @@ -7,6 +7,6 @@
- + diff --git a/packages/create-app/template-react/index.html b/packages/create-app/template-react/index.html index 4ab2dc7dbd3545..a380e811bf0564 100644 --- a/packages/create-app/template-react/index.html +++ b/packages/create-app/template-react/index.html @@ -7,6 +7,6 @@
- + diff --git a/packages/create-app/template-vanilla/index.html b/packages/create-app/template-vanilla/index.html index 9d76af872457fa..60fd73fa5ae2d7 100644 --- a/packages/create-app/template-vanilla/index.html +++ b/packages/create-app/template-vanilla/index.html @@ -7,6 +7,6 @@
- + diff --git a/packages/create-app/template-vue-ts/index.html b/packages/create-app/template-vue-ts/index.html index 40b8a68c241d13..a508f2037dec8e 100644 --- a/packages/create-app/template-vue-ts/index.html +++ b/packages/create-app/template-vue-ts/index.html @@ -2,12 +2,12 @@ - + Vite App
- + diff --git a/packages/create-app/template-vue/index.html b/packages/create-app/template-vue/index.html index 54db60dd203b64..d49c18c6fb142f 100644 --- a/packages/create-app/template-vue/index.html +++ b/packages/create-app/template-vue/index.html @@ -2,12 +2,12 @@ - + Vite App
- + From 52069112a64b067a0cdb0159e17c7968345c9712 Mon Sep 17 00:00:00 2001 From: bompus Date: Sat, 16 Jan 2021 01:39:04 +0000 Subject: [PATCH 06/15] feat: support base option during dev (#833) --- docs/config/index.md | 14 +-- docs/guide/build.md | 2 +- docs/guide/env-and-mode.md | 2 +- .../assets/__tests__/assets.spec.ts | 6 +- packages/playground/assets/vite.config.js | 2 +- packages/plugin-vue/src/template.ts | 2 +- packages/vite/src/client/client.ts | 14 ++- packages/vite/src/node/build.ts | 3 +- packages/vite/src/node/cli.ts | 7 +- packages/vite/src/node/config.ts | 28 ++--- packages/vite/src/node/plugins/asset.ts | 4 +- .../vite/src/node/plugins/clientInjections.ts | 1 + packages/vite/src/node/plugins/css.ts | 9 +- packages/vite/src/node/plugins/html.ts | 32 +++--- .../vite/src/node/plugins/importAnalysis.ts | 22 ++-- packages/vite/src/node/server/hmr.ts | 1 - packages/vite/src/node/server/index.ts | 7 +- .../vite/src/node/server/middlewares/base.ts | 16 ++- .../src/node/server/middlewares/indexHtml.ts | 102 ++++++++++++++++-- packages/vite/types/hmrPayload.d.ts | 1 - scripts/jestPerTestSetup.ts | 7 +- 21 files changed, 194 insertions(+), 88 deletions(-) diff --git a/docs/config/index.md b/docs/config/index.md index 1c62c7f84a9a96..0ddb49454bc4c8 100644 --- a/docs/config/index.md +++ b/docs/config/index.md @@ -98,6 +98,13 @@ export default ({ command, mode }) => { See [Project Root](/guide/#project-root) for more details. +### base + +- **Type:** `string` +- **Default:** `/` + + Base public path when served in development or production. Note the path should start and end with `/`. See [Public Base Path](/guide/build#public-base-path) for more details. + ### mode - **Type:** `string` @@ -314,13 +321,6 @@ export default ({ command, mode }) => { ## Build Options -### build.base - -- **Type:** `string` -- **Default:** `/` - - Base public path when served in production. Note the path should start and end with `/`. See [Public Base Path](/guide/build#public-base-path) for more details. - ### build.target - **Type:** `string` diff --git a/docs/guide/build.md b/docs/guide/build.md index deff04cbc6b59f..80a5c94d9b327b 100644 --- a/docs/guide/build.md +++ b/docs/guide/build.md @@ -23,7 +23,7 @@ Legacy browsers can be supported via [@vitejs/plugin-legacy](https://github.com/ - Related: [Asset Handling](./features#asset-handling) -If you are deploying your project under a nested public path, simply specify the [`build.base` config option](/config/#build-base) and all asset paths will be rewritten accordingly. This option can also be specified as a command line flag, e.g. `vite build --base=/my/public/path/`. +If you are deploying your project under a nested public path, simply specify the [`base` config option](/config/#base) and all asset paths will be rewritten accordingly. This option can also be specified as a command line flag, e.g. `vite build --base=/my/public/path/`. JS-imported asset URLs, CSS `url()` references, and asset references in your `.html` files are all automatically adjusted to respect this option during build. diff --git a/docs/guide/env-and-mode.md b/docs/guide/env-and-mode.md index ab5db2b317e1a3..38bb1e118ccf34 100644 --- a/docs/guide/env-and-mode.md +++ b/docs/guide/env-and-mode.md @@ -6,7 +6,7 @@ Vite exposes env variables on the special **`import.meta.env`** object. Some bui - **`import.meta.env.MODE`**: {string} the [mode](#modes) the app is running in. -- **`import.meta.env.BASE_URL`**: {string} the base url the app is being served from. In development, this is always `/`. In production, this is determined by the [`build.base` config option](/config/#build-base). +- **`import.meta.env.BASE_URL`**: {string} the base url the app is being served from. This is determined by the [`base` config option](/config/#base). - **`import.meta.env.PROD`**: {boolean} whether the app is running in production. diff --git a/packages/playground/assets/__tests__/assets.spec.ts b/packages/playground/assets/__tests__/assets.spec.ts index c7250c43b8c23d..42c4a7b8724a6f 100644 --- a/packages/playground/assets/__tests__/assets.spec.ts +++ b/packages/playground/assets/__tests__/assets.spec.ts @@ -10,9 +10,9 @@ import { const assetMatch = isBuild ? /\/foo\/assets\/asset\.\w{8}\.png/ - : '/nested/asset.png' + : '/foo/nested/asset.png' -const iconMatch = isBuild ? `/foo/icon.png` : `icon.png` +const iconMatch = `/foo/icon.png` test('should have no 404s', () => { browserLogs.forEach((msg) => { @@ -66,7 +66,7 @@ describe('css url() references', () => { }) test('base64 inline', async () => { - const match = isBuild ? `data:image/png;base64` : `/icon.png` + const match = isBuild ? `data:image/png;base64` : `/foo/nested/icon.png` expect(await getBg('.css-url-base64-inline')).toMatch(match) expect(await getBg('.css-url-quotes-base64-inline')).toMatch(match) }) diff --git a/packages/playground/assets/vite.config.js b/packages/playground/assets/vite.config.js index 875c0cff93b254..9bfd9ac261a6c0 100644 --- a/packages/playground/assets/vite.config.js +++ b/packages/playground/assets/vite.config.js @@ -2,8 +2,8 @@ * @type {import('vite').UserConfig} */ module.exports = { + base: '/foo/', build: { - base: '/foo/', outDir: 'dist/foo' } } diff --git a/packages/plugin-vue/src/template.ts b/packages/plugin-vue/src/template.ts index edd9d1bf8d4128..39ea432aa1def8 100644 --- a/packages/plugin-vue/src/template.ts +++ b/packages/plugin-vue/src/template.ts @@ -105,7 +105,7 @@ export function resolveTemplateCompilerOptions( if (filename.startsWith(options.root)) { assetUrlOptions = { base: - options.devServer.config.env.BASE_URL + + options.devServer.config.base + slash(path.relative(options.root, path.dirname(filename))) } } diff --git a/packages/vite/src/client/client.ts b/packages/vite/src/client/client.ts index c0c80fc09bf02b..6af2ff8875792f 100644 --- a/packages/vite/src/client/client.ts +++ b/packages/vite/src/client/client.ts @@ -3,6 +3,7 @@ import { ErrorOverlay, overlayId } from './overlay' // injected by the hmr plugin when served declare const __ROOT__: string +declare const __BASE__: string declare const __MODE__: string declare const __DEFINES__: Record declare const __HMR_PROTOCOL__: string @@ -38,6 +39,8 @@ const socketProtocol = __HMR_PROTOCOL__ || (location.protocol === 'https:' ? 'wss' : 'ws') const socketHost = `${__HMR_HOSTNAME__ || location.hostname}:${__HMR_PORT__}` const socket = new WebSocket(`${socketProtocol}://${socketHost}`, 'vite-hmr') +const base = __BASE__ || '/' +const baseNoSlash = base.replace(/\/$/, '') function warnFailedFetch(err: Error, path: string | string[]) { if (!err.message.match('fetch')) { @@ -107,9 +110,10 @@ async function handleMessage(payload: HMRPayload) { // if html file is edited, only reload the page if the browser is // currently on that page. const pagePath = location.pathname + const payloadPath = baseNoSlash + payload.path if ( - pagePath === payload.path || - (pagePath.endsWith('/') && pagePath + 'index.html' === payload.path) + pagePath === payloadPath || + (pagePath.endsWith('/') && pagePath + 'index.html' === payloadPath) ) { location.reload() } @@ -258,9 +262,9 @@ export function removeStyle(id: string) { } } -async function fetchUpdate({ base, path, acceptedPath, timestamp }: Update) { - path = base + path - acceptedPath = base + acceptedPath +async function fetchUpdate({ path, acceptedPath, timestamp }: Update) { + path = baseNoSlash + path + acceptedPath = baseNoSlash + acceptedPath const mod = hotModulesMap.get(path) if (!mod) { diff --git a/packages/vite/src/node/build.ts b/packages/vite/src/node/build.ts index 2f0b1c285a8ebf..b659b557e06e19 100644 --- a/packages/vite/src/node/build.ts +++ b/packages/vite/src/node/build.ts @@ -160,10 +160,11 @@ export interface LibraryOptions { export type LibraryFormats = 'es' | 'cjs' | 'umd' | 'iife' export function resolveBuildOptions( + base: string, raw?: BuildOptions ): Required { const resolved: Required = { - base: '/', + base: base || '/', target: 'modules', polyfillDynamicImport: raw?.target !== 'esnext' && !raw?.lib, outDir: 'dist', diff --git a/packages/vite/src/node/cli.ts b/packages/vite/src/node/cli.ts index c3fdf6862f08b6..808aa6ecee347e 100644 --- a/packages/vite/src/node/cli.ts +++ b/packages/vite/src/node/cli.ts @@ -17,6 +17,7 @@ interface GlobalCLIOptions { config?: string c?: boolean | string root?: string + base?: string r?: string mode?: string m?: string @@ -38,6 +39,7 @@ function cleanOptions(options: GlobalCLIOptions) { delete ret.config delete ret.c delete ret.root + delete ret.base delete ret.r delete ret.mode delete ret.m @@ -50,6 +52,7 @@ function cleanOptions(options: GlobalCLIOptions) { cli .option('-c, --config ', `[string] use specified config file`) .option('-r, --root ', `[string] use specified root directory`) + .option('--base ', `[string] public base path (default: /)`) .option('-l, --logLevel ', `[string] silent | error | warn | all`) .option('--clearScreen', `[boolean] allow/disable clear screen when logging`) .option('-d, --debug [feat]', `[string | boolean] show debug logs`) @@ -77,6 +80,7 @@ cli try { const server = await createServer({ root, + base: options.base, mode: options.mode, configFile: options.config, logLevel: options.logLevel, @@ -95,7 +99,6 @@ cli // build cli .command('build [root]') - .option('--base ', `[string] public base path (default: /)`) .option('--target ', `[string] transpile target (default: 'modules')`) .option('--outDir ', `[string] output directory (default: dist)`) .option( @@ -127,6 +130,7 @@ cli try { await build({ root, + base: options.base, mode: options.mode, configFile: options.config, logLevel: options.logLevel, @@ -155,6 +159,7 @@ cli const config = await resolveConfig( { root, + base: options.base, configFile: options.config, logLevel: options.logLevel }, diff --git a/packages/vite/src/node/config.ts b/packages/vite/src/node/config.ts index 6b16c0c02a4e02..8cb5b0c258332d 100644 --- a/packages/vite/src/node/config.ts +++ b/packages/vite/src/node/config.ts @@ -102,6 +102,11 @@ export interface UserConfig { * Default: true */ clearScreen?: boolean + /** + * Base public path when served in development or production. + * @default '/' + */ + base?: string } export interface InlineConfig extends UserConfig { @@ -124,6 +129,7 @@ export type ResolvedConfig = Readonly< build: Required assetsInclude: (file: string) => boolean logger: Logger + base: string } > @@ -203,7 +209,8 @@ export async function resolveConfig( process.env.NODE_ENV = 'production' } - const resolvedBuildOptions = resolveBuildOptions(config.build) + const BASE_URL = config.base || '/' + const resolvedBuildOptions = resolveBuildOptions(BASE_URL, config.build) // resolve optimizer cache directory const pkgPath = lookupFile( @@ -218,17 +225,10 @@ export async function resolveConfig( ? createFilter(config.assetsInclude) : () => false - const serverBase = config.server?.base || '/' - const BASE_URL = command === 'build' ? resolvedBuildOptions.base : serverBase - const trailingSlashRE = /\/$/ - - let hmr = undefined - if (serverBase !== '/') { - hmr = config.server?.hmr === true ? {} : config.server?.hmr - hmr = { - ...hmr, - path: BASE_URL !== '/' ? BASE_URL.substr(1) : undefined - } + let hmr = config.server?.hmr === true ? {} : config.server?.hmr + hmr = { + ...hmr, + path: BASE_URL !== '/' ? BASE_URL.substr(1) : undefined } const server = { @@ -252,7 +252,6 @@ export async function resolveConfig( env: { ...userEnv, BASE_URL, - BASE_URL_NOSLASH: BASE_URL.replace(trailingSlashRE, ''), MODE: mode, DEV: !isProduction, PROD: isProduction @@ -260,7 +259,8 @@ export async function resolveConfig( assetsInclude(file: string) { return DEFAULT_ASSETS_RE.test(file) || assetsFilter(file) }, - logger: createLogger(config.logLevel, config.clearScreen) + logger: createLogger(config.logLevel, config.clearScreen), + base: BASE_URL } resolved.plugins = await resolvePlugins( diff --git a/packages/vite/src/node/plugins/asset.ts b/packages/vite/src/node/plugins/asset.ts index 649eca1995b89d..99328e05a40764 100644 --- a/packages/vite/src/node/plugins/asset.ts +++ b/packages/vite/src/node/plugins/asset.ts @@ -104,7 +104,7 @@ export function fileToUrl( } } -function fileToDevUrl(id: string, { root, env }: ResolvedConfig) { +function fileToDevUrl(id: string, { root, base }: ResolvedConfig) { let rtn: string if (checkPublicFile(id, root)) { @@ -119,7 +119,7 @@ function fileToDevUrl(id: string, { root, env }: ResolvedConfig) { rtn = FS_PREFIX + id } - return env.BASE_URL_NOSLASH + rtn + return path.posix.join(base, rtn) } const assetCache = new WeakMap>() diff --git a/packages/vite/src/node/plugins/clientInjections.ts b/packages/vite/src/node/plugins/clientInjections.ts index d4913fe770d14c..ed21e81fb0b9cc 100644 --- a/packages/vite/src/node/plugins/clientInjections.ts +++ b/packages/vite/src/node/plugins/clientInjections.ts @@ -37,6 +37,7 @@ export function clientInjectionsPlugin(config: ResolvedConfig): Plugin { return code .replace(`__MODE__`, JSON.stringify(config.mode)) + .replace(`__BASE__`, JSON.stringify(config.base)) .replace(`__ROOT__`, JSON.stringify(config.root)) .replace(`__DEFINES__`, JSON.stringify(config.define || {})) .replace(`__HMR_PROTOCOL__`, JSON.stringify(protocol)) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 90e10b6bf38df4..c9a9d82cec383b 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -112,7 +112,7 @@ export function cssPlugin(config: ResolvedConfig): Plugin { thisModule.isSelfAccepting = isSelfAccepting } // rewrite urls using current module's url as base - css = await rewriteCssUrls(css, thisModule.url, config.env.BASE_URL_NOSLASH) + css = await rewriteCssUrls(css, thisModule.url, config.base) } else { // if build, analyze url() asset reference // account for comments https://github.com/vitejs/vite/issues/426 @@ -157,7 +157,7 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin { // server only return [ `import { updateStyle, removeStyle } from ${JSON.stringify( - config.env.BASE_URL_NOSLASH + CLIENT_PUBLIC_PATH + path.posix.join(config.base, CLIENT_PUBLIC_PATH) )}`, `const id = ${JSON.stringify(id)}`, `const css = ${JSON.stringify(css)}`, @@ -598,7 +598,10 @@ function rewriteCssUrls( let replacer: Replacer if (typeof replacerOrBase === 'string') { replacer = (rawUrl) => { - return prependBase + path.posix.resolve(path.posix.dirname(replacerOrBase), rawUrl) + return path.posix.join( + prependBase, + path.posix.resolve(path.posix.dirname(replacerOrBase), rawUrl) + ) } } else { replacer = replacerOrBase diff --git a/packages/vite/src/node/plugins/html.ts b/packages/vite/src/node/plugins/html.ts index f428bfe751789b..2fa89f25321d65 100644 --- a/packages/vite/src/node/plugins/html.ts +++ b/packages/vite/src/node/plugins/html.ts @@ -48,8 +48,21 @@ export function htmlPlugin(): Plugin { } } +export function formatParseError(e: any, id: string, html: string): Error { + // normalize the error to rollup format + if (e.loc) { + e.frame = generateCodeFrame(html, e.loc.start.offset) + e.loc = { + file: id, + line: e.loc.start.line, + column: e.loc.start.column + } + } + return e +} + // this extends the config in @vue/compiler-sfc with -const assetAttrsConfig: Record = { +export const assetAttrsConfig: Record = { link: ['href'], video: ['src', 'poster'], source: ['src'], @@ -76,19 +89,6 @@ export function buildHtmlPlugin(config: ResolvedConfig): Plugin { // pre-transform html = await applyHtmlTransforms(html, publicPath, id, preHooks) - function formatError(e: any): Error { - // normalize the error to rollup format - if (e.loc) { - e.frame = generateCodeFrame(html, e.loc.start.offset) - e.loc = { - file: id, - line: e.loc.start.line, - column: e.loc.start.column - } - } - return e - } - // lazy load compiler-dom const { parse, transform } = await import('@vue/compiler-dom') // @vue/compiler-core doesn't like lowercase doctypes @@ -97,7 +97,7 @@ export function buildHtmlPlugin(config: ResolvedConfig): Plugin { try { ast = parse(html, { comments: true }) } catch (e) { - this.error(formatError(e)) + this.error(formatParseError(e, id, html)) } let js = '' @@ -189,7 +189,7 @@ export function buildHtmlPlugin(config: ResolvedConfig): Plugin { nodeTransforms: [viteHtmlTransform] }) } catch (e) { - this.error(formatError(e)) + this.error(formatParseError(e, id, html)) } // for each encountered asset url, rewrite original html so that it diff --git a/packages/vite/src/node/plugins/importAnalysis.ts b/packages/vite/src/node/plugins/importAnalysis.ts index 61cf0aeb98b8d0..c0e085c8bdb497 100644 --- a/packages/vite/src/node/plugins/importAnalysis.ts +++ b/packages/vite/src/node/plugins/importAnalysis.ts @@ -83,6 +83,7 @@ function markExplicitImport(url: string) { * ``` */ export function importAnalysisPlugin(config: ResolvedConfig): Plugin { + const clientPublicPath = path.posix.join(config.base, CLIENT_PUBLIC_PATH) let server: ViteDevServer return { @@ -159,11 +160,8 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin { url: string, pos: number ): Promise<[string, string]> => { - if ( - config.env.BASE_URL !== '/' && - url.startsWith(config.env.BASE_URL) - ) { - url = url.replace(config.env.BASE_URL, '/') + if (config.base !== '/' && url.startsWith(config.base)) { + url = url.replace(config.base, '/') } const resolved = await this.resolve(url, importer) @@ -205,7 +203,7 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin { url = markExplicitImport(url) // prepend base path without trailing slash ( default empty string ) - url = config.env.BASE_URL_NOSLASH + url + url = path.posix.join(config.base, url) // for relative js/css imports, inherit importer's version query // do not do this for unknown type imports, otherwise the appended @@ -304,7 +302,7 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin { // If resolvable, let's resolve it if (dynamicIndex === -1 || isLiteralDynamicId) { // skip client - if (url === config.env.BASE_URL_NOSLASH + CLIENT_PUBLIC_PATH) { + if (url === clientPublicPath) { continue } @@ -395,20 +393,16 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin { ) // inject hot context str().prepend( - `import { createHotContext as __vite__createHotContext } from "${ - config.env.BASE_URL_NOSLASH + CLIENT_PUBLIC_PATH - }";` + + `import { createHotContext as __vite__createHotContext } from "${clientPublicPath}";` + `import.meta.hot = __vite__createHotContext(${JSON.stringify( - config.env.BASE_URL_NOSLASH + importerModule.url + path.posix.join(config.base, importerModule.url) )});` ) } if (needQueryInjectHelper) { str().prepend( - `import { injectQuery as __vite__injectQuery } from "${ - config.env.BASE_URL_NOSLASH + CLIENT_PUBLIC_PATH - }";` + `import { injectQuery as __vite__injectQuery } from "${clientPublicPath}";` ) } diff --git a/packages/vite/src/node/server/hmr.ts b/packages/vite/src/node/server/hmr.ts index ca62a594ebfb70..ba9f928961f0be 100644 --- a/packages/vite/src/node/server/hmr.ts +++ b/packages/vite/src/node/server/hmr.ts @@ -135,7 +135,6 @@ export async function handleHMRUpdate( ...[...boundaries].map(({ boundary, acceptedVia }) => ({ type: `${boundary.type}-update` as Update['type'], timestamp, - base: config.env.BASE_URL_NOSLASH, path: boundary.url, acceptedPath: acceptedVia.url })) diff --git a/packages/vite/src/node/server/index.ts b/packages/vite/src/node/server/index.ts index 20bae1624876be..d17f70298511b1 100644 --- a/packages/vite/src/node/server/index.ts +++ b/packages/vite/src/node/server/index.ts @@ -305,7 +305,8 @@ export async function createServer( app.use(proxyMiddleware(server)) } - if (config.env.BASE_URL !== '/') { + // base + if (config.base !== '/') { app.use(baseMiddleware(server)) } @@ -427,11 +428,11 @@ async function startServer( let port = inlinePort || options.port || 3000 let hostname = options.host || 'localhost' const protocol = options.https ? 'https' : 'http' - const base = options.base || '/' const info = server.config.logger.info + const base = server.config.base if (!base.startsWith('/') || !base.endsWith('/')) { - throw new Error(`server.base must start and end with "/".`) + throw new Error(`"base" must start and end with "/".`) } return new Promise((resolve, reject) => { diff --git a/packages/vite/src/node/server/middlewares/base.ts b/packages/vite/src/node/server/middlewares/base.ts index 66879c806fa410..6bf124a1a4b073 100644 --- a/packages/vite/src/node/server/middlewares/base.ts +++ b/packages/vite/src/node/server/middlewares/base.ts @@ -1,17 +1,29 @@ +import { parse as parseUrl } from 'url' import { ViteDevServer } from '..' import { Connect } from 'types/connect' +// this middleware is only active when (config.base !== '/') + export function baseMiddleware({ config }: ViteDevServer): Connect.NextHandleFunction { - const base = config.env.BASE_URL! + const base = config.base return (req, res, next) => { const url = req.url! - if (url.startsWith(base)) { + const parsed = parseUrl(url) + const path = parsed.pathname || '/' + + if (path.startsWith(base)) { // rewrite url to remove base.. this ensures that other middleware does not need to consider base being prepended or not req.url = url.replace(base, '/') + } else if (path === '/' || path === '/index.html') { + // to prevent confusion, do not allow access at / if we have specified a base path + res.statusCode = 404 + res.end() + return } + next() } } diff --git a/packages/vite/src/node/server/middlewares/indexHtml.ts b/packages/vite/src/node/server/middlewares/indexHtml.ts index 8b04436a41dfda..7484931cd5a9fb 100644 --- a/packages/vite/src/node/server/middlewares/indexHtml.ts +++ b/packages/vite/src/node/server/middlewares/indexHtml.ts @@ -1,5 +1,13 @@ import fs from 'fs' import path from 'path' +import MagicString from 'magic-string' +import { + AttributeNode, + NodeTransform, + NodeTypes, + parse, + transform +} from '@vue/compiler-dom' import { Connect } from 'types/connect' import { Plugin } from '../../plugin' import { @@ -13,14 +21,16 @@ import { ViteDevServer } from '../..' import { send } from '../send' import { CLIENT_PUBLIC_PATH, FS_PREFIX } from '../../constants' import { cleanUrl } from '../../utils' +import { assetAttrsConfig, formatParseError } from '../../plugins/html' -const devHtmlHook: IndexHtmlTransformHook = ( +const devHtmlHook: IndexHtmlTransformHook = async ( html, { path: filePath, server } ) => { let index = -1 const comments: string[] = [] - const base: string = server?.config.env.BASE_URL || '/' + const config = server?.config! + const base = config.base || '/' html = html .replace(htmlCommentRE, (m) => { @@ -36,18 +46,94 @@ const devHtmlHook: IndexHtmlTransformHook = ( return _match }) .replace(//g, (_, i) => comments[i]) + // @vue/compiler-core doesn't like lowercase doctypes + .replace(/ { + if (node.type !== NodeTypes.ELEMENT) { + return + } + + // script tags + if (node.tag === 'script') { + const srcAttr = node.props.find( + (p) => p.type === NodeTypes.ATTRIBUTE && p.name === 'src' + ) as AttributeNode + + const url = srcAttr?.value?.content || '' + if (url.startsWith('/')) { + // prefix with base + s.overwrite( + srcAttr.value!.loc.start.offset, + srcAttr.value!.loc.end.offset, + config.base + url.slice(1) + ) + } + } + + // elements with [href/src] attrs + const assetAttrs = assetAttrsConfig[node.tag] + if (assetAttrs) { + for (const p of node.props) { + if ( + p.type === NodeTypes.ATTRIBUTE && + p.value && + assetAttrs.includes(p.name) + ) { + const url = p.value.content || '' + if (url.startsWith('/')) { + s.overwrite( + p.value.loc.start.offset, + p.value.loc.end.offset, + config.base + url.slice(1) + ) + } + } + } + } + } + + try { + transform(ast, { + nodeTransforms: [viteDevIndexHtmlTransform] + }) + } catch (e) { + const parseError = { + loc: filePath, + frame: '', + ...formatParseError(e, filePath, html) + } + throw new Error( + `Unable to parse ${JSON.stringify(parseError.loc)}\n${parseError.frame}` + ) + } + + html = s.toString() return { html, tags: [ - { - tag: 'base', - attrs: { href: path.join(base, path.dirname(filePath), '/') }, - injectTo: 'head-prepend' - }, { tag: 'script', - attrs: { type: 'module', src: path.join(base, CLIENT_PUBLIC_PATH) }, + attrs: { + type: 'module', + src: path.posix.join(base, CLIENT_PUBLIC_PATH) + }, injectTo: 'head-prepend' } ] diff --git a/packages/vite/types/hmrPayload.d.ts b/packages/vite/types/hmrPayload.d.ts index 25790ba79a56b5..2fbed3a821466f 100644 --- a/packages/vite/types/hmrPayload.d.ts +++ b/packages/vite/types/hmrPayload.d.ts @@ -18,7 +18,6 @@ export interface UpdatePayload { export interface Update { type: 'js-update' | 'css-update' path: string - base: string acceptedPath: string timestamp: number } diff --git a/scripts/jestPerTestSetup.ts b/scripts/jestPerTestSetup.ts index dc7c6b28ca7bdd..b2cbfed0cbc51f 100644 --- a/scripts/jestPerTestSetup.ts +++ b/scripts/jestPerTestSetup.ts @@ -66,8 +66,9 @@ beforeAll(async () => { if (!isBuildTest) { process.env.VITE_INLINE = 'inline-serve' server = await (await createServer(options)).listen() - // use resolved port from server - const url = ((global as any).viteTestUrl = `http://localhost:${server.config.server.port}`) + // use resolved port/base from server + const base = server.config.base === '/' ? '' : server.config.base + const url = ((global as any).viteTestUrl = `http://localhost:${server.config.server.port}${base}`) await page.goto(url) } else { process.env.VITE_INLINE = 'inline-build' @@ -100,7 +101,7 @@ function startStaticServer(): Promise { try { config = require(configFile) } catch (e) {} - const base = config?.build?.base || '' + const base = (config?.base || '/') === '/' ? '' : config.base // @ts-ignore if (config && config.__test__) { From a1d2676e2d692c50a368f14c91efed21339be758 Mon Sep 17 00:00:00 2001 From: bompus Date: Mon, 18 Jan 2021 18:01:20 +0000 Subject: [PATCH 07/15] test: assets - add describe for injected scripts --- .../assets/__tests__/assets.spec.ts | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/packages/playground/assets/__tests__/assets.spec.ts b/packages/playground/assets/__tests__/assets.spec.ts index 42c4a7b8724a6f..bdfaff5ffc4fb3 100644 --- a/packages/playground/assets/__tests__/assets.spec.ts +++ b/packages/playground/assets/__tests__/assets.spec.ts @@ -20,6 +20,30 @@ test('should have no 404s', () => { }) }) +describe('injected scripts', () => { + test('@vite/client', async () => { + const hasClient = await page.$( + 'script[type="module"][src="/foo/@vite/client"]' + ) + if (isBuild) { + expect(hasClient).toBeFalsy() + } else { + expect(hasClient).toBeTruthy() + } + }) + + test('html-proxy', async () => { + const hasHtmlProxy = await page.$( + 'script[type="module"][src="/foo/index.html?html-proxy&index=0.js"]' + ) + if (isBuild) { + expect(hasHtmlProxy).toBeFalsy() + } else { + expect(hasHtmlProxy).toBeTruthy() + } + }) +}) + describe('raw references from /public', () => { test('load raw js from /public', async () => { expect(await page.textContent('.raw-js')).toMatch('[success]') From c27d9a0f0d8996ae643dbdcd5236872da9e6b189 Mon Sep 17 00:00:00 2001 From: bompus Date: Thu, 21 Jan 2021 17:58:47 +0000 Subject: [PATCH 08/15] chore: refactor due to upstream changes --- packages/vite/src/node/server/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vite/src/node/server/index.ts b/packages/vite/src/node/server/index.ts index 07ed872e416780..2123572e0eb39d 100644 --- a/packages/vite/src/node/server/index.ts +++ b/packages/vite/src/node/server/index.ts @@ -378,7 +378,7 @@ export async function createServer( // base if (config.base !== '/') { - app.use(baseMiddleware(server)) + middlewares.use(baseMiddleware(server)) } // open in editor support From f6095d332a8a2b0d7c4f0aecb9ae89d7d8a7561e Mon Sep 17 00:00:00 2001 From: bompus Date: Fri, 22 Jan 2021 17:49:17 +0000 Subject: [PATCH 09/15] chore: rebased for 52ae44f --- packages/vite/src/node/plugins/css.ts | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index ada4308832c116..1ecf9aef7cee17 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -100,15 +100,20 @@ export function cssPlugin(config: ResolvedConfig): Plugin { const urlReplacer: CssUrlReplacer = server ? (url, importer) => { - if (url.startsWith('/')) return url - const filePath = normalizePath( - path.resolve(path.dirname(importer || id), url) - ) - if (filePath.startsWith(config.root)) { - return filePath.slice(config.root.length) + let rtn: string + + if (url.startsWith('/')) { + rtn = url } else { - return `${FS_PREFIX}${filePath}` + const filePath = normalizePath( + path.resolve(path.dirname(importer || id), url) + ) + rtn = filePath.startsWith(config.root) + ? filePath.slice(config.root.length) + : `${FS_PREFIX}${filePath}` } + + return path.posix.join(config.base, rtn) } : (url, importer) => { return urlToBuiltUrl(url, importer || id, config, this) From f92c0ce78a7157238b7f40743c7d33ed3225e058 Mon Sep 17 00:00:00 2001 From: Evan You Date: Fri, 22 Jan 2021 16:02:05 -0500 Subject: [PATCH 10/15] chore: fix wrong merge --- packages/vite/src/node/server/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/vite/src/node/server/index.ts b/packages/vite/src/node/server/index.ts index 45abee94ba4acb..5e3bdd5ed4b308 100644 --- a/packages/vite/src/node/server/index.ts +++ b/packages/vite/src/node/server/index.ts @@ -407,6 +407,7 @@ export async function createServer( from: /\/$/, to({ parsedUrl }: any) { return parsedUrl.pathname + 'index.html' + } } ] }) From 1697eeb5a7fc07537a71535416e504e88f15c0c2 Mon Sep 17 00:00:00 2001 From: Evan You Date: Fri, 22 Jan 2021 16:14:53 -0500 Subject: [PATCH 11/15] fix: lazy import @vue/compiler-dom --- packages/vite/src/node/server/middlewares/indexHtml.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/packages/vite/src/node/server/middlewares/indexHtml.ts b/packages/vite/src/node/server/middlewares/indexHtml.ts index 7484931cd5a9fb..122ff64b56674e 100644 --- a/packages/vite/src/node/server/middlewares/indexHtml.ts +++ b/packages/vite/src/node/server/middlewares/indexHtml.ts @@ -1,13 +1,7 @@ import fs from 'fs' import path from 'path' import MagicString from 'magic-string' -import { - AttributeNode, - NodeTransform, - NodeTypes, - parse, - transform -} from '@vue/compiler-dom' +import { AttributeNode, NodeTransform, NodeTypes } from '@vue/compiler-dom' import { Connect } from 'types/connect' import { Plugin } from '../../plugin' import { @@ -49,6 +43,8 @@ const devHtmlHook: IndexHtmlTransformHook = async ( // @vue/compiler-core doesn't like lowercase doctypes .replace(/ Date: Fri, 22 Jan 2021 16:19:30 -0500 Subject: [PATCH 12/15] refactor: move base validation to resolveConfig --- packages/vite/src/node/config.ts | 4 ++++ packages/vite/src/node/server/index.ts | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/vite/src/node/config.ts b/packages/vite/src/node/config.ts index e4001b6ae440c4..47e7132f8e9440 100644 --- a/packages/vite/src/node/config.ts +++ b/packages/vite/src/node/config.ts @@ -225,6 +225,10 @@ export async function resolveConfig( } const BASE_URL = config.base || '/' + if (!BASE_URL.startsWith('/') || !BASE_URL.endsWith('/')) { + throw new Error(`config error: "base" must start and end with "/".`) + } + const resolvedBuildOptions = resolveBuildOptions(BASE_URL, config.build) // resolve optimizer cache directory diff --git a/packages/vite/src/node/server/index.ts b/packages/vite/src/node/server/index.ts index 5e3bdd5ed4b308..f0e81b27737506 100644 --- a/packages/vite/src/node/server/index.ts +++ b/packages/vite/src/node/server/index.ts @@ -507,10 +507,6 @@ async function startServer( const info = server.config.logger.info const base = server.config.base - if (!base.startsWith('/') || !base.endsWith('/')) { - throw new Error(`"base" must start and end with "/".`) - } - return new Promise((resolve, reject) => { const onError = (e: Error & { code?: string }) => { if (e.code === 'EADDRINUSE') { From 9c7d5f4f68577a330b595b27b39becd725645d84 Mon Sep 17 00:00:00 2001 From: Evan You Date: Fri, 22 Jan 2021 17:06:24 -0500 Subject: [PATCH 13/15] refactor: reuse html traverse logic between dev and build --- packages/vite/src/node/plugins/html.ts | 121 +++++++++++------- packages/vite/src/node/plugins/index.ts | 4 +- .../src/node/server/middlewares/indexHtml.ts | 98 +++++--------- 3 files changed, 105 insertions(+), 118 deletions(-) diff --git a/packages/vite/src/node/plugins/html.ts b/packages/vite/src/node/plugins/html.ts index 2fa89f25321d65..803f9998d8680d 100644 --- a/packages/vite/src/node/plugins/html.ts +++ b/packages/vite/src/node/plugins/html.ts @@ -10,14 +10,20 @@ import MagicString from 'magic-string' import { checkPublicFile, assetUrlRE, urlToBuiltUrl } from './asset' import { isCSSRequest, chunkToEmittedCssFileMap } from './css' import { polyfillId } from './dynamicImportPolyfill' -import { AttributeNode, NodeTransform, NodeTypes } from '@vue/compiler-dom' +import { + AttributeNode, + NodeTransform, + NodeTypes, + ElementNode +} from '@vue/compiler-dom' const htmlProxyRE = /\?html-proxy&index=(\d+)\.js$/ export const isHTMLProxy = (id: string) => htmlProxyRE.test(id) -export const htmlCommentRE = //g -export const scriptModuleRE = /(]*type\s*=\s*(?:"module"|'module')[^>]*>)([\s\S]*?)<\/script>/gm -export function htmlPlugin(): Plugin { +const htmlCommentRE = //g +const scriptModuleRE = /(]*type\s*=\s*(?:"module"|'module')[^>]*>)([\s\S]*?)<\/script>/gm + +export function htmlInlineScriptProxyPlugin(): Plugin { return { name: 'vite:html', @@ -48,7 +54,59 @@ export function htmlPlugin(): Plugin { } } -export function formatParseError(e: any, id: string, html: string): Error { +// this extends the config in @vue/compiler-sfc with +export const assetAttrsConfig: Record = { + link: ['href'], + video: ['src', 'poster'], + source: ['src'], + img: ['src'], + image: ['xlink:href', 'href'], + use: ['xlink:href', 'href'] +} + +export async function traverseHtml( + html: string, + filePath: string, + visitor: NodeTransform +) { + // lazy load compiler + const { parse, transform } = await import('@vue/compiler-dom') + // @vue/compiler-core doesn't like lowercase doctypes + html = html.replace(/ -export const assetAttrsConfig: Record = { - link: ['href'], - video: ['src', 'poster'], - source: ['src'], - img: ['src'], - image: ['xlink:href', 'href'], - use: ['xlink:href', 'href'] -} - /** * Compiles index.html into an entry js module */ @@ -89,22 +137,12 @@ export function buildHtmlPlugin(config: ResolvedConfig): Plugin { // pre-transform html = await applyHtmlTransforms(html, publicPath, id, preHooks) - // lazy load compiler-dom - const { parse, transform } = await import('@vue/compiler-dom') - // @vue/compiler-core doesn't like lowercase doctypes - html = html.replace(/ { + + await traverseHtml(html, id, (node) => { if (node.type !== NodeTypes.ELEMENT) { return } @@ -113,26 +151,19 @@ export function buildHtmlPlugin(config: ResolvedConfig): Plugin { // script tags if (node.tag === 'script') { - const srcAttr = node.props.find( - (p) => p.type === NodeTypes.ATTRIBUTE && p.name === 'src' - ) as AttributeNode - const typeAttr = node.props.find( - (p) => p.type === NodeTypes.ATTRIBUTE && p.name === 'type' - ) as AttributeNode - const isJsModule = - typeAttr && typeAttr.value && typeAttr.value.content === 'module' - - const url = srcAttr && srcAttr.value && srcAttr.value.content + const { src, isModule } = getScriptInfo(node) + + const url = src && src.value && src.value.content if (url && checkPublicFile(url, config.root)) { // referencing public dir url, prefix with base s.overwrite( - srcAttr.value!.loc.start.offset, - srcAttr.value!.loc.end.offset, + src!.value!.loc.start.offset, + src!.value!.loc.end.offset, config.build.base + url.slice(1) ) } - if (isJsModule) { + if (isModule) { inlineModuleIndex++ if (url && !isExcludedUrl(url)) { // ` - } - return _match - }) - .replace(//g, (_, i) => comments[i]) - // @vue/compiler-core doesn't like lowercase doctypes - .replace(/ { + let scriptModuleIndex = -1 + + await traverseHtml(html, htmlPath, (node) => { if (node.type !== NodeTypes.ELEMENT) { return } // script tags if (node.tag === 'script') { - const srcAttr = node.props.find( - (p) => p.type === NodeTypes.ATTRIBUTE && p.name === 'src' - ) as AttributeNode + const { src, isModule } = getScriptInfo(node) + if (isModule) { + scriptModuleIndex++ + } - const url = srcAttr?.value?.content || '' - if (url.startsWith('/')) { - // prefix with base + if (src) { + const url = src.value?.content || '' + if (url.startsWith('/')) { + // prefix with base + s.overwrite( + src.value!.loc.start.offset, + src.value!.loc.end.offset, + `"${config.base + url.slice(1)}"` + ) + } + } else if (isModule) { + // inline js module. convert to src="proxy" s.overwrite( - srcAttr.value!.loc.start.offset, - srcAttr.value!.loc.end.offset, - config.base + url.slice(1) + node.loc.start.offset, + node.loc.end.offset, + `` ) } } @@ -96,28 +75,13 @@ const devHtmlHook: IndexHtmlTransformHook = async ( s.overwrite( p.value.loc.start.offset, p.value.loc.end.offset, - config.base + url.slice(1) + `"${config.base + url.slice(1)}"` ) } } } } - } - - try { - transform(ast, { - nodeTransforms: [viteDevIndexHtmlTransform] - }) - } catch (e) { - const parseError = { - loc: filePath, - frame: '', - ...formatParseError(e, filePath, html) - } - throw new Error( - `Unable to parse ${JSON.stringify(parseError.loc)}\n${parseError.frame}` - ) - } + }) html = s.toString() From 5a133534d0ba727c0219ca31c63e924f4cb0e218 Mon Sep 17 00:00:00 2001 From: Evan You Date: Fri, 22 Jan 2021 17:30:05 -0500 Subject: [PATCH 14/15] refactor: depreacte build.base --- packages/plugin-legacy/index.js | 6 +-- packages/vite/src/node/build.ts | 15 +++---- packages/vite/src/node/config.ts | 44 ++++++++++++++++--- packages/vite/src/node/logger.ts | 7 ++- packages/vite/src/node/plugins/asset.ts | 6 +-- packages/vite/src/node/plugins/css.ts | 2 +- .../src/node/plugins/dynamicImportPolyfill.ts | 2 +- packages/vite/src/node/plugins/html.ts | 8 ++-- .../src/node/plugins/importAnaysisBuild.ts | 4 +- packages/vite/src/node/server/index.ts | 4 +- .../vite/src/node/ssr/ssrManifestPlugin.ts | 2 +- 11 files changed, 68 insertions(+), 32 deletions(-) diff --git a/packages/plugin-legacy/index.js b/packages/plugin-legacy/index.js index 77f840cc811e99..4a3c90a47c4f2e 100644 --- a/packages/plugin-legacy/index.js +++ b/packages/plugin-legacy/index.js @@ -265,7 +265,7 @@ function viteLegacyPlugin(options = {}) { tag: 'script', attrs: { type: 'module', - src: `${config.build.base}${modernPolyfillFilename}` + src: `${config.base}${modernPolyfillFilename}` } }) } else if (modernPolyfills.size) { @@ -295,7 +295,7 @@ function viteLegacyPlugin(options = {}) { tag: 'script', attrs: { nomodule: true, - src: `${config.build.base}${legacyPolyfillFilename}` + src: `${config.base}${legacyPolyfillFilename}` }, injectTo: 'body' }) @@ -318,7 +318,7 @@ function viteLegacyPlugin(options = {}) { // script content will stay consistent - which allows using a constant // hash value for CSP. id: legacyEntryId, - 'data-src': config.build.base + legacyEntryFilename + 'data-src': config.base + legacyEntryFilename }, children: systemJSInlineCode, injectTo: 'body' diff --git a/packages/vite/src/node/build.ts b/packages/vite/src/node/build.ts index fe0c2bd0ca2fa3..a2856d1dbb57d0 100644 --- a/packages/vite/src/node/build.ts +++ b/packages/vite/src/node/build.ts @@ -34,7 +34,7 @@ import { ssrManifestPlugin } from './ssr/ssrManifestPlugin' export interface BuildOptions { /** * Base public path when served in production. - * @default '/' + * @deprecated `base` is now a root-level config option. */ base?: string /** @@ -168,12 +168,10 @@ export interface LibraryOptions { export type LibraryFormats = 'es' | 'cjs' | 'umd' | 'iife' -export function resolveBuildOptions( - base: string, - raw?: BuildOptions -): Required { - const resolved: Required = { - base: base || '/', +export type ResolvedBuildOptions = Required> + +export function resolveBuildOptions(raw?: BuildOptions): ResolvedBuildOptions { + const resolved: ResolvedBuildOptions = { target: 'modules', polyfillDynamicImport: raw?.target !== 'esnext' && !raw?.lib, outDir: 'dist', @@ -208,9 +206,6 @@ export function resolveBuildOptions( resolved.target = 'es2019' } - // ensure base ending slash - resolved.base = resolved.base.replace(/([^/])$/, '$1/') - // normalize false string into actual false if ((resolved.minify as any) === 'false') { resolved.minify = false diff --git a/packages/vite/src/node/config.ts b/packages/vite/src/node/config.ts index 47e7132f8e9440..4111fc54341be5 100644 --- a/packages/vite/src/node/config.ts +++ b/packages/vite/src/node/config.ts @@ -22,6 +22,7 @@ import { resolvePlugin } from './plugins/resolve' import { createLogger, Logger, LogLevel } from './logger' import { DepOptimizationOptions } from './optimizer' import { createFilter } from '@rollup/pluginutils' +import { ResolvedBuildOptions } from '.' const debug = createDebugger('vite:config') @@ -141,7 +142,7 @@ export type ResolvedConfig = Readonly< alias: Alias[] plugins: readonly Plugin[] server: ServerOptions - build: Required + build: ResolvedBuildOptions assetsInclude: (file: string) => boolean logger: Logger base: string @@ -155,6 +156,7 @@ export async function resolveConfig( ): Promise { let config = inlineConfig let mode = inlineConfig.mode || defaultMode + const logger = createLogger(config.logLevel, config.clearScreen) // some dependencies e.g. @vue/compiler-* relies on NODE_ENV for getting // production-specific behavior, so set it here even though we haven't @@ -224,12 +226,44 @@ export async function resolveConfig( process.env.NODE_ENV = 'production' } - const BASE_URL = config.base || '/' + // resolve public base url + // TODO remove when out of beta + if (config.build?.base) { + logger.warn( + chalk.yellow.bold( + `(!) "build.base" config option is deprecated. ` + + `"base" is now a root-level config option.` + ) + ) + config.base = config.build.base + } + + let BASE_URL = config.base || '/' if (!BASE_URL.startsWith('/') || !BASE_URL.endsWith('/')) { - throw new Error(`config error: "base" must start and end with "/".`) + logger.warn( + chalk.bold.yellow( + `(!) "base" config option should start and end with "/".` + ) + ) + if (!BASE_URL.startsWith('/')) BASE_URL = '/' + BASE_URL + if (!BASE_URL.endsWith('/')) BASE_URL = BASE_URL + '/' } - const resolvedBuildOptions = resolveBuildOptions(BASE_URL, config.build) + const resolvedBuildOptions = resolveBuildOptions(config.build) + + // TODO remove when out of beta + Object.defineProperty(resolvedBuildOptions, 'base', { + get() { + logger.warn( + chalk.yellow.bold( + `(!) "build.base" config option is deprecated. ` + + `"base" is now a root-level config option.\n` + + new Error().stack + ) + ) + return config.base + } + }) // resolve optimizer cache directory const pkgPath = lookupFile( @@ -278,7 +312,7 @@ export async function resolveConfig( assetsInclude(file: string) { return DEFAULT_ASSETS_RE.test(file) || assetsFilter(file) }, - logger: createLogger(config.logLevel, config.clearScreen), + logger, base: BASE_URL } diff --git a/packages/vite/src/node/logger.ts b/packages/vite/src/node/logger.ts index 5d8988dc8958d8..73cedc7cd78a9e 100644 --- a/packages/vite/src/node/logger.ts +++ b/packages/vite/src/node/logger.ts @@ -10,6 +10,7 @@ export interface Logger { warn(msg: string, options?: LogOptions): void error(msg: string, options?: LogOptions): void clearScreen(type: LogType): void + hasWarned: boolean } export interface LogOptions { @@ -74,11 +75,13 @@ export function createLogger( } } - return { + const logger: Logger = { + hasWarned: false, info(msg, opts) { output('info', msg, opts) }, warn(msg, opts) { + logger.hasWarned = true output('warn', msg, opts) }, error(msg, opts) { @@ -90,4 +93,6 @@ export function createLogger( } } } + + return logger } diff --git a/packages/vite/src/node/plugins/asset.ts b/packages/vite/src/node/plugins/asset.ts index 69644ced672ca7..0f86defc276b10 100644 --- a/packages/vite/src/node/plugins/asset.ts +++ b/packages/vite/src/node/plugins/asset.ts @@ -59,7 +59,7 @@ export function assetPlugin(config: ResolvedConfig): Plugin { s = s || (s = new MagicString(code)) const [full, fileHandle, postfix = ''] = match const outputFilepath = - config.build.base + this.getFileName(fileHandle) + postfix + config.base + this.getFileName(fileHandle) + postfix s.overwrite( match.index, match.index + full.length, @@ -149,7 +149,7 @@ async function fileToBuiltUrl( skipPublicCheck = false ): Promise { if (!skipPublicCheck && checkPublicFile(id, config.root)) { - return config.build.base + id.slice(1) + return config.base + id.slice(1) } let cache = assetCache.get(config) @@ -201,7 +201,7 @@ export async function urlToBuiltUrl( pluginContext: PluginContext ): Promise { if (checkPublicFile(url, config.root)) { - return config.build.base + url.slice(1) + return config.base + url.slice(1) } const file = url.startsWith('/') ? path.join(config.root, url) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 1ecf9aef7cee17..b17aa65b726677 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -240,7 +240,7 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin { // replace asset url references with resolved url chunkCSS = chunkCSS.replace(assetUrlRE, (_, fileId, postfix = '') => { - return config.build.base + this.getFileName(fileId) + postfix + return config.base + this.getFileName(fileId) + postfix }) if (config.build.cssCodeSplit) { diff --git a/packages/vite/src/node/plugins/dynamicImportPolyfill.ts b/packages/vite/src/node/plugins/dynamicImportPolyfill.ts index 5ac75f35921288..b42b9db3b0c6e3 100644 --- a/packages/vite/src/node/plugins/dynamicImportPolyfill.ts +++ b/packages/vite/src/node/plugins/dynamicImportPolyfill.ts @@ -11,7 +11,7 @@ export function dynamicImportPolyfillPlugin(config: ResolvedConfig): Plugin { const polyfillString = `const p = ${polyfill.toString()};` + `${isModernFlag}&&p(${JSON.stringify( - path.posix.join(config.build.base, config.build.assetsDir, '/') + path.posix.join(config.base, config.build.assetsDir, '/') )});` return { diff --git a/packages/vite/src/node/plugins/html.ts b/packages/vite/src/node/plugins/html.ts index 803f9998d8680d..874cb19804ff15 100644 --- a/packages/vite/src/node/plugins/html.ts +++ b/packages/vite/src/node/plugins/html.ts @@ -159,7 +159,7 @@ export function buildHtmlPlugin(config: ResolvedConfig): Plugin { s.overwrite( src!.value!.loc.start.offset, src!.value!.loc.end.offset, - config.build.base + url.slice(1) + config.base + url.slice(1) ) } @@ -201,7 +201,7 @@ export function buildHtmlPlugin(config: ResolvedConfig): Plugin { s.overwrite( p.value.loc.start.offset, p.value.loc.end.offset, - config.build.base + url.slice(1) + config.base + url.slice(1) ) } } @@ -286,7 +286,7 @@ export function buildHtmlPlugin(config: ResolvedConfig): Plugin { for (const [id, html] of processedHtml) { // resolve asset url references let result = html.replace(assetUrlRE, (_, fileId, postfix = '') => { - return config.build.base + this.getFileName(fileId) + postfix + return config.base + this.getFileName(fileId) + postfix }) // find corresponding entry chunk @@ -489,7 +489,7 @@ export async function applyHtmlTransforms( } function toPublicPath(filename: string, config: ResolvedConfig) { - return isExternalUrl(filename) ? filename : config.build.base + filename + return isExternalUrl(filename) ? filename : config.base + filename } const headInjectRE = /<\/head>/ diff --git a/packages/vite/src/node/plugins/importAnaysisBuild.ts b/packages/vite/src/node/plugins/importAnaysisBuild.ts index 654a99bdc76c51..52fb5841ca2a35 100644 --- a/packages/vite/src/node/plugins/importAnaysisBuild.ts +++ b/packages/vite/src/node/plugins/importAnaysisBuild.ts @@ -202,10 +202,10 @@ export function buildImportAnalysisPlugin(config: ResolvedConfig): Plugin { if (filename === ownerFilename) return const chunk = bundle[filename] as OutputChunk | undefined if (chunk) { - deps.add(config.build.base + chunk.fileName) + deps.add(config.base + chunk.fileName) const cssId = chunkToEmittedCssFileMap.get(chunk) if (cssId) { - deps.add(config.build.base + this.getFileName(cssId)) + deps.add(config.base + this.getFileName(cssId)) } chunk.imports.forEach(addDeps) } diff --git a/packages/vite/src/node/server/index.ts b/packages/vite/src/node/server/index.ts index f0e81b27737506..557e30b1ccf5a8 100644 --- a/packages/vite/src/node/server/index.ts +++ b/packages/vite/src/node/server/index.ts @@ -528,7 +528,9 @@ async function startServer( httpServer.listen(port, () => { httpServer.removeListener('error', onError) - info(`\n Vite dev server running at:\n`, { clear: true }) + info(`\n Vite dev server running at:\n`, { + clear: !server.config.logger.hasWarned + }) const interfaces = os.networkInterfaces() Object.keys(interfaces).forEach((key) => (interfaces[key] || []) diff --git a/packages/vite/src/node/ssr/ssrManifestPlugin.ts b/packages/vite/src/node/ssr/ssrManifestPlugin.ts index 2f724a790ebb92..0044e63df39b52 100644 --- a/packages/vite/src/node/ssr/ssrManifestPlugin.ts +++ b/packages/vite/src/node/ssr/ssrManifestPlugin.ts @@ -5,7 +5,7 @@ import { chunkToEmittedCssFileMap } from '../plugins/css' export function ssrManifestPlugin(config: ResolvedConfig): Plugin { // module id => preload assets mapping const ssrManifest: Record = {} - const base = config.build.base + const base = config.base return { name: 'vite:manifest', From a21ea082096416a77268070245fa7bded356d27f Mon Sep 17 00:00:00 2001 From: Evan You Date: Fri, 22 Jan 2021 17:40:50 -0500 Subject: [PATCH 15/15] fix: optimized import check with base --- packages/vite/src/node/plugins/importAnalysis.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vite/src/node/plugins/importAnalysis.ts b/packages/vite/src/node/plugins/importAnalysis.ts index 2611b1084c732f..78073707548ef8 100644 --- a/packages/vite/src/node/plugins/importAnalysis.ts +++ b/packages/vite/src/node/plugins/importAnalysis.ts @@ -357,7 +357,7 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin { if (url !== rawUrl) { // for optimized cjs deps, support named imports by rewriting named // imports to const assignments. - if (url.startsWith(OPTIMIZED_PREFIX)) { + if (resolvedId.startsWith(OPTIMIZED_PREFIX)) { const depId = resolvedId.slice(OPTIMIZED_PREFIX.length) const optimizedId = makeLegalIdentifier(depId) optimizedSource =