Skip to main content

接近 7.0 版本发布

· 26 min read

查看 7.0 计划 了解 7.0 预发布版的最新更新。如果这篇文章中有不清楚的地方,告诉我吧!

项目更新​

🌐 Project Updates

  • 我们创建了一个新的视频页面!我们建立这个页面是为了那些想更多了解 Babel 工作原理的人,同时也帮助其他人回馈社区。这个页面包含了团队成员和社区中人士的 Babel 以及相关概念的会议演讲视频(如果你也做过类似的演讲,可以提交 PR)。

视频

  • 我们也创建了一个新的团队页面!我们未来会在这个页面上更新更多关于大家工作内容以及他们参与原因的信息。对于这样一个大型项目,有很多方式可以参与和提供帮助。

团队

  • Babel在2017年9月28日满3岁啦!
  • Daniel 将 babel/babylon 和 babel/babel-preset-env 移动到了主 Babel monorepo,babel/babel,这包括所有的 git 历史、标签和问题。
  • 我们收到了来自 Facebook 开源项目的 $1k/月捐赠!
    • 这是自从开始以来我们收到的最高月捐赠(下一个最高的是每月100美元)。
    • 同时,我们会用我们的资金来安排线下见面,并派人参加 TC39 会议。这些会议每两个月在全球各地举行。
    • 如果公司想特别赞助某件事,我们可以创建单独的问题来跟踪。以前这很困难,因为我们得自掏腰包,或者得找一个同一周可以演讲的会议来帮忙覆盖费用。

你可以怎么帮忙!​

🌐 How you can help!

如果你的公司想通过支持 JavaScript 开发及其未来的基础部分来回馈社会,可以考虑向我们的 Open Collective 捐款。你也可以贡献开发者时间来帮助维护这个项目。

🌐 If your company would like to give back by supporting a fundamental part of JavaScript development and it's future, consider donating to our Open Collective. You can also donate developer time to help maintain the project.

#1 帮助维护项目(开发者上班时间)​

🌐 #1 Help Maintain the Project (developer time at work)

在这个项目上,我们能得到的最好的是那些愿意投入帮助的人,因为这个项目需要承担巨大的工作量和责任。再说一次,我从来没觉得自己准备好去做维护者,但不知怎么的还是碰上了这件事,不过我只是一个人,我们的团队也只有几个人。

🌐 The best thing we can get on this project are people committed to helping out with the project given the massive amount of work/responsibility it takes. Again, I never felt ready to be a maintainer but somehow stumbled upon it but I'm just one person, and our team is just a few people.

#2 基金发展​

🌐 #2 Fund development

我们确实希望能够为团队里的成员提供资金,让他们全职工作。尤其是 Logan,他前段时间辞了工作,目前正在用我们的现有资金兼职做 Babel!

🌐 We are definitely looking to be able to fund people on the team to work full-time. Logan in particular left his job a while ago and is using our current funds to work on Babel part time at the moment!

#3 以其他方式做出贡献 😊​

🌐 #3 Contribute in other ways 😊

例如,Angus 为我们创作了一首官方歌曲!

🌐 For example, Angus made us an official song!

升级中​

🌐 Upgrading

我们还将开发一个升级工具,帮助你重写你的 package.json/.babelrc 文件等。理想情况下,这意味着它可以修改任何必要的版本号、更改包名以及配置调整。

🌐 We will also be working on a upgrade tool that will help rewrite your package.json/.babelrc files and more. Ideally this means it would modify any necessary version number changes, package renames, and config changes.

在尝试更新时,请联系寻求帮助或发布问题!这是一个参与并帮助生态系统更新的好机会!

🌐 Please reach out to help and to post issues when trying to update! This is a great opportunity to get involved and to help the ecosystem update!

上一篇帖子的总结​

🌐 Summary of the previous post

  • 不再支持 Node 0.10/0.12/5。
  • 更新的 TC39 提案
    • 数字分隔符:1_000
    • 可选链操作符:a?.b
    • import.meta(可解析的)
    • 可选捕获绑定:try { a } catch {}
    • 大整数(可解析):2n
    • 将导出扩展拆分为 export-default-from 和 export-ns-form
  • .babelrc.js 支持(使用 JavaScript 而不是 JSON 的配置)
  • 新增了一个 TypeScript 预设,并且将 React/Flow 预设分开了
  • 移除了内部 babel-runtime 依赖,以减小体积

最新更新的 TC39 提案​

🌐 Newly Updated TC39 Proposals

  • 管道操作符:a |> b
  • 抛出表达式:() => throw 'hi'
  • 空值合并运算符:a ?? b

已弃用的年度预设(例如 babel-preset-es20xx)​

🌐 Deprecated Yearly Presets (e.g. babel-preset-es20xx)

简而言之:用 babel-preset-env。

🌐 TL;DR: use babel-preset-env.

比起你自己决定用哪个 Babel 预设更棒的是什么?就是让它自动为你完成!

🌐 What's better than you having to decide which Babel preset to use? Having it done for you, automatically!

即使维护这些数据列表的工作量非常巨大——这也是为什么我们需要帮助——它解决了多个问题。它确保用户跟上规范的最新信息。它意味着配置/包的混淆更少。它意味着升级路径更简单。它也意味着关于什么是什么的问题更少。

🌐 Even though the amount of work that goes into maintaining the lists of data is humongous — again, why we need help — it solves multiple issues. It makes sure users are up to date with the spec. It means less configuration/package confusion. It means an easier upgrade path. And it means less issues about what is what.

babel-preset-env 实际上是一个相当老的预设,它可以替代你需要的其他所有语法预设(es2015、es2016、es2017、es20xx、latest 等等...)。

npm 预设

它会编译最新的年度 JavaScript 版本(任何在 Stage 4 的特性),替换掉所有旧的预设。但它也可以根据你指定的目标环境进行编译:无论是开发模式,比如最新版本的浏览器,还是多种构建,比如一个 IE 版本,再加上一个适用于最新浏览器的版本。

🌐 It compiles the latest yearly release of JavaScript (whatever is in Stage 4) which replaces all the old presets. But it also has the ability to compile according to target environments you specify: whether that is for development mode, like the latest version of a browser, or for multiple builds, like a version for IE, and then another version for evergreen browsers.

不移除 Stage 预设(babel-preset-stage-x)​

🌐 Not removing the Stage presets (babel-preset-stage-x)

编辑:我们把它们移除了,解释见这里

🌐 EDIT: We removed them, explained here

我们总是可以保持它的更新,也许我们只需要找出一个比这些预设更好的系统。

🌐 We can always keep it up to date, and maybe we just need to determine a better system than what these presets are currently.

现在,舞台预设实际上只是我们在 TC39 会议后手动更新的一系列插件。为了让这件事可控,我们需要允许这些“不稳定”包进行大版本升级。部分原因是社区反正会重新创建这些包,所以我们不如直接用官方包来做,然后还能提供更好的信息提示等。

🌐 Right now, stage presets are literally just a list of plugins that we manually update after TC39 meetings. To make this manageable, we need to allow major version bumps for these "unstable" packages. Part of the reason for this is because the community will re-create these packages anyway, so we might as well do it from an official package and then have the ability to provide better messaging, etc.

重命名:Scoped 包(@babel/x)​

🌐 Renames: Scoped Packages (@babel/x)

这是我差不多一年前做的一个投票:

🌐 Here is a poll I did almost a year ago:

那时候,很少有项目使用作用域包,所以大多数人甚至都不知道它们的存在。你当时可能还得为 npm 组织账户付费,而现在是免费的(而且也支持非作用域包)。搜索作用域包的问题已经解决,下载次数也能正常显示。唯一剩下的问题是一些第三方注册表仍然不支持作用域包,但我觉得现在已经到了一种几乎不值得再等的地步。

🌐 Back then, not a lot of projects used scoped packages, so most people didn't even know they existed. You may also have had to pay for a npm org account back then, while now it's free (and supports non scoped packages, too). The issues with searching for scoped packages are solved and download counts work. The only thing left is that some 3rd party registries still don't support scoped packages, and I think we are at a point where it seems pretty unreasonable to wait on that.

如果你想知道我们为什么更喜欢使用带作用域的包:

🌐 If you want reasons why we prefer scoped packages:

  • 起名字很难:我们不用去检查别人是否决定用我们的命名规则为他们自己的插件命名
  • 类似地,包占用
    • 有时候人们会创建 babel-preset-20xx 或其他什么包,因为觉得好玩,然后我们就得提交问题/发邮件去要回来。
    • 别人有一个合法的包,但它恰好和我们想用的名字一样。  - 有人看到一个新的提案正在合并(比如可选链、管道操作符),然后决定分叉并用同样的名字发布一个版本。然后,当我们发布时,它告诉我们这个包已经被发布了 🤔。然后,我得找到他们的邮箱,给他们和 npm 支持都发邮件,才能把包拿回来再重新发布。
  • 什么是“官方”包,什么是同名的用户/社区包?我们可能会收到有人使用命名错误或非官方包的问题报告,因为他们以为它是 Babel 的一部分。一个例子是,有人报告 babel-env 重写了他们的 .babelrc 文件,他们花了一段时间才意识到那不是 babel-preset-env。

所以,很明显我们应该使用作用域包,而且,如果说有什么的话,我们本应该更早就这样做🙂!

🌐 So, it seems obvious we should use scoped packages, and, if anything, we should have done it much earlier 🙂!

作用域名称更改的示例:

🌐 Examples of the scoped name change:

  • babel-cli -> @babel/cli
  • babel-core -> @babel/core
  • babel-preset-env -> @babel/preset-env

重命名: -proposal-​

🌐 Renames: -proposal-

现在任何提案都会用 -proposal- 来命名,以表示它们还不是 JavaScript 的官方内容。

🌐 Any proposals will be named with -proposal- now to signify that they aren't officially in JavaScript yet.

所以@babel/plugin-transform-class-properties变成了@babel/plugin-proposal-class-properties,一旦进入第四阶段,我们会再把它改回名字。

🌐 So @babel/plugin-transform-class-properties becomes @babel/plugin-proposal-class-properties, and we would name it back once it gets into Stage 4.

重命名:从插件名称中去掉年份​

🌐 Renames: Drop the year from the plugin name

以前的插件名字里有年份,但现在似乎没必要了。

🌐 Previous plugins had the year in the name, but it doesn't seem to be necessary now.

所以 @babel/plugin-transform-es2015-classes 变成了 @babel/plugin-transform-classes。

🌐 So @babel/plugin-transform-es2015-classes becomes @babel/plugin-transform-classes.

由于年份只适用于 es3/es2015,我们没有对 es2016 或 es2017 做任何更改。不过,我们正在弃用那些预设,转而使用 preset-env,而且为了模板字符串的修改,我们只是为了简单起见把它加到了模板字符串转换中。

🌐 Since years were only the case for es3/es2015, we didn't change anything from es2016 or es2017. However, we are deprecating those presets in favor of preset-env, and, for the template literal revision, we just added it to the template literal transform for simplicity.

同级依赖 + 集成​

🌐 Peer Dependencies + Integrations

我们正在为所有插件(@babel/plugin-class-properties)、预设(@babel/preset-env)以及顶层包(@babel/cli、babel-loader)引入对 @babel/core 的同级依赖。

🌐 We are introducing a peer dependencies on @babel/core for all the plugins (@babel/plugin-class-properties), presets (@babel/preset-env), and top level packages (@babel/cli, babel-loader).

peerDependencies 是你代码中预期会用到的依赖,而不是仅作为实现细节使用的依赖。 — Stijn de Witt via StackOverflow.

babel-loader 在 babel-core 上已经有一个 peerDependency,所以这只是把它改成 @babel/core。这样做只是为了防止有人在错误的 Babel 版本上试图安装这些包。

对于那些已经在 babel-core 上有 peerDependency 的工具,而且还没准备好进行重大更新(因为修改 peer 依赖会造成破坏性变更)的情况,我们发布了一个新版本的 babel-core,用来在新版本 babel-core@7.0.0-bridge.0 上桥接这些变化。想了解更多信息,可以查看 这个问题。

🌐 For tools that already have a peerDependency on babel-core and aren't ready for a major bump (since changing the peer dependency is a breaking change), we have published a new version of babel-core to bridge the changes over with the new version babel-core@7.0.0-bridge.0. For more information check out this issue.

类似地,像 gulp-babel、rollup-plugin-babel 之类的包,以前都依赖 babel-core。现在它们只会在 @babel/core 上有一个 peerDependency。这样这些包在 @babel/core API 没有变化时就不用升级主版本了。

🌐 Similarly, packages like gulp-babel, rollup-plugin-babel, etc, all used to have babel-core as a dependency. Now these will just have a peerDependency on @babel/core. This lets these packages not have to bump major versions when the @babel/core API hasn't changed.

#5224 实验包的独立发布​

🌐 #5224 Independent Publishing of Experimental Packages

我在《Babel的状态》(http://babel.nodejs.cn/blog/2016/12/07/the-state-of-babel) 的 Versioning 部分提到过这个。Github 问题

你可能记得,在 Babel 6 之后,Babel 成为了一个由 npm 包组成的集合,并且有自己的一套自定义预设和插件生态系统。

🌐 You might remember that after Babel 6, Babel became a set of npm packages with its own ecosystem of custom presets and plugins.

不过从那以后,我们一直使用“固定/同步”的版本系统(所以没有任何包的版本是 v7.0 或以上)。当我们发布新版本比如 v6.23.0 时,只有源码有更新的包会发布新的版本,其余的包则保持不变。实际上这大多是可行的,因为我们的包中都使用了 ^。

🌐 However since then, we have always used a "fixed/synchronized" versioning system (so that no package is on v7.0 or above). When we do a new release such as v6.23.0 only packages that have updated code in the source are published with the new version while the rest of the packages are left as is. This mostly works in practice because we use ^ in our packages.

不幸的是,这种系统要求一旦某个包需要发布主要版本,所有包都必须发布主要版本。这要么意味着我们做很多小的破坏性更改(不必要),要么我们把很多破坏性更改集中到一次发布中。相反,我们希望区分实验性包(Stage 0 等)和其他所有包(es2015)。

🌐 Unfortunately this kind of system requires that a major version be released for all packages once a single package needs it. This either means we make a lot small breaking changes (unnecessary), or we batch lots of breaking changes into a single release. Instead, we want to differentiate between the experimental packages (Stage 0, etc.) and everything else (es2015).

这意味着我们打算在规范变化时,对任何实验性提案插件进行大版本升级,而不是等到更新整个 Babel。所以任何低于 Stage 4 的内容都可能以大版本升级的形式出现破坏性变更,Stage 预设本身也是如此(如果我们不完全弃用的话)。

🌐 This means we intend to make major version bumps to any experimental proposal plugins when the spec changes rather than waiting to update all of Babel. So anything that is < Stage 4 would be open to breaking changes in the form of major version bumps and same with the Stage presets themselves (if we don't drop them entirely).

这与我们决定将 TC39 提案插件改为使用 -proposal- 名称的决定一致。如果规范发生变化,我们将对插件及其所属的预设进行大版本更新(而不是只做一个可能会导致问题的补丁版本)。然后,我们需要弃用旧版本,并建立一个自动更新的机制,让大家都能及时了解规范将会变成什么样(这样他们就不会像现在装饰器那样卡住了)。

🌐 This goes with our decision to change TC39 proposal plugins to use the -proposal- name. If the spec changes, we will do a major version bump to the plugin and the preset it belongs to (as opposed to just making a patch version which may break for people). Then, we will need to deprecate the old versions and setup an infrastructure to automatically update people so that everyone is up to date on what the spec will become (and so they don't get stuck on something, like we have with decorators).

.babelrc 中的 env 选项不会被废弃!​

🌐 The env option in .babelrc is not being deprecated!

不像在上一篇文章里,我们只是把合并行为修复得更一致了。

🌐 Unlike in the last post, we just fixed the merging behavior to be more consistent.

env 中的配置优先级高于根配置项,而且现在插件和预设会根据它们的身份合并,而不仅仅是两者并用的奇怪方式,所以你可以这样做

🌐 The configuration in env is given higher priority than root config items, and instead of just being a weird approach of using both, plugins and presets now merge based on their identity, so you can do

JavaScript
{
presets: [
['env', { modules: false}],
],
env: {
test: {
presets: [
'env'
],
}
},
}

用 BABEL_ENV=test,它会用测试环境的配置替换根环境配置,而测试环境没有任何选项。

🌐 with BABEL_ENV=test, which would replace the root env config, with the one from test, which has no options.

支持 class A extends Array(最老的注意事项)​

🌐 Support class A extends Array (oldest caveat)

Babel 会自动封装任何原生内置对象,比如 Array、Error、HTMLElement 等,这样在编译类的时候直接使用就可以了。

🌐 Babel will automatically wrap any native built-ins like Array, Error, HTMLElement etc so that doing this just works when compiling classes.

速度​

🌐 Speed

preset-env: "useBuiltins": "usage"​

babel-preset-env 提出了将语法编译到不同目标的想法,并通过 useBuiltIns 选项,还可以只为目标不支持的功能添加 polyfill。

所以有了这个选项,就像这样:

🌐 So with this option, something like:

JavaScript
import "babel-polyfill";

可以变成

🌐 Can turn into

JavaScript
import "core-js/modules/es7.string.pad-start";
import "core-js/modules/es7.string.pad-end";
// ...

如果目标环境恰好支持除 padStart 或 padEnd 之外的 polyfill。

🌐 if the target environment happens to support polyfills other than padStart or padEnd.

不过为了让情况更好,我们应该只引入在代码库中“实际使用”的 polyfill。如果代码根本没用到 padStart,干嘛还要引入它呢?

🌐 However in order to make that even better, we should only import polyfills that are "used" in the codebase itself. Why even import padStart if it's not even used in the code?

"useBuiltins": "usage" 是我们首次尝试实现这个想法。它会在每个文件的顶部进行导入,但只有在代码中发现使用时才会添加导入。采用这种方法意味着我们可以为应用导入最少量的 polyfill(而且只有在目标环境不支持时才导入)。

所以如果你在代码中使用 Promise,它会在文件顶部导入它(如果你的目标环境不支持的话)。打包工具会去重相同的文件,所以这种做法不会导致多个 polyfill 被导入。

🌐 So if you use Promise in your code, it will import it at the top of the file (if your target doesn't support it). Bundlers will dedupe the file if it's the same so this approach won't cause multiple polyfills to be imported.

JavaScript
import "core-js/modules/es6.promise";
var a = new Promise();
JavaScript
import "core-js/modules/es7.array.includes";
[].includes
a.includes

通过类型推断,我们可以知道像 .includes 这样的实例方法是用于数组还是不是,即使有误报也没关系,直到逻辑更完善,因为这比以前导入整个 polyfill 要好。

🌐 With type inference we can know if an instance method like .includes is for an array or not, and having a false positive is ok until that logic is better since it's still better than importing the whole polyfill like before.

杂项更新​

🌐 Misc Updates

  • babel-template 使用起来更快/更简单
  • regenerator 是在 MIT 许可证 下发布的——它是用来编译生成器/异步的依赖
  • 通过 #6952 向 modules-commonjs 插件添加“懒惰”选项
  • 你现在可以在 .babelrc 中使用 envName: "something",或者通过命令行传递 babel --envName=something,而不必使用 process.env.BABEL_ENV 或 process.env.NODE_ENV
  • ["transform-for-of", { "assumeArray": true }] 让所有 for-of 循环输出为普通数组
  • 在 preset-env 的宽松模式下排除 transform-typeof-symbol #6831
  • 已合并 PR,以提供更好的语法错误提示

发布前的待办事项​

🌐 Todos Before Release

  • 处理 .babelrc 查找(希望在第一个 RC 版本发布前完成)
  • “overrides” 支持:基于全局模式的不同配置
  • babel-core 中的缓存和失效逻辑。
  • 要么自己实现,要么有计划独立处理版本控制和 polyfill,而不是依赖 helpers,这样我们就不会明确绑定到 core-js 2 或 3,因为有人可能依赖其中一个,而且大多数时候也不想两个都加载。
  • 要么是一个可用的装饰器实现,要么是功能性的旧版实现,并且有明确的路径在 7.x 生命周期内实现当前规范的行为。

谢谢​

🌐 Thanks

向我们的志愿者团队致敬:Logan 一直在努力解决我们很多核心配置问题以及其他问题,Brian 接手了很多 preset-env 的维护工作,还有我之前做的各种事情 😛,以及 Daniel 无论是维护 babel-loader 还是帮忙迁移 babylon/babel-preset-env 仓库,只要我们需要帮助他总会挺身而出。同样也要感谢 Nicolo、Sven、Artem 和 Jessica 在过去一年中站出来提供帮助。

🌐 Shoutout to our team of volunteers: Logan who has been really pushing hard to fix a lot of our core issues regarding configs and more and the one doing all of that hard work, Brian who has been taking over maintenance of a lot of preset-env work and just whatever I was doing before 😛, and Daniel who has always been stepping in when we need the help whether it be maintaining babel-loader or helping move the babylon/babel-preset-env repo's over. And same with Nicolo, Sven, Artem, and Jessica for stepping up in the last year to help out.

我真的很期待这次发布(我也累了;都快一年了 😝),但也不想只是因为想快而匆忙行动!这次发布过程中经历了很多起伏,但我确实学到了很多,我相信团队的其他人也一样。

🌐 I'm really looking forward to a release (I'm tired too; it's almost been a year 😝), but also don't want to rush anything just because! Been a lot of ups and downs throughout this release but I've certainly learned a lot and I'm sure the rest of the team has as well.

如果今年我学到了什么,那我真的应该听从这个建议,而不是仅仅写写而已。

🌐 And if I've learned anything at all this year, I should really heed this advice rather than just write about it.

也感谢 Mariko 对我实际完成这篇文章的小小推动(花了两个月才完成)