mirror of
https://github.com/vuejs/vue-cli.git
synced 2026-01-28 10:09:18 -06:00
feat(babel): better Babel polyfill defaults
- Now includes polyfills for Promise and Object.assign by default; - New option "polyfills" for @vue/babel-preset-app allows customization of included-by-default polyfills.
This commit is contained in:
@@ -12,6 +12,7 @@ This is the default Babel preset used in all Vue CLI projects.
|
||||
- `targets` is determined:
|
||||
- using `browserslist` field in `package.json` when building for browsers
|
||||
- set to `{ node: 'current' }` when running unit tests in Node.js
|
||||
- Includes `Promise` and `Object.assign` polyfills by default so that they are usable even in non-transpiled dependencies (only for environments that need them)
|
||||
- [@babel/plugin-transform-runtime](https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-runtime)
|
||||
- Only enabled for helpers since polyfills are handled by `babel-preset-env`
|
||||
- [dynamic import syntax](https://github.com/tc39/proposal-dynamic-import)
|
||||
@@ -45,7 +46,25 @@ This is the default Babel preset used in all Vue CLI projects.
|
||||
|
||||
Default: `'usage'`
|
||||
|
||||
Explicitly set `useBuiltIns` option for `babel-preset-env`. See [babel-preset-env docs](https://github.com/babel/babel/tree/master/packages/babel-preset-env#usebuiltins) for more details.
|
||||
Explicitly set `useBuiltIns` option for `babel-preset-env`.
|
||||
|
||||
The default value is `'usage'`, which adds imports to polyfills based on the usage in transpiled code. Note that the usage detection does not apply to your dependencies (which are excluded by `cli-plugin-babel` by default). If one of your dependencies need polyfills, you have three options:
|
||||
|
||||
1. Add that dependency to the `transpileDependencies` option in `vue.config.js`. This would enable the same usage-based polyfill detection for that dependency as well;
|
||||
|
||||
2. OR, you can explicitly include the needed polyfills using the [polyfills](#polyfills) option for this preset.
|
||||
|
||||
3. Use `useBuiltIns: 'entry'` and then add `import '@babel/polyfill'` to your entry file. This will import **ALL** polyfills based on your `browserslist` targets so that you don't need to worry about dependency polyfills anymore, but will likely bloat your final bundle with some unused polyfills.
|
||||
|
||||
See [babel-preset-env docs](https://github.com/babel/babel/tree/master/packages/babel-preset-env#usebuiltins) for more details.
|
||||
|
||||
- **polyfills**
|
||||
|
||||
Default: `['es6.promise', 'es6.object.assign']`
|
||||
|
||||
A list of [core-js](https://github.com/zloirock/core-js) polyfills to force-include when using `useBuiltIns: 'usage'`.
|
||||
|
||||
Use this option when you have 3rd party dependencies that are not processed by Babel but have specific polyfill requirements. **These polyfills are automatically excluded if they are not needed for your target environments specified via `browserslist`**.
|
||||
|
||||
- **jsx**
|
||||
|
||||
|
||||
@@ -7,24 +7,32 @@ const defaultOptions = {
|
||||
|
||||
test('polyfill detection', () => {
|
||||
let { code } = babel.transformSync(`
|
||||
const a = Promise.resolve()
|
||||
const a = new Map()
|
||||
`.trim(), {
|
||||
babelrc: false,
|
||||
presets: [[preset, {
|
||||
targets: { node: 'current' }
|
||||
}]]
|
||||
})
|
||||
// default includes
|
||||
expect(code).not.toMatch(`import "core-js/modules/es6.promise"`)
|
||||
expect(code).not.toMatch(`import "core-js/modules/es6.object.assign"`)
|
||||
// usage-based detection
|
||||
expect(code).not.toMatch(`import "core-js/modules/es6.map"`)
|
||||
|
||||
;({ code } = babel.transformSync(`
|
||||
const a = Promise.resolve()
|
||||
const a = new Map()
|
||||
`.trim(), {
|
||||
babelrc: false,
|
||||
presets: [[preset, {
|
||||
targets: { ie: 9 }
|
||||
}]]
|
||||
}))
|
||||
// default includes
|
||||
expect(code).toMatch(`import "core-js/modules/es6.promise"`)
|
||||
expect(code).toMatch(`import "core-js/modules/es6.object.assign"`)
|
||||
// usage-based detection
|
||||
expect(code).toMatch(`import "core-js/modules/es6.map"`)
|
||||
})
|
||||
|
||||
test('object spread', () => {
|
||||
@@ -52,7 +60,7 @@ test('async/await', () => {
|
||||
// should use regenerator runtime
|
||||
expect(code).toMatch(`import "regenerator-runtime/runtime"`)
|
||||
// should use required helper instead of inline
|
||||
expect(code).toMatch(/@babel.*runtime\/helpers\/asyncToGenerator/)
|
||||
expect(code).toMatch(/@babel.*runtime\/helpers\/.*asyncToGenerator/)
|
||||
})
|
||||
|
||||
test('jsx', () => {
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
const path = require('path')
|
||||
|
||||
const defaultPolyfills = [
|
||||
'es6.promise',
|
||||
'es6.object.assign'
|
||||
]
|
||||
|
||||
function getPolyfills (targets, includes, { ignoreBrowserslistConfig, configPath }) {
|
||||
const { isPluginRequired } = require('@babel/preset-env')
|
||||
const builtInsList = require('@babel/preset-env/data/built-ins.json')
|
||||
const getTargets = require('@babel/preset-env/lib/targets-parser').default
|
||||
const builtInTargets = getTargets(targets, {
|
||||
ignoreBrowserslistConfig,
|
||||
configPath
|
||||
})
|
||||
|
||||
return includes.filter(item => {
|
||||
return isPluginRequired(builtInTargets, builtInsList[item])
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = (context, options = {}) => {
|
||||
const presets = []
|
||||
const plugins = []
|
||||
@@ -15,23 +34,55 @@ module.exports = (context, options = {}) => {
|
||||
}
|
||||
|
||||
const {
|
||||
polyfills: userPolyfills,
|
||||
loose = false,
|
||||
useBuiltIns = 'usage',
|
||||
modules = false,
|
||||
targets,
|
||||
targets: rawTargets,
|
||||
spec,
|
||||
ignoreBrowserslistConfig,
|
||||
configPath,
|
||||
include,
|
||||
exclude,
|
||||
shippedProposals,
|
||||
forceAllTransforms,
|
||||
decoratorsLegacy
|
||||
} = options
|
||||
|
||||
const targets = process.env.VUE_CLI_BABEL_TARGET_NODE
|
||||
? { node: 'current' }
|
||||
: rawTargets
|
||||
|
||||
// included-by-default polyfills. These are common polyfills that 3rd party
|
||||
// dependencies may rely on (e.g. Vuex relies on Promise), but since with
|
||||
// useBuiltIns: 'usage' we won't be running Babel on these deps, they need to
|
||||
// be force-included.
|
||||
let polyfills
|
||||
const buildTarget = process.env.VUE_CLI_TARGET || 'app'
|
||||
if (buildTarget === 'app' && useBuiltIns === 'usage') {
|
||||
polyfills = getPolyfills(targets, userPolyfills || defaultPolyfills, {
|
||||
ignoreBrowserslistConfig,
|
||||
configPath
|
||||
})
|
||||
plugins.push([require('./polyfillsPlugin'), { polyfills }])
|
||||
} else {
|
||||
polyfills = []
|
||||
}
|
||||
|
||||
const envOptions = {
|
||||
spec,
|
||||
loose,
|
||||
modules,
|
||||
targets,
|
||||
useBuiltIns
|
||||
}
|
||||
// target running node version (this is set by unit testing plugins)
|
||||
if (process.env.VUE_CLI_BABEL_TARGET_NODE) {
|
||||
envOptions.targets = { node: 'current' }
|
||||
useBuiltIns,
|
||||
ignoreBrowserslistConfig,
|
||||
configPath,
|
||||
include,
|
||||
exclude: polyfills.concat(exclude || []),
|
||||
shippedProposals,
|
||||
forceAllTransforms
|
||||
}
|
||||
|
||||
// cli-plugin-jest sets this to true because Jest runs without bundling
|
||||
if (process.env.VUE_CLI_BABEL_TRANSPILE_MODULES) {
|
||||
envOptions.modules = 'commonjs'
|
||||
@@ -53,7 +104,9 @@ module.exports = (context, options = {}) => {
|
||||
// transform runtime, but only for helpers
|
||||
plugins.push([require('@babel/plugin-transform-runtime'), {
|
||||
polyfill: false,
|
||||
regenerator: false,
|
||||
regenerator: useBuiltIns !== 'usage',
|
||||
useBuiltIns: useBuiltIns !== false,
|
||||
useESModules: true,
|
||||
moduleName: path.dirname(require.resolve('@babel/runtime/package.json'))
|
||||
}])
|
||||
|
||||
|
||||
22
packages/@vue/babel-preset-app/polyfillsPlugin.js
Normal file
22
packages/@vue/babel-preset-app/polyfillsPlugin.js
Normal file
@@ -0,0 +1,22 @@
|
||||
// add polyfill imports to the first file encountered.
|
||||
module.exports = ({ types }) => {
|
||||
let entryFile
|
||||
return {
|
||||
name: 'vue-cli-inject-polyfills',
|
||||
visitor: {
|
||||
Program (path, state) {
|
||||
if (!entryFile) {
|
||||
entryFile = state.filename
|
||||
} else if (state.filename !== entryFile) {
|
||||
return
|
||||
}
|
||||
|
||||
const { polyfills } = state.opts
|
||||
const { createImport } = require('@babel/preset-env/lib/utils')
|
||||
polyfills.forEach(p => {
|
||||
createImport(path, p)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user