在前端项目中,常常会在 TypeScript、Vite、Webpack、Babel 等工具中看到类似如下配置项:
json
"target": "es2020"
这些配置中的 "es5"
、"es6"
、"es2020"
、"esnext"
是 ECMAScript 的不同版本标识,决定了构建产物所使用的语法标准。本篇文章将系统梳理这些标准的区别,并深入讲解:
- 各版本的差异
tsconfig.json
中的target
与构建工具中target
的关系- 如何配置 polyfill 以支持旧浏览器
各版本 ECMAScript 的语法差异
构建目标 | 等价标准 | 发布年份 | 主要新特性 |
---|---|---|---|
es5 |
ECMAScript 5 | 2009 | 严格模式、getter/setter、Array 方法如 forEach 、map |
es6 或 es2015 |
ECMAScript 6 | 2015 | let/const 、箭头函数、模块导入导出、Promise、类、解构 |
es2016 |
ECMAScript 7 | 2016 | Array.prototype.includes 、指数运算符 ** |
es2017 |
ECMAScript 8 | 2017 | async/await 、Object.entries/values |
es2018 |
ECMAScript 9 | 2018 | 异步迭代器、命名捕获组、Promise.finally |
es2019 |
ECMAScript 10 | 2019 | flatMap 、可选 catch 参数、Object.fromEntries |
es2020 |
ECMAScript 11 | 2020 | 可选链 ?. 、空值合并 ?? 、BigInt 、Promise.allSettled |
es2021 |
ECMAScript 12 | 2021 | 逻辑赋值运算符、字符串 replaceAll 、WeakRef |
es2022 |
ECMAScript 13 | 2022 | 类字段、顶级 await、.at() 方法 |
esnext |
最新提案 | -- | 表示"构建时支持的最新语法",可能包含实验特性 |
TypeScript tsconfig.json
中的 target
json
{
"compilerOptions": {
"target": "es2020"
}
}
target
控制 TypeScript 输出的 JavaScript 使用的 语法级别:
- ✅ 是否保留
async/await
- ✅ 是否保留箭头函数
- ✅ 是否使用模块语法
import/export
- ❌ 不影响内置 API,如
Promise.allSettled
是否存在(需另加 polyfill)
构建工具中的 target
(Vite、esbuild、Webpack)
Vite / esbuild 示例
ts
export default defineConfig({
build: {
target: 'es2020'
}
})
- 控制构建产物保留的语法,如
?.
、??
、import.meta
- 不会自动插入 polyfill(如
Promise.allSettled
、BigInt
)
Webpack + Babel 示例
js
presets: [
['@babel/preset-env', {
targets: '> 0.25%, not dead',
useBuiltIns: 'usage',
corejs: 3
}]
]
- Babel 会根据目标环境:
- 降级语法
- 自动插入 polyfill(结合
core-js
)
TypeScript target
与构建工具 target
的关系
项目 | TypeScript target |
构建工具 target |
---|---|---|
控制语法降级 | ✅ 是 | ✅ 是 |
控制 API 支持 | ❌ 否 | ❌ 否(需 polyfill) |
控制代码压缩语法 | ❌ 否 | ✅ 是(如 Terser) |
控制 tree-shaking | ❌ 否 | ✅ 是(现代语法更利于优化) |
推荐配置建议
TypeScript 的
target
不要高于构建工具的target
。
否则可能出现:
- 构建工具无法解析新语法,导致构建失败或运行时报错。
esbuild
不会再对降级后的语法进行优化,导致文件体积变大。
场景 | tsconfig.json 中 target | 构建工具中 target |
---|---|---|
兼容 IE11 | es5 |
es5 |
支持现代浏览器 | es2020 |
es2020 |
Electron/Node.js 环境 | es2022 |
es2022 |
尽可能现代(实验) | esnext |
esnext |
Vite 和 esbuild 中如何引入 polyfill?
构建工具默认不插入 polyfill
Vite 使用 esbuild,只负责语法转换,不会自动处理以下情况:
js
Promise.allSettled([...]);
Object.fromEntries(...);
BigInt(123);
方法一:手动引入 core-js
polyfill(推荐)
ts
// main.ts
import 'core-js/features/promise/all-settled';
import 'core-js/features/object/from-entries';
import 'core-js/features/array/flat-map';
适用于只 polyfill 项目实际用到的部分,构建体积更小、控制更精细。
方法二:通过 Babel 插入 polyfill(兼容性优先)
json
// babel.config.json
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": 3
}
]
]
}
并在 vite.config.ts
中接入 Babel 插件:
ts
import legacy from '@vitejs/plugin-legacy';
export default defineConfig({
plugins: [
legacy({
targets: ['defaults', 'not IE 11']
})
]
});
方法三:使用 polyfill.io CDN(公网项目)
html
<script src="https://polyfill.io/v3/polyfill.min.js?features=default,Promise.allSettled"></script>
特点:
- 根据浏览器 User-Agent 自动加载缺失的 polyfill
- 不适用于内网、Electron、App 内嵌 WebView 等场景
polyfill 方案对比总结
方法 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
手动引入 core-js |
控制精细、体积小 | 需手动维护 | 大多数项目 |
Babel 插入 polyfill | 自动处理、完整兼容 | 构建慢、体积大 | 兼容性要求高的公共项目 |
polyfill.io CDN | 动态按需加载 | 依赖网络、不适合私有部署 | 对公网用户兼容老设备 |
总结
target
配置决定构建产物所使用的 JS 语法版本。tsconfig.json
的target
控制 TypeScript 输出的语法;构建工具(Vite/Webpack)的target
控制最终产物保留哪些语法。- 若需要兼容低版本浏览器,还需手动或通过 Babel 插入 polyfill。
- 建议保持 TypeScript 的
target
≤ 构建工具的target
。 - 在现代浏览器为主的项目中,推荐设置为
es2020
。