7.9.0发布。更小的预设-env输出,支持Typescript 3.8和一个新的JSX转换
在准备Babel 8.0.0版本(未来几个月)的同时,我们刚刚完成了一个新的小版本,其中包括与@babel/preset-env 、TypeScript 3.8、Flow和JSX相关的更新!
几个月前,Jason Miller开始在 @babel/preset-modules:一个实验,当使用module/nomodule 模式时,可以大大减少包的大小。我们很高兴地宣布,它的功能现在已经被合并到@babel/preset-env!这意味着它的优化可以应用于所有的preset-env 目标值,而无需单独的预设。
注意:在Babel 8中,这些优化将被默认启用。在Babel 7.9中,可以通过在{ bugfixes: true } 中加入选项preset-env ,手动启用这些优化。
这个版本也完全支持TypeScript 3.8,它引入了显式的纯类型导入和导出(即export type { foo } ),也支持Flow 0.120,它为类字段引入了declare 修改器(即class C { declare foo: string } )。
我们还与React团队合作,提供了一个新的JsX转换,这将使React和类似React的库有可能进一步优化JsX元素的创建,增加了jsx 函数与React.createElement 。
最后,@babel/parser 现在支持一个额外的ECMAScript提议。Record & Tuple。请注意,这只是对解析器的支持,而转换仍在进行中。
特别感谢React团队(Facebook)的Luna Ruan贡献了新的JJSX转换,以及Rick Button(Bloomberg)为Record & Tuple提案实现了解析器的支持。
如果你或你的公司想支持Babel和JavaScript的发展,但不确定如何支持,你可以在我们的开放集体中为我们捐款,更好的是,你可以直接和我们一起实现ECMAScript的新提案。作为一个志愿者驱动的项目,我们依靠社区的支持来资助我们支持广大的JavaScript用户。如果你想讨论更多,请联系team@babeljs.io!
@babel/preset-env的bugfixes 选项
@babel/preset-env 中新的bugfixes 选项是直接使用@babel/preset-modules 的继承者。
如果你想了解更多关于这一变化所帮助解决的问题的背景,我们建议你听听(或读读)最近发表的与Jason的播客节目集。#2 现代JavaScript和preset-env的未来和#3 编译你的依赖。
到目前为止,@babel/preset-env (以及一般的Babel插件)将ECMAScript的语法特性归为密切相关的小特性集合。这些组可能很大,包括很多边缘情况。例如,"函数参数 "组和插件包括非结构化参数、默认参数和其余参数。
从这些分组信息中,Babel根据你对@babel/preset-env'stargets 选项指定的浏览器支持目标来启用或禁用每个组。
问题是这样的:如果该列表中任何浏览器的任何版本都包含一个由现代语法引发的bug,唯一的解决方案(我们当时考虑的)是启用修复该bug的相应转化组。
随着时间的推移,更多的bug最终会被发现并报告给我们的问题,这导致preset-env ,为了这些边缘案例而输出更多的代码。在最坏的情况下,这意味着输出的结果与直接将所有东西编译成ES5的结果一样,而创建preset-env 就是为了帮助防止这种情况。
当启用bugfixes: true 选项时,@babel/preset-env 采取了一种不同的方法:它将破损的语法转为最接近的非破损的现代语法。
例如:所有与函数参数有关的新语法特性都被归入同一个Babel插件(@babel/plugin-transform-function-parameters )。当针对edge 16 ,它有一个与解析箭头函数内具有默认值的速记去结构化参数有关的错误。
// this breaks in Edge 16:
const foo = ({ a = 1 }) => {};
// .. but this doesn't:
function foo({ a = 1, b }, ...args) {}
// ... and neither does this:
const foo = ({ a: a = 1 }) => {};
这意味着,如果我们给@babel/preset-env 这个输入并针对Edge 16。
const foo = ({ a = 1 }, b = 2, ...args) => [a, b, args];
它将其转化为类似ES5的参数。
const foo = function foo(_ref, b) {
let { a = 1 } = _ref;
if (b === void 0) { b = 2; }
for (
var _len = arguments.length,
args = new Array(_len > 2 ? _len - 2 : 0),
_key = 2; _key < _len; _key++
) {
args[_key - 2] = arguments[_key];
}
return [a, b, args];
};
然而,如果我们启用bugfixes 选项,它就只对破碎的语法进行转换。
const foo = ({ a: a = 1 }, b = 2, ...args) => [a, b, args];
你可以在我们的REPL中看到这个例子的作用
今天你可以通过在你的配置中加入@babel/preset-env 来启用这个选项。
{
"presets": [
["@babel/preset-env", {
"targets": { "esmodules": true }, // Use the targets that you was already using
"bugfixes": true
}]
]
}
ℹ️目前,在使用
esmodules: true目标时,bugfixes选项给出了最好的结果,它允许你以支持本地 ES 模块的浏览器为目标,并使用module/nomodule模式。我们希望在接下来的几个版本中继续改进它,并在Babel 8中默认启用它。
今后,我们希望与社区(包括浏览器)合作,让这种方法在我们不断过渡到JavaScript的发展中顺利运作。在理想的情况下,Babel将能够实施并帮助影响未来的新建议,因为它们被建议和完善,并为现有的标准平滑地解决这些边缘情况,以便为所有的JavaScript用户提供基于目标的最小编译输出。
TypeScript 3.8:仅限类型的导入和导出
你现在可以明确地将导入和导出标记为仅有类型,类似于你在Flow中已经可以做到的。
import type { SomeThing } from "./some-module.js";
export type { SomeThing };
通过这样做,Babel可以安全地决定哪些导入或导出是用于类型,哪些是用于值。
由于Babel不分析类型,而是在每个文件的基础上工作(类似于TypeScript的--isolatedModules 选项),所以直到现在@babel/plugin-transform-typescript ,把不用作值的导入当作只用于类型。
从Babel 7.9开始,你可以使用新的type 修改器而不需要改变任何配置。
我们建议配置@babel/preset-typescript 或@babel/plugin-transform-typescript ,使其只在有明确的type 关键字时才将导入视为仅有类型,类似于TypeScript的--importsNotUsedAsValues preserve 选项。
{
"presets": [
["@babel/preset-typescript", {
"onlyRemoveTypeImports": true
}]
]
}
ℹ️这些功能是由Babel团队和Siddhant N Trivedi共同贡献的。如果你有兴趣看到这一切是如何完成的,请在YouTube上查看我们是如何做到的!。
流declare 场
类字段提案规定未初始化的类字段被初始化为undefined :这与Babel在Flow中的做法不同,因为它直接忽略了它们。
出于这个原因,Flow团队为类字段增加了对declare modfier的支持。
class Foo {
x: ?string; // A "real" field
declare y: number; // A type-only field
}
在上面的例子中,只有y 应该被Babel完全删除。
为了避免破坏性的变化,我们引入了对在类字段中声明的支持,在一个标志后面。"allowDeclareFields",@babel/plugin-transform-flow 和@babel/preset-flow 都支持。这将成为Babel 8的默认行为,因此建议您迁移您的配置以使用它。
{
"presets": [
["@babel/preset-flow", {
"allowDeclareFields": true
}]
]
}
一个新的JSX转换
React团队早在去年2月就创建了一个RFC,讨论简化元素的创建。
在未来的稳定版本中,React将支持一组用于实例化JJSX元素的新函数,以替代传统的通用React.createElement 函数。这将使它们在未来得到更好的优化。
ℹ️虽然它还没有在稳定版本中发布,但你可以在实验性的React发布频道中试用。
npm install react@experimental react-dom@experimental
我们与团队合作,完成了一个新的转换,支持将JSX编译为这些新的函数。它还会在需要时自动导入"react" (或其他支持新API的库),所以你不必再手动包含它。
作为一个例子,这个输入。
function Foo() {
return <div />;
}
将变成:
import { jsx as _jsx } from "react/jsx-runtime";
function Foo() {
return _jsx("div", ...);
}
注意:
react/jsx-runtime和react/jsx-dev-runtime里面的函数并不是为了在@babel/plugin-transform-react-jsx和@babel/plugin-transform-react-jsx-development插件本身之外使用。
综上所述(更多信息请查看RFC),转换将:
- 始终将儿童作为道具传递。
- 将
key与其他道具分开传递。 - 在DEV中。
- 传递一个标志,确定它是否是静态的。
- 将
__source和__self与其他道具分开传递。
使用方法。你可以通过将{ "runtime": "automatic" } (相对于"classic" )传递给@babel/preset-react (或@babel/plugin-transform-react-jsx )来启用这个新的转换。
{
"presets": [
["@babel/preset-react", {
"runtime": "automatic"
}]
]
}
而从Babel 8开始,"automatic" 将成为默认的运行时间。
您也可以通过使用新的@babel/plugin-transform-react-jsx-development 变换或将{ "development": true, "runtime": "automatic" } 传递给@babel/preset-react ,为这个新的变换启用开发模式。
你可以在文档中阅读关于这个新转换的模式。