You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
713 lines
20 KiB
713 lines
20 KiB
2 years ago
|
// @ts-check
|
||
|
const path = require('path')
|
||
|
const { createHash } = require('crypto')
|
||
|
const { build } = require('vite')
|
||
|
const MagicString = require('magic-string').default
|
||
|
|
||
|
// lazy load babel since it's not used during dev
|
||
|
let babel
|
||
|
/**
|
||
|
* @return {import('@babel/standalone')}
|
||
|
*/
|
||
|
const loadBabel = () => babel || (babel = require('@babel/standalone'))
|
||
|
|
||
|
// https://gist.github.com/samthor/64b114e4a4f539915a95b91ffd340acc
|
||
|
// DO NOT ALTER THIS CONTENT
|
||
|
const safari10NoModuleFix = `!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",(function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()}),!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();`
|
||
|
|
||
|
const legacyPolyfillId = 'vite-legacy-polyfill'
|
||
|
const legacyEntryId = 'vite-legacy-entry'
|
||
|
const systemJSInlineCode = `System.import(document.getElementById('${legacyEntryId}').getAttribute('data-src'))`
|
||
|
|
||
|
const detectDynamicImportVarName = '__vite_is_dynamic_import_support'
|
||
|
const detectDynamicImportCode = `try{import("_").catch(()=>1);}catch(e){}window.${detectDynamicImportVarName}=true;`
|
||
|
const dynamicFallbackInlineCode = `!function(){if(window.${detectDynamicImportVarName})return;console.warn("vite: loading legacy build because dynamic import is unsupported, syntax error above should be ignored");var e=document.getElementById("${legacyPolyfillId}"),n=document.createElement("script");n.src=e.src,n.onload=function(){${systemJSInlineCode}},document.body.appendChild(n)}();`
|
||
|
|
||
|
const forceDynamicImportUsage = `export function __vite_legacy_guard(){import('data:text/javascript,')};`
|
||
|
|
||
|
const legacyEnvVarMarker = `__VITE_IS_LEGACY__`
|
||
|
|
||
|
/**
|
||
|
* @param {import('.').Options} options
|
||
|
* @returns {import('vite').Plugin[]}
|
||
|
*/
|
||
|
function viteLegacyPlugin(options = {}) {
|
||
|
/**
|
||
|
* @type {import('vite').ResolvedConfig}
|
||
|
*/
|
||
|
let config
|
||
|
const targets = options.targets || 'defaults'
|
||
|
const genLegacy = options.renderLegacyChunks !== false
|
||
|
const genDynamicFallback = genLegacy
|
||
|
|
||
|
const debugFlags = (process.env.DEBUG || '').split(',')
|
||
|
const isDebug =
|
||
|
debugFlags.includes('vite:*') || debugFlags.includes('vite:legacy')
|
||
|
|
||
|
const facadeToLegacyChunkMap = new Map()
|
||
|
const facadeToLegacyPolyfillMap = new Map()
|
||
|
const facadeToModernPolyfillMap = new Map()
|
||
|
const modernPolyfills = new Set()
|
||
|
// System JS relies on the Promise interface. It needs to be polyfilled for IE 11. (array.iterator is mandatory for supporting Promise.all)
|
||
|
const DEFAULT_LEGACY_POLYFILL = [
|
||
|
'core-js/modules/es.promise',
|
||
|
'core-js/modules/es.array.iterator'
|
||
|
]
|
||
|
const legacyPolyfills = new Set(DEFAULT_LEGACY_POLYFILL)
|
||
|
|
||
|
if (Array.isArray(options.modernPolyfills)) {
|
||
|
options.modernPolyfills.forEach((i) => {
|
||
|
modernPolyfills.add(
|
||
|
i.includes('/') ? `core-js/${i}` : `core-js/modules/${i}.js`
|
||
|
)
|
||
|
})
|
||
|
}
|
||
|
if (Array.isArray(options.polyfills)) {
|
||
|
options.polyfills.forEach((i) => {
|
||
|
if (i.startsWith(`regenerator`)) {
|
||
|
legacyPolyfills.add(`regenerator-runtime/runtime.js`)
|
||
|
} else {
|
||
|
legacyPolyfills.add(
|
||
|
i.includes('/') ? `core-js/${i}` : `core-js/modules/${i}.js`
|
||
|
)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
if (Array.isArray(options.additionalLegacyPolyfills)) {
|
||
|
options.additionalLegacyPolyfills.forEach((i) => {
|
||
|
legacyPolyfills.add(i)
|
||
|
})
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @type {import('vite').Plugin}
|
||
|
*/
|
||
|
const legacyConfigPlugin = {
|
||
|
name: 'vite:legacy-config',
|
||
|
|
||
|
apply: 'build',
|
||
|
config(config) {
|
||
|
if (!config.build) {
|
||
|
config.build = {}
|
||
|
}
|
||
|
|
||
|
if (!config.build.cssTarget) {
|
||
|
// Hint for esbuild that we are targeting legacy browsers when minifying CSS.
|
||
|
// Full CSS compat table available at https://github.com/evanw/esbuild/blob/78e04680228cf989bdd7d471e02bbc2c8d345dc9/internal/compat/css_table.go
|
||
|
// But note that only the `HexRGBA` feature affects the minify outcome.
|
||
|
// HSL & rebeccapurple values will be minified away regardless the target.
|
||
|
// So targeting `chrome61` suffices to fix the compatiblity issue.
|
||
|
config.build.cssTarget = 'chrome61'
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @type {import('vite').Plugin}
|
||
|
*/
|
||
|
const legacyGenerateBundlePlugin = {
|
||
|
name: 'vite:legacy-generate-polyfill-chunk',
|
||
|
apply: 'build',
|
||
|
|
||
|
async generateBundle(opts, bundle) {
|
||
|
if (config.build.ssr) {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if (!isLegacyBundle(bundle, opts)) {
|
||
|
if (!modernPolyfills.size) {
|
||
|
return
|
||
|
}
|
||
|
isDebug &&
|
||
|
console.log(
|
||
|
`[@vitejs/plugin-legacy] modern polyfills:`,
|
||
|
modernPolyfills
|
||
|
)
|
||
|
await buildPolyfillChunk(
|
||
|
'polyfills-modern',
|
||
|
modernPolyfills,
|
||
|
bundle,
|
||
|
facadeToModernPolyfillMap,
|
||
|
config.build,
|
||
|
options.externalSystemJS
|
||
|
)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if (!genLegacy) {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// legacy bundle
|
||
|
if (legacyPolyfills.size || genDynamicFallback) {
|
||
|
if (!legacyPolyfills.has('es.promise')) {
|
||
|
// check if the target needs Promise polyfill because SystemJS relies
|
||
|
// on it
|
||
|
detectPolyfills(`Promise.resolve()`, targets, legacyPolyfills)
|
||
|
}
|
||
|
|
||
|
isDebug &&
|
||
|
console.log(
|
||
|
`[@vitejs/plugin-legacy] legacy polyfills:`,
|
||
|
legacyPolyfills
|
||
|
)
|
||
|
|
||
|
await buildPolyfillChunk(
|
||
|
'polyfills-legacy',
|
||
|
legacyPolyfills,
|
||
|
bundle,
|
||
|
facadeToLegacyPolyfillMap,
|
||
|
// force using terser for legacy polyfill minification, since esbuild
|
||
|
// isn't legacy-safe
|
||
|
config.build,
|
||
|
options.externalSystemJS
|
||
|
)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @type {import('vite').Plugin}
|
||
|
*/
|
||
|
const legacyPostPlugin = {
|
||
|
name: 'vite:legacy-post-process',
|
||
|
enforce: 'post',
|
||
|
apply: 'build',
|
||
|
|
||
|
configResolved(_config) {
|
||
|
if (_config.build.lib) {
|
||
|
throw new Error('@vitejs/plugin-legacy does not support library mode.')
|
||
|
}
|
||
|
config = _config
|
||
|
|
||
|
if (!genLegacy || config.build.ssr) {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param {string | ((chunkInfo: import('rollup').PreRenderedChunk) => string)} fileNames
|
||
|
* @param {string?} defaultFileName
|
||
|
* @returns {string | ((chunkInfo: import('rollup').PreRenderedChunk) => string)}
|
||
|
*/
|
||
|
const getLegacyOutputFileName = (
|
||
|
fileNames,
|
||
|
defaultFileName = '[name]-legacy.[hash].js'
|
||
|
) => {
|
||
|
if (!fileNames) {
|
||
|
return path.posix.join(config.build.assetsDir, defaultFileName)
|
||
|
}
|
||
|
|
||
|
return (chunkInfo) => {
|
||
|
let fileName =
|
||
|
typeof fileNames === 'function' ? fileNames(chunkInfo) : fileNames
|
||
|
|
||
|
if (fileName.includes('[name]')) {
|
||
|
// [name]-[hash].[format] -> [name]-legacy-[hash].[format]
|
||
|
fileName = fileName.replace('[name]', '[name]-legacy')
|
||
|
} else {
|
||
|
// entry.js -> entry-legacy.js
|
||
|
fileName = fileName.replace(/(.+)\.(.+)/, '$1-legacy.$2')
|
||
|
}
|
||
|
|
||
|
return fileName
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param {import('rollup').OutputOptions} options
|
||
|
* @returns {import('rollup').OutputOptions}
|
||
|
*/
|
||
|
const createLegacyOutput = (options = {}) => {
|
||
|
return {
|
||
|
...options,
|
||
|
format: 'system',
|
||
|
entryFileNames: getLegacyOutputFileName(options.entryFileNames),
|
||
|
chunkFileNames: getLegacyOutputFileName(options.chunkFileNames)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const { rollupOptions } = config.build
|
||
|
const { output } = rollupOptions
|
||
|
if (Array.isArray(output)) {
|
||
|
rollupOptions.output = [...output.map(createLegacyOutput), ...output]
|
||
|
} else {
|
||
|
rollupOptions.output = [createLegacyOutput(output), output || {}]
|
||
|
}
|
||
|
},
|
||
|
|
||
|
renderChunk(raw, chunk, opts) {
|
||
|
if (config.build.ssr) {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if (!isLegacyChunk(chunk, opts)) {
|
||
|
if (
|
||
|
options.modernPolyfills &&
|
||
|
!Array.isArray(options.modernPolyfills)
|
||
|
) {
|
||
|
// analyze and record modern polyfills
|
||
|
detectPolyfills(raw, { esmodules: true }, modernPolyfills)
|
||
|
}
|
||
|
|
||
|
const ms = new MagicString(raw)
|
||
|
|
||
|
if (genDynamicFallback && chunk.isEntry) {
|
||
|
ms.prepend(forceDynamicImportUsage)
|
||
|
}
|
||
|
|
||
|
if (raw.includes(legacyEnvVarMarker)) {
|
||
|
const re = new RegExp(legacyEnvVarMarker, 'g')
|
||
|
let match
|
||
|
while ((match = re.exec(raw))) {
|
||
|
ms.overwrite(
|
||
|
match.index,
|
||
|
match.index + legacyEnvVarMarker.length,
|
||
|
`false`
|
||
|
)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (config.build.sourcemap) {
|
||
|
return {
|
||
|
code: ms.toString(),
|
||
|
map: ms.generateMap({ hires: true })
|
||
|
}
|
||
|
}
|
||
|
return ms.toString()
|
||
|
}
|
||
|
|
||
|
if (!genLegacy) {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// @ts-ignore avoid esbuild transform on legacy chunks since it produces
|
||
|
// legacy-unsafe code - e.g. rewriting object properties into shorthands
|
||
|
opts.__vite_skip_esbuild__ = true
|
||
|
|
||
|
// @ts-ignore force terser for legacy chunks. This only takes effect if
|
||
|
// minification isn't disabled, because that leaves out the terser plugin
|
||
|
// entirely.
|
||
|
opts.__vite_force_terser__ = true
|
||
|
|
||
|
// @ts-ignore
|
||
|
// In the `generateBundle` hook,
|
||
|
// we'll delete the assets from the legacy bundle to avoid emitting duplicate assets.
|
||
|
// But that's still a waste of computing resource.
|
||
|
// So we add this flag to avoid emitting the asset in the first place whenever possible.
|
||
|
opts.__vite_skip_asset_emit__ = true
|
||
|
|
||
|
// @ts-ignore avoid emitting assets for legacy bundle
|
||
|
const needPolyfills =
|
||
|
options.polyfills !== false && !Array.isArray(options.polyfills)
|
||
|
|
||
|
// transform the legacy chunk with @babel/preset-env
|
||
|
const sourceMaps = !!config.build.sourcemap
|
||
|
const { code, map } = loadBabel().transform(raw, {
|
||
|
babelrc: false,
|
||
|
configFile: false,
|
||
|
compact: true,
|
||
|
sourceMaps,
|
||
|
inputSourceMap: sourceMaps && chunk.map,
|
||
|
presets: [
|
||
|
// forcing our plugin to run before preset-env by wrapping it in a
|
||
|
// preset so we can catch the injected import statements...
|
||
|
[
|
||
|
() => ({
|
||
|
plugins: [
|
||
|
recordAndRemovePolyfillBabelPlugin(legacyPolyfills),
|
||
|
replaceLegacyEnvBabelPlugin(),
|
||
|
wrapIIFEBabelPlugin()
|
||
|
]
|
||
|
})
|
||
|
],
|
||
|
[
|
||
|
'env',
|
||
|
{
|
||
|
targets,
|
||
|
modules: false,
|
||
|
bugfixes: true,
|
||
|
loose: false,
|
||
|
useBuiltIns: needPolyfills ? 'usage' : false,
|
||
|
corejs: needPolyfills
|
||
|
? {
|
||
|
version: require('core-js/package.json').version,
|
||
|
proposals: false
|
||
|
}
|
||
|
: undefined,
|
||
|
shippedProposals: true,
|
||
|
ignoreBrowserslistConfig: options.ignoreBrowserslistConfig
|
||
|
}
|
||
|
]
|
||
|
]
|
||
|
})
|
||
|
|
||
|
return { code, map }
|
||
|
},
|
||
|
|
||
|
transformIndexHtml(html, { chunk }) {
|
||
|
if (config.build.ssr) return
|
||
|
if (!chunk) return
|
||
|
if (chunk.fileName.includes('-legacy')) {
|
||
|
// The legacy bundle is built first, and its index.html isn't actually
|
||
|
// emitted. Here we simply record its corresponding legacy chunk.
|
||
|
facadeToLegacyChunkMap.set(chunk.facadeModuleId, chunk.fileName)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @type {import('vite').HtmlTagDescriptor[]}
|
||
|
*/
|
||
|
const tags = []
|
||
|
const htmlFilename = chunk.facadeModuleId.replace(/\?.*$/, '')
|
||
|
|
||
|
// 1. inject modern polyfills
|
||
|
const modernPolyfillFilename = facadeToModernPolyfillMap.get(
|
||
|
chunk.facadeModuleId
|
||
|
)
|
||
|
if (modernPolyfillFilename) {
|
||
|
tags.push({
|
||
|
tag: 'script',
|
||
|
attrs: {
|
||
|
type: 'module',
|
||
|
src: `${config.base}${modernPolyfillFilename}`
|
||
|
}
|
||
|
})
|
||
|
} else if (modernPolyfills.size) {
|
||
|
throw new Error(
|
||
|
`No corresponding modern polyfill chunk found for ${htmlFilename}`
|
||
|
)
|
||
|
}
|
||
|
|
||
|
if (!genLegacy) {
|
||
|
return { html, tags }
|
||
|
}
|
||
|
|
||
|
// 2. inject Safari 10 nomodule fix
|
||
|
tags.push({
|
||
|
tag: 'script',
|
||
|
attrs: { nomodule: true },
|
||
|
children: safari10NoModuleFix,
|
||
|
injectTo: 'body'
|
||
|
})
|
||
|
|
||
|
// 3. inject legacy polyfills
|
||
|
const legacyPolyfillFilename = facadeToLegacyPolyfillMap.get(
|
||
|
chunk.facadeModuleId
|
||
|
)
|
||
|
if (legacyPolyfillFilename) {
|
||
|
tags.push({
|
||
|
tag: 'script',
|
||
|
attrs: {
|
||
|
nomodule: true,
|
||
|
id: legacyPolyfillId,
|
||
|
src: `${config.base}${legacyPolyfillFilename}`
|
||
|
},
|
||
|
injectTo: 'body'
|
||
|
})
|
||
|
} else if (legacyPolyfills.size) {
|
||
|
throw new Error(
|
||
|
`No corresponding legacy polyfill chunk found for ${htmlFilename}`
|
||
|
)
|
||
|
}
|
||
|
|
||
|
// 4. inject legacy entry
|
||
|
const legacyEntryFilename = facadeToLegacyChunkMap.get(
|
||
|
chunk.facadeModuleId
|
||
|
)
|
||
|
if (legacyEntryFilename) {
|
||
|
tags.push({
|
||
|
tag: 'script',
|
||
|
attrs: {
|
||
|
nomodule: true,
|
||
|
// we set the entry path on the element as an attribute so that the
|
||
|
// script content will stay consistent - which allows using a constant
|
||
|
// hash value for CSP.
|
||
|
id: legacyEntryId,
|
||
|
'data-src': config.base + legacyEntryFilename
|
||
|
},
|
||
|
children: systemJSInlineCode,
|
||
|
injectTo: 'body'
|
||
|
})
|
||
|
} else {
|
||
|
throw new Error(
|
||
|
`No corresponding legacy entry chunk found for ${htmlFilename}`
|
||
|
)
|
||
|
}
|
||
|
|
||
|
// 5. inject dynamic import fallback entry
|
||
|
if (genDynamicFallback && legacyPolyfillFilename && legacyEntryFilename) {
|
||
|
tags.push({
|
||
|
tag: 'script',
|
||
|
attrs: { type: 'module' },
|
||
|
children: detectDynamicImportCode,
|
||
|
injectTo: 'head'
|
||
|
})
|
||
|
tags.push({
|
||
|
tag: 'script',
|
||
|
attrs: { type: 'module' },
|
||
|
children: dynamicFallbackInlineCode,
|
||
|
injectTo: 'head'
|
||
|
})
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
html,
|
||
|
tags
|
||
|
}
|
||
|
},
|
||
|
|
||
|
generateBundle(opts, bundle) {
|
||
|
if (config.build.ssr) {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if (isLegacyBundle(bundle, opts)) {
|
||
|
// avoid emitting duplicate assets
|
||
|
for (const name in bundle) {
|
||
|
if (bundle[name].type === 'asset') {
|
||
|
delete bundle[name]
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
let envInjectionFailed = false
|
||
|
/**
|
||
|
* @type {import('vite').Plugin}
|
||
|
*/
|
||
|
const legacyEnvPlugin = {
|
||
|
name: 'vite:legacy-env',
|
||
|
|
||
|
config(config, env) {
|
||
|
if (env) {
|
||
|
return {
|
||
|
define: {
|
||
|
'import.meta.env.LEGACY':
|
||
|
env.command === 'serve' || config.build.ssr
|
||
|
? false
|
||
|
: legacyEnvVarMarker
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
envInjectionFailed = true
|
||
|
}
|
||
|
},
|
||
|
|
||
|
configResolved(config) {
|
||
|
if (envInjectionFailed) {
|
||
|
config.logger.warn(
|
||
|
`[@vitejs/plugin-legacy] import.meta.env.LEGACY was not injected due ` +
|
||
|
`to incompatible vite version (requires vite@^2.0.0-beta.69).`
|
||
|
)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return [
|
||
|
legacyConfigPlugin,
|
||
|
legacyGenerateBundlePlugin,
|
||
|
legacyPostPlugin,
|
||
|
legacyEnvPlugin
|
||
|
]
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param {string} code
|
||
|
* @param {any} targets
|
||
|
* @param {Set<string>} list
|
||
|
*/
|
||
|
function detectPolyfills(code, targets, list) {
|
||
|
const { ast } = loadBabel().transform(code, {
|
||
|
ast: true,
|
||
|
babelrc: false,
|
||
|
configFile: false,
|
||
|
presets: [
|
||
|
[
|
||
|
'env',
|
||
|
{
|
||
|
targets,
|
||
|
modules: false,
|
||
|
useBuiltIns: 'usage',
|
||
|
corejs: { version: 3, proposals: false },
|
||
|
shippedProposals: true,
|
||
|
ignoreBrowserslistConfig: true
|
||
|
}
|
||
|
]
|
||
|
]
|
||
|
})
|
||
|
for (const node of ast.program.body) {
|
||
|
if (node.type === 'ImportDeclaration') {
|
||
|
const source = node.source.value
|
||
|
if (
|
||
|
source.startsWith('core-js/') ||
|
||
|
source.startsWith('regenerator-runtime/')
|
||
|
) {
|
||
|
list.add(source)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param {string} name
|
||
|
* @param {Set<string>} imports
|
||
|
* @param {import('rollup').OutputBundle} bundle
|
||
|
* @param {Map<string, string>} facadeToChunkMap
|
||
|
* @param {import('vite').BuildOptions} buildOptions
|
||
|
*/
|
||
|
async function buildPolyfillChunk(
|
||
|
name,
|
||
|
imports,
|
||
|
bundle,
|
||
|
facadeToChunkMap,
|
||
|
buildOptions,
|
||
|
externalSystemJS
|
||
|
) {
|
||
|
let { minify, assetsDir } = buildOptions
|
||
|
minify = minify ? 'terser' : false
|
||
|
const res = await build({
|
||
|
// so that everything is resolved from here
|
||
|
root: __dirname,
|
||
|
configFile: false,
|
||
|
logLevel: 'error',
|
||
|
plugins: [polyfillsPlugin(imports, externalSystemJS)],
|
||
|
build: {
|
||
|
write: false,
|
||
|
target: false,
|
||
|
minify,
|
||
|
assetsDir,
|
||
|
rollupOptions: {
|
||
|
input: {
|
||
|
[name]: polyfillId
|
||
|
},
|
||
|
output: {
|
||
|
format: name.includes('legacy') ? 'iife' : 'es',
|
||
|
manualChunks: undefined
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
})
|
||
|
const _polyfillChunk = Array.isArray(res) ? res[0] : res
|
||
|
if (!('output' in _polyfillChunk)) return
|
||
|
const polyfillChunk = _polyfillChunk.output[0]
|
||
|
|
||
|
// associate the polyfill chunk to every entry chunk so that we can retrieve
|
||
|
// the polyfill filename in index html transform
|
||
|
for (const key in bundle) {
|
||
|
const chunk = bundle[key]
|
||
|
if (chunk.type === 'chunk' && chunk.facadeModuleId) {
|
||
|
facadeToChunkMap.set(chunk.facadeModuleId, polyfillChunk.fileName)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// add the chunk to the bundle
|
||
|
bundle[polyfillChunk.name] = polyfillChunk
|
||
|
}
|
||
|
|
||
|
const polyfillId = '\0vite/legacy-polyfills'
|
||
|
|
||
|
/**
|
||
|
* @param {Set<string>} imports
|
||
|
* @return {import('rollup').Plugin}
|
||
|
*/
|
||
|
function polyfillsPlugin(imports, externalSystemJS) {
|
||
|
return {
|
||
|
name: 'vite:legacy-polyfills',
|
||
|
resolveId(id) {
|
||
|
if (id === polyfillId) {
|
||
|
return id
|
||
|
}
|
||
|
},
|
||
|
load(id) {
|
||
|
if (id === polyfillId) {
|
||
|
return (
|
||
|
[...imports].map((i) => `import "${i}";`).join('') +
|
||
|
(externalSystemJS ? '' : `import "systemjs/dist/s.min.js";`)
|
||
|
)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param {import('rollup').RenderedChunk} chunk
|
||
|
* @param {import('rollup').NormalizedOutputOptions} options
|
||
|
*/
|
||
|
function isLegacyChunk(chunk, options) {
|
||
|
return options.format === 'system' && chunk.fileName.includes('-legacy')
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param {import('rollup').OutputBundle} bundle
|
||
|
* @param {import('rollup').NormalizedOutputOptions} options
|
||
|
*/
|
||
|
function isLegacyBundle(bundle, options) {
|
||
|
if (options.format === 'system') {
|
||
|
const entryChunk = Object.values(bundle).find(
|
||
|
(output) => output.type === 'chunk' && output.isEntry
|
||
|
)
|
||
|
|
||
|
return !!entryChunk && entryChunk.fileName.includes('-legacy')
|
||
|
}
|
||
|
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param {Set<string>} polyfills
|
||
|
*/
|
||
|
function recordAndRemovePolyfillBabelPlugin(polyfills) {
|
||
|
return ({ types: t }) => ({
|
||
|
name: 'vite-remove-polyfill-import',
|
||
|
post({ path }) {
|
||
|
path.get('body').forEach((p) => {
|
||
|
if (t.isImportDeclaration(p)) {
|
||
|
polyfills.add(p.node.source.value)
|
||
|
p.remove()
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
|
||
|
function replaceLegacyEnvBabelPlugin() {
|
||
|
return ({ types: t }) => ({
|
||
|
name: 'vite-replace-env-legacy',
|
||
|
visitor: {
|
||
|
Identifier(path) {
|
||
|
if (path.node.name === legacyEnvVarMarker) {
|
||
|
path.replaceWith(t.booleanLiteral(true))
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
|
||
|
function wrapIIFEBabelPlugin() {
|
||
|
return ({ types: t, template }) => {
|
||
|
const buildIIFE = template(';(function(){%%body%%})();')
|
||
|
|
||
|
return {
|
||
|
name: 'vite-wrap-iife',
|
||
|
post({ path }) {
|
||
|
if (!this.isWrapped) {
|
||
|
this.isWrapped = true
|
||
|
path.replaceWith(t.program(buildIIFE({ body: path.node.body })))
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
module.exports = viteLegacyPlugin
|
||
|
|
||
|
viteLegacyPlugin.default = viteLegacyPlugin
|
||
|
|
||
|
viteLegacyPlugin.cspHashes = [
|
||
|
createHash('sha256').update(safari10NoModuleFix).digest('base64'),
|
||
|
createHash('sha256').update(systemJSInlineCode).digest('base64'),
|
||
|
createHash('sha256').update(detectDynamicImportCode).digest('base64'),
|
||
|
createHash('sha256').update(dynamicFallbackInlineCode).digest('base64')
|
||
|
]
|