From 184e214d24116e5510ad958c67338f6cd7741183 Mon Sep 17 00:00:00 2001 From: Haoqun Jiang Date: Mon, 15 Mar 2021 15:30:42 +0800 Subject: [PATCH 1/8] feat: when `transpileDependencies` is set to `true`, transpile all dependencies in `node_modules` --- packages/@vue/cli-plugin-babel/index.js | 34 +++++++++++++------ packages/@vue/cli-service/lib/options.js | 11 +++--- .../cli-service/types/ProjectOptions.d.ts | 8 +++-- 3 files changed, 35 insertions(+), 18 deletions(-) diff --git a/packages/@vue/cli-plugin-babel/index.js b/packages/@vue/cli-plugin-babel/index.js index d42039c46d..7a1c540332 100644 --- a/packages/@vue/cli-plugin-babel/index.js +++ b/packages/@vue/cli-plugin-babel/index.js @@ -3,6 +3,10 @@ const babel = require('@babel/core') const { isWindows } = require('@vue/cli-shared-utils') function genTranspileDepRegex (transpileDependencies) { + if (!Array.isArray(transpileDependencies)) { + return + } + const deps = transpileDependencies.map(dep => { if (typeof dep === 'string') { const depPath = path.join('node_modules', dep, '/') @@ -39,34 +43,44 @@ module.exports = (api, options) => { .test(/\.m?jsx?$/) .exclude .add(filepath => { + const SHOULD_SKIP = true + const SHOULD_TRANSPILE = false + // With data URI support in webpack 5, filepath could be undefined if (!filepath) { - return true + return SHOULD_SKIP } - // always transpile js in vue files + // Always transpile js in vue files if (/\.vue\.jsx?$/.test(filepath)) { - return false + return SHOULD_TRANSPILE } - // exclude dynamic entries from cli-service + // Exclude dynamic entries from cli-service if (filepath.startsWith(cliServicePath)) { - return true + return SHOULD_SKIP } - // only include @babel/runtime when the @vue/babel-preset-app preset is used + // To transpile `@babel/runtime`, the config needs to be + // carefully adjusted to avoid infinite loops. + // So we only do the tranpilation when the special flag is on. if ( process.env.VUE_CLI_TRANSPILE_BABEL_RUNTIME && filepath.includes(path.join('@babel', 'runtime')) ) { - return false + return SHOULD_TRANSPILE + } + + // if `transpileDependencies` is set to true, transpile all deps + if (options.transpileDependencies === true) { + return SHOULD_TRANSPILE } - // check if this is something the user explicitly wants to transpile + // Otherwise, check if this is something the user explicitly wants to transpile if (transpileDepRegex && transpileDepRegex.test(filepath)) { - return false + return SHOULD_TRANSPILE } // Don't transpile node_modules - return /node_modules/.test(filepath) + return /node_modules/.test(filepath) ? SHOULD_SKIP : SHOULD_TRANSPILE }) .end() diff --git a/packages/@vue/cli-service/lib/options.js b/packages/@vue/cli-service/lib/options.js index 3a1655ebb5..e25c60266e 100644 --- a/packages/@vue/cli-service/lib/options.js +++ b/packages/@vue/cli-service/lib/options.js @@ -7,7 +7,10 @@ const schema = createSchema(joi => joi.object({ indexPath: joi.string(), filenameHashing: joi.boolean(), runtimeCompiler: joi.boolean(), - transpileDependencies: joi.array(), + transpileDependencies: joi.alternatives().try( + joi.booelan(), + joi.array() + ), productionSourceMap: joi.boolean(), parallel: joi.alternatives().try( joi.boolean(), @@ -94,10 +97,8 @@ exports.defaults = () => ({ // boolean, use full build? runtimeCompiler: false, - // deps to transpile - transpileDependencies: [ - /* string or regex */ - ], + // whether to transpile all dependencies + transpileDependencies: false, // sourceMap for production build? productionSourceMap: !process.env.VUE_CLI_TEST, diff --git a/packages/@vue/cli-service/types/ProjectOptions.d.ts b/packages/@vue/cli-service/types/ProjectOptions.d.ts index 0485ba5c0b..4ea5b1fe38 100644 --- a/packages/@vue/cli-service/types/ProjectOptions.d.ts +++ b/packages/@vue/cli-service/types/ProjectOptions.d.ts @@ -87,11 +87,13 @@ interface ProjectOptions { */ runtimeCompiler?: boolean; /** - * Default: `[]` + * Default: `false` * - * If you want to explicitly transpile a dependency with Babel, you can list it in this option + * If set to `true`, all dependencies in `node_modules` will be transpiled by Babel; + * Or, if you only want to selectively transpile some of the dependencies, you can list them + * in this option. */ - transpileDependencies?: Array; + transpileDependencies?: boolean | Array; /** * Default: `true` * From bca824ad8d116ee8ff6d551e7d9d6e64b0e1b720 Mon Sep 17 00:00:00 2001 From: Haoqun Jiang Date: Mon, 15 Mar 2021 16:00:34 +0800 Subject: [PATCH 2/8] fix: typo --- packages/@vue/cli-service/lib/options.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@vue/cli-service/lib/options.js b/packages/@vue/cli-service/lib/options.js index e25c60266e..232192c3e6 100644 --- a/packages/@vue/cli-service/lib/options.js +++ b/packages/@vue/cli-service/lib/options.js @@ -8,7 +8,7 @@ const schema = createSchema(joi => joi.object({ filenameHashing: joi.boolean(), runtimeCompiler: joi.boolean(), transpileDependencies: joi.alternatives().try( - joi.booelan(), + joi.boolean(), joi.array() ), productionSourceMap: joi.boolean(), From e85c452c08f2feb24d343b25ab03e2bc942508c8 Mon Sep 17 00:00:00 2001 From: Haoqun Jiang Date: Thu, 18 Mar 2021 17:35:43 +0800 Subject: [PATCH 3/8] docs: update `transpileDependencies` documentation --- docs/config/README.md | 8 +++++--- docs/core-plugins/babel.md | 4 +++- docs/zh/config/README.md | 9 ++++++--- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/docs/config/README.md b/docs/config/README.md index b2a6f720a8..7866543f54 100644 --- a/docs/config/README.md +++ b/docs/config/README.md @@ -183,10 +183,12 @@ Deprecated since Vue CLI 3.3, please use [`publicPath`](#publicPath) instead. ### transpileDependencies -- Type: `Array` -- Default: `[]` +- Type: `boolean | Array` +- Default: `false` + + By default `babel-loader` ignores all files inside `node_modules`. You can enable this option to avoid unexpected untranspiled code from third-party dependencies. - By default `babel-loader` ignores all files inside `node_modules`. If you want to explicitly transpile a dependency with Babel, you can list it in this option. + Transpiling all the dependencies could slow down the build process, though. If build performance is a concern, you can explicitly transpile only some of the dependencies by passing an array of package names or name patterns to this option. ::: warning Jest config This option is not respected by the [cli-unit-jest plugin](#jest), because in jest, we don't have to transpile code from `/node_modules` unless it uses non-standard features - Node >8.11 supports the latest ECMAScript features already. diff --git a/docs/core-plugins/babel.md b/docs/core-plugins/babel.md index 70eea46f79..113ffb477d 100644 --- a/docs/core-plugins/babel.md +++ b/docs/core-plugins/babel.md @@ -6,10 +6,12 @@ Uses Babel 7 + `babel-loader` + [@vue/babel-preset-app](https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/babel-preset-app) by default, but can be configured via `babel.config.js` to use any other Babel presets or plugins. -By default, `babel-loader` excludes files inside `node_modules` dependencies. If you wish to explicitly transpile a dependency module, you will need to add it to the `transpileDependencies` option in `vue.config.js`: +By default, `babel-loader` excludes files inside `node_modules` dependencies. You can enable the `transpileDependencies` option in `vue.config.js` to transpile the dependencies. Or, if you want to only transpile some of the dependency modules, you can pass an array to the `transpileDependencies` option: ``` js module.exports = { + // Set to `true` to transpile all dependencies. + // Or pass an array to transpile selectively. transpileDependencies: [ // can be string or regex 'my-dep', diff --git a/docs/zh/config/README.md b/docs/zh/config/README.md index 752d3e5015..004ec5a7a9 100644 --- a/docs/zh/config/README.md +++ b/docs/zh/config/README.md @@ -183,10 +183,13 @@ module.exports = { ### transpileDependencies -- Type: `Array` -- Default: `[]` +- Type: `boolean | Array` +- Default: `false` + + 默认情况下 `babel-loader` 会忽略所有 `node_modules` 中的文件。你可以启用本选项,以避免构建后的代码中出现未转译的第三方依赖。 + + 不过,对所有的依赖都进行转译可能会降低构建速度。如果对构建性能有所顾虑,你可以只转译部分特定的依赖:给本选项传一个数组,列出需要转译的第三方包包名或正则表达式即可。 - 默认情况下 `babel-loader` 会忽略所有 `node_modules` 中的文件。如果你想要通过 Babel 显式转译一个依赖,可以在这个选项中列出来。 ### productionSourceMap From 23897054cca108c1f42c635638fef12734149f92 Mon Sep 17 00:00:00 2001 From: Haoqun Jiang Date: Thu, 18 Mar 2021 17:41:30 +0800 Subject: [PATCH 4/8] docs: mention in the migration guide --- docs/migrations/migrate-from-v4.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/migrations/migrate-from-v4.md b/docs/migrations/migrate-from-v4.md index b00b73d4dd..b1f5af7b92 100644 --- a/docs/migrations/migrate-from-v4.md +++ b/docs/migrations/migrate-from-v4.md @@ -92,6 +92,10 @@ No longer supports generating project with `node-sass`. It has been [deprecated] * `terser-webpack-plugin` is upgraded from v2 to v5 (v4 if you choose to stay at webpack 4), using terser 5 and some there are some changes in the options format. See full details in its [changelog](https://github.com/webpack-contrib/terser-webpack-plugin/blob/master/CHANGELOG.md). * When creating new projects, the default `less-loader` is updated from [v5 to v8](https://github.com/webpack-contrib/less-loader/blob/master/CHANGELOG.md)(v7 for webpack 4 users); `less` from [v3 to v4](https://github.com/less/less.js/pull/3573); `sass-loader` from [v8 to v11](https://github.com/webpack-contrib/sass-loader/blob/master/CHANGELOG.md) (v10 for webpack 4 users); `stylus-loader` from [v3 to v5](https://github.com/webpack-contrib/stylus-loader/blob/master/CHANGELOG.md) (v4 for webpack 4 users). +### Babel Plugin + +The [`transpileDependencies` option](../config/#transpiledependencies) now accepts a boolean value. Setting it to `true` will transpile all dependencies inside `node_modules`. + ### ESLint Plugin * `eslint-loader` is replaced by [eslint-webpack-plugin](https://github.com/webpack-contrib/eslint-webpack-plugin), dropping support for ESLint <= 6. From 9f1d55ba18dc84b63e9a4c58156a2bd55a016b73 Mon Sep 17 00:00:00 2001 From: Haoqun Jiang Date: Mon, 22 Mar 2021 20:28:33 +0800 Subject: [PATCH 5/8] fix: should skip babel runtime transpilation even if node_modules are included --- packages/@vue/cli-plugin-babel/index.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/@vue/cli-plugin-babel/index.js b/packages/@vue/cli-plugin-babel/index.js index 7a1c540332..7cb631afd3 100644 --- a/packages/@vue/cli-plugin-babel/index.js +++ b/packages/@vue/cli-plugin-babel/index.js @@ -63,11 +63,8 @@ module.exports = (api, options) => { // To transpile `@babel/runtime`, the config needs to be // carefully adjusted to avoid infinite loops. // So we only do the tranpilation when the special flag is on. - if ( - process.env.VUE_CLI_TRANSPILE_BABEL_RUNTIME && - filepath.includes(path.join('@babel', 'runtime')) - ) { - return SHOULD_TRANSPILE + if (filepath.includes(path.join('@babel', 'runtime'))) { + return process.env.VUE_CLI_TRANSPILE_BABEL_RUNTIME ? SHOULD_TRANSPILE : SHOULD_SKIP } // if `transpileDependencies` is set to true, transpile all deps From 5f6ee3fc8f75ab25673ae7a4f132393e0f7c2e44 Mon Sep 17 00:00:00 2001 From: Haoqun Jiang Date: Mon, 22 Mar 2021 20:33:18 +0800 Subject: [PATCH 6/8] test: add test for `transpileDependencies: true` --- .../__tests__/transpileDependencies.spec.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/@vue/cli-plugin-babel/__tests__/transpileDependencies.spec.js b/packages/@vue/cli-plugin-babel/__tests__/transpileDependencies.spec.js index 3f3dba1ba1..1c5d6c25c5 100644 --- a/packages/@vue/cli-plugin-babel/__tests__/transpileDependencies.spec.js +++ b/packages/@vue/cli-plugin-babel/__tests__/transpileDependencies.spec.js @@ -68,12 +68,12 @@ afterAll(async () => { await project.rm('package.json') }) -test('dep from node_modules should not been transpiled', async () => { +test('dep from node_modules should not been transpiled by default', async () => { await project.run('vue-cli-service build') expect(await readVendorFile()).toMatch('() => "__TEST__"') }) -test('dep from node_modules should been transpiled', async () => { +test('dep from node_modules should been transpiled when matched by transpileDependencies', async () => { await project.write( 'vue.config.js', `module.exports = { transpileDependencies: ['external-dep', '@scope/external-dep'] }` @@ -84,6 +84,17 @@ test('dep from node_modules should been transpiled', async () => { expect(await readVendorFile()).toMatch('return "__SCOPE_TEST__"') }) +test('dep from node_modules should been transpiled when transpileDependencies is true', async () => { + await project.write( + 'vue.config.js', + `module.exports = { transpileDependencies: true }` + ) + await project.run('vue-cli-service build') + expect(await readVendorFile()).toMatch('return "__TEST__"') + + expect(await readVendorFile()).toMatch('return "__SCOPE_TEST__"') +}) + // https://github.com/vuejs/vue-cli/issues/3057 test('only transpile package with same name specified in transpileDependencies', async () => { await project.write( From 701bb12099e56349d6fe05d6034b84cf0f81ec3f Mon Sep 17 00:00:00 2001 From: Haoqun Jiang Date: Tue, 23 Mar 2021 16:29:57 +0800 Subject: [PATCH 7/8] test: the iterableToArray test is outdated --- .../__tests__/babelRuntime.spec.js | 43 ++++++++++--------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/packages/@vue/cli-plugin-babel/__tests__/babelRuntime.spec.js b/packages/@vue/cli-plugin-babel/__tests__/babelRuntime.spec.js index de56514f49..89a0b0584a 100644 --- a/packages/@vue/cli-plugin-babel/__tests__/babelRuntime.spec.js +++ b/packages/@vue/cli-plugin-babel/__tests__/babelRuntime.spec.js @@ -4,30 +4,31 @@ const { defaultPreset } = require('@vue/cli/lib/options') const create = require('@vue/cli-test-utils/createTestProject') const serve = require('@vue/cli-test-utils/serveWithPuppeteer') -test('should add polyfills for code in @babel/runtime', async () => { - const project = await create('babel-runtime-polyfills', defaultPreset) +// iterableToArray no longer required in babel/runtime 7.8.7+ +// test('should add polyfills for code in @babel/runtime', async () => { +// const project = await create('babel-runtime-polyfills', defaultPreset) - await project.write('src/main.js', ` - const x = function () { - setTimeout( - // eslint-disable-next-line - () => console.log(...arguments), 100 - ); - } - x(1, 2) - `) +// await project.write('src/main.js', ` +// const x = function () { +// setTimeout( +// // eslint-disable-next-line +// () => console.log(...arguments), 100 +// ); +// } +// x(1, 2) +// `) - await project.run('vue-cli-service build --mode development') - const vendorFile = await project.read('dist/js/chunk-vendors.js') +// await project.run('vue-cli-service build --mode development') +// const vendorFile = await project.read('dist/js/chunk-vendors.js') - // iterableToArray is used to transform `console.log(...arguments)` - expect(vendorFile).toMatch('iterableToArray') - // with inline helpers, preset-env can detect the symbol polyfill is required - // (because the implementation of `iterableToArray` relies on it) - // however, with transform-runtime plugin, helpers are only references to @babel/runtime modules - // so we need to make sure polyfill detection is enabled for @babel/runtime too - expect(vendorFile).toMatch('es.symbol') -}) +// // iterableToArray is used to transform `console.log(...arguments)` +// expect(vendorFile).toMatch('iterableToArray') +// // with inline helpers, preset-env can detect the symbol polyfill is required +// // (because the implementation of `iterableToArray` relies on it) +// // however, with transform-runtime plugin, helpers are only references to @babel/runtime modules +// // so we need to make sure polyfill detection is enabled for @babel/runtime too +// expect(vendorFile).toMatch('es.symbol') +// }) test('should not transpile babel helpers multiple times', async () => { const project = await create('babel-runtime-helpers', defaultPreset) From 08a4f5e648a7d7b599972c2c444b03ccd14ba263 Mon Sep 17 00:00:00 2001 From: Haoqun Jiang Date: Tue, 23 Mar 2021 16:30:18 +0800 Subject: [PATCH 8/8] fix: some of the deps can not be transpiled --- packages/@vue/cli-plugin-babel/index.js | 38 +++++++++++++++++-------- 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/packages/@vue/cli-plugin-babel/index.js b/packages/@vue/cli-plugin-babel/index.js index 7cb631afd3..414896396f 100644 --- a/packages/@vue/cli-plugin-babel/index.js +++ b/packages/@vue/cli-plugin-babel/index.js @@ -2,12 +2,8 @@ const path = require('path') const babel = require('@babel/core') const { isWindows } = require('@vue/cli-shared-utils') -function genTranspileDepRegex (transpileDependencies) { - if (!Array.isArray(transpileDependencies)) { - return - } - - const deps = transpileDependencies.map(dep => { +function getDepPathRegex (dependencies) { + const deps = dependencies.map(dep => { if (typeof dep === 'string') { const depPath = path.join('node_modules', dep, '/') return isWindows @@ -26,7 +22,6 @@ function genTranspileDepRegex (transpileDependencies) { module.exports = (api, options) => { const useThreads = process.env.NODE_ENV === 'production' && !!options.parallel const cliServicePath = path.dirname(require.resolve('@vue/cli-service')) - const transpileDepRegex = genTranspileDepRegex(options.transpileDependencies) // try to load the project babel config; // if the default preset is used, @@ -63,19 +58,38 @@ module.exports = (api, options) => { // To transpile `@babel/runtime`, the config needs to be // carefully adjusted to avoid infinite loops. // So we only do the tranpilation when the special flag is on. - if (filepath.includes(path.join('@babel', 'runtime'))) { - return process.env.VUE_CLI_TRANSPILE_BABEL_RUNTIME ? SHOULD_TRANSPILE : SHOULD_SKIP + if (getDepPathRegex(['@babel/runtime']).test(filepath)) { + return process.env.VUE_CLI_TRANSPILE_BABEL_RUNTIME + ? SHOULD_TRANSPILE + : SHOULD_SKIP } // if `transpileDependencies` is set to true, transpile all deps if (options.transpileDependencies === true) { - return SHOULD_TRANSPILE + // Some of the deps cannot be transpiled, though + // https://stackoverflow.com/a/58517865/2302258 + const NON_TRANSPILABLE_DEPS = [ + 'core-js', + 'webpack', + 'webpack-4', + 'css-loader', + 'mini-css-extract-plugin', + 'promise-polyfill', + 'html-webpack-plugin', + 'whatwg-fetch' + ] + const nonTranspilableDepsRegex = getDepPathRegex(NON_TRANSPILABLE_DEPS) + return nonTranspilableDepsRegex.test(filepath) ? SHOULD_SKIP : SHOULD_TRANSPILE } // Otherwise, check if this is something the user explicitly wants to transpile - if (transpileDepRegex && transpileDepRegex.test(filepath)) { - return SHOULD_TRANSPILE + if (Array.isArray(options.transpileDependencies)) { + const transpileDepRegex = getDepPathRegex(options.transpileDependencies) + if (transpileDepRegex && transpileDepRegex.test(filepath)) { + return SHOULD_TRANSPILE + } } + // Don't transpile node_modules return /node_modules/.test(filepath) ? SHOULD_SKIP : SHOULD_TRANSPILE })