2022年,一个react应用可能需要哪些配置?
这里要搞清楚三个概念,三方面根据babel的配置和 browserlist的配置结合一起生成最终的打包代码
- ECMAScript规范里的JS语法和api
-
- Stage 提案阶段的api
- 已完成 阶段的api
- 活跃的提案
- 不活跃的提案
- 浏览器实现的JS语法和api(主要实现ECMAScript已完成阶段的语法)
- babel转译的语法和api(提案阶段和以完成的都有插件可以降级为es2022-es3)
-
- 通过browserlist知道哪个版本支持特定语法,从而实现语法降级
@babel/preset-env
解决各种浏览器兼容性问题,自动的确定babel插件及polyfills,转译ES2015及此版本以上的语言
包含了ES2022/ES2021/ES2020/ES2019/ES2018/ES2017/ES2016/ES5/ES3的一些语法转译插件
具体看文档 @babel/preset-env
@babel/preset-react
可以编译react
@babel/preset-typescript
可以编译typescript
@babel/plugin-proposal-decorators
支持class装饰器和class内函数装饰器
@annotation
class MyClass {}
function annotation(target) {
target.annotated = true;
}
class C {
@enumerable(false)
method() {}
}
function enumerable(value) {
return function(target, key, descriptor) {
descriptor.enumerable = value;
return descriptor;
};
}
@babel/plugin-proposal-do-expressions
可以使用do表达式替换if else
// 不用do
const getColoredComponent = color => {
if (color === "blue") {
return <BlueComponent />;
}
if (color === "red") {
return <RedComponent />;
}
if (color === "green") {
return <GreenComponent />;
}
};
const Component = props => (
<div className="myComponent">{getColoredComponent()}</div>
);
// 使用do,不需要再写在函数内
const Component = props => (
<div className="myComponent">
{do {
if (color === "blue") {
<BlueComponent />;
} else if (color === "red") {
<RedComponent />;
} else if (color === "green") {
<GreenComponent />;
}
}}
</div>
);
@babel/plugin-proposal-export-default-from
提供 export v from "mod"; 语法
@babel/plugin-proposal-export-namespace-from
提供 export * as ns from 'mod' 语法
@babel/plugin-proposal-function-bind
提供bind的操作符,@babel/preset-env包含了这个插件, in ES2020
obj::func;
// is equivalent to:
func.bind(obj)
::obj.func;
// is equivalent to:
obj.func.bind(obj);
obj::func(val);
// is equivalent to:
func
.call(obj, val)
::obj.func(val);
// is equivalent to:
obj.func.call(obj, val);
@babel/plugin-proposal-private-methods
class中 私有属性操作符,@babel/preset-env包含了这个插件
class Counter extends HTMLElement {
#xValue = 0;
get #x() {
return this.#xValue;
}
set #x(value) {
this.#xValue = value;
window.requestAnimationFrame(this.#render.bind(this));
}
#clicked() {
this.#x++;
}
}
@babel/plugin-proposal-private-property-in-object
object中的私有属性标识符,@babel/preset-env包含了这个插件
class Foo {
#bar = "bar";
test(obj) {
return #bar in obj;
}
}
@babel/plugin-proposal-partial-application
不完整的函数表达式,可以通过?暂存,然后继续操作
function add(x, y) { return x + y; }
const addOne = add(1, ?); // apply from the left
addOne(2); // 3
const addTen = add(?, 10); // apply from the right
addTen(2); // 12
f(x, ?) // partial application from left
f(?, x) // partial application from right
f(?, x, ?) // partial application for any arg
o.f(x, ?) // partial application from left
o.f(?, x) // partial application from right
o.f(?, x, ?) // partial application for any arg
super.f(?) // partial application allowed for call on |SuperProperty|
@babel/plugin-proposal-record-and-tuple
元组的数字式替代写法
let a = #[1, 2, 3];
// ⬇ ⬇ ⬇ ⬇ ⬇ ⬇ ⬇ ⬇ ⬇ ⬇
let a = Tuple(1, 2, 3);
@babel/plugin-transform-runtime
babel-polyfill解决了Babel不转换新API的问题,但是直接在代码中插入帮助函数,会导致污染了全局环境,并且不同的代码文件中包含重复的代码,导致编译后的代码体积变大。
Babel为了解决这个问题,提供了单独的包babel-runtime用以提供编译模块的工具函数, 启用插件babel-plugin-transform-runtime后,Babel就会使用babel-runtime下的工具函数
使用transform-runtime代替babel-polyfill目的是按需引入你需要babel转换的特性,而不是将整个polyfill引入,并且不会像polyfill一样重写原本的API。缺点是某些不支持的API,例如Object.assign Array.includes, 需要引入单独插件