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<string | RegExp>` -- Default: `[]` +- Type: `boolean | Array<string | RegExp>` +- 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/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. 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<string | RegExp>` -- Default: `[]` +- Type: `boolean | Array<string | RegExp>` +- Default: `false` + + 默认情况下 `babel-loader` 会忽略所有 `node_modules` 中的文件。你可以启用本选项,以避免构建后的代码中出现未转译的第三方依赖。 + + 不过,对所有的依赖都进行转译可能会降低构建速度。如果对构建性能有所顾虑,你可以只转译部分特定的依赖:给本选项传一个数组,列出需要转译的第三方包包名或正则表达式即可。 - 默认情况下 `babel-loader` 会忽略所有 `node_modules` 中的文件。如果你想要通过 Babel 显式转译一个依赖,可以在这个选项中列出来。 ### productionSourceMap 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) 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( diff --git a/packages/@vue/cli-plugin-babel/index.js b/packages/@vue/cli-plugin-babel/index.js index d42039c46d..414896396f 100644 --- a/packages/@vue/cli-plugin-babel/index.js +++ b/packages/@vue/cli-plugin-babel/index.js @@ -2,8 +2,8 @@ const path = require('path') const babel = require('@babel/core') const { isWindows } = require('@vue/cli-shared-utils') -function genTranspileDepRegex (transpileDependencies) { - 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 @@ -22,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, @@ -39,34 +38,60 @@ 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 + } + + // 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 (getDepPathRegex(['@babel/runtime']).test(filepath)) { + return process.env.VUE_CLI_TRANSPILE_BABEL_RUNTIME + ? SHOULD_TRANSPILE + : SHOULD_SKIP } - // only include @babel/runtime when the @vue/babel-preset-app preset is used - if ( - process.env.VUE_CLI_TRANSPILE_BABEL_RUNTIME && - filepath.includes(path.join('@babel', 'runtime')) - ) { - return false + // if `transpileDependencies` is set to true, transpile all deps + if (options.transpileDependencies === true) { + // 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 } - // check if this is something the user explicitly wants to transpile - if (transpileDepRegex && transpileDepRegex.test(filepath)) { - return false + // Otherwise, check if this is something the user explicitly wants to 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) + 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..232192c3e6 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.boolean(), + 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<string | RegExp>; + transpileDependencies?: boolean | Array<string | RegExp>; /** * Default: `true` *