转换的东西分成两类: 语法 和 api
语法
我习惯称之为指令, esbuild 语法对照表
| target | Example |
|---|---|
| es2020 | a?.b |
| esnext | import "x" with {} |
在编译时做转换, 借助AST, 比如 @babel/preset-env
api
也称 polyfill
类(Promise), 原型上的方法Array.prototype.at, 宿主环境的api(<dialog>)
在运行时调用前提供, 常见的有 core-js polyfill.io , 阿里的 polyfill
如何确定大多数用户的浏览器能低能支持哪个esm的语法和api?
- 浏览器 ua (不是很准,比如 esbuild 作者手动维护顶层await) browserslist
- 特性检测(感觉用的很少) Modernizr , 阮一峰 es-checker
因为语法转换发生在编译时, 所以项目打包前你就得知道用户浏览器版本
除此之外, 有些构建工具可以在构建时帮你注入polyfill, 比如 @babel/preset-env
对于‘ useBuiltIns: ‘ using’’,您不应该自己添加‘ core-js’导入,它们将被自动添加。 请注意,默认情况下 Vite 只处理语法转译,且 不包含任何 polyfill core-js文档链接
因为 vite 完全使用 esbuild (dev 和 build)来转换代码, 而 esbuild 不注入任何polyfill, 见 esbuild.github.io/api/#target
请注意,这仅与语法功能有关,与 API 无关。它不会自动为这些环境未使用的新 API 添加polyfill。您必须明确导入所需 API 的 polyfill(例如通过导入
core-js)。自动 polyfill 注入超出了 esbuild 的范围。
此外, esbuild targat值是 esNext, vite 的 build.target 是 特殊值 modules,即 ['es2020', 'edge88', 'firefox78', 'chrome87', 'safari14'], 我感觉vite的默认值完全够用了
在vite中如何添加 polyfill ?
@vitejs/plugin-legacy只会注入polyfill到 <script nomodule>中, 在现在浏览器里,是不会执行这个脚本的, 所以无效
使用 swc 或者 babel-preset,默认情况下,vite在build时是不会使用swc的, swc.rs/docs/config…
在开发时会将 Babel 替换为 SWC。在构建时,若使用了插件则会使用 SWC+esbuild,若没有使用插件则仅会用到 esbuild。
开启swc的方法, 正在探索
react({ plugins: [["@swc/plugin-styled-components", {}]] });
在暂不知道如何开启swc的情况下
- (自动)使用babel来转换,接机使用babel/preset-env
- (手动)通过ts报错来告知缺失的polyfill,来手动
import 'core-js/actual/'
并不是设置了 target 就会降级所有语法
比如 esbuild 中,就不会处理顶层await,以及太新的提案语法也不会处理, 如果项目中使用ts, 那么ts的相关编译器在转换到js并且处理类型的时候会做一些降级, 剩下的会交给babel等
# "Top-level await is not available in the configured target environment"
[vite:esbuild-transpile] Transform failed with 1 error:
assets/index-!~{001}~.js:511:13: ERROR: Top-level await is not available in the configured target environment ("chrome87", "edge88", "es2020", "firefox78", "safari14" + 2 overrides)
tsconfig 如何配置?
推荐配置
// tsconfig.json
{
compilerOptions:{
"target": "ES2020", // 因为 vite dev 时的esbuild target是2020
"lib": [..., "ES2020",], // 同步添加es2020的类型文件
"module": "ESNext", // 规定 import 语法如何转换, 比如顶层await,以及cjs还是esm,具体版本不是很重要
}
}
配置es2022不支持.at语法,在vscode里会出现报错,报错来自于 tsconfig中的lib字段
https://polyfill.alicdn.com/polyfill.js?features=Array.prototype.at
我们会使用core-js做转换,.at是可以使用的, 如何让错误消失呢?
设置 "lib": ["ES2020",...,"ES2022.Array"],
另外依赖于插件usage的按需使用难免有问题, 所以可以采集这个错误,设置到在线 polyfill的query里, 或者直接在文件顶部import core-js/xxx, 也是不错的方法
如果使用eslint, 那么eslint应该也会报错,或者不报错, 都可以使用eslint-plugin-compat 明确告知eslint你的target以及polyfills