babel默认只转换js语法,而不转换新的API,比如Iterator, Generator, Set, Maps, Proxy, Reflect,Symbol,Promise
如果想让这些方法运行,必须使用polyfill来转换
@babel/polyfill
是一个javascript库,可以为旧版浏览器提供缺失的 ECMAScript 新特性和 API。它通过在全局对象上添加缺失的方法和属性来模拟 ECMAScript 的新特性,以便在旧版浏览器中运行现代的 JavaScript 代码
@babel/polyfill 会将所有特性添加到全局对象上,因此它的体积很大
// 打包出的bundle会非常大
import '@babel/polyfill';
let sum = (a, b) => a + b;
let promise = Promise.resolve();
console.log([1, 2, 3].find(item => item === 2));
useBuiltIns
useBuiltIns有三个选项:usage,entry,false
如果useBuiltIns为false,@babel/preset-env 不会自动在代码中注入 polyfill,这意味着如果你使用了一些新的 ECMAScript 特性或 API,它们在旧版浏览器中可能不被支持,你需要手动引入对应的 polyfill
如果useBuiltIns为entry,@babel/preset-env 会根据目标浏览器的版本和你的代码中使用的 ECMAScript 特性,自动引入对应的 polyfill,并将它们添加到入口文件中。根据浏览器兼容,引入浏览器不兼容的polyfill,需要在入口文件中手动添加import '@babel/polyfill',并且需要在入口文件指定core-js版本
import 'core-js/stable';
import 'regenerator-runtime/runtime';
let sum = (a, b) => a + b;
let promise = Promise.resolve();
console.log([1, 2, 3].find(item => item === 2));
{
test: /\.js?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [["@babel/preset-env", { useBuiltIns: 'entry', corejs: 3 }]]
}
}
}
如果useBuiltIns为usage,会根据配置的浏览器兼容,以及你代码中用到的 API 来进行 polyfill,实现了按需添加。不需要手动引入@babel/polyfill
{
test: /\.js?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [["@babel/preset-env", { useBuiltIns: 'usage', corejs: 3 }]]
}
}
}
babel-runtime
- Babel为了解决全局空间污染的问题,提供了单独的包babel-runtime用以提供编译模块的工具函数
- 与
@babel/polyfill不同,babel-runtime并不会在全局对象上添加新的方法和属性,而是将这些方法和属性封装在一个独立的运行时库中,以便在编译后的代码中使用 - 简单说
babel-runtime更像是一种按需加载的实现,比如你哪里需要使用Promise,只要在这个文件头部import Promise from 'babel-runtime/core-js/promise'就行了
babel-plugin-transform-runtime
- 解决多个文件重复引用
- 新API方法全局污染
- 启动
babel-plugin-transform-runtime插件,babel就会使用babel-runtime下的工具函数 - 插件能够将这些工具函数代码转换成
require语句,指向为对babel-runtime的引用 - 就是可以在使用新的api时自动import
babel-runtime里面的polyfill- 如当使用await/async时,自动引入
babel-runtime/regenerator - 当我们使用 ES6 的静态事件或内置对象时,自动引入
babel-runtime/core-js - 移除内联
babel helpers并替换使用babel-runtime/helpers来替换
- 如当使用await/async时,自动引入
{
test: /\.js?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [["@babel/preset-env", { useBuiltIns: 'usage', corejs: 3 }]],
plugins: [
[
"@babel/plugin-transform-runtime",
{ corejs: 3, helpers: true, regenerator: true }
],
]
}
}
}
最佳实践
@babel/preset-env和plugin-transform-runtime二者都可以设置使用corejs来处理polyfill
项目开发
如果是项目开发,则可以全局污染。useBuiltLns使用usage,plugin-transform-runtime只使用其移除内联复用的辅助函数的特性,减小打包体积
{
test: /\.js?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [["@babel/preset-env", { useBuiltIns: 'usage', corejs: 3 }]],
plugins: [
[
"@babel/plugin-transform-runtime",
{ corejs: false}
],
]
}
}
}
类库开发
类库开发最好不使用污染全局变量的polyfill,polyfill由@babel/plugin-transform-runtime处理
{
test: /\.js?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [["@babel/preset-env"]],
plugins: [
[
"@babel/plugin-transform-runtime",
{ corejs: {"version": 3}}
],
]
}
}
}