通用解决方案
- 结合前端成熟的编译工具链 Babel
- 结合运行时基础库 core.js 做Polyfill
install npm modules
pnpm i @babel/cli @babel/core @babel/preset-env
配置 Babel file
{
"presets": [
[
"@babel/preset-env",
{
// 指定兼容的浏览器版本
"targets": {
"ie": "11"
},
"corejs": 3,
// Polyfill 注入策略
"useBuiltIns": "usage",
// 不将 ES 模块语法转换为其他模块语法
"modules": false
}
]
]
}
useBuiltIns 可以设置 entry 和 usage 两个值,usage 设置成按需引入Polyfill。
@babel/preset-env 注入 Polyfill 痛点:
- 全局注入,污染全局环境
- 重复函数多次出现,文件体积冗余
推荐使用 transform-runtime
pnpm i @babel/plugin-transform-runtime -D
pnpm i @babel/runtime-corejs3 -S
@babel/runtime-corejs3 使用的是 core-js-pure,不全局注入不全量引入。
配置 Babel 文件
{
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"corejs": 3
}
]
],
"presets": [
[
"@babel/preset-env",
{
"targets": {
"ie": "11"
},
"corejs": 3,
// 关闭 @babel/preset-env 默认的 Polyfill 注入
"useBuiltIns": false,
"modules": false
}
]
]
}
工具函数引入,引入 @babel/runtime-corejs3
Vite 解决方案
@vitejs/plugin-legacy 底部仍然使用 @babel/preset-env 以及 core-js 基础库
配置 vite
// vite.config.ts
import legacy from '@vitejs/plugin-legacy';
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [
legacy({
// 设置目标浏览器,browserslist 配置语法
targets: ['ie >= 11'],
})
]
})
构建产物
!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/assets/favicon.17e50649.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
<!-- 1. Modern 模式产物 -->
<script type="module" crossorigin src="/assets/index.c1383506.js"></script>
<link rel="modulepreload" href="/assets/vendor.0f99bfcc.js">
<link rel="stylesheet" href="/assets/index.91183920.css">
</head>
<body>
<div id="root"></div>
<!-- 2. Legacy 模式产物 -->
<script nomodule>兼容 iOS nomodule 特性的 polyfill,省略具体代码</script>
<script nomodule id="vite-legacy-polyfill" src="/assets/polyfills-legacy.36fe2f9e.js"></script>
<script nomodule id="vite-legacy-entry" data-src="/assets/index-legacy.c3d3f501.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
</body>
</html>
插件原理
- configResolved 钩子调整output属性,打包出一份Legacy 模式的产物
- renderChunk 对 Legacy 模式产物进行语法转译和 Polyfill 收集
- generateChunk 对先前收集到的 Polyfill 统一打包
- transformIndexHtml 将打包产物插入到 HTML 的结构中