From 122c6e75202eb295cabb8c9bcbcc5a6d3bf5ec40 Mon Sep 17 00:00:00 2001 From: yoho Date: Thu, 28 Jul 2022 14:11:42 +0800 Subject: [PATCH 001/100] fix: url constructor import asset no as url (#9399) --- packages/vite/src/node/plugins/assetImportMetaUrl.ts | 2 +- playground/assets/__tests__/assets.spec.ts | 3 +++ playground/assets/index.html | 7 +++++++ playground/assets/nested/test.js | 3 +++ 4 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 playground/assets/nested/test.js diff --git a/packages/vite/src/node/plugins/assetImportMetaUrl.ts b/packages/vite/src/node/plugins/assetImportMetaUrl.ts index 6d7a657706cf9c..4b52a225a68458 100644 --- a/packages/vite/src/node/plugins/assetImportMetaUrl.ts +++ b/packages/vite/src/node/plugins/assetImportMetaUrl.ts @@ -55,7 +55,7 @@ export function assetImportMetaUrlPlugin(config: ResolvedConfig): Plugin { s.overwrite( index, index + exp.length, - `new URL((import.meta.glob(${pattern}, { eager: true, import: 'default' }))[${rawUrl}], self.location)`, + `new URL((import.meta.glob(${pattern}, { eager: true, import: 'default', as: 'url' }))[${rawUrl}], self.location)`, { contentOnly: true } ) continue diff --git a/playground/assets/__tests__/assets.spec.ts b/playground/assets/__tests__/assets.spec.ts index 5b265578e98751..600ea3b0bba971 100644 --- a/playground/assets/__tests__/assets.spec.ts +++ b/playground/assets/__tests__/assets.spec.ts @@ -288,6 +288,9 @@ test('new URL(`${dynamic}`, import.meta.url)', async () => { expect(await page.textContent('.dynamic-import-meta-url-2')).toMatch( assetMatch ) + expect(await page.textContent('.dynamic-import-meta-url-js')).toMatch( + isBuild ? 'data:application/javascript;base64' : '/foo/nested/test.js' + ) }) test('new URL(`non-existent`, import.meta.url)', async () => { diff --git a/playground/assets/index.html b/playground/assets/index.html index a741379e82013e..5a49d42791d058 100644 --- a/playground/assets/index.html +++ b/playground/assets/index.html @@ -199,6 +199,9 @@

new URL(`./${dynamic}`, import.meta.url)

+

+ +

new URL(`./${dynamic}`, import.meta.url,) (with comma)

@@ -390,6 +393,10 @@

style in svg

testDynamicImportMetaUrlWithComma('icon', 1) testDynamicImportMetaUrlWithComma('asset', 2) + const name = 'test' + const js = new URL(`./nested/${name}.js`, import.meta.url).href + text('.dynamic-import-meta-url-js', js) + function text(el, text) { document.querySelector(el).textContent = text } diff --git a/playground/assets/nested/test.js b/playground/assets/nested/test.js new file mode 100644 index 00000000000000..1a292f36ac7916 --- /dev/null +++ b/playground/assets/nested/test.js @@ -0,0 +1,3 @@ +export default class a { + name = 'a' +} From cd69358177dd3d93bc19084ad0ee09f6b85c047c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BF=A0=20/=20green?= Date: Thu, 28 Jul 2022 17:58:37 +0900 Subject: [PATCH 002/100] fix: inline dynamic imports for ssr-webworker (fixes #9385) (#9401) --- packages/vite/src/node/build.ts | 8 +++++--- playground/ssr-vue/vite.config.js | 5 +++-- .../ssr-webworker/__tests__/ssr-webworker.spec.ts | 7 ++++++- playground/ssr-webworker/src/dynamic.js | 1 + playground/ssr-webworker/src/entry-worker.jsx | 4 ++++ playground/test-utils.ts | 13 ++++++++++--- 6 files changed, 29 insertions(+), 9 deletions(-) create mode 100644 playground/ssr-webworker/src/dynamic.js diff --git a/packages/vite/src/node/build.ts b/packages/vite/src/node/build.ts index 12f123413534a4..6c8e0169eeeab4 100644 --- a/packages/vite/src/node/build.ts +++ b/packages/vite/src/node/build.ts @@ -444,11 +444,13 @@ async function doBuild( ) } - const ssrWorkerBuild = ssr && config.ssr?.target !== 'webworker' - const cjsSsrBuild = ssr && config.ssr?.format === 'cjs' + const ssrNodeBuild = ssr && config.ssr.target === 'node' + const ssrWorkerBuild = ssr && config.ssr.target === 'webworker' + const cjsSsrBuild = ssr && config.ssr.format === 'cjs' + const format = output.format || (cjsSsrBuild ? 'cjs' : 'es') const jsExt = - ssrWorkerBuild || libOptions + ssrNodeBuild || libOptions ? resolveOutputJsExtension(format, getPkgJson(config.root)?.type) : 'js' return { diff --git a/playground/ssr-vue/vite.config.js b/playground/ssr-vue/vite.config.js index c2c90bbc32c4bf..a313ea7dd479b2 100644 --- a/playground/ssr-vue/vite.config.js +++ b/playground/ssr-vue/vite.config.js @@ -85,14 +85,15 @@ export default defineConfig(({ command, ssrBuild }) => ({ } }, transform(code, id) { + const cleanId = cleanUrl(id) if ( config.build.ssr && - cleanUrl(id).endsWith('.js') && + (cleanId.endsWith('.js') || cleanId.endsWith('.vue')) && !code.includes('__ssr_vue_processAssetPath') ) { return { code: - `import { __ssr_vue_processAssetPath } from '${virtualId}';` + + `import { __ssr_vue_processAssetPath } from '${virtualId}';__ssr_vue_processAssetPath;` + code, sourcemap: null // no sourcemap support to speed up CI } diff --git a/playground/ssr-webworker/__tests__/ssr-webworker.spec.ts b/playground/ssr-webworker/__tests__/ssr-webworker.spec.ts index 7a5c1bdad2880e..931e8f7d32199f 100644 --- a/playground/ssr-webworker/__tests__/ssr-webworker.spec.ts +++ b/playground/ssr-webworker/__tests__/ssr-webworker.spec.ts @@ -1,5 +1,5 @@ import { port } from './serve' -import { page } from '~utils' +import { findAssetFile, isBuild, page } from '~utils' const url = `http://localhost:${port}` @@ -9,3 +9,8 @@ test('/', async () => { expect(await page.textContent('.linked')).toMatch('dep from upper directory') expect(await page.textContent('.external')).toMatch('object') }) + +test.runIf(isBuild)('inlineDynamicImports', () => { + const dynamicJsContent = findAssetFile(/dynamic\.\w+\.js/, 'worker') + expect(dynamicJsContent).toBe('') +}) diff --git a/playground/ssr-webworker/src/dynamic.js b/playground/ssr-webworker/src/dynamic.js new file mode 100644 index 00000000000000..cb356468240d50 --- /dev/null +++ b/playground/ssr-webworker/src/dynamic.js @@ -0,0 +1 @@ +export const foo = 'foo' diff --git a/playground/ssr-webworker/src/entry-worker.jsx b/playground/ssr-webworker/src/entry-worker.jsx index c885657b18a6d3..940d0d2943d632 100644 --- a/playground/ssr-webworker/src/entry-worker.jsx +++ b/playground/ssr-webworker/src/entry-worker.jsx @@ -1,6 +1,10 @@ import { msg as linkedMsg } from 'resolve-linked' import React from 'react' +import('./dynamic').then(({ foo }) => { + console.log(foo) +}) + addEventListener('fetch', function (event) { return event.respondWith( new Response( diff --git a/playground/test-utils.ts b/playground/test-utils.ts index a0fedd0db426d6..17e4517df43776 100644 --- a/playground/test-utils.ts +++ b/playground/test-utils.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/triple-slash-reference */ // test utils used in e2e tests for playgrounds. // `import { getColor } from '~utils'` @@ -8,7 +7,7 @@ import fs from 'node:fs' import path from 'node:path' import colors from 'css-color-names' -import type { ElementHandle, ConsoleMessage } from 'playwright-chromium' +import type { ConsoleMessage, ElementHandle } from 'playwright-chromium' import type { Manifest } from 'vite' import { normalizePath } from 'vite' import { fromComment } from 'convert-source-map' @@ -128,7 +127,15 @@ export function findAssetFile( assets = 'assets' ): string { const assetsDir = path.join(testDir, 'dist', base, assets) - const files = fs.readdirSync(assetsDir) + let files: string[] + try { + files = fs.readdirSync(assetsDir) + } catch (e) { + if (e.code === 'ENOENT') { + return '' + } + throw e + } const file = files.find((file) => { return file.match(match) }) From c91813971944ea3263062e8955267453feef88ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BF=A0=20/=20green?= Date: Fri, 29 Jul 2022 16:50:42 +0900 Subject: [PATCH 003/100] docs: add troubleshooting page (#9379) Co-authored-by: Bjorn Lu --- docs/.vitepress/config.ts | 4 +++ docs/config/server-options.md | 2 ++ docs/guide/troubleshooting.md | 67 +++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 docs/guide/troubleshooting.md diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 2f378826fa3cb4..e61c9cc00d6262 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -211,6 +211,10 @@ export default defineConfig({ text: 'Comparisons', link: '/guide/comparisons' }, + { + text: 'Troubleshooting', + link: '/guide/troubleshooting' + }, { text: 'Migration from v2', link: '/guide/migration' diff --git a/docs/config/server-options.md b/docs/config/server-options.md index 33208bd4b04155..29a3582665c7a6 100644 --- a/docs/config/server-options.md +++ b/docs/config/server-options.md @@ -145,6 +145,8 @@ Set `server.hmr.overlay` to `false` to disable the server error overlay. When `server.hmr.server` is defined, Vite will process the HMR connection requests through the provided server. If not in middleware mode, Vite will attempt to process HMR connection requests through the existing server. This can be helpful when using self-signed certificates or when you want to expose Vite over a network on a single port. +Check out [`vite-setup-catalogue`](https://github.com/sapphi-red/vite-setup-catalogue) for some examples. + ::: tip NOTE With the default configuration, reverse proxies in front of Vite are expected to support proxying WebSocket. If the Vite HMR client fails to connect WebSocket, the client will fallback to connecting the WebSocket directly to the Vite HMR server bypassing the reverse proxies: diff --git a/docs/guide/troubleshooting.md b/docs/guide/troubleshooting.md new file mode 100644 index 00000000000000..c7e558f0f08192 --- /dev/null +++ b/docs/guide/troubleshooting.md @@ -0,0 +1,67 @@ +# Troubleshooting + +See [Rollup's troubleshooting guide](https://rollupjs.org/guide/en/#troubleshooting) for more information too. + +If the suggestions here don't work, please try posting questions on [GitHub Discussions](https://github.com/vitejs/vite/discussions) or in the `#help` channel of [Vite Land Discord](https://chat.vitejs.dev). + +## CLI + +### `Error: Cannot find module 'C:\foo\bar&baz\vite\bin\vite.js'` + +The path to your project folder may include `?`, which doesn't work with `npm` on Windows ([npm/cmd-shim#45](https://github.com/npm/cmd-shim/issues/45)). + +You will need to either: + +- Switch to another package manager (e.g. `pnpm`, `yarn`) +- Remove `?` from the path to your project + +## Dev Server + +### Requests are stalled forever + +If you are using Linux, file descriptor limits and inotify limits may be causing the issue. As Vite does not bundle most of the files, browsers may request many files which require many file descriptors, going over the limit. + +To solve this: + +- Increase file descriptor limit by `ulimit` + + ```shell + # Check current limit + $ ulimit -Sn + # Change limit (temporary) + $ ulimit -Sn 10000 # You might need to change the hard limit too + # Restart your browser + ``` + +- Increase the following inotify related limits by `sysctl` + + ```shell + # Check current limits + $ sysctl fs.inotify + # Change limits (temporary) + $ sudo sysctl fs.inotify.max_queued_events=16384 + $ sudo sysctl fs.inotify.max_user_instances=8192 + $ sudo sysctl fs.inotify.max_user_watches=524288 + ``` + +## HMR + +### Vite detects a file change but the HMR is not working + +You may be importing a file with a different case. For example, `src/foo.js` exists and `src/bar.js` contains: + +```js +import './Foo.js' // should be './foo.js' +``` + +Related issue: [#964](https://github.com/vitejs/vite/issues/964) + +### Vite does not detect a file change + +If you are running Vite with WSL2, Vite cannot watch file changes in some conditions. See [`server.watch` option](/config/server-options.md#server-watch). + +### A full reload happens instead of HMR + +If HMR is not handled by Vite or a plugin, a full reload will happen. + +Also if there is a dependency loop, a full reload will happen. To solve this, try removing the loop. From 156a3a43ebcf77425f20ee0d72bcb2e4b59365ed Mon Sep 17 00:00:00 2001 From: Tony Trinh Date: Fri, 29 Jul 2022 02:52:53 -0500 Subject: [PATCH 004/100] fix(glob): server perf when globbing huge dirs (#9425) --- packages/vite/src/node/plugins/importMetaGlob.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/vite/src/node/plugins/importMetaGlob.ts b/packages/vite/src/node/plugins/importMetaGlob.ts index e6512dbcd6724b..aef833e3879888 100644 --- a/packages/vite/src/node/plugins/importMetaGlob.ts +++ b/packages/vite/src/node/plugins/importMetaGlob.ts @@ -74,10 +74,6 @@ export function importGlobPlugin(config: ResolvedConfig): Plugin { if (server) { const allGlobs = result.matches.map((i) => i.globsResolved) server._importGlobMap.set(id, allGlobs) - result.files.forEach((file) => { - // update watcher - server!.watcher.add(dirname(file)) - }) } return transformStableResult(result.s, id, config) } From e60368f937f7b2b223811321e66c4aacad72fa6a Mon Sep 17 00:00:00 2001 From: Bjorn Lu Date: Fri, 29 Jul 2022 15:59:24 +0800 Subject: [PATCH 005/100] fix(ssr): allow virtual paths on node modules (#9405) --- packages/vite/src/node/ssr/ssrExternal.ts | 33 +++++++++++-------- .../ssr-deps/__tests__/ssr-deps.spec.ts | 5 +++ playground/ssr-deps/package.json | 3 +- playground/ssr-deps/pkg-exports/index.js | 1 + playground/ssr-deps/pkg-exports/package.json | 9 +++++ playground/ssr-deps/server.js | 18 +++++++++- playground/ssr-deps/src/app.js | 3 ++ pnpm-lock.yaml | 11 +++++++ 8 files changed, 67 insertions(+), 16 deletions(-) create mode 100644 playground/ssr-deps/pkg-exports/index.js create mode 100644 playground/ssr-deps/pkg-exports/package.json diff --git a/packages/vite/src/node/ssr/ssrExternal.ts b/packages/vite/src/node/ssr/ssrExternal.ts index 5fa073ddc2d58a..04b60afdd263eb 100644 --- a/packages/vite/src/node/ssr/ssrExternal.ts +++ b/packages/vite/src/node/ssr/ssrExternal.ts @@ -129,20 +129,25 @@ export function createIsConfiguredAsSsrExternal( if (!bareImportRE.test(id) || id.includes('\0')) { return false } - return !!tryNodeResolve( - id, - undefined, - resolveOptions, - ssr?.target === 'webworker', - undefined, - true, - // try to externalize, will return undefined or an object without - // a external flag if it isn't externalizable - true, - // Allow linked packages to be externalized if they are explicitly - // configured as external - !!configuredAsExternal - )?.external + try { + return !!tryNodeResolve( + id, + undefined, + resolveOptions, + ssr?.target === 'webworker', + undefined, + true, + // try to externalize, will return undefined or an object without + // a external flag if it isn't externalizable + true, + // Allow linked packages to be externalized if they are explicitly + // configured as external + !!configuredAsExternal + )?.external + } catch (e) { + // may be an invalid import that's resolved by a plugin + return false + } } // Returns true if it is configured as external, false if it is filtered diff --git a/playground/ssr-deps/__tests__/ssr-deps.spec.ts b/playground/ssr-deps/__tests__/ssr-deps.spec.ts index 8f4e097aec1c81..f20dca26263f65 100644 --- a/playground/ssr-deps/__tests__/ssr-deps.spec.ts +++ b/playground/ssr-deps/__tests__/ssr-deps.spec.ts @@ -103,3 +103,8 @@ test('msg from linked no external', async () => { await page.goto(url) expect(await page.textContent('.linked-no-external')).toMatch('Hello World!') }) + +test('msg from linked no external', async () => { + await page.goto(url) + expect(await page.textContent('.dep-virtual')).toMatch('[success]') +}) diff --git a/playground/ssr-deps/package.json b/playground/ssr-deps/package.json index 20f840d0f27133..13e7c627a2139e 100644 --- a/playground/ssr-deps/package.json +++ b/playground/ssr-deps/package.json @@ -27,7 +27,8 @@ "optimized-cjs-with-nested-external": "file:./optimized-with-nested-external", "external-using-external-entry": "file:./external-using-external-entry", "external-entry": "file:./external-entry", - "linked-no-external": "link:./linked-no-external" + "linked-no-external": "link:./linked-no-external", + "pkg-exports": "file:./pkg-exports" }, "devDependencies": { "cross-env": "^7.0.3", diff --git a/playground/ssr-deps/pkg-exports/index.js b/playground/ssr-deps/pkg-exports/index.js new file mode 100644 index 00000000000000..edb72725b9e7c6 --- /dev/null +++ b/playground/ssr-deps/pkg-exports/index.js @@ -0,0 +1 @@ +export default undefined diff --git a/playground/ssr-deps/pkg-exports/package.json b/playground/ssr-deps/pkg-exports/package.json new file mode 100644 index 00000000000000..6947a065e74cea --- /dev/null +++ b/playground/ssr-deps/pkg-exports/package.json @@ -0,0 +1,9 @@ +{ + "name": "pkg-exports", + "private": true, + "version": "0.0.0", + "exports": { + ".": "./index.js" + }, + "type": "module" +} diff --git a/playground/ssr-deps/server.js b/playground/ssr-deps/server.js index 764e5b5d8da657..aa47a6055321ac 100644 --- a/playground/ssr-deps/server.js +++ b/playground/ssr-deps/server.js @@ -45,7 +45,23 @@ export async function createServer(root = process.cwd(), hmrPort) { optimizeDeps: { disabled: 'build' } - } + }, + plugins: [ + { + name: 'dep-virtual', + enforce: 'pre', + resolveId(id) { + if (id === 'pkg-exports/virtual') { + return 'pkg-exports/virtual' + } + }, + load(id) { + if (id === 'pkg-exports/virtual') { + return 'export default "[success]"' + } + } + } + ] }) // use vite's connect instance as middleware app.use(vite.middlewares) diff --git a/playground/ssr-deps/src/app.js b/playground/ssr-deps/src/app.js index 987eaa3e1b43e9..0b0fe2d9b968ec 100644 --- a/playground/ssr-deps/src/app.js +++ b/playground/ssr-deps/src/app.js @@ -12,6 +12,7 @@ import requireAbsolute from 'require-absolute' import noExternalCjs from 'no-external-cjs' import importBuiltinCjs from 'import-builtin-cjs' import { hello as linkedNoExternal } from 'linked-no-external' +import virtualMessage from 'pkg-exports/virtual' // This import will set a 'Hello World!" message in the nested-external non-entry dependency import 'non-optimized-with-nested-external' @@ -79,5 +80,7 @@ export async function render(url, rootDir) { const linkedNoExternalMessage = linkedNoExternal() html += `\n

message from linked-no-external: ${linkedNoExternalMessage}

` + html += `\n

message from dep-virtual: ${virtualMessage}

` + return html + '\n' } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3d8f46d5cd0af3..4c9742082efe58 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -915,6 +915,7 @@ importers: only-object-assigned-exports: file:./only-object-assigned-exports optimized-cjs-with-nested-external: file:./optimized-with-nested-external optimized-with-nested-external: file:./optimized-with-nested-external + pkg-exports: file:./pkg-exports primitive-export: file:./primitive-export read-file-content: file:./read-file-content require-absolute: file:./require-absolute @@ -935,6 +936,7 @@ importers: only-object-assigned-exports: file:playground/ssr-deps/only-object-assigned-exports optimized-cjs-with-nested-external: file:playground/ssr-deps/optimized-with-nested-external optimized-with-nested-external: file:playground/ssr-deps/optimized-with-nested-external + pkg-exports: file:playground/ssr-deps/pkg-exports primitive-export: file:playground/ssr-deps/primitive-export read-file-content: file:playground/ssr-deps/read-file-content require-absolute: file:playground/ssr-deps/require-absolute @@ -1003,6 +1005,9 @@ importers: dependencies: nested-external: file:playground/ssr-deps/nested-external + playground/ssr-deps/pkg-exports: + specifiers: {} + playground/ssr-deps/primitive-export: specifiers: {} @@ -9190,6 +9195,12 @@ packages: nested-external: file:playground/ssr-deps/nested-external dev: false + file:playground/ssr-deps/pkg-exports: + resolution: {directory: playground/ssr-deps/pkg-exports, type: directory} + name: pkg-exports + version: 0.0.0 + dev: false + file:playground/ssr-deps/primitive-export: resolution: {directory: playground/ssr-deps/primitive-export, type: directory} name: primitive-export From a2b24eea4a43a39bc4104335d21f2ec5353d6a13 Mon Sep 17 00:00:00 2001 From: Hung Viet Nguyen Date: Fri, 29 Jul 2022 16:22:16 +0800 Subject: [PATCH 006/100] fix: __VITE_PUBLIC_ASSET__hash__ in HTML (#9247) --- packages/vite/src/node/plugins/asset.ts | 7 +++++++ packages/vite/src/node/plugins/html.ts | 23 ++++++++++++++++++++-- playground/assets/__tests__/assets.spec.ts | 11 +++++++++++ playground/assets/index.html | 10 ++++++++++ 4 files changed, 49 insertions(+), 2 deletions(-) diff --git a/packages/vite/src/node/plugins/asset.ts b/packages/vite/src/node/plugins/asset.ts index 648b34f1d6d6f1..719269c5934290 100644 --- a/packages/vite/src/node/plugins/asset.ts +++ b/packages/vite/src/node/plugins/asset.ts @@ -229,6 +229,13 @@ export function getAssetFilename( return assetHashToFilenameMap.get(config)?.get(hash) } +export function getPublicAssetFilename( + hash: string, + config: ResolvedConfig +): string | undefined { + return publicAssetUrlCache.get(config)?.get(hash) +} + export function resolveAssetFileNames( config: ResolvedConfig ): string | ((chunkInfo: PreRenderedAsset) => string) { diff --git a/packages/vite/src/node/plugins/html.ts b/packages/vite/src/node/plugins/html.ts index ac7ac834ff941a..188134d4166442 100644 --- a/packages/vite/src/node/plugins/html.ts +++ b/packages/vite/src/node/plugins/html.ts @@ -34,6 +34,8 @@ import { assetUrlRE, checkPublicFile, getAssetFilename, + getPublicAssetFilename, + publicAssetUrlRE, urlToBuiltUrl } from './asset' import { isCSSRequest } from './css' @@ -613,13 +615,16 @@ export function buildHtmlPlugin(config: ResolvedConfig): Plugin { for (const [id, html] of processedHtml) { const relativeUrlPath = path.posix.relative(config.root, id) const assetsBase = getBaseInHTML(relativeUrlPath, config) - const toOutputAssetFilePath = (filename: string) => { + const toOutputFilePath = ( + filename: string, + type: 'asset' | 'public' + ) => { if (isExternalUrl(filename)) { return filename } else { return toOutputFilePathInHtml( filename, - 'asset', + type, relativeUrlPath, 'html', config, @@ -628,6 +633,12 @@ export function buildHtmlPlugin(config: ResolvedConfig): Plugin { } } + const toOutputAssetFilePath = (filename: string) => + toOutputFilePath(filename, 'asset') + + const toOutputPublicAssetFilePath = (filename: string) => + toOutputFilePath(filename, 'public') + const isAsync = isAsyncScriptMap.get(config)!.get(id)! let result = html @@ -716,6 +727,14 @@ export function buildHtmlPlugin(config: ResolvedConfig): Plugin { ) }) + result = result.replace(publicAssetUrlRE, (_, fileHash) => { + return normalizePath( + toOutputPublicAssetFilePath( + getPublicAssetFilename(fileHash, config)! + ) + ) + }) + if (chunk && canInlineEntry) { // all imports from entry have been inlined to html, prevent rollup from outputting it delete bundle[chunk.fileName] diff --git a/playground/assets/__tests__/assets.spec.ts b/playground/assets/__tests__/assets.spec.ts index 600ea3b0bba971..ceb259102d4031 100644 --- a/playground/assets/__tests__/assets.spec.ts +++ b/playground/assets/__tests__/assets.spec.ts @@ -367,3 +367,14 @@ test('relative path in html asset', async () => { expect(await page.textContent('.relative-js')).toMatch('hello') expect(await getColor('.relative-css')).toMatch('red') }) + +test('url() contains file in publicDir, in +

+ inline style +

+

use style class

@import

diff --git a/playground/vue-legacy/__tests__/vue-legacy.spec.ts b/playground/vue-legacy/__tests__/vue-legacy.spec.ts new file mode 100644 index 00000000000000..908e04567ca35b --- /dev/null +++ b/playground/vue-legacy/__tests__/vue-legacy.spec.ts @@ -0,0 +1,10 @@ +import { test } from 'vitest' +import { getBg, untilUpdated } from '~utils' + +test('vue legacy assets', async () => { + await untilUpdated(() => getBg('.main'), 'assets/asset', true) +}) + +test('async vue legacy assets', async () => { + await untilUpdated(() => getBg('.module'), 'assets/asset', true) +}) diff --git a/playground/vue-legacy/assets/asset.png b/playground/vue-legacy/assets/asset.png new file mode 100644 index 0000000000000000000000000000000000000000..1b3356a746b8bb5510aaee51f7df5aea4378ee8d GIT binary patch literal 12772 zcmch82T)Ym)-H$&N*olL90vnANET3%3IdXIY@%ek$x$T;2*MyJ*+y~(p$Scr3=&#V zauARp&>%U(zmMb0?|pUet@~cpyH;6pHhZnL_ln2ZQ@20&bcI#; zRb1q(Z0+v)xLIlXsA|D|?BU{;Y%QIg6L0gA+o+ON#9WUkUItw9LoG z@?#6qUW)C{L+PnJV3BinvtkkE73P8S3*2B473UQY7PuiMz|A7aFCfInFT^Jx#3LXm z!7nZ$Ak6af4;zr?W@#;0kvqd6ZB>4C|Jw16ng?OFaZ1@Dk#l`vf1^EO8 zdB6@HgtrsY+>6Hv!TuKqc`F3m&CUgB=j_A+aWuDZc1KFFfs_7u1xFVZmA@G~A$}?f zsEp6c+=Wkom!Hqk5xUop-3X+H)&CyjpYBFzdAnHgX;>kg-QD289@gxC5d+=*dqL1f za2g4DXSlngl@s!wyc8Q);kC50l(;P_D#|Y+&o3r=TUJ0oK}c4VUtU3hUkF;26A%>o zi}s!q0%`69xB83L?r&N-#eYjHA?Idgj&yd@a&~t3%X$xNosrH6TW1#*IXRYVD&}xI zC+PV)q}!iIwQ{rbu(DKib9Q9;p&SXje{uj3VUgPcf}-N0BI1J3;l%~S#Kq*r`DGQw z

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 literal 0 HcmV?d00001 diff --git a/playground/vue-legacy/env.d.ts b/playground/vue-legacy/env.d.ts new file mode 100644 index 00000000000000..31dca6bb40c906 --- /dev/null +++ b/playground/vue-legacy/env.d.ts @@ -0,0 +1 @@ +declare module '*.png' diff --git a/playground/vue-legacy/index.html b/playground/vue-legacy/index.html new file mode 100644 index 00000000000000..0f7b79435ed47d --- /dev/null +++ b/playground/vue-legacy/index.html @@ -0,0 +1,7 @@ +

+ diff --git a/playground/vue-legacy/inline.css b/playground/vue-legacy/inline.css new file mode 100644 index 00000000000000..2207a25763ca6d --- /dev/null +++ b/playground/vue-legacy/inline.css @@ -0,0 +1,3 @@ +.inline-css { + color: #0088ff; +} diff --git a/playground/vue-legacy/module.vue b/playground/vue-legacy/module.vue new file mode 100644 index 00000000000000..10c7b42e4c4215 --- /dev/null +++ b/playground/vue-legacy/module.vue @@ -0,0 +1,13 @@ + + diff --git a/playground/vue-legacy/package.json b/playground/vue-legacy/package.json new file mode 100644 index 00000000000000..201a5ae47bb293 --- /dev/null +++ b/playground/vue-legacy/package.json @@ -0,0 +1,18 @@ +{ + "name": "test-vue-legacy", + "private": true, + "version": "0.0.0", + "scripts": { + "dev": "vite", + "build": "vite build", + "debug": "node --inspect-brk ../../packages/vite/bin/vite", + "preview": "vite preview" + }, + "dependencies": { + "vue": "^3.2.37" + }, + "devDependencies": { + "@vitejs/plugin-vue": "workspace:*", + "@vitejs/plugin-legacy": "workspace:*" + } +} diff --git a/playground/vue-legacy/vite.config.ts b/playground/vue-legacy/vite.config.ts new file mode 100644 index 00000000000000..5bb2f0efa06f53 --- /dev/null +++ b/playground/vue-legacy/vite.config.ts @@ -0,0 +1,35 @@ +import path from 'node:path' +import fs from 'node:fs' +import { defineConfig } from 'vite' +import vuePlugin from '@vitejs/plugin-vue' +import legacyPlugin from '@vitejs/plugin-legacy' + +export default defineConfig({ + base: '', + resolve: { + alias: { + '@': __dirname + } + }, + plugins: [ + legacyPlugin({ + targets: ['defaults', 'not IE 11', 'chrome > 48'] + }), + vuePlugin() + ], + build: { + minify: false + }, + // special test only hook + // for tests, remove ` + +

test elements below should show circles and their url

+
+
diff --git a/playground/assets-sanitize/index.js b/playground/assets-sanitize/index.js new file mode 100644 index 00000000000000..bac3b3b83e6b1d --- /dev/null +++ b/playground/assets-sanitize/index.js @@ -0,0 +1,9 @@ +import plusCircle from './+circle.svg' +import underscoreCircle from './_circle.svg' +function setData(classname, file) { + const el = document.body.querySelector(classname) + el.style.backgroundImage = `url(${file})` + el.textContent = file +} +setData('.plus-circle', plusCircle) +setData('.underscore-circle', underscoreCircle) diff --git a/playground/assets-sanitize/package.json b/playground/assets-sanitize/package.json new file mode 100644 index 00000000000000..3ade78a2bd33fe --- /dev/null +++ b/playground/assets-sanitize/package.json @@ -0,0 +1,11 @@ +{ + "name": "test-assets-sanitize", + "private": true, + "version": "0.0.0", + "scripts": { + "dev": "vite", + "build": "vite build", + "debug": "node --inspect-brk ../../packages/vite/bin/vite", + "preview": "vite preview" + } +} diff --git a/playground/assets-sanitize/vite.config.js b/playground/assets-sanitize/vite.config.js new file mode 100644 index 00000000000000..0e365a95383833 --- /dev/null +++ b/playground/assets-sanitize/vite.config.js @@ -0,0 +1,11 @@ +const { defineConfig } = require('vite') + +module.exports = defineConfig({ + build: { + //speed up build + minify: false, + target: 'esnext', + assetsInlineLimit: 0, + manifest: true + } +}) From eec38860670a84b17d839500d812b27f61ebdf79 Mon Sep 17 00:00:00 2001 From: Bjorn Lu Date: Fri, 19 Aug 2022 20:55:04 +0800 Subject: [PATCH 093/100] fix: handle resolve optional peer deps (#9321) --- .../src/node/optimizer/esbuildDepPlugin.ts | 24 ++++++++++++- packages/vite/src/node/plugins/resolve.ts | 35 +++++++++++++++++++ packages/vite/src/node/utils.ts | 8 ++++- .../__tests__/optimize-deps.spec.ts | 13 +++++++ .../dep-with-optional-peer-dep/index.js | 7 ++++ .../dep-with-optional-peer-dep/package.json | 15 ++++++++ playground/optimize-deps/index.html | 10 ++++++ playground/optimize-deps/package.json | 1 + pnpm-lock.yaml | 20 +++++++++++ 9 files changed, 131 insertions(+), 2 deletions(-) create mode 100644 playground/optimize-deps/dep-with-optional-peer-dep/index.js create mode 100644 playground/optimize-deps/dep-with-optional-peer-dep/package.json diff --git a/packages/vite/src/node/optimizer/esbuildDepPlugin.ts b/packages/vite/src/node/optimizer/esbuildDepPlugin.ts index 57e67c2b47a166..04c978130f256c 100644 --- a/packages/vite/src/node/optimizer/esbuildDepPlugin.ts +++ b/packages/vite/src/node/optimizer/esbuildDepPlugin.ts @@ -12,7 +12,7 @@ import { moduleListContains, normalizePath } from '../utils' -import { browserExternalId } from '../plugins/resolve' +import { browserExternalId, optionalPeerDepId } from '../plugins/resolve' import type { ExportsData } from '.' const externalWithConversionNamespace = @@ -93,6 +93,12 @@ export function esbuildDepPlugin( namespace: 'browser-external' } } + if (resolved.startsWith(optionalPeerDepId)) { + return { + path: resolved, + namespace: 'optional-peer-dep' + } + } if (ssr && isBuiltin(resolved)) { return } @@ -279,6 +285,22 @@ module.exports = Object.create(new Proxy({}, { } ) + build.onLoad( + { filter: /.*/, namespace: 'optional-peer-dep' }, + ({ path }) => { + if (config.isProduction) { + return { + contents: 'module.exports = {}' + } + } else { + const [, peerDep, parentDep] = path.split(':') + return { + contents: `throw new Error(\`Could not resolve "${peerDep}" imported by "${parentDep}". Is it installed?\`)` + } + } + } + ) + // yarn 2 pnp compat if (isRunningWithYarnPnp) { build.onResolve( diff --git a/packages/vite/src/node/plugins/resolve.ts b/packages/vite/src/node/plugins/resolve.ts index 13ac18ae384371..f33105d265a27a 100644 --- a/packages/vite/src/node/plugins/resolve.ts +++ b/packages/vite/src/node/plugins/resolve.ts @@ -30,6 +30,7 @@ import { isPossibleTsOutput, isTsRequest, isWindows, + lookupFile, nestedResolveFrom, normalizePath, resolveFrom, @@ -44,6 +45,8 @@ import { loadPackageData, resolvePackageData } from '../packages' // special id for paths marked with browser: false // https://github.com/defunctzombie/package-browser-field-spec#ignore-a-module export const browserExternalId = '__vite-browser-external' +// special id for packages that are optional peer deps +export const optionalPeerDepId = '__vite-optional-peer-dep' const isDebug = process.env.DEBUG const debug = createDebugger('vite:resolve-details', { @@ -365,6 +368,14 @@ export default new Proxy({}, { })` } } + if (id.startsWith(optionalPeerDepId)) { + if (isProduction) { + return `export default {}` + } else { + const [, peerDep, parentDep] = id.split(':') + return `throw new Error(\`Could not resolve "${peerDep}" imported by "${parentDep}". Is it installed?\`)` + } + } } } } @@ -618,6 +629,30 @@ export function tryNodeResolve( })! if (!pkg) { + // if import can't be found, check if it's an optional peer dep. + // if so, we can resolve to a special id that errors only when imported. + if ( + basedir !== root && // root has no peer dep + !isBuiltin(id) && + !id.includes('\0') && + bareImportRE.test(id) + ) { + // find package.json with `name` as main + const mainPackageJson = lookupFile(basedir, ['package.json'], { + predicate: (content) => !!JSON.parse(content).name + }) + if (mainPackageJson) { + const mainPkg = JSON.parse(mainPackageJson) + if ( + mainPkg.peerDependencies?.[id] && + mainPkg.peerDependenciesMeta?.[id]?.optional + ) { + return { + id: `${optionalPeerDepId}:${id}:${mainPkg.name}` + } + } + } + } return } diff --git a/packages/vite/src/node/utils.ts b/packages/vite/src/node/utils.ts index 85f85adf3cf550..0f681ec8f7378f 100644 --- a/packages/vite/src/node/utils.ts +++ b/packages/vite/src/node/utils.ts @@ -390,6 +390,7 @@ export function isDefined(value: T | undefined | null): value is T { interface LookupFileOptions { pathOnly?: boolean rootDir?: string + predicate?: (file: string) => boolean } export function lookupFile( @@ -400,7 +401,12 @@ export function lookupFile( for (const format of formats) { const fullPath = path.join(dir, format) if (fs.existsSync(fullPath) && fs.statSync(fullPath).isFile()) { - return options?.pathOnly ? fullPath : fs.readFileSync(fullPath, 'utf-8') + const result = options?.pathOnly + ? fullPath + : fs.readFileSync(fullPath, 'utf-8') + if (!options?.predicate || options.predicate(result)) { + return result + } } } const parentDir = path.dirname(dir) diff --git a/playground/optimize-deps/__tests__/optimize-deps.spec.ts b/playground/optimize-deps/__tests__/optimize-deps.spec.ts index df0c080f09ab47..fd717b0401499b 100644 --- a/playground/optimize-deps/__tests__/optimize-deps.spec.ts +++ b/playground/optimize-deps/__tests__/optimize-deps.spec.ts @@ -88,6 +88,19 @@ test('dep with dynamic import', async () => { ) }) +test('dep with optional peer dep', async () => { + expect(await page.textContent('.dep-with-optional-peer-dep')).toMatch( + `[success]` + ) + if (isServe) { + expect(browserErrors.map((error) => error.message)).toEqual( + expect.arrayContaining([ + 'Could not resolve "foobar" imported by "dep-with-optional-peer-dep". Is it installed?' + ]) + ) + } +}) + test('dep with css import', async () => { expect(await getColor('.dep-linked-include')).toBe('red') }) diff --git a/playground/optimize-deps/dep-with-optional-peer-dep/index.js b/playground/optimize-deps/dep-with-optional-peer-dep/index.js new file mode 100644 index 00000000000000..bce89ca18f3ad7 --- /dev/null +++ b/playground/optimize-deps/dep-with-optional-peer-dep/index.js @@ -0,0 +1,7 @@ +export function callItself() { + return '[success]' +} + +export async function callPeerDep() { + return await import('foobar') +} diff --git a/playground/optimize-deps/dep-with-optional-peer-dep/package.json b/playground/optimize-deps/dep-with-optional-peer-dep/package.json new file mode 100644 index 00000000000000..bf43db6b7919d9 --- /dev/null +++ b/playground/optimize-deps/dep-with-optional-peer-dep/package.json @@ -0,0 +1,15 @@ +{ + "name": "dep-with-optional-peer-dep", + "private": true, + "version": "0.0.0", + "main": "index.js", + "type": "module", + "peerDependencies": { + "foobar": "0.0.0" + }, + "peerDependenciesMeta": { + "foobar": { + "optional": true + } + } +} diff --git a/playground/optimize-deps/index.html b/playground/optimize-deps/index.html index 7b0c43e82fdcbc..fe507e9ba568f4 100644 --- a/playground/optimize-deps/index.html +++ b/playground/optimize-deps/index.html @@ -59,6 +59,9 @@

Import from dependency with dynamic import

+

Import from dependency with optional peer dep

+
+

Dep w/ special file format supported via plugins

@@ -152,6 +155,13 @@

Flatten Id

text('.reused-variable-names', reusedName) + +