Nuxt/packages/webpack/src/utils/babel-preset.js

203 lines
4.9 KiB
JavaScript
Raw Normal View History

2020-07-02 13:02:35 +00:00
const coreJsMeta = {
2: {
prefixes: {
es6: 'es6',
es7: 'es7'
},
builtIns: '@babel/compat-data/corejs2-built-ins'
},
3: {
prefixes: {
es6: 'es',
es7: 'es'
},
builtIns: 'core-js-compat/data'
}
}
function getDefaultPolyfills (corejs) {
const { prefixes: { es6, es7 } } = coreJsMeta[corejs.version]
return [
// Promise polyfill alone doesn't work in IE,
// Needs this as well. see: #1642
`${es6}.array.iterator`,
// This is required for webpack code splitting, vuex etc.
`${es6}.promise`,
// this is needed for object rest spread support in templates
// as vue-template-es2015-compiler 1.8+ compiles it to Object.assign() calls.
`${es6}.object.assign`,
// #2012 es7.promise replaces native Promise in FF and causes missing finally
`${es7}.promise.finally`
]
}
function getPolyfills (targets, includes, { ignoreBrowserslistConfig, configPath, corejs }) {
const { default: getTargets, isRequired } = require('@babel/helper-compilation-targets')
const builtInsList = require(coreJsMeta[corejs.version].builtIns)
const builtInTargets = getTargets(targets, {
ignoreBrowserslistConfig,
configPath
})
return includes.filter(item => isRequired(
'nuxt-polyfills',
builtInTargets,
{
compatData: { 'nuxt-polyfills': builtInsList[item] }
}
))
}
function isPackageHoisted (packageName) {
const path = require('path')
const installedPath = require.resolve(packageName)
const relativePath = path.resolve(__dirname, '..', 'node_modules', packageName)
return installedPath !== relativePath
}
module.exports = (api, options = {}) => {
const presets = []
const plugins = []
const envName = api.env()
const {
bugfixes,
polyfills: userPolyfills,
loose = false,
debug = false,
useBuiltIns = 'usage',
modules = false,
spec,
ignoreBrowserslistConfig = envName === 'modern',
configPath,
include,
exclude,
shippedProposals,
forceAllTransforms,
decoratorsBeforeExport,
decoratorsLegacy,
absoluteRuntime
} = options
let { corejs = { version: 3 } } = options
if (typeof corejs !== 'object') {
corejs = { version: Number(corejs) }
}
const isCorejs3Hoisted = isPackageHoisted('core-js')
if (
(corejs.version === 3 && !isCorejs3Hoisted) ||
(corejs.version === 2 && isCorejs3Hoisted)
) {
// eslint-disable-next-line no-console
(console.fatal || console.error)(`babel corejs option is ${corejs.version}, please directlly install core-js@${corejs.version}.`)
}
const defaultTargets = {
server: { node: 'current' },
client: { ie: 9 },
modern: { esmodules: true }
}
let { targets = defaultTargets[envName] } = options
// modern mode can only be { esmodules: true }
if (envName === 'modern') {
targets = defaultTargets.modern
}
const polyfills = []
if (envName === 'client' && useBuiltIns === 'usage') {
polyfills.push(
...getPolyfills(
targets,
userPolyfills || getDefaultPolyfills(corejs),
{
ignoreBrowserslistConfig,
configPath,
corejs
}
)
)
2021-03-29 09:33:38 +00:00
plugins.push([polyfillsPlugin, { polyfills }])
2020-07-02 13:02:35 +00:00
}
// Pass options along to babel-preset-env
presets.push([
require('@babel/preset-env'), {
bugfixes,
spec,
loose,
debug,
modules,
targets,
useBuiltIns,
corejs,
ignoreBrowserslistConfig,
configPath,
include,
exclude: polyfills.concat(exclude || []),
shippedProposals,
forceAllTransforms
}
], [
require('@babel/preset-typescript')
2020-07-02 13:02:35 +00:00
])
// JSX
if (options.jsx !== false) {
// presets.push([require('@vue/babel-preset-jsx'), Object.assign({}, options.jsx)])
}
plugins.push(
[require('@babel/plugin-proposal-decorators'), {
decoratorsBeforeExport,
legacy: decoratorsLegacy !== false
}],
[require('@babel/plugin-proposal-class-properties'), { loose: true }]
)
// Transform runtime, but only for helpers
plugins.push([require('@babel/plugin-transform-runtime'), {
regenerator: useBuiltIns !== 'usage',
corejs: false,
helpers: useBuiltIns === 'usage',
useESModules: envName !== 'server',
absoluteRuntime
}])
return {
sourceType: 'unambiguous',
presets,
plugins
}
}
2021-03-29 09:33:38 +00:00
// Add polyfill imports to the first file encountered.
function polyfillsPlugin ({ _types }) {
let entryFile
return {
name: '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')
// Imports are injected in reverse order
polyfills.slice().reverse().forEach((p) => {
createImport(path, p)
})
}
}
}
}