From de7f351e89d48af48a9c02c9b659fc944c499bab Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Sat, 7 May 2022 01:25:49 +0900 Subject: [PATCH 01/18] chore: make terser an optional dependency BREAKING CHANGE: `terser` must be installed for minification with terser --- docs/config/index.md | 6 +++++ packages/plugin-legacy/README.md | 6 +++++ packages/vite/package.json | 7 ++++-- packages/vite/rollup.config.js | 31 +----------------------- packages/vite/src/node/plugins/css.ts | 8 +++--- packages/vite/src/node/plugins/terser.ts | 30 ++++++++++++++++------- packages/vite/src/node/utils.ts | 13 ++++++++++ playground/legacy/package.json | 3 ++- playground/preload/package.json | 3 ++- pnpm-lock.yaml | 6 +++-- 10 files changed, 63 insertions(+), 50 deletions(-) diff --git a/docs/config/index.md b/docs/config/index.md index 1c61f2bef5b7ac..bd039951081581 100644 --- a/docs/config/index.md +++ b/docs/config/index.md @@ -880,6 +880,12 @@ export default defineConfig({ Set to `false` to disable minification, or specify the minifier to use. The default is [esbuild](https://github.com/evanw/esbuild) which is 20 ~ 40x faster than terser and only 1 ~ 2% worse compression. [Benchmarks](https://github.com/privatenumber/minification-benchmarks) + terser must be installed when it is set to `'terser'`. + + ```sh + npm add -D terser + ``` + Note the `build.minify` option is not available when using the `'es'` format in lib mode. ### build.terserOptions diff --git a/packages/plugin-legacy/README.md b/packages/plugin-legacy/README.md index fc4167f4f1010f..bbfd3ac154b1ea 100644 --- a/packages/plugin-legacy/README.md +++ b/packages/plugin-legacy/README.md @@ -27,6 +27,12 @@ export default { } ``` +terser must be installed because plugin-legacy uses terser for minification. + +```sh +npm add -D terser +``` + ## Options ### `targets` diff --git a/packages/vite/package.json b/packages/vite/package.json index 7fa8f652b56729..cdecabe1ce0690 100644 --- a/packages/vite/package.json +++ b/packages/vite/package.json @@ -99,7 +99,6 @@ "source-map-support": "^0.5.21", "strip-ansi": "^6.0.1", "strip-literal": "^0.3.0", - "terser": "^5.13.1", "tsconfck": "^2.0.0", "tslib": "^2.4.0", "types": "link:./types", @@ -109,7 +108,8 @@ "peerDependencies": { "less": "*", "sass": "*", - "stylus": "*" + "stylus": "*", + "terser": "^5.13.1" }, "peerDependenciesMeta": { "sass": { @@ -120,6 +120,9 @@ }, "less": { "optional": true + }, + "terser": { + "optional": true } } } diff --git a/packages/vite/rollup.config.js b/packages/vite/rollup.config.js index 93f4f33bdec398..62e0167477914d 100644 --- a/packages/vite/rollup.config.js +++ b/packages/vite/rollup.config.js @@ -149,10 +149,6 @@ const createNodeConfig = (isProduction) => { // Shim them with eval() so rollup can skip these calls. isProduction && shimDepsPlugin({ - 'plugins/terser.ts': { - src: `require.resolve('terser'`, - replacement: `require.resolve('vite/dist/node/terser'` - }, // chokidar -> fsevents 'fsevents-handler.js': { src: `require('fsevents')`, @@ -192,26 +188,6 @@ const createNodeConfig = (isProduction) => { return nodeConfig } -/** - * Terser needs to be run inside a worker, so it cannot be part of the main - * bundle. We produce a separate bundle for it and shims plugin/terser.ts to - * use the production path during build. - * - * @type { import('rollup').RollupOptions } - */ -const terserConfig = { - ...sharedNodeOptions, - output: { - ...sharedNodeOptions.output, - exports: 'default', - sourcemap: false - }, - input: { - terser: require.resolve('terser') - }, - plugins: [nodeResolve(), commonjs()] -} - /** * @type { (deps: Record) => import('rollup').Plugin } */ @@ -388,10 +364,5 @@ export default (commandLineArgs) => { const isDev = commandLineArgs.watch const isProduction = !isDev - return [ - envConfig, - clientConfig, - createNodeConfig(isProduction), - ...(isProduction ? [terserConfig] : []) - ] + return [envConfig, clientConfig, createNodeConfig(isProduction)] } diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 1f58de158fdea3..207f0466a96c99 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -39,7 +39,8 @@ import { isObject, normalizePath, parseRequest, - processSrcSet + processSrcSet, + requireResolveFromRootWithFallback } from '../utils' import { emptyCssComments } from '../utils' import { addToHTMLProxyTransformResult } from './html' @@ -1237,10 +1238,7 @@ function loadPreprocessor(lang: PreprocessLang, root: string): any { return loadedPreprocessors[lang] } try { - // Search for the preprocessor in the root directory first, and fall back - // to the default require paths. - const fallbackPaths = require.resolve.paths?.(lang) || [] - const resolved = require.resolve(lang, { paths: [root, ...fallbackPaths] }) + const resolved = requireResolveFromRootWithFallback(root, lang) return (loadedPreprocessors[lang] = require(resolved)) } catch (e) { if (e.code === 'MODULE_NOT_FOUND') { diff --git a/packages/vite/src/node/plugins/terser.ts b/packages/vite/src/node/plugins/terser.ts index 9dc546191d14f7..e022862a5dd87a 100644 --- a/packages/vite/src/node/plugins/terser.ts +++ b/packages/vite/src/node/plugins/terser.ts @@ -2,18 +2,29 @@ import { Worker } from 'okie' import type { Terser } from 'types/terser' import type { Plugin } from '../plugin' import type { ResolvedConfig } from '..' +import { requireResolveFromRootWithFallback } from '../utils' + +let terserPath: string | undefined +const loadTerserPath = (root: string) => { + if (terserPath) return terserPath + try { + terserPath = requireResolveFromRootWithFallback(root, 'terser') + } catch (e) { + if (e.code === 'MODULE_NOT_FOUND') { + throw new Error(`terser not found. Did you install it?`) + } else { + const message = new Error(`terser failed to load:\n${e.message}`) + message.stack = e.stack + '\n' + message.stack + throw message + } + } + return terserPath +} export function terserPlugin(config: ResolvedConfig): Plugin { const makeWorker = () => new Worker( - async (basedir: string, code: string, options: Terser.MinifyOptions) => { - // when vite is linked, the worker thread won't share the same resolve - // root with vite itself, so we have to pass in the basedir and resolve - // terser first. - // eslint-disable-next-line node/no-restricted-require - const terserPath = require.resolve('terser', { - paths: [basedir] - }) + (terserPath: string, code: string, options: Terser.MinifyOptions) => { return require(terserPath).minify(code, options) as Terser.MinifyOutput } ) @@ -44,7 +55,8 @@ export function terserPlugin(config: ResolvedConfig): Plugin { // Lazy load worker. worker ||= makeWorker() - const res = await worker.run(__dirname, code, { + const terserPath = loadTerserPath(config.root) + const res = await worker.run(terserPath, code, { safari10: true, ...config.build.terserOptions, sourceMap: !!outputOptions.sourcemap, diff --git a/packages/vite/src/node/utils.ts b/packages/vite/src/node/utils.ts index 3748aa3b465b2c..6c0887d959dd9a 100644 --- a/packages/vite/src/node/utils.ts +++ b/packages/vite/src/node/utils.ts @@ -774,6 +774,19 @@ export function getHash(text: Buffer | string): string { return createHash('sha256').update(text).digest('hex').substring(0, 8) } +export const requireResolveFromRootWithFallback = ( + root: string, + id: string +) => { + // Search in the root directory first, and fallback to the default require paths. + const fallbackPaths = require.resolve.paths?.(id) || [] + // eslint-disable-next-line node/no-missing-require + const path = require.resolve(id, { + paths: [root, ...fallbackPaths] + }) + return path +} + // Based on node-graceful-fs // The ISC License diff --git a/playground/legacy/package.json b/playground/legacy/package.json index 4f11c234573f40..347e410e2bf4d6 100644 --- a/playground/legacy/package.json +++ b/playground/legacy/package.json @@ -12,6 +12,7 @@ }, "devDependencies": { "@vitejs/plugin-legacy": "workspace:*", - "express": "^4.18.1" + "express": "^4.18.1", + "terser": "^5.13.1" } } diff --git a/playground/preload/package.json b/playground/preload/package.json index f38267b0b8f8d7..617fdc04336b3f 100644 --- a/playground/preload/package.json +++ b/playground/preload/package.json @@ -13,6 +13,7 @@ "vue-router": "^4.0.15" }, "devDependencies": { - "@vitejs/plugin-vue": "workspace:*" + "@vitejs/plugin-vue": "workspace:*", + "terser": "^5.13.1" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 00d6847a132bf4..81fa4ea8b34bbd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -261,7 +261,6 @@ importers: source-map-support: ^0.5.21 strip-ansi: ^6.0.1 strip-literal: ^0.3.0 - terser: ^5.13.1 tsconfck: ^2.0.0 tslib: ^2.4.0 types: link:./types @@ -323,7 +322,6 @@ importers: source-map-support: 0.5.21 strip-ansi: 6.0.1 strip-literal: 0.3.0 - terser: 5.13.1 tsconfck: 2.0.0 tslib: 2.4.0 types: link:types @@ -491,9 +489,11 @@ importers: specifiers: '@vitejs/plugin-legacy': workspace:* express: ^4.18.1 + terser: ^5.13.1 devDependencies: '@vitejs/plugin-legacy': link:../../packages/plugin-legacy express: 4.18.1 + terser: 5.13.1 playground/lib: specifiers: {} @@ -660,6 +660,7 @@ importers: playground/preload: specifiers: '@vitejs/plugin-vue': workspace:* + terser: ^5.13.1 vue: ^3.2.33 vue-router: ^4.0.15 dependencies: @@ -667,6 +668,7 @@ importers: vue-router: 4.0.15_vue@3.2.33 devDependencies: '@vitejs/plugin-vue': link:../../packages/plugin-vue + terser: 5.13.1 playground/preserve-symlinks: specifiers: From cc697cf0642376f7c3387f1fecb9b8eeb99fec5e Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Fri, 20 May 2022 23:56:50 +0900 Subject: [PATCH 02/18] chore(plugin-legacy): add terser to peer dep --- packages/plugin-legacy/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/plugin-legacy/package.json b/packages/plugin-legacy/package.json index 828b31d57ddfe2..2864bac3e43c10 100644 --- a/packages/plugin-legacy/package.json +++ b/packages/plugin-legacy/package.json @@ -42,6 +42,7 @@ "systemjs": "^6.12.1" }, "peerDependencies": { + "terser": "^5.13.1", "vite": "^2.8.0" }, "devDependencies": { From faac5cd94920805b569a78303b2c964e1cbe84b2 Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Sat, 21 May 2022 00:03:13 +0900 Subject: [PATCH 03/18] chore: downgrade terser requirements to 5.4.0 --- packages/plugin-legacy/package.json | 2 +- packages/vite/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/plugin-legacy/package.json b/packages/plugin-legacy/package.json index 2864bac3e43c10..43682698cc864f 100644 --- a/packages/plugin-legacy/package.json +++ b/packages/plugin-legacy/package.json @@ -42,7 +42,7 @@ "systemjs": "^6.12.1" }, "peerDependencies": { - "terser": "^5.13.1", + "terser": "^5.4.0", "vite": "^2.8.0" }, "devDependencies": { diff --git a/packages/vite/package.json b/packages/vite/package.json index cdecabe1ce0690..eab6a8886bbaf9 100644 --- a/packages/vite/package.json +++ b/packages/vite/package.json @@ -109,7 +109,7 @@ "less": "*", "sass": "*", "stylus": "*", - "terser": "^5.13.1" + "terser": "^5.4.0" }, "peerDependenciesMeta": { "sass": { From e077d7e917f34504d5f346099750a886577121a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BF=A0=20/=20green?= Date: Sat, 21 May 2022 04:20:01 +0900 Subject: [PATCH 04/18] chore: improve terser not found message --- packages/vite/src/node/plugins/terser.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vite/src/node/plugins/terser.ts b/packages/vite/src/node/plugins/terser.ts index e022862a5dd87a..1dc39dbfe26e0d 100644 --- a/packages/vite/src/node/plugins/terser.ts +++ b/packages/vite/src/node/plugins/terser.ts @@ -11,7 +11,7 @@ const loadTerserPath = (root: string) => { terserPath = requireResolveFromRootWithFallback(root, 'terser') } catch (e) { if (e.code === 'MODULE_NOT_FOUND') { - throw new Error(`terser not found. Did you install it?`) + throw new Error('terser not found. Did you install it? Since v3.0.0, terser has become a optional dependency and needs to be installed individually.') } else { const message = new Error(`terser failed to load:\n${e.message}`) message.stack = e.stack + '\n' + message.stack From ecfc29539da335068debb0df669d019478c843b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BF=A0=20/=20green?= Date: Sat, 21 May 2022 17:09:22 +0900 Subject: [PATCH 05/18] docs: use Terser instead of terser Co-authored-by: patak --- docs/config/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/config/index.md b/docs/config/index.md index 2f70aee7152a3f..821650b66f6304 100644 --- a/docs/config/index.md +++ b/docs/config/index.md @@ -880,7 +880,7 @@ export default defineConfig({ Set to `false` to disable minification, or specify the minifier to use. The default is [esbuild](https://github.com/evanw/esbuild) which is 20 ~ 40x faster than terser and only 1 ~ 2% worse compression. [Benchmarks](https://github.com/privatenumber/minification-benchmarks) - terser must be installed when it is set to `'terser'`. + Terser must be installed when it is set to `'terser'`. ```sh npm add -D terser From caacc4ee6158dc1515b0406bc7f8be779ac7a9eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BF=A0=20/=20green?= Date: Sat, 21 May 2022 17:10:01 +0900 Subject: [PATCH 06/18] chore: simplify terser not found message Co-authored-by: patak --- packages/vite/src/node/plugins/terser.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vite/src/node/plugins/terser.ts b/packages/vite/src/node/plugins/terser.ts index 1dc39dbfe26e0d..386f04d6fcd00a 100644 --- a/packages/vite/src/node/plugins/terser.ts +++ b/packages/vite/src/node/plugins/terser.ts @@ -11,7 +11,7 @@ const loadTerserPath = (root: string) => { terserPath = requireResolveFromRootWithFallback(root, 'terser') } catch (e) { if (e.code === 'MODULE_NOT_FOUND') { - throw new Error('terser not found. Did you install it? Since v3.0.0, terser has become a optional dependency and needs to be installed individually.') + throw new Error('terser not found. Since Vite v3, terser has become an optional dependency. You need to install it.') } else { const message = new Error(`terser failed to load:\n${e.message}`) message.stack = e.stack + '\n' + message.stack From 9278fc2f10cba88c9fd27bfea8acaecb7d5b7199 Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Sat, 21 May 2022 17:30:31 +0900 Subject: [PATCH 07/18] fix: terser import --- packages/vite/package.json | 3 --- packages/vite/src/node/plugins/terser.ts | 30 ++++++++++++++---------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/packages/vite/package.json b/packages/vite/package.json index 4f6759fc5da2ac..2dfd594d5189be 100644 --- a/packages/vite/package.json +++ b/packages/vite/package.json @@ -19,9 +19,6 @@ }, "./client": { "types": "./client.d.ts" - }, - "./terser": { - "require": "./dist/node-cjs/terser.cjs" } }, "files": [ diff --git a/packages/vite/src/node/plugins/terser.ts b/packages/vite/src/node/plugins/terser.ts index 5d585a5228169d..e94fd792e51249 100644 --- a/packages/vite/src/node/plugins/terser.ts +++ b/packages/vite/src/node/plugins/terser.ts @@ -1,15 +1,17 @@ -import { createRequire } from 'module' +import { pathToFileURL } from 'url' import { Worker } from 'okie' import type { Terser } from 'types/terser' import type { Plugin } from '../plugin' import type { ResolvedConfig } from '..' import { requireResolveFromRootWithFallback } from '../utils' -let terserPath: string | undefined -const loadTerserPath = (root: string) => { - if (terserPath) return terserPath +let terserFileUrl: URL | undefined +const loadTerserFileUrl = (root: string) => { + if (terserFileUrl) return terserFileUrl try { - terserPath = requireResolveFromRootWithFallback(root, 'terser') + terserFileUrl = pathToFileURL( + requireResolveFromRootWithFallback(root, 'terser') + ) } catch (e) { if (e.code === 'MODULE_NOT_FOUND') { throw new Error( @@ -21,17 +23,19 @@ const loadTerserPath = (root: string) => { throw message } } - return terserPath + return terserFileUrl } -// TODO: use import() -const _require = createRequire(import.meta.url) - export function terserPlugin(config: ResolvedConfig): Plugin { const makeWorker = () => new Worker( - (terserPath: string, code: string, options: Terser.MinifyOptions) => { - return _require(terserPath).minify(code, options) as Terser.MinifyOutput + async ( + terserFileUrl: string, + code: string, + options: Terser.MinifyOptions + ) => { + const terser = await import(terserFileUrl) + return terser.minify(code, options) as Terser.MinifyOutput } ) @@ -61,8 +65,8 @@ export function terserPlugin(config: ResolvedConfig): Plugin { // Lazy load worker. worker ||= makeWorker() - const terserPath = loadTerserPath(config.root) - const res = await worker.run(terserPath, code, { + const terserFileUrl = loadTerserFileUrl(config.root) + const res = await worker.run(terserFileUrl.href, code, { safari10: true, ...config.build.terserOptions, sourceMap: !!outputOptions.sourcemap, From ec34abf8be88ee82a5dad5c7c3b5290d82f0e564 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BF=A0=20/=20green?= Date: Sat, 21 May 2022 17:33:02 +0900 Subject: [PATCH 08/18] docs: use Terser instead of terser --- packages/plugin-legacy/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugin-legacy/README.md b/packages/plugin-legacy/README.md index 2e6521456812b3..557ca4bc20c210 100644 --- a/packages/plugin-legacy/README.md +++ b/packages/plugin-legacy/README.md @@ -27,7 +27,7 @@ export default { } ``` -terser must be installed because plugin-legacy uses terser for minification. +Terser must be installed because plugin-legacy uses Terser for minification. ```sh npm add -D terser From 0b054fcb7f12f175ca29005dbed0e852cad240f4 Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Sun, 22 May 2022 00:13:37 +0900 Subject: [PATCH 09/18] test: set `emptyOutDir: false` for flaky tests --- playground/vitestSetup.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/playground/vitestSetup.ts b/playground/vitestSetup.ts index 70ac682d7bec27..92ca0b89c5c86e 100644 --- a/playground/vitestSetup.ts +++ b/playground/vitestSetup.ts @@ -182,7 +182,8 @@ export async function startDefaultServe() { build: { // esbuild do not minify ES lib output since that would remove pure annotations and break tree-shaking // skip transpilation during tests to make it faster - target: 'esnext' + target: 'esnext', + emptyOutDir: false }, customLogger: createInMemoryLogger(serverLogs) } From f3d84505c850206f32aede3fe0e8d621bffdcf93 Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Sun, 22 May 2022 16:52:33 +0900 Subject: [PATCH 10/18] chore(deps): bump vitest to 0.12.9 from 0.12.4 --- package.json | 2 +- pnpm-lock.yaml | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index bcfa5acb5efdf0..da186e0b9ed3f0 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,7 @@ "unbuild": "^0.7.4", "vite": "workspace:*", "vitepress": "1.0.0-draft.1", - "vitest": "^0.12.4", + "vitest": "^0.12.9", "vue": "^3.2.33" }, "simple-git-hooks": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dfeecf1608e441..0355d78df817cf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -63,7 +63,7 @@ importers: unbuild: ^0.7.4 vite: workspace:* vitepress: 1.0.0-draft.1 - vitest: ^0.12.4 + vitest: ^0.12.9 vue: ^3.2.33 devDependencies: '@microsoft/api-extractor': 7.23.2 @@ -119,7 +119,7 @@ importers: unbuild: 0.7.4 vite: link:packages/vite vitepress: 1.0.0-draft.1 - vitest: 0.12.4 + vitest: 0.12.9 vue: 3.2.33 packages/create-vite: @@ -2911,7 +2911,7 @@ packages: dev: true /check-error/1.0.2: - resolution: {integrity: sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=} + resolution: {integrity: sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==} dev: true /chokidar/3.5.3: @@ -8416,8 +8416,8 @@ packages: - react-dom dev: true - /vitest/0.12.4: - resolution: {integrity: sha512-EDxdhlAt6vcu6y4VouAI60z78iCAVFnfBL4VlSQVQnGmOk5altOtIKvp3xfZ+cfo4iVHgqq1QNyf5qOFiL4leg==} + /vitest/0.12.9: + resolution: {integrity: sha512-1NtyUANS72Qw5PwYvoztk067NX4fSiis2xQxhByOWS33eL2er/yupHyLxlBCOkF2ANe0dLFRvT1GVb+nczL5aw==} engines: {node: '>=v14.16.0'} hasBin: true peerDependencies: @@ -8438,10 +8438,13 @@ packages: '@types/chai': 4.3.1 '@types/chai-subset': 1.3.3 chai: 4.3.6 + debug: 4.3.4 local-pkg: 0.4.1 tinypool: 0.1.3 tinyspy: 0.3.2 vite: link:packages/vite + transitivePeerDependencies: + - supports-color dev: true /void-elements/3.1.0: From 925fd584cd490f80432e1bffb4ba629e6fca627d Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Tue, 24 May 2022 21:08:16 +0900 Subject: [PATCH 11/18] chore: use require inside worker --- packages/vite/src/node/plugins/terser.ts | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/packages/vite/src/node/plugins/terser.ts b/packages/vite/src/node/plugins/terser.ts index e94fd792e51249..3ead4b3ad06dda 100644 --- a/packages/vite/src/node/plugins/terser.ts +++ b/packages/vite/src/node/plugins/terser.ts @@ -1,17 +1,14 @@ -import { pathToFileURL } from 'url' import { Worker } from 'okie' import type { Terser } from 'types/terser' import type { Plugin } from '../plugin' import type { ResolvedConfig } from '..' import { requireResolveFromRootWithFallback } from '../utils' -let terserFileUrl: URL | undefined -const loadTerserFileUrl = (root: string) => { - if (terserFileUrl) return terserFileUrl +let terserPath: string | undefined +const loadTerserPath = (root: string) => { + if (terserPath) return terserPath try { - terserFileUrl = pathToFileURL( - requireResolveFromRootWithFallback(root, 'terser') - ) + terserPath = requireResolveFromRootWithFallback(root, 'terser') } catch (e) { if (e.code === 'MODULE_NOT_FOUND') { throw new Error( @@ -23,18 +20,19 @@ const loadTerserFileUrl = (root: string) => { throw message } } - return terserFileUrl + return terserPath } export function terserPlugin(config: ResolvedConfig): Plugin { const makeWorker = () => new Worker( async ( - terserFileUrl: string, + terserPath: string, code: string, options: Terser.MinifyOptions ) => { - const terser = await import(terserFileUrl) + // eslint-disable-next-line no-restricted-globals -- this function runs inside cjs + const terser = require(terserPath) return terser.minify(code, options) as Terser.MinifyOutput } ) @@ -65,8 +63,8 @@ export function terserPlugin(config: ResolvedConfig): Plugin { // Lazy load worker. worker ||= makeWorker() - const terserFileUrl = loadTerserFileUrl(config.root) - const res = await worker.run(terserFileUrl.href, code, { + const terserPath = loadTerserPath(config.root) + const res = await worker.run(terserPath, code, { safari10: true, ...config.build.terserOptions, sourceMap: !!outputOptions.sourcemap, From eb0cc6133c3aaaec3b51c68852c3b1bb54a7b2a7 Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Tue, 24 May 2022 21:29:14 +0900 Subject: [PATCH 12/18] Revert "chore: use require inside worker" This reverts commit 925fd584cd490f80432e1bffb4ba629e6fca627d. --- packages/vite/src/node/plugins/terser.ts | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/packages/vite/src/node/plugins/terser.ts b/packages/vite/src/node/plugins/terser.ts index 3ead4b3ad06dda..e94fd792e51249 100644 --- a/packages/vite/src/node/plugins/terser.ts +++ b/packages/vite/src/node/plugins/terser.ts @@ -1,14 +1,17 @@ +import { pathToFileURL } from 'url' import { Worker } from 'okie' import type { Terser } from 'types/terser' import type { Plugin } from '../plugin' import type { ResolvedConfig } from '..' import { requireResolveFromRootWithFallback } from '../utils' -let terserPath: string | undefined -const loadTerserPath = (root: string) => { - if (terserPath) return terserPath +let terserFileUrl: URL | undefined +const loadTerserFileUrl = (root: string) => { + if (terserFileUrl) return terserFileUrl try { - terserPath = requireResolveFromRootWithFallback(root, 'terser') + terserFileUrl = pathToFileURL( + requireResolveFromRootWithFallback(root, 'terser') + ) } catch (e) { if (e.code === 'MODULE_NOT_FOUND') { throw new Error( @@ -20,19 +23,18 @@ const loadTerserPath = (root: string) => { throw message } } - return terserPath + return terserFileUrl } export function terserPlugin(config: ResolvedConfig): Plugin { const makeWorker = () => new Worker( async ( - terserPath: string, + terserFileUrl: string, code: string, options: Terser.MinifyOptions ) => { - // eslint-disable-next-line no-restricted-globals -- this function runs inside cjs - const terser = require(terserPath) + const terser = await import(terserFileUrl) return terser.minify(code, options) as Terser.MinifyOutput } ) @@ -63,8 +65,8 @@ export function terserPlugin(config: ResolvedConfig): Plugin { // Lazy load worker. worker ||= makeWorker() - const terserPath = loadTerserPath(config.root) - const res = await worker.run(terserPath, code, { + const terserFileUrl = loadTerserFileUrl(config.root) + const res = await worker.run(terserFileUrl.href, code, { safari10: true, ...config.build.terserOptions, sourceMap: !!outputOptions.sourcemap, From 706840f4e847b1264c18da75ad528d4d2decab1c Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Tue, 24 May 2022 21:35:14 +0900 Subject: [PATCH 13/18] Revert "Revert "chore: use require inside worker"" This reverts commit eb0cc6133c3aaaec3b51c68852c3b1bb54a7b2a7. --- packages/vite/src/node/plugins/terser.ts | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/packages/vite/src/node/plugins/terser.ts b/packages/vite/src/node/plugins/terser.ts index e94fd792e51249..3ead4b3ad06dda 100644 --- a/packages/vite/src/node/plugins/terser.ts +++ b/packages/vite/src/node/plugins/terser.ts @@ -1,17 +1,14 @@ -import { pathToFileURL } from 'url' import { Worker } from 'okie' import type { Terser } from 'types/terser' import type { Plugin } from '../plugin' import type { ResolvedConfig } from '..' import { requireResolveFromRootWithFallback } from '../utils' -let terserFileUrl: URL | undefined -const loadTerserFileUrl = (root: string) => { - if (terserFileUrl) return terserFileUrl +let terserPath: string | undefined +const loadTerserPath = (root: string) => { + if (terserPath) return terserPath try { - terserFileUrl = pathToFileURL( - requireResolveFromRootWithFallback(root, 'terser') - ) + terserPath = requireResolveFromRootWithFallback(root, 'terser') } catch (e) { if (e.code === 'MODULE_NOT_FOUND') { throw new Error( @@ -23,18 +20,19 @@ const loadTerserFileUrl = (root: string) => { throw message } } - return terserFileUrl + return terserPath } export function terserPlugin(config: ResolvedConfig): Plugin { const makeWorker = () => new Worker( async ( - terserFileUrl: string, + terserPath: string, code: string, options: Terser.MinifyOptions ) => { - const terser = await import(terserFileUrl) + // eslint-disable-next-line no-restricted-globals -- this function runs inside cjs + const terser = require(terserPath) return terser.minify(code, options) as Terser.MinifyOutput } ) @@ -65,8 +63,8 @@ export function terserPlugin(config: ResolvedConfig): Plugin { // Lazy load worker. worker ||= makeWorker() - const terserFileUrl = loadTerserFileUrl(config.root) - const res = await worker.run(terserFileUrl.href, code, { + const terserPath = loadTerserPath(config.root) + const res = await worker.run(terserPath, code, { safari10: true, ...config.build.terserOptions, sourceMap: !!outputOptions.sourcemap, From 80de213d16a61f8df41bf441dca518a423a2153b Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Sat, 28 May 2022 21:52:57 +0900 Subject: [PATCH 14/18] chore: add comment about import inside worker --- packages/vite/src/node/plugins/terser.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/vite/src/node/plugins/terser.ts b/packages/vite/src/node/plugins/terser.ts index 3ead4b3ad06dda..6362ca0b726fbf 100644 --- a/packages/vite/src/node/plugins/terser.ts +++ b/packages/vite/src/node/plugins/terser.ts @@ -31,6 +31,7 @@ export function terserPlugin(config: ResolvedConfig): Plugin { code: string, options: Terser.MinifyOptions ) => { + // test fails when using `import`. maybe related: https://github.com/nodejs/node/issues/43205 // eslint-disable-next-line no-restricted-globals -- this function runs inside cjs const terser = require(terserPath) return terser.minify(code, options) as Terser.MinifyOutput From 6385a9b3df9de72f83237a565a4f9a94caed5839 Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Sat, 28 May 2022 21:54:15 +0900 Subject: [PATCH 15/18] chore: add comment about emptyOutDir --- playground/vitestSetup.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/playground/vitestSetup.ts b/playground/vitestSetup.ts index 92ca0b89c5c86e..13e7592ad380f2 100644 --- a/playground/vitestSetup.ts +++ b/playground/vitestSetup.ts @@ -183,6 +183,7 @@ export async function startDefaultServe() { // esbuild do not minify ES lib output since that would remove pure annotations and break tree-shaking // skip transpilation during tests to make it faster target: 'esnext', + // tests are flaky when `emptyOutDir` is `true` emptyOutDir: false }, customLogger: createInMemoryLogger(serverLogs) From d449ace487dbb833e7e8cef6d0c2c9902fffe38f Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Tue, 31 May 2022 14:06:44 +0900 Subject: [PATCH 16/18] chore: add return type to requireResolveFromRootWithFallback --- packages/vite/src/node/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vite/src/node/utils.ts b/packages/vite/src/node/utils.ts index e8e6706e023422..8d52dc2bfe1e53 100644 --- a/packages/vite/src/node/utils.ts +++ b/packages/vite/src/node/utils.ts @@ -794,7 +794,7 @@ export function getHash(text: Buffer | string): string { export const requireResolveFromRootWithFallback = ( root: string, id: string -) => { +): string => { // Search in the root directory first, and fallback to the default require paths. const fallbackPaths = _require.resolve.paths?.(id) || [] const path = _require.resolve(id, { From b6ec807e863e0e27cb16846f995c8e3a5c48b9fd Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Tue, 31 May 2022 20:13:01 +0900 Subject: [PATCH 17/18] fix: use createRequire(root) --- packages/vite/src/node/utils.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/vite/src/node/utils.ts b/packages/vite/src/node/utils.ts index 8d52dc2bfe1e53..b3d61c72e99bd4 100644 --- a/packages/vite/src/node/utils.ts +++ b/packages/vite/src/node/utils.ts @@ -795,12 +795,12 @@ export const requireResolveFromRootWithFallback = ( root: string, id: string ): string => { - // Search in the root directory first, and fallback to the default require paths. - const fallbackPaths = _require.resolve.paths?.(id) || [] - const path = _require.resolve(id, { - paths: [root, ...fallbackPaths] - }) - return path + // require in the root directory first, and fallback to the default require. + const _requireFromRoot = createRequire(path.resolve(root, './index.cjs')) + try { + return _requireFromRoot.resolve(id) + } catch {} + return _require.resolve(id) } // Based on node-graceful-fs From 8e1d22b39ca6715cde4f5634e01399ba7114e606 Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Tue, 31 May 2022 21:21:25 +0900 Subject: [PATCH 18/18] Revert "fix: use createRequire(root)" This reverts commit b6ec807e863e0e27cb16846f995c8e3a5c48b9fd. --- packages/vite/src/node/utils.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/vite/src/node/utils.ts b/packages/vite/src/node/utils.ts index b3d61c72e99bd4..8d52dc2bfe1e53 100644 --- a/packages/vite/src/node/utils.ts +++ b/packages/vite/src/node/utils.ts @@ -795,12 +795,12 @@ export const requireResolveFromRootWithFallback = ( root: string, id: string ): string => { - // require in the root directory first, and fallback to the default require. - const _requireFromRoot = createRequire(path.resolve(root, './index.cjs')) - try { - return _requireFromRoot.resolve(id) - } catch {} - return _require.resolve(id) + // Search in the root directory first, and fallback to the default require paths. + const fallbackPaths = _require.resolve.paths?.(id) || [] + const path = _require.resolve(id, { + paths: [root, ...fallbackPaths] + }) + return path } // Based on node-graceful-fs