2025/2/8第一次更新

This commit is contained in:
爱吃咸鱼小猫咪
2025-02-08 18:50:38 +08:00
commit d7af560866
26519 changed files with 5046029 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019-present, Yuxi (Evan) You and Vite contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+193
View File
@@ -0,0 +1,193 @@
# @vitejs/plugin-legacy [![npm](https://img.shields.io/npm/v/@vitejs/plugin-legacy.svg)](https://npmjs.com/package/@vitejs/plugin-legacy)
Vite's default browser support baseline is [Native ESM](https://caniuse.com/es6-module), [native ESM dynamic import](https://caniuse.com/es6-module-dynamic-import), and [`import.meta`](https://caniuse.com/mdn-javascript_operators_import_meta). This plugin provides support for legacy browsers that do not support those features when building for production.
By default, this plugin will:
- Generate a corresponding legacy chunk for every chunk in the final bundle, transformed with [@babel/preset-env](https://babeljs.io/docs/en/babel-preset-env) and emitted as [SystemJS modules](https://github.com/systemjs/systemjs) (code splitting is still supported!).
- Generate a polyfill chunk including SystemJS runtime, and any necessary polyfills determined by specified browser targets and **actual usage** in the bundle.
- Inject `<script nomodule>` tags into generated HTML to conditionally load the polyfills and legacy bundle only in browsers without widely-available features support.
- Inject the `import.meta.env.LEGACY` env variable, which will only be `true` in the legacy production build, and `false` in all other cases.
## Usage
```js
// vite.config.js
import legacy from '@vitejs/plugin-legacy'
export default {
plugins: [
legacy({
targets: ['defaults', 'not IE 11'],
}),
],
}
```
Terser must be installed because plugin-legacy uses Terser for minification.
```sh
npm add -D terser
```
## Options
### `targets`
- **Type:** `string | string[] | { [key: string]: string }`
- **Default:** [`'last 2 versions and not dead, > 0.3%, Firefox ESR'`](https://browsersl.ist/#q=last+2+versions+and+not+dead%2C+%3E+0.3%25%2C+Firefox+ESR)
If explicitly set, it's passed on to [`@babel/preset-env`](https://babeljs.io/docs/en/babel-preset-env#targets) when rendering **legacy chunks**.
The query is also [Browserslist compatible](https://github.com/browserslist/browserslist). See [Browserslist Best Practices](https://github.com/browserslist/browserslist#best-practices) for more details.
If it's not set, plugin-legacy will load [the browserslist config sources](https://github.com/browserslist/browserslist#queries) and then fallback to the default value.
### `modernTargets`
- **Type:** `string | string[]`
- **Default:** [`'edge>=80, firefox>=72, chrome>=80, safari>=13.1, chromeAndroid>=80, iOS>=13.1'`](https://browsersl.ist/#q=edge%3E%3D80%2C+firefox%3E%3D72%2C+chrome%3E%3D80%2C+safari%3E%3D13.1%2C+chromeAndroid%3E%3D80%2C+iOS%3E%3D13.1)
If explicitly set, it's passed on to [`@babel/preset-env`](https://babeljs.io/docs/en/babel-preset-env#targets) when rendering **modern chunks**.
The query is also [Browserslist compatible](https://github.com/browserslist/browserslist). See [Browserslist Best Practices](https://github.com/browserslist/browserslist#best-practices) for more details.
If it's not set, plugin-legacy will fallback to the default value.
### `polyfills`
- **Type:** `boolean | string[]`
- **Default:** `true`
By default, a polyfills chunk is generated based on the target browser ranges and actual usage in the final bundle (detected via `@babel/preset-env`'s `useBuiltIns: 'usage'`).
Set to a list of strings to explicitly control which polyfills to include. See [Polyfill Specifiers](#polyfill-specifiers) for details.
Set to `false` to avoid generating polyfills and handle it yourself (will still generate legacy chunks with syntax transformations).
### `additionalLegacyPolyfills`
- **Type:** `string[]`
Add custom imports to the legacy polyfills chunk. Since the usage-based polyfill detection only covers ES language features, it may be necessary to manually specify additional DOM API polyfills using this option.
Note: if additional polyfills are needed for both the modern and legacy chunks, they can simply be imported in the application source code.
### `modernPolyfills`
- **Type:** `boolean | string[]`
- **Default:** `false`
Defaults to `false`. Enabling this option will generate a separate polyfills chunk for the modern build (targeting [browsers that support widely-available features](#browsers-that-supports-esm-but-does-not-support-widely-available-features)).
Set to a list of strings to explicitly control which polyfills to include. See [Polyfill Specifiers](#polyfill-specifiers) for details.
Note it is **not recommended** to use the `true` value (which uses auto-detection) because `core-js@3` is very aggressive in polyfill inclusions due to all the bleeding edge features it supports. Even when targeting native ESM support, it injects 15kb of polyfills!
If you don't have hard reliance on bleeding edge runtime features, it is not that hard to avoid having to use polyfills in the modern build altogether. Alternatively, consider using an on-demand service like [Polyfill.io](https://polyfill.io) to only inject necessary polyfills based on actual browser user-agents (most modern browsers will need nothing!).
### `renderLegacyChunks`
- **Type:** `boolean`
- **Default:** `true`
Set to `false` to disable legacy chunks. This is only useful if you are using `modernPolyfills`, which essentially allows you to use this plugin for injecting polyfills to the modern build only:
```js
import legacy from '@vitejs/plugin-legacy'
export default {
plugins: [
legacy({
modernPolyfills: [
/* ... */
],
renderLegacyChunks: false,
}),
],
}
```
### `externalSystemJS`
- **Type:** `boolean`
- **Default:** `false`
Defaults to `false`. Enabling this option will exclude `systemjs/dist/s.min.js` inside polyfills-legacy chunk.
### `renderModernChunks`
- **Type:** `boolean`
- **Default:** `true`
Set to `false` to only output the legacy bundles that support all target browsers.
## Browsers that supports ESM but does not support widely-available features
The legacy plugin offers a way to use widely-available features natively in the modern build, while falling back to the legacy build in browsers with native ESM but without those features supported (e.g. Legacy Edge). This feature works by injecting a runtime check and loading the legacy bundle with SystemJs runtime if needed. There are the following drawbacks:
- Modern bundle is downloaded in all ESM browsers
- Modern bundle throws `SyntaxError` in browsers without those features support
The following syntax are considered as widely-available:
- dynamic import
- `import.meta`
- async generator
## Polyfill Specifiers
Polyfill specifier strings for `polyfills` and `modernPolyfills` can be either of the following:
- Any [`core-js` 3 sub import paths](https://unpkg.com/browse/core-js@latest/) - e.g. `es/map` will import `core-js/es/map`
- Any [individual `core-js` 3 modules](https://unpkg.com/browse/core-js@latest/modules/) - e.g. `es.array.iterator` will import `core-js/modules/es.array.iterator.js`
**Example**
```js
import legacy from '@vitejs/plugin-legacy'
export default {
plugins: [
legacy({
polyfills: ['es.promise.finally', 'es/map', 'es/set'],
modernPolyfills: ['es.promise.finally'],
}),
],
}
```
## Content Security Policy
The legacy plugin requires inline scripts for [Safari 10.1 `nomodule` fix](https://gist.github.com/samthor/64b114e4a4f539915a95b91ffd340acc), SystemJS initialization, and dynamic import fallback. If you have a strict CSP policy requirement, you will need to [add the corresponding hashes to your `script-src` list](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src#unsafe_inline_script).
The hash values (without the `sha256-` prefix) can be retrieved via:
```js
import { cspHashes } from '@vitejs/plugin-legacy'
```
The current values are:
- `sha256-MS6/3FCg4WjP9gwgaBGwLpRCY6fZBgwmhVCdrPrNf3E=`
- `sha256-tQjf8gvb2ROOMapIxFvFAYBeUJ0v1HCbOcSmDNXGtDo=`
- `sha256-VA8O2hAdooB288EpSTrGLl7z3QikbWU9wwoebO/QaYk=`
- `sha256-+5XkZFazzJo8n0iOP4ti/cLCMUudTf//Mzkb7xNPXIc=`
<!--
Run `node --input-type=module -e "import {cspHashes} from '@vitejs/plugin-legacy'; console.log(cspHashes.map(h => 'sha256-'+h))"` to retrieve the value.
-->
Note that these values could change between minor versions. Thus, we recommend generating the CSP header from the exported `cspHashes` variable. If you copy the values manually, then you should pin the minor version using `~`.
When using the `regenerator-runtime` polyfill, it will attempt to use the `globalThis` object to register itself. If `globalThis` is not available (it is [fairly new](https://caniuse.com/?search=globalThis) and not widely supported, including IE 11), it attempts to perform dynamic `Function(...)` call which violates the CSP. To avoid dynamic `eval` in the absence of `globalThis` consider adding `core-js/proposals/global-this` to `additionalLegacyPolyfills` to define it.
## References
- [Vue CLI modern mode](https://cli.vuejs.org/guide/browser-compatibility.html#modern-mode)
- [Using Native JavaScript Modules in Production Today](https://philipwalton.com/articles/using-native-javascript-modules-in-production-today/)
- [rollup-native-modules-boilerplate](https://github.com/philipwalton/rollup-native-modules-boilerplate)
+738
View File
@@ -0,0 +1,738 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
const path = require('node:path');
const node_crypto = require('node:crypto');
const node_module = require('node:module');
const node_url = require('node:url');
const vite = require('vite');
const MagicString = require('magic-string');
const require$$0 = require('tty');
const browserslist = require('browserslist');
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
const path__default = /*#__PURE__*/_interopDefaultCompat(path);
const MagicString__default = /*#__PURE__*/_interopDefaultCompat(MagicString);
const require$$0__default = /*#__PURE__*/_interopDefaultCompat(require$$0);
const browserslist__default = /*#__PURE__*/_interopDefaultCompat(browserslist);
function getDefaultExportFromCjs (x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}
var picocolors = {exports: {}};
let tty = require$$0__default;
let isColorSupported =
!("NO_COLOR" in process.env || process.argv.includes("--no-color")) &&
("FORCE_COLOR" in process.env ||
process.argv.includes("--color") ||
process.platform === "win32" ||
(tty.isatty(1) && process.env.TERM !== "dumb") ||
"CI" in process.env);
let formatter =
(open, close, replace = open) =>
input => {
let string = "" + input;
let index = string.indexOf(close, open.length);
return ~index
? open + replaceClose(string, close, replace, index) + close
: open + string + close
};
let replaceClose = (string, close, replace, index) => {
let start = string.substring(0, index) + replace;
let end = string.substring(index + close.length);
let nextIndex = end.indexOf(close);
return ~nextIndex ? start + replaceClose(end, close, replace, nextIndex) : start + end
};
let createColors = (enabled = isColorSupported) => ({
isColorSupported: enabled,
reset: enabled ? s => `\x1b[0m${s}\x1b[0m` : String,
bold: enabled ? formatter("\x1b[1m", "\x1b[22m", "\x1b[22m\x1b[1m") : String,
dim: enabled ? formatter("\x1b[2m", "\x1b[22m", "\x1b[22m\x1b[2m") : String,
italic: enabled ? formatter("\x1b[3m", "\x1b[23m") : String,
underline: enabled ? formatter("\x1b[4m", "\x1b[24m") : String,
inverse: enabled ? formatter("\x1b[7m", "\x1b[27m") : String,
hidden: enabled ? formatter("\x1b[8m", "\x1b[28m") : String,
strikethrough: enabled ? formatter("\x1b[9m", "\x1b[29m") : String,
black: enabled ? formatter("\x1b[30m", "\x1b[39m") : String,
red: enabled ? formatter("\x1b[31m", "\x1b[39m") : String,
green: enabled ? formatter("\x1b[32m", "\x1b[39m") : String,
yellow: enabled ? formatter("\x1b[33m", "\x1b[39m") : String,
blue: enabled ? formatter("\x1b[34m", "\x1b[39m") : String,
magenta: enabled ? formatter("\x1b[35m", "\x1b[39m") : String,
cyan: enabled ? formatter("\x1b[36m", "\x1b[39m") : String,
white: enabled ? formatter("\x1b[37m", "\x1b[39m") : String,
gray: enabled ? formatter("\x1b[90m", "\x1b[39m") : String,
bgBlack: enabled ? formatter("\x1b[40m", "\x1b[49m") : String,
bgRed: enabled ? formatter("\x1b[41m", "\x1b[49m") : String,
bgGreen: enabled ? formatter("\x1b[42m", "\x1b[49m") : String,
bgYellow: enabled ? formatter("\x1b[43m", "\x1b[49m") : String,
bgBlue: enabled ? formatter("\x1b[44m", "\x1b[49m") : String,
bgMagenta: enabled ? formatter("\x1b[45m", "\x1b[49m") : String,
bgCyan: enabled ? formatter("\x1b[46m", "\x1b[49m") : String,
bgWhite: enabled ? formatter("\x1b[47m", "\x1b[49m") : String,
});
picocolors.exports = createColors();
picocolors.exports.createColors = createColors;
var picocolorsExports = picocolors.exports;
const colors = /*@__PURE__*/getDefaultExportFromCjs(picocolorsExports);
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 detectModernBrowserVarName = "__vite_is_modern_browser";
const detectModernBrowserDetector = `import.meta.url;import("_").catch(()=>1);(async function*(){})().next()`;
const detectModernBrowserCode = `${detectModernBrowserDetector};if(location.protocol!="file:"){window.${detectModernBrowserVarName}=true}`;
const dynamicFallbackInlineCode = `!function(){if(window.${detectModernBrowserVarName})return;console.warn("vite: loading legacy chunks, syntax error above and the same error below 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 modernChunkLegacyGuard = `export function __vite_legacy_guard(){${detectModernBrowserDetector}};`;
let babel;
async function loadBabel() {
if (!babel) {
babel = await import('@babel/core');
}
return babel;
}
const { loadConfig: browserslistLoadConfig } = browserslist__default;
function toOutputFilePathInHtml(filename, type, hostId, hostType, config, toRelative) {
const { renderBuiltUrl } = config.experimental;
let relative = config.base === "" || config.base === "./";
if (renderBuiltUrl) {
const result = renderBuiltUrl(filename, {
hostId,
hostType,
type,
ssr: !!config.build.ssr
});
if (typeof result === "object") {
if (result.runtime) {
throw new Error(
`{ runtime: "${result.runtime}" } is not supported for assets in ${hostType} files: ${filename}`
);
}
if (typeof result.relative === "boolean") {
relative = result.relative;
}
} else if (result) {
return result;
}
}
if (relative && !config.build.ssr) {
return toRelative(filename, hostId);
} else {
return config.base + filename;
}
}
function getBaseInHTML(urlRelativePath, config) {
return config.base === "./" || config.base === "" ? path__default.posix.join(
path__default.posix.relative(urlRelativePath, "").slice(0, -2),
"./"
) : config.base;
}
function toAssetPathFromHtml(filename, htmlPath, config) {
const relativeUrlPath = vite.normalizePath(path__default.relative(config.root, htmlPath));
const toRelative = (filename2, hostId) => getBaseInHTML(relativeUrlPath, config) + filename2;
return toOutputFilePathInHtml(
filename,
"asset",
htmlPath,
"html",
config,
toRelative
);
}
const legacyEnvVarMarker = `__VITE_IS_LEGACY__`;
const _require = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
const nonLeadingHashInFileNameRE = /[^/]+\[hash(?::\d+)?\]/;
const prefixedHashInFileNameRE = /\W?\[hash(:\d+)?\]/;
function viteLegacyPlugin(options = {}) {
let config;
let targets;
let modernTargets;
const modernTargetsEsbuild = [
"es2020",
"edge79",
"firefox67",
"chrome64",
"safari12"
];
const modernTargetsBabel = "edge>=80, firefox>=72, chrome>=80, safari>=13.1, chromeAndroid>=80, iOS>=13.1";
const genLegacy = options.renderLegacyChunks !== false;
const genModern = options.renderModernChunks !== false;
if (!genLegacy && !genModern) {
throw new Error(
"`renderLegacyChunks` and `renderModernChunks` cannot be both false"
);
}
const debugFlags = (process.env.DEBUG || "").split(",");
const isDebug = debugFlags.includes("vite:*") || debugFlags.includes("vite:legacy");
const facadeToLegacyChunkMap = /* @__PURE__ */ new Map();
const facadeToLegacyPolyfillMap = /* @__PURE__ */ new Map();
const facadeToModernPolyfillMap = /* @__PURE__ */ new Map();
const modernPolyfills = /* @__PURE__ */ new Set();
const legacyPolyfills = /* @__PURE__ */ new Set();
if (Array.isArray(options.modernPolyfills) && genModern) {
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);
});
}
let overriddenBuildTarget = false;
let overriddenDefaultModernTargets = false;
const legacyConfigPlugin = {
name: "vite:legacy-config",
async config(config2, env) {
if (env.command === "build" && !config2.build?.ssr) {
if (!config2.build) {
config2.build = {};
}
if (!config2.build.cssTarget) {
config2.build.cssTarget = "chrome61";
}
if (genLegacy) {
overriddenBuildTarget = config2.build.target !== void 0;
overriddenDefaultModernTargets = options.modernTargets !== void 0;
if (options.modernTargets) {
const { default: browserslistToEsbuild } = await import('browserslist-to-esbuild');
config2.build.target = browserslistToEsbuild(options.modernTargets);
} else {
config2.build.target = modernTargetsEsbuild;
}
}
}
return {
define: {
"import.meta.env.LEGACY": env.command === "serve" || config2.build?.ssr ? false : legacyEnvVarMarker
}
};
},
configResolved(config2) {
if (overriddenBuildTarget) {
config2.logger.warn(
colors.yellow(
`plugin-legacy overrode 'build.target'. You should pass 'targets' as an option to this plugin with the list of legacy browsers to support instead.`
)
);
}
if (overriddenDefaultModernTargets) {
config2.logger.warn(
colors.yellow(
`plugin-legacy 'modernTargets' option overrode the builtin targets of modern chunks. Some versions of browsers between legacy and modern may not be supported.`
)
);
}
}
};
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
);
const polyfillChunk = await buildPolyfillChunk(
config.mode,
modernPolyfills,
bundle,
facadeToModernPolyfillMap,
config.build,
"es",
opts,
true
);
if (genLegacy && polyfillChunk) {
polyfillChunk.code = modernChunkLegacyGuard + polyfillChunk.code;
}
return;
}
if (!genLegacy) {
return;
}
if (options.polyfills !== false) {
await detectPolyfills(
`Promise.resolve(); Promise.all();`,
targets,
legacyPolyfills
);
}
if (legacyPolyfills.size || !options.externalSystemJS) {
isDebug && console.log(
`[@vitejs/plugin-legacy] legacy polyfills:`,
legacyPolyfills
);
await buildPolyfillChunk(
config.mode,
legacyPolyfills,
bundle,
facadeToLegacyPolyfillMap,
// force using terser for legacy polyfill minification, since esbuild
// isn't legacy-safe
config.build,
"iife",
opts,
options.externalSystemJS
);
}
}
};
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;
modernTargets = options.modernTargets || modernTargetsBabel;
isDebug && console.log(`[@vitejs/plugin-legacy] modernTargets:`, modernTargets);
if (!genLegacy || config.build.ssr) {
return;
}
targets = options.targets || browserslistLoadConfig({ path: config.root }) || "last 2 versions and not dead, > 0.3%, Firefox ESR";
isDebug && console.log(`[@vitejs/plugin-legacy] targets:`, targets);
const getLegacyOutputFileName = (fileNames, defaultFileName = "[name]-legacy-[hash].js") => {
if (!fileNames) {
return path__default.posix.join(config.build.assetsDir, defaultFileName);
}
return (chunkInfo) => {
let fileName = typeof fileNames === "function" ? fileNames(chunkInfo) : fileNames;
if (fileName.includes("[name]")) {
fileName = fileName.replace("[name]", "[name]-legacy");
} else if (nonLeadingHashInFileNameRE.test(fileName)) {
fileName = fileName.replace(prefixedHashInFileNameRE, "-legacy$&");
} else {
fileName = fileName.replace(/(.+?)\.(.+)/, "$1-legacy.$2");
}
return fileName;
};
};
const createLegacyOutput = (options2 = {}) => {
return {
...options2,
format: "system",
entryFileNames: getLegacyOutputFileName(options2.entryFileNames),
chunkFileNames: getLegacyOutputFileName(options2.chunkFileNames)
};
};
const { rollupOptions } = config.build;
const { output } = rollupOptions;
if (Array.isArray(output)) {
rollupOptions.output = [
...output.map(createLegacyOutput),
...genModern ? output : []
];
} else {
rollupOptions.output = [
createLegacyOutput(output),
...genModern ? [output || {}] : []
];
}
},
async renderChunk(raw, chunk, opts) {
if (config.build.ssr) {
return null;
}
if (!isLegacyChunk(chunk, opts)) {
if (options.modernPolyfills && !Array.isArray(options.modernPolyfills) && genModern) {
await detectPolyfills(raw, modernTargets, modernPolyfills);
}
const ms = new MagicString__default(raw);
if (genLegacy && chunk.isEntry) {
ms.prepend(modernChunkLegacyGuard);
}
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: "boundary" })
};
}
return {
code: ms.toString()
};
}
if (!genLegacy) {
return null;
}
opts.__vite_skip_esbuild__ = true;
opts.__vite_force_terser__ = true;
opts.__vite_skip_asset_emit__ = true;
const needPolyfills = options.polyfills !== false && !Array.isArray(options.polyfills);
const sourceMaps = !!config.build.sourcemap;
const babel2 = await loadBabel();
const result = babel2.transform(raw, {
babelrc: false,
configFile: false,
compact: !!config.build.minify,
sourceMaps,
inputSourceMap: void 0,
// sourceMaps ? chunk.map : undefined, `.map` TODO: moved to OutputChunk?
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()
]
})
],
[
(await import('@babel/preset-env')).default,
createBabelPresetEnvOptions(targets, { needPolyfills })
]
]
});
if (result)
return { code: result.code, map: result.map };
return null;
},
transformIndexHtml(html, { chunk }) {
if (config.build.ssr)
return;
if (!chunk)
return;
if (chunk.fileName.includes("-legacy")) {
facadeToLegacyChunkMap.set(chunk.facadeModuleId, chunk.fileName);
if (genModern) {
return;
}
}
if (!genModern) {
html = html.replace(/<script type="module".*?<\/script>/g, "");
}
const tags = [];
const htmlFilename = chunk.facadeModuleId?.replace(/\?.*$/, "");
if (genModern) {
const modernPolyfillFilename = facadeToModernPolyfillMap.get(
chunk.facadeModuleId
);
if (modernPolyfillFilename) {
tags.push({
tag: "script",
attrs: {
type: "module",
crossorigin: true,
src: toAssetPathFromHtml(
modernPolyfillFilename,
chunk.facadeModuleId,
config
)
}
});
} else if (modernPolyfills.size) {
throw new Error(
`No corresponding modern polyfill chunk found for ${htmlFilename}`
);
}
}
if (!genLegacy) {
return { html, tags };
}
if (genModern) {
tags.push({
tag: "script",
attrs: { nomodule: genModern },
children: safari10NoModuleFix,
injectTo: "body"
});
}
const legacyPolyfillFilename = facadeToLegacyPolyfillMap.get(
chunk.facadeModuleId
);
if (legacyPolyfillFilename) {
tags.push({
tag: "script",
attrs: {
nomodule: genModern,
crossorigin: true,
id: legacyPolyfillId,
src: toAssetPathFromHtml(
legacyPolyfillFilename,
chunk.facadeModuleId,
config
)
},
injectTo: "body"
});
} else if (legacyPolyfills.size) {
throw new Error(
`No corresponding legacy polyfill chunk found for ${htmlFilename}`
);
}
const legacyEntryFilename = facadeToLegacyChunkMap.get(
chunk.facadeModuleId
);
if (legacyEntryFilename) {
tags.push({
tag: "script",
attrs: {
nomodule: genModern,
crossorigin: 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": toAssetPathFromHtml(
legacyEntryFilename,
chunk.facadeModuleId,
config
)
},
children: systemJSInlineCode,
injectTo: "body"
});
} else {
throw new Error(
`No corresponding legacy entry chunk found for ${htmlFilename}`
);
}
if (legacyPolyfillFilename && legacyEntryFilename && genModern) {
tags.push({
tag: "script",
attrs: { type: "module" },
children: detectModernBrowserCode,
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) && genModern) {
for (const name in bundle) {
if (bundle[name].type === "asset" && !/.+\.map$/.test(name)) {
delete bundle[name];
}
}
}
}
};
return [legacyConfigPlugin, legacyGenerateBundlePlugin, legacyPostPlugin];
}
async function detectPolyfills(code, targets, list) {
const babel2 = await loadBabel();
const result = babel2.transform(code, {
ast: true,
babelrc: false,
configFile: false,
compact: false,
presets: [
[
(await import('@babel/preset-env')).default,
createBabelPresetEnvOptions(targets, {})
]
]
});
for (const node of result.ast.program.body) {
if (node.type === "ImportDeclaration") {
const source = node.source.value;
if (source.startsWith("core-js/") || source.startsWith("regenerator-runtime/")) {
list.add(source);
}
}
}
}
function createBabelPresetEnvOptions(targets, { needPolyfills = true }) {
return {
targets,
bugfixes: true,
loose: false,
modules: false,
useBuiltIns: needPolyfills ? "usage" : false,
corejs: needPolyfills ? {
version: _require("core-js/package.json").version,
proposals: false
} : void 0,
shippedProposals: true,
ignoreBrowserslistConfig: true
};
}
async function buildPolyfillChunk(mode, imports, bundle, facadeToChunkMap, buildOptions, format, rollupOutputOptions, excludeSystemJS) {
let { minify, assetsDir } = buildOptions;
minify = minify ? "terser" : false;
const res = await vite.build({
mode,
// so that everything is resolved from here
root: path__default.dirname(node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)))),
configFile: false,
logLevel: "error",
plugins: [polyfillsPlugin(imports, excludeSystemJS)],
build: {
write: false,
minify,
assetsDir,
rollupOptions: {
input: {
polyfills: polyfillId
},
output: {
format,
entryFileNames: rollupOutputOptions.entryFileNames
}
}
},
// Don't run esbuild for transpilation or minification
// because we don't want to transpile code.
esbuild: false,
optimizeDeps: {
esbuildOptions: {
// If a value above 'es5' is set, esbuild injects helper functions which uses es2015 features.
// This limits the input code not to include es2015+ codes.
// But core-js is the only dependency which includes commonjs code
// and core-js doesn't include es2015+ codes.
target: "es5"
}
}
});
const _polyfillChunk = Array.isArray(res) ? res[0] : res;
if (!("output" in _polyfillChunk))
return;
const polyfillChunk = _polyfillChunk.output[0];
for (const key in bundle) {
const chunk = bundle[key];
if (chunk.type === "chunk" && chunk.facadeModuleId) {
facadeToChunkMap.set(chunk.facadeModuleId, polyfillChunk.fileName);
}
}
bundle[polyfillChunk.fileName] = polyfillChunk;
return polyfillChunk;
}
const polyfillId = "\0vite/legacy-polyfills";
function polyfillsPlugin(imports, excludeSystemJS) {
return {
name: "vite:legacy-polyfills",
resolveId(id) {
if (id === polyfillId) {
return id;
}
},
load(id) {
if (id === polyfillId) {
return [...imports].map((i) => `import ${JSON.stringify(i)};`).join("") + (excludeSystemJS ? "" : `import "systemjs/dist/s.min.js";`);
}
}
};
}
function isLegacyChunk(chunk, options) {
return options.format === "system" && chunk.fileName.includes("-legacy");
}
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;
}
function recordAndRemovePolyfillBabelPlugin(polyfills) {
return ({ types: t }) => ({
name: "vite-remove-polyfill-import",
post({ path: path2 }) {
path2.get("body").forEach((p) => {
if (t.isImportDeclaration(p.node)) {
polyfills.add(p.node.source.value);
p.remove();
}
});
}
});
}
function replaceLegacyEnvBabelPlugin() {
return ({ types: t }) => ({
name: "vite-replace-env-legacy",
visitor: {
Identifier(path2) {
if (path2.node.name === legacyEnvVarMarker) {
path2.replaceWith(t.booleanLiteral(true));
}
}
}
});
}
function wrapIIFEBabelPlugin() {
return ({ types: t, template }) => {
const buildIIFE = template(";(function(){%%body%%})();");
return {
name: "vite-wrap-iife",
post({ path: path2 }) {
if (!this.isWrapped) {
this.isWrapped = true;
path2.replaceWith(t.program(buildIIFE({ body: path2.node.body })));
}
}
};
};
}
const cspHashes = [
safari10NoModuleFix,
systemJSInlineCode,
detectModernBrowserCode,
dynamicFallbackInlineCode
].map((i) => node_crypto.createHash("sha256").update(i).digest("base64"));
module.exports = viteLegacyPlugin;
module.exports.cspHashes = cspHashes;
module.exports.default = viteLegacyPlugin;
module.exports.detectPolyfills = detectPolyfills;
+41
View File
@@ -0,0 +1,41 @@
import { Plugin } from 'vite';
interface Options {
/**
* default: 'defaults'
*/
targets?: string | string[] | {
[key: string]: string;
};
/**
* default: 'edge>=80, firefox>=72, chrome>=80, safari>=13.1, chromeAndroid>=80, iOS>=13.1'
*/
modernTargets?: string | string[];
/**
* default: true
*/
polyfills?: boolean | string[];
additionalLegacyPolyfills?: string[];
/**
* default: false
*/
modernPolyfills?: boolean | string[];
/**
* default: true
*/
renderLegacyChunks?: boolean;
/**
* default: false
*/
externalSystemJS?: boolean;
/**
* default: true
*/
renderModernChunks?: boolean;
}
declare function viteLegacyPlugin(options?: Options): Plugin[];
declare function detectPolyfills(code: string, targets: any, list: Set<string>): Promise<void>;
declare const cspHashes: string[];
export { type Options, cspHashes, viteLegacyPlugin as default, detectPolyfills };
+41
View File
@@ -0,0 +1,41 @@
import { Plugin } from 'vite';
interface Options {
/**
* default: 'defaults'
*/
targets?: string | string[] | {
[key: string]: string;
};
/**
* default: 'edge>=80, firefox>=72, chrome>=80, safari>=13.1, chromeAndroid>=80, iOS>=13.1'
*/
modernTargets?: string | string[];
/**
* default: true
*/
polyfills?: boolean | string[];
additionalLegacyPolyfills?: string[];
/**
* default: false
*/
modernPolyfills?: boolean | string[];
/**
* default: true
*/
renderLegacyChunks?: boolean;
/**
* default: false
*/
externalSystemJS?: boolean;
/**
* default: true
*/
renderModernChunks?: boolean;
}
declare function viteLegacyPlugin(options?: Options): Plugin[];
declare function detectPolyfills(code: string, targets: any, list: Set<string>): Promise<void>;
declare const cspHashes: string[];
export { type Options, cspHashes, viteLegacyPlugin as default, detectPolyfills };
+41
View File
@@ -0,0 +1,41 @@
import { Plugin } from 'vite';
interface Options {
/**
* default: 'defaults'
*/
targets?: string | string[] | {
[key: string]: string;
};
/**
* default: 'edge>=80, firefox>=72, chrome>=80, safari>=13.1, chromeAndroid>=80, iOS>=13.1'
*/
modernTargets?: string | string[];
/**
* default: true
*/
polyfills?: boolean | string[];
additionalLegacyPolyfills?: string[];
/**
* default: false
*/
modernPolyfills?: boolean | string[];
/**
* default: true
*/
renderLegacyChunks?: boolean;
/**
* default: false
*/
externalSystemJS?: boolean;
/**
* default: true
*/
renderModernChunks?: boolean;
}
declare function viteLegacyPlugin(options?: Options): Plugin[];
declare function detectPolyfills(code: string, targets: any, list: Set<string>): Promise<void>;
declare const cspHashes: string[];
export { type Options, cspHashes, viteLegacyPlugin as default, detectPolyfills };
+723
View File
@@ -0,0 +1,723 @@
import path from 'node:path';
import { createHash } from 'node:crypto';
import { createRequire } from 'node:module';
import { fileURLToPath } from 'node:url';
import { build, normalizePath } from 'vite';
import MagicString from 'magic-string';
import require$$0 from 'tty';
import browserslist from 'browserslist';
function getDefaultExportFromCjs (x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}
var picocolors = {exports: {}};
let tty = require$$0;
let isColorSupported =
!("NO_COLOR" in process.env || process.argv.includes("--no-color")) &&
("FORCE_COLOR" in process.env ||
process.argv.includes("--color") ||
process.platform === "win32" ||
(tty.isatty(1) && process.env.TERM !== "dumb") ||
"CI" in process.env);
let formatter =
(open, close, replace = open) =>
input => {
let string = "" + input;
let index = string.indexOf(close, open.length);
return ~index
? open + replaceClose(string, close, replace, index) + close
: open + string + close
};
let replaceClose = (string, close, replace, index) => {
let start = string.substring(0, index) + replace;
let end = string.substring(index + close.length);
let nextIndex = end.indexOf(close);
return ~nextIndex ? start + replaceClose(end, close, replace, nextIndex) : start + end
};
let createColors = (enabled = isColorSupported) => ({
isColorSupported: enabled,
reset: enabled ? s => `\x1b[0m${s}\x1b[0m` : String,
bold: enabled ? formatter("\x1b[1m", "\x1b[22m", "\x1b[22m\x1b[1m") : String,
dim: enabled ? formatter("\x1b[2m", "\x1b[22m", "\x1b[22m\x1b[2m") : String,
italic: enabled ? formatter("\x1b[3m", "\x1b[23m") : String,
underline: enabled ? formatter("\x1b[4m", "\x1b[24m") : String,
inverse: enabled ? formatter("\x1b[7m", "\x1b[27m") : String,
hidden: enabled ? formatter("\x1b[8m", "\x1b[28m") : String,
strikethrough: enabled ? formatter("\x1b[9m", "\x1b[29m") : String,
black: enabled ? formatter("\x1b[30m", "\x1b[39m") : String,
red: enabled ? formatter("\x1b[31m", "\x1b[39m") : String,
green: enabled ? formatter("\x1b[32m", "\x1b[39m") : String,
yellow: enabled ? formatter("\x1b[33m", "\x1b[39m") : String,
blue: enabled ? formatter("\x1b[34m", "\x1b[39m") : String,
magenta: enabled ? formatter("\x1b[35m", "\x1b[39m") : String,
cyan: enabled ? formatter("\x1b[36m", "\x1b[39m") : String,
white: enabled ? formatter("\x1b[37m", "\x1b[39m") : String,
gray: enabled ? formatter("\x1b[90m", "\x1b[39m") : String,
bgBlack: enabled ? formatter("\x1b[40m", "\x1b[49m") : String,
bgRed: enabled ? formatter("\x1b[41m", "\x1b[49m") : String,
bgGreen: enabled ? formatter("\x1b[42m", "\x1b[49m") : String,
bgYellow: enabled ? formatter("\x1b[43m", "\x1b[49m") : String,
bgBlue: enabled ? formatter("\x1b[44m", "\x1b[49m") : String,
bgMagenta: enabled ? formatter("\x1b[45m", "\x1b[49m") : String,
bgCyan: enabled ? formatter("\x1b[46m", "\x1b[49m") : String,
bgWhite: enabled ? formatter("\x1b[47m", "\x1b[49m") : String,
});
picocolors.exports = createColors();
picocolors.exports.createColors = createColors;
var picocolorsExports = picocolors.exports;
const colors = /*@__PURE__*/getDefaultExportFromCjs(picocolorsExports);
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 detectModernBrowserVarName = "__vite_is_modern_browser";
const detectModernBrowserDetector = `import.meta.url;import("_").catch(()=>1);(async function*(){})().next()`;
const detectModernBrowserCode = `${detectModernBrowserDetector};if(location.protocol!="file:"){window.${detectModernBrowserVarName}=true}`;
const dynamicFallbackInlineCode = `!function(){if(window.${detectModernBrowserVarName})return;console.warn("vite: loading legacy chunks, syntax error above and the same error below 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 modernChunkLegacyGuard = `export function __vite_legacy_guard(){${detectModernBrowserDetector}};`;
let babel;
async function loadBabel() {
if (!babel) {
babel = await import('@babel/core');
}
return babel;
}
const { loadConfig: browserslistLoadConfig } = browserslist;
function toOutputFilePathInHtml(filename, type, hostId, hostType, config, toRelative) {
const { renderBuiltUrl } = config.experimental;
let relative = config.base === "" || config.base === "./";
if (renderBuiltUrl) {
const result = renderBuiltUrl(filename, {
hostId,
hostType,
type,
ssr: !!config.build.ssr
});
if (typeof result === "object") {
if (result.runtime) {
throw new Error(
`{ runtime: "${result.runtime}" } is not supported for assets in ${hostType} files: ${filename}`
);
}
if (typeof result.relative === "boolean") {
relative = result.relative;
}
} else if (result) {
return result;
}
}
if (relative && !config.build.ssr) {
return toRelative(filename, hostId);
} else {
return config.base + filename;
}
}
function getBaseInHTML(urlRelativePath, config) {
return config.base === "./" || config.base === "" ? path.posix.join(
path.posix.relative(urlRelativePath, "").slice(0, -2),
"./"
) : config.base;
}
function toAssetPathFromHtml(filename, htmlPath, config) {
const relativeUrlPath = normalizePath(path.relative(config.root, htmlPath));
const toRelative = (filename2, hostId) => getBaseInHTML(relativeUrlPath, config) + filename2;
return toOutputFilePathInHtml(
filename,
"asset",
htmlPath,
"html",
config,
toRelative
);
}
const legacyEnvVarMarker = `__VITE_IS_LEGACY__`;
const _require = createRequire(import.meta.url);
const nonLeadingHashInFileNameRE = /[^/]+\[hash(?::\d+)?\]/;
const prefixedHashInFileNameRE = /\W?\[hash(:\d+)?\]/;
function viteLegacyPlugin(options = {}) {
let config;
let targets;
let modernTargets;
const modernTargetsEsbuild = [
"es2020",
"edge79",
"firefox67",
"chrome64",
"safari12"
];
const modernTargetsBabel = "edge>=80, firefox>=72, chrome>=80, safari>=13.1, chromeAndroid>=80, iOS>=13.1";
const genLegacy = options.renderLegacyChunks !== false;
const genModern = options.renderModernChunks !== false;
if (!genLegacy && !genModern) {
throw new Error(
"`renderLegacyChunks` and `renderModernChunks` cannot be both false"
);
}
const debugFlags = (process.env.DEBUG || "").split(",");
const isDebug = debugFlags.includes("vite:*") || debugFlags.includes("vite:legacy");
const facadeToLegacyChunkMap = /* @__PURE__ */ new Map();
const facadeToLegacyPolyfillMap = /* @__PURE__ */ new Map();
const facadeToModernPolyfillMap = /* @__PURE__ */ new Map();
const modernPolyfills = /* @__PURE__ */ new Set();
const legacyPolyfills = /* @__PURE__ */ new Set();
if (Array.isArray(options.modernPolyfills) && genModern) {
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);
});
}
let overriddenBuildTarget = false;
let overriddenDefaultModernTargets = false;
const legacyConfigPlugin = {
name: "vite:legacy-config",
async config(config2, env) {
if (env.command === "build" && !config2.build?.ssr) {
if (!config2.build) {
config2.build = {};
}
if (!config2.build.cssTarget) {
config2.build.cssTarget = "chrome61";
}
if (genLegacy) {
overriddenBuildTarget = config2.build.target !== void 0;
overriddenDefaultModernTargets = options.modernTargets !== void 0;
if (options.modernTargets) {
const { default: browserslistToEsbuild } = await import('browserslist-to-esbuild');
config2.build.target = browserslistToEsbuild(options.modernTargets);
} else {
config2.build.target = modernTargetsEsbuild;
}
}
}
return {
define: {
"import.meta.env.LEGACY": env.command === "serve" || config2.build?.ssr ? false : legacyEnvVarMarker
}
};
},
configResolved(config2) {
if (overriddenBuildTarget) {
config2.logger.warn(
colors.yellow(
`plugin-legacy overrode 'build.target'. You should pass 'targets' as an option to this plugin with the list of legacy browsers to support instead.`
)
);
}
if (overriddenDefaultModernTargets) {
config2.logger.warn(
colors.yellow(
`plugin-legacy 'modernTargets' option overrode the builtin targets of modern chunks. Some versions of browsers between legacy and modern may not be supported.`
)
);
}
}
};
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
);
const polyfillChunk = await buildPolyfillChunk(
config.mode,
modernPolyfills,
bundle,
facadeToModernPolyfillMap,
config.build,
"es",
opts,
true
);
if (genLegacy && polyfillChunk) {
polyfillChunk.code = modernChunkLegacyGuard + polyfillChunk.code;
}
return;
}
if (!genLegacy) {
return;
}
if (options.polyfills !== false) {
await detectPolyfills(
`Promise.resolve(); Promise.all();`,
targets,
legacyPolyfills
);
}
if (legacyPolyfills.size || !options.externalSystemJS) {
isDebug && console.log(
`[@vitejs/plugin-legacy] legacy polyfills:`,
legacyPolyfills
);
await buildPolyfillChunk(
config.mode,
legacyPolyfills,
bundle,
facadeToLegacyPolyfillMap,
// force using terser for legacy polyfill minification, since esbuild
// isn't legacy-safe
config.build,
"iife",
opts,
options.externalSystemJS
);
}
}
};
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;
modernTargets = options.modernTargets || modernTargetsBabel;
isDebug && console.log(`[@vitejs/plugin-legacy] modernTargets:`, modernTargets);
if (!genLegacy || config.build.ssr) {
return;
}
targets = options.targets || browserslistLoadConfig({ path: config.root }) || "last 2 versions and not dead, > 0.3%, Firefox ESR";
isDebug && console.log(`[@vitejs/plugin-legacy] targets:`, targets);
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]")) {
fileName = fileName.replace("[name]", "[name]-legacy");
} else if (nonLeadingHashInFileNameRE.test(fileName)) {
fileName = fileName.replace(prefixedHashInFileNameRE, "-legacy$&");
} else {
fileName = fileName.replace(/(.+?)\.(.+)/, "$1-legacy.$2");
}
return fileName;
};
};
const createLegacyOutput = (options2 = {}) => {
return {
...options2,
format: "system",
entryFileNames: getLegacyOutputFileName(options2.entryFileNames),
chunkFileNames: getLegacyOutputFileName(options2.chunkFileNames)
};
};
const { rollupOptions } = config.build;
const { output } = rollupOptions;
if (Array.isArray(output)) {
rollupOptions.output = [
...output.map(createLegacyOutput),
...genModern ? output : []
];
} else {
rollupOptions.output = [
createLegacyOutput(output),
...genModern ? [output || {}] : []
];
}
},
async renderChunk(raw, chunk, opts) {
if (config.build.ssr) {
return null;
}
if (!isLegacyChunk(chunk, opts)) {
if (options.modernPolyfills && !Array.isArray(options.modernPolyfills) && genModern) {
await detectPolyfills(raw, modernTargets, modernPolyfills);
}
const ms = new MagicString(raw);
if (genLegacy && chunk.isEntry) {
ms.prepend(modernChunkLegacyGuard);
}
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: "boundary" })
};
}
return {
code: ms.toString()
};
}
if (!genLegacy) {
return null;
}
opts.__vite_skip_esbuild__ = true;
opts.__vite_force_terser__ = true;
opts.__vite_skip_asset_emit__ = true;
const needPolyfills = options.polyfills !== false && !Array.isArray(options.polyfills);
const sourceMaps = !!config.build.sourcemap;
const babel2 = await loadBabel();
const result = babel2.transform(raw, {
babelrc: false,
configFile: false,
compact: !!config.build.minify,
sourceMaps,
inputSourceMap: void 0,
// sourceMaps ? chunk.map : undefined, `.map` TODO: moved to OutputChunk?
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()
]
})
],
[
(await import('@babel/preset-env')).default,
createBabelPresetEnvOptions(targets, { needPolyfills })
]
]
});
if (result)
return { code: result.code, map: result.map };
return null;
},
transformIndexHtml(html, { chunk }) {
if (config.build.ssr)
return;
if (!chunk)
return;
if (chunk.fileName.includes("-legacy")) {
facadeToLegacyChunkMap.set(chunk.facadeModuleId, chunk.fileName);
if (genModern) {
return;
}
}
if (!genModern) {
html = html.replace(/<script type="module".*?<\/script>/g, "");
}
const tags = [];
const htmlFilename = chunk.facadeModuleId?.replace(/\?.*$/, "");
if (genModern) {
const modernPolyfillFilename = facadeToModernPolyfillMap.get(
chunk.facadeModuleId
);
if (modernPolyfillFilename) {
tags.push({
tag: "script",
attrs: {
type: "module",
crossorigin: true,
src: toAssetPathFromHtml(
modernPolyfillFilename,
chunk.facadeModuleId,
config
)
}
});
} else if (modernPolyfills.size) {
throw new Error(
`No corresponding modern polyfill chunk found for ${htmlFilename}`
);
}
}
if (!genLegacy) {
return { html, tags };
}
if (genModern) {
tags.push({
tag: "script",
attrs: { nomodule: genModern },
children: safari10NoModuleFix,
injectTo: "body"
});
}
const legacyPolyfillFilename = facadeToLegacyPolyfillMap.get(
chunk.facadeModuleId
);
if (legacyPolyfillFilename) {
tags.push({
tag: "script",
attrs: {
nomodule: genModern,
crossorigin: true,
id: legacyPolyfillId,
src: toAssetPathFromHtml(
legacyPolyfillFilename,
chunk.facadeModuleId,
config
)
},
injectTo: "body"
});
} else if (legacyPolyfills.size) {
throw new Error(
`No corresponding legacy polyfill chunk found for ${htmlFilename}`
);
}
const legacyEntryFilename = facadeToLegacyChunkMap.get(
chunk.facadeModuleId
);
if (legacyEntryFilename) {
tags.push({
tag: "script",
attrs: {
nomodule: genModern,
crossorigin: 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": toAssetPathFromHtml(
legacyEntryFilename,
chunk.facadeModuleId,
config
)
},
children: systemJSInlineCode,
injectTo: "body"
});
} else {
throw new Error(
`No corresponding legacy entry chunk found for ${htmlFilename}`
);
}
if (legacyPolyfillFilename && legacyEntryFilename && genModern) {
tags.push({
tag: "script",
attrs: { type: "module" },
children: detectModernBrowserCode,
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) && genModern) {
for (const name in bundle) {
if (bundle[name].type === "asset" && !/.+\.map$/.test(name)) {
delete bundle[name];
}
}
}
}
};
return [legacyConfigPlugin, legacyGenerateBundlePlugin, legacyPostPlugin];
}
async function detectPolyfills(code, targets, list) {
const babel2 = await loadBabel();
const result = babel2.transform(code, {
ast: true,
babelrc: false,
configFile: false,
compact: false,
presets: [
[
(await import('@babel/preset-env')).default,
createBabelPresetEnvOptions(targets, {})
]
]
});
for (const node of result.ast.program.body) {
if (node.type === "ImportDeclaration") {
const source = node.source.value;
if (source.startsWith("core-js/") || source.startsWith("regenerator-runtime/")) {
list.add(source);
}
}
}
}
function createBabelPresetEnvOptions(targets, { needPolyfills = true }) {
return {
targets,
bugfixes: true,
loose: false,
modules: false,
useBuiltIns: needPolyfills ? "usage" : false,
corejs: needPolyfills ? {
version: _require("core-js/package.json").version,
proposals: false
} : void 0,
shippedProposals: true,
ignoreBrowserslistConfig: true
};
}
async function buildPolyfillChunk(mode, imports, bundle, facadeToChunkMap, buildOptions, format, rollupOutputOptions, excludeSystemJS) {
let { minify, assetsDir } = buildOptions;
minify = minify ? "terser" : false;
const res = await build({
mode,
// so that everything is resolved from here
root: path.dirname(fileURLToPath(import.meta.url)),
configFile: false,
logLevel: "error",
plugins: [polyfillsPlugin(imports, excludeSystemJS)],
build: {
write: false,
minify,
assetsDir,
rollupOptions: {
input: {
polyfills: polyfillId
},
output: {
format,
entryFileNames: rollupOutputOptions.entryFileNames
}
}
},
// Don't run esbuild for transpilation or minification
// because we don't want to transpile code.
esbuild: false,
optimizeDeps: {
esbuildOptions: {
// If a value above 'es5' is set, esbuild injects helper functions which uses es2015 features.
// This limits the input code not to include es2015+ codes.
// But core-js is the only dependency which includes commonjs code
// and core-js doesn't include es2015+ codes.
target: "es5"
}
}
});
const _polyfillChunk = Array.isArray(res) ? res[0] : res;
if (!("output" in _polyfillChunk))
return;
const polyfillChunk = _polyfillChunk.output[0];
for (const key in bundle) {
const chunk = bundle[key];
if (chunk.type === "chunk" && chunk.facadeModuleId) {
facadeToChunkMap.set(chunk.facadeModuleId, polyfillChunk.fileName);
}
}
bundle[polyfillChunk.fileName] = polyfillChunk;
return polyfillChunk;
}
const polyfillId = "\0vite/legacy-polyfills";
function polyfillsPlugin(imports, excludeSystemJS) {
return {
name: "vite:legacy-polyfills",
resolveId(id) {
if (id === polyfillId) {
return id;
}
},
load(id) {
if (id === polyfillId) {
return [...imports].map((i) => `import ${JSON.stringify(i)};`).join("") + (excludeSystemJS ? "" : `import "systemjs/dist/s.min.js";`);
}
}
};
}
function isLegacyChunk(chunk, options) {
return options.format === "system" && chunk.fileName.includes("-legacy");
}
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;
}
function recordAndRemovePolyfillBabelPlugin(polyfills) {
return ({ types: t }) => ({
name: "vite-remove-polyfill-import",
post({ path: path2 }) {
path2.get("body").forEach((p) => {
if (t.isImportDeclaration(p.node)) {
polyfills.add(p.node.source.value);
p.remove();
}
});
}
});
}
function replaceLegacyEnvBabelPlugin() {
return ({ types: t }) => ({
name: "vite-replace-env-legacy",
visitor: {
Identifier(path2) {
if (path2.node.name === legacyEnvVarMarker) {
path2.replaceWith(t.booleanLiteral(true));
}
}
}
});
}
function wrapIIFEBabelPlugin() {
return ({ types: t, template }) => {
const buildIIFE = template(";(function(){%%body%%})();");
return {
name: "vite-wrap-iife",
post({ path: path2 }) {
if (!this.isWrapped) {
this.isWrapped = true;
path2.replaceWith(t.program(buildIIFE({ body: path2.node.body })));
}
}
};
};
}
const cspHashes = [
safari10NoModuleFix,
systemJSInlineCode,
detectModernBrowserCode,
dynamicFallbackInlineCode
].map((i) => createHash("sha256").update(i).digest("base64"));
export { cspHashes, viteLegacyPlugin as default, detectPolyfills };
+61
View File
@@ -0,0 +1,61 @@
{
"name": "@vitejs/plugin-legacy",
"version": "5.3.2",
"license": "MIT",
"author": "Evan You",
"files": [
"dist"
],
"keywords": [
"frontend",
"vite",
"vite-plugin",
"@vitejs/plugin-legacy"
],
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
}
},
"engines": {
"node": "^18.0.0 || >=20.0.0"
},
"repository": {
"type": "git",
"url": "git+https://github.com/vitejs/vite.git",
"directory": "packages/plugin-legacy"
},
"bugs": {
"url": "https://github.com/vitejs/vite/issues"
},
"homepage": "https://github.com/vitejs/vite/tree/main/packages/plugin-legacy#readme",
"funding": "https://github.com/vitejs/vite?sponsor=1",
"dependencies": {
"@babel/core": "^7.23.9",
"@babel/preset-env": "^7.23.9",
"browserslist": "^4.23.0",
"browserslist-to-esbuild": "^2.1.1",
"core-js": "^3.36.0",
"magic-string": "^0.30.7",
"regenerator-runtime": "^0.14.1",
"systemjs": "^6.14.3"
},
"peerDependencies": {
"terser": "^5.4.0",
"vite": "^5.0.0"
},
"devDependencies": {
"acorn": "^8.11.3",
"picocolors": "^1.0.0",
"vite": "5.1.5"
},
"scripts": {
"dev": "unbuild --stub",
"build": "unbuild && pnpm run patch-cjs",
"patch-cjs": "tsx ../../scripts/patchCJS.ts"
}
}