mirror of
https://github.com/vuejs/vue-cli.git
synced 2026-01-25 00:29:06 -06:00
refactor: improve the polyfill importing logic of modern mode (#5513)
TODO: - should remove core-js from `dependencies` in the next major.
This commit is contained in:
@@ -48,37 +48,52 @@ test('polyfill detection', () => {
|
||||
expect(code).toMatch('"core-js/modules/es.map"')
|
||||
})
|
||||
|
||||
test('modern mode always skips polyfills', () => {
|
||||
test('modern mode always skips unnecessary polyfills', () => {
|
||||
process.env.VUE_CLI_MODERN_BUILD = true
|
||||
let { code } = babel.transformSync(`
|
||||
const a = new Map()
|
||||
console.log(globalThis)
|
||||
`.trim(), {
|
||||
babelrc: false,
|
||||
presets: [[preset, {
|
||||
targets: { ie: 9 },
|
||||
targets: { ie: 9, safari: '12' },
|
||||
useBuiltIns: 'usage'
|
||||
}]],
|
||||
filename: 'test-entry-file.js'
|
||||
})
|
||||
// default includes
|
||||
expect(code).not.toMatch(getAbsolutePolyfill('es.promise'))
|
||||
// default includes that are supported in all modern browsers should be skipped
|
||||
expect(code).not.toMatch('es.assign')
|
||||
// though es.promise is not supported in all modern browsers
|
||||
// (modern: safari >= 10.1, es.promise: safrai >= 11)
|
||||
// the custom configuration only expects to support safari >= 12
|
||||
// so it can be skipped
|
||||
expect(code).not.toMatch('es.promise"')
|
||||
// es.promise.finally is supported in safari >= 13.0.3
|
||||
// so still needs to be included
|
||||
expect(code).toMatch('es.promise.finally')
|
||||
|
||||
// usage-based detection
|
||||
expect(code).not.toMatch('"core-js/modules/es.map"')
|
||||
// Map is supported in all modern browsers
|
||||
expect(code).not.toMatch('es.map')
|
||||
// globalThis is not supported until safari 12.1
|
||||
expect(code).toMatch('es.global-this')
|
||||
|
||||
;({ code } = babel.transformSync(`
|
||||
const a = new Map()
|
||||
`.trim(), {
|
||||
babelrc: false,
|
||||
presets: [[preset, {
|
||||
targets: { ie: 9 },
|
||||
targets: { ie: 9, safari: '12' },
|
||||
useBuiltIns: 'entry'
|
||||
}]],
|
||||
filename: 'test-entry-file.js'
|
||||
}))
|
||||
// default includes
|
||||
expect(code).not.toMatch(getAbsolutePolyfill('es.promise'))
|
||||
expect(code).not.toMatch('es.promise"')
|
||||
expect(code).not.toMatch('es.promise.finally')
|
||||
// usage-based detection
|
||||
expect(code).not.toMatch('"core-js/modules/es.map"')
|
||||
expect(code).not.toMatch('es.global-this')
|
||||
delete process.env.VUE_CLI_MODERN_BUILD
|
||||
})
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const path = require('path')
|
||||
const semver = require('semver')
|
||||
|
||||
const defaultPolyfills = [
|
||||
// promise polyfill alone doesn't work in IE,
|
||||
@@ -9,21 +10,78 @@ const defaultPolyfills = [
|
||||
// this is needed for object rest spread support in templates
|
||||
// as vue-template-es2015-compiler 1.8+ compiles it to Object.assign() calls.
|
||||
'es.object.assign',
|
||||
// #2012 es6.promise replaces native Promise in FF and causes missing finally
|
||||
// #2012 es.promise replaces native Promise in FF and causes missing finally
|
||||
'es.promise.finally'
|
||||
]
|
||||
|
||||
function getPolyfills (targets, includes, { ignoreBrowserslistConfig, configPath }) {
|
||||
const getTargets = require('@babel/helper-compilation-targets').default
|
||||
const builtInTargets = getTargets(targets, { ignoreBrowserslistConfig, configPath })
|
||||
const {
|
||||
default: getTargets,
|
||||
isRequired
|
||||
} = require('@babel/helper-compilation-targets')
|
||||
|
||||
function getIntersectionTargets (targets, constraintTargets) {
|
||||
const intersection = Object.keys(constraintTargets).reduce(
|
||||
(results, browser) => {
|
||||
// exclude the browsers that the user does not need
|
||||
if (!targets[browser]) {
|
||||
return results
|
||||
}
|
||||
|
||||
// if the user-specified version is higher the minimum version that supports esmodule, than use it
|
||||
results[browser] = semver.gt(
|
||||
semver.coerce(constraintTargets[browser]),
|
||||
semver.coerce(targets[browser])
|
||||
)
|
||||
? constraintTargets[browser]
|
||||
: targets[browser]
|
||||
|
||||
return results
|
||||
},
|
||||
{}
|
||||
)
|
||||
|
||||
return intersection
|
||||
}
|
||||
|
||||
function getModernTargets (targets) {
|
||||
const allModernTargets = getTargets(
|
||||
{ esmodules: true },
|
||||
{ ignoreBrowserslistConfig: true }
|
||||
)
|
||||
|
||||
// use the intersection of modern mode browsers and user defined targets config
|
||||
return getIntersectionTargets(targets, allModernTargets)
|
||||
}
|
||||
|
||||
function getWCTargets (targets) {
|
||||
// targeting browsers that at least support ES2015 classes
|
||||
// https://github.com/babel/babel/blob/v7.9.6/packages/babel-compat-data/data/plugins.json#L194-L204
|
||||
const allWCTargets = getTargets(
|
||||
{
|
||||
browsers: [
|
||||
'Chrome >= 46',
|
||||
'Firefox >= 45',
|
||||
'Safari >= 10',
|
||||
'Edge >= 13',
|
||||
'iOS >= 10',
|
||||
'Electron >= 0.36'
|
||||
]
|
||||
},
|
||||
{ ignoreBrowserslistConfig: true }
|
||||
)
|
||||
|
||||
// use the intersection of browsers supporting Web Components and user defined targets config
|
||||
return getIntersectionTargets(targets, allWCTargets)
|
||||
}
|
||||
|
||||
function getPolyfills (targets, includes) {
|
||||
// if no targets specified, include all default polyfills
|
||||
if (!targets && !Object.keys(builtInTargets).length) {
|
||||
if (!targets || !Object.keys(targets).length) {
|
||||
return includes
|
||||
}
|
||||
|
||||
const { list } = require('core-js-compat')({ targets: builtInTargets })
|
||||
return includes.filter(item => list.includes(item))
|
||||
const compatData = require('core-js-compat').data
|
||||
return includes.filter(item => isRequired(item, targets, { compatData }))
|
||||
}
|
||||
|
||||
module.exports = (context, options = {}) => {
|
||||
@@ -36,7 +94,7 @@ module.exports = (context, options = {}) => {
|
||||
// dropping them may break some projects.
|
||||
// So in the following blocks we don't directly test the `NODE_ENV`.
|
||||
// Rather, we turn it into the two commonly used feature flags.
|
||||
if (process.env.NODE_ENV === 'test') {
|
||||
if (!process.env.VUE_CLI_TEST && process.env.NODE_ENV === 'test') {
|
||||
// Both Jest & Mocha set NODE_ENV to 'test'.
|
||||
// And both requires the `node` target.
|
||||
process.env.VUE_CLI_BABEL_TARGET_NODE = 'true'
|
||||
@@ -62,7 +120,7 @@ module.exports = (context, options = {}) => {
|
||||
bugfixes = true,
|
||||
targets: rawTargets,
|
||||
spec,
|
||||
ignoreBrowserslistConfig = !!process.env.VUE_CLI_MODERN_BUILD,
|
||||
ignoreBrowserslistConfig,
|
||||
configPath,
|
||||
include,
|
||||
exclude,
|
||||
@@ -88,29 +146,17 @@ module.exports = (context, options = {}) => {
|
||||
version = runtimeVersion
|
||||
} = options
|
||||
|
||||
// resolve targets
|
||||
let targets
|
||||
// resolve targets for preset-env
|
||||
let targets = getTargets(rawTargets, { ignoreBrowserslistConfig, configPath })
|
||||
if (process.env.VUE_CLI_BABEL_TARGET_NODE) {
|
||||
// running tests in Node.js
|
||||
targets = { node: 'current' }
|
||||
} else if (process.env.VUE_CLI_BUILD_TARGET === 'wc' || process.env.VUE_CLI_BUILD_TARGET === 'wc-async') {
|
||||
// targeting browsers that at least support ES2015 classes
|
||||
// https://github.com/babel/babel/blob/master/packages/babel-preset-env/data/plugins.json#L52-L61
|
||||
targets = {
|
||||
browsers: [
|
||||
'Chrome >= 49',
|
||||
'Firefox >= 45',
|
||||
'Safari >= 10',
|
||||
'Edge >= 13',
|
||||
'iOS >= 10',
|
||||
'Electron >= 0.36'
|
||||
]
|
||||
}
|
||||
targets = getWCTargets(targets)
|
||||
} else if (process.env.VUE_CLI_MODERN_BUILD) {
|
||||
// targeting browsers that support <script type="module">
|
||||
targets = { esmodules: true }
|
||||
} else {
|
||||
targets = rawTargets
|
||||
// targeting browsers that at least support <script type="module">
|
||||
targets = getModernTargets(targets)
|
||||
}
|
||||
|
||||
// included-by-default polyfills. These are common polyfills that 3rd party
|
||||
@@ -122,13 +168,9 @@ module.exports = (context, options = {}) => {
|
||||
if (
|
||||
buildTarget === 'app' &&
|
||||
useBuiltIns === 'usage' &&
|
||||
!process.env.VUE_CLI_BABEL_TARGET_NODE &&
|
||||
!process.env.VUE_CLI_MODERN_BUILD
|
||||
!process.env.VUE_CLI_BABEL_TARGET_NODE
|
||||
) {
|
||||
polyfills = getPolyfills(targets, userPolyfills || defaultPolyfills, {
|
||||
ignoreBrowserslistConfig,
|
||||
configPath
|
||||
})
|
||||
polyfills = getPolyfills(targets, userPolyfills || defaultPolyfills)
|
||||
plugins.push([
|
||||
require('./polyfillsPlugin'),
|
||||
{ polyfills, entryFiles, useAbsolutePath: !!absoluteRuntime }
|
||||
@@ -139,7 +181,7 @@ module.exports = (context, options = {}) => {
|
||||
|
||||
const envOptions = {
|
||||
bugfixes,
|
||||
corejs: useBuiltIns ? 3 : false,
|
||||
corejs: useBuiltIns ? require('core-js/package.json').version : false,
|
||||
spec,
|
||||
loose,
|
||||
debug,
|
||||
@@ -206,7 +248,7 @@ module.exports = (context, options = {}) => {
|
||||
presets: [
|
||||
[require('@babel/preset-env'), {
|
||||
useBuiltIns,
|
||||
corejs: useBuiltIns ? 3 : false
|
||||
corejs: useBuiltIns ? require('core-js/package.json').version : false
|
||||
}]
|
||||
]
|
||||
}]
|
||||
|
||||
@@ -35,9 +35,16 @@
|
||||
"@vue/babel-preset-jsx": "^1.1.2",
|
||||
"babel-plugin-dynamic-import-node": "^2.3.3",
|
||||
"core-js": "^3.6.5",
|
||||
"core-js-compat": "^3.6.5"
|
||||
"core-js-compat": "^3.6.5",
|
||||
"semver": "^6.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@babel/core": "*"
|
||||
"@babel/core": "*",
|
||||
"core-js": "^3"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"core-js": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,9 @@ const { addSideEffect } = require('@babel/helper-module-imports')
|
||||
|
||||
// slightly modifiled from @babel/preset-env/src/utils
|
||||
// use an absolute path for core-js modules, to fix conflicts of different core-js versions
|
||||
// TODO: remove the `useAbsolutePath` option in v5,
|
||||
// because `core-js` is sure to be present in newer projects;
|
||||
// we only need absolute path for babel runtime helpers, not for polyfills
|
||||
function getModulePath (mod, useAbsolutePath) {
|
||||
const modPath =
|
||||
mod === 'regenerator-runtime'
|
||||
|
||||
Reference in New Issue
Block a user