babel 7 发布两天了,试着对当前项目更新了下,仅此记录分享css
主要改动参考 官方博客node
官方升级指南react
let a = {b: 11} a?.b // a ? a.b : undefined a &&= b // a = a && (a=b) 或 a = a && b 复制代码
let c = a ?? b // 只有 a 是 undefined 或 null 时,c 等于 b let res = foo(boo(aaa('nice'))) === let res = 'nice' |> aaa |> boo |> foo 复制代码
npx babel-upgrade --write
# 或是安裝 babel-upgrade 在 global 並執行 npm install babel-upgrade -g babel-upgrade --write 复制代码
能够看到 package.json 中移除了旧版本的依赖,自动新增了新版名称,.babelrc 文件的配置也会自动修改 可是不会删除已有的插件,如原来的 transform-decorators-legacywebpack
// 移除就版本依赖后从新安装依赖git
rm -rf node_modules
yarn install
复制代码
由于 babel 7 新增的 @babel 命名空间,因此原来的 babel-polyfill 须要修更名称github
// index.js 头部导入修改
import '@babel/polyfill' // webpack config 入口修改 entry: ['@babel/polyfill', './src/index.js'], 复制代码
yarn add @babel/plugin-proposal-decorators -D
复制代码
注意web
@babel/plugin-proposal-decorators
必须在 @babel/plugin-proposal-class-properties
以前配置"dev": { "plugins": [ "@babel/plugin-proposal-object-rest-spread", "@babel/transform-async-to-generator", [ "@babel/plugin-proposal-decorators", { "legacy": true } ], ["@babel/plugin-proposal-class-properties", { "loose": true }], "@babel/plugin-proposal-optional-chaining", "react-hot-loader/babel", [ "react-css-modules", { "webpackHotModuleReloading": true, "generateScopedName": "[path][name]__[local]--[hash:base64:5]", "filetypes": { ".less": { "syntax": "postcss-less" } } } ], [ "import", { "libraryName": "antd" } ] ] }, 复制代码
"@babel/plugin-syntax-dynamic-import", "@babel/plugin-syntax-import-meta", "@babel/plugin-proposal-class-properties", "@babel/plugin-proposal-json-strings", [ "@babel/plugin-proposal-decorators", { "legacy": true } ], "@babel/plugin-proposal-function-sent", "@babel/plugin-proposal-export-namespace-from", "@babel/plugin-proposal-numeric-separator", "@babel/plugin-proposal-throw-expressions", "@babel/plugin-proposal-export-default-from", "@babel/plugin-proposal-logical-assignment-operators", "@babel/plugin-proposal-optional-chaining", [ "@babel/plugin-proposal-pipeline-operator", { "proposal": "minimal" } ], "@babel/plugin-proposal-nullish-coalescing-operator", "@babel/plugin-proposal-do-expressions", "@babel/plugin-proposal-function-bind"
好比 es2015 是一套规范,包含大概十几二十个转译插件。若是每次要开发者一个个添加并安装,配置文件很长不说,npm install
的时间也会很长,更不谈咱们可能还要同时使用其余规范呢。typescript
为了解决这个问题,babel 还提供了一组插件的集合。由于经常使用,因此没必要重复定义 & 安装。(单点和套餐的差异,套餐省下了巨多的时间和配置的精力)express
preset 分为如下几种:npm
例如 syntax-dynamic-import
就是 stage-2 的内容,transform-object-rest-spread
就是 stage-3 的内容。
此外,低一级的 stage 会包含全部高级 stage 的内容,例如 stage-1 会包含 stage-2, stage-3 的全部内容。
stage-4 在下一年更新会直接放到 env 中,因此没有单独的 stage-4 可供使用。
arrow-functions
,es2017 包含 syntax-trailing-function-commas
。但由于 env 的出现,使得 es2016 和 es2017 都已经废弃。因此咱们常常能够看到 es2015 被单独列出来,但极少看到其余两个。很简单的几条原则:
preset 的逆向顺序主要是为了保证向后兼容,由于大多数用户的编写顺序是 ['es2015', 'stage-0']
。这样必须先执行 stage-0
才能确保 babel 不报错。所以咱们编排 preset 的时候,也要注意顺序,其实只要按照规范的时间顺序列出便可。
简略状况下,插件和 preset 只要列出字符串格式的名字便可。但若是某个 preset 或者插件须要一些配置项(或者说参数),就须要把本身先变成数组。第一个元素依然是字符串,表示本身的名字;第二个元素是一个对象,即配置对象。
最须要配置的当属 env,以下:
"presets": [ // 带了配置项,本身变成数组 [ // 第一个元素依然是名字 "env", // 第二个元素是对象,列出配置项 { "module": false } ], // 不带配置项,直接列出名字 "stage-2" ]
由于 env 最为经常使用也最重要,因此咱们有必要重点关注。
env 的核心目的是经过配置得知目标环境的特色,而后只作必要的转换。例如目标浏览器支持 es2015,那么 es2015 这个 preset 实际上是不须要的,因而代码就能够小一点(通常转化后的代码老是更长),构建时间也能够缩短一些。
若是不写任何配置项,env 等价于 latest,也等价于 es2015 + es2016 + es2017 三个相加(不包含 stage-x 中的插件)。env 包含的插件列表维护在这里
下面列出几种比较经常使用的配置方法:
{ "presets": [ ["env", { "targets": { "browsers": ["last 2 versions", "safari >= 7"] } }] ] }
如上配置将考虑全部浏览器的最新2个版本(safari大于等于7.0的版本)的特性,将必要的代码进行转换。而这些版本已有的功能就不进行转化了。这里的语法能够参考 browserslist
{ "presets": [ ["env", { "targets": { "node": "6.10" } }] ] }
如上配置将目标设置为 nodejs,而且支持 6.10 及以上的版本。也可使用 node: 'current'
来支持最新稳定版本。例如箭头函数在 nodejs 6 及以上将不被转化,但若是是 nodejs 0.12 就会被转化了。
另一个有用的配置项是 modules
。它的取值能够是 amd
, umd
, systemjs
, commonjs
和 false
。这可让 babel 以特定的模块化格式来输出代码。若是选择 false
就不进行模块化处理。
这是 babel 7 的一个重大变化,把全部 babel-*
重命名为 @babel/*
,例如:
babel-cli
变成了 @babel/cli
。babel-preset-env
变成了 @babel/preset-env
。进一步,还能够省略 preset
而简写为 @babel/env
。babel-plugin-transform-arrow-functions
变成了 @babel/plugin-transform-arrow-functions
。和 preset
同样,plugin
也能够省略,因而简写为 @babel/transform-arrow-functions
。这个变化不仅仅应用于 package.json 的依赖中,包括 .babelrc 的配置 (plugins
, presets
) 也要这么写,为了保持一致。例如
{
"presets": [
- "env" + "@babel/preset-env" ] }
顺带提一句,上面提过的 babel 解析语法的内核 babylon
如今重命名为 @babel/parser
,看起来是被收编了。
上文提过的 stage-x 被删除了,它包含的插件虽然保留,但也被重命名了。babel 团队但愿更明显地区分已经位于规范中的插件 (如 es2015 的 babel-plugin-transform-arrow-functions
) 和仅仅位于草案中的插件 (如 stage-0 的 @babel/plugin-proposal-function-bind
)。方式就是在名字中增长 proposal
,全部包含在 stage-x 的转译插件都使用了这个前缀,语法插件不在其列。
最后,若是插件名称中包含了规范名称 (-es2015-
, -es3-
之类的),一概删除。例如 babel-plugin-transform-es2015-classes
变成了 @babel/plugin-transform-classes
。(这个插件我本身没有单独用过,惭愧)
babel 7.0 开始再也不支持 nodejs 0.10, 0.12, 4, 5 这四个版本,至关于要求 nodejs >= 6 (当前 nodejs LTS 是 8,要求也不算太过度吧)。
这里的再也不支持,指的是在这些低版本 node 环境中不能使用 babel 转译代码,但 babel 转译后的代码依然能在这些环境上运行,这点不要混淆。
在 babel 6 时,ignore
选项若是包含 *.foo.js
,实际上的含义 (转化为 glob) 是 ./**/*.foo.js
,也就是当前目录 包括子目录 的全部 foo.js
结尾的文件。这可能和开发者常规的认识有悖。
因而在 babel 7,相同的表达式 *.foo.js
只做用于当前目录,不做用于子目录。若是依然想做用于子目录的,就要按照 glob 的完整规范书写为 ./**/*.foo.js
才能够。only
也是相同。
这个规则变化只做用于通配符,不做用于路径。因此 node_modules
依然包含全部它的子目录,而不仅仅只有一层。(不然全世界开发者都要爆炸)
和 babel 6 不一样,若是要使用 @babel/node
,就必须单独安装,并添加到依赖中。
在提到删除 stage-x 时候提过这个工具,它的目的是帮助用户自动化地从 babel 6 升级到 7。
这款升级工具的功能包括:(这里并不列出完整列表,只列出比较重要和经常使用的内容)
babel-*
替换为 @babel/*
@babel/*
依赖的版本更新为最新版 (例如 ^7.0.0
)scripts
中有使用 babel-node
,自动添加 @babel/node
为开发依赖babel
配置项,检查其中的 plugins
和 presets
,把短名 (env
) 替换为完整的名字 (@babel/preset-env
)plugins
和 presets
,把短名 (env
) 替换为完整的名字 (@babel/preset-env
)preset-stage-x
,若有替换为对应的插件并添加到 plugins
使用方式以下:
# 不安装到本地而是直接运行命令,npm 的新功能 npx babel-upgrade --write # 或者常规方式 npm i babel-upgrade -g babel-upgrade --write
babel-upgrade
工具自己也还在开发中,还列出了许多 TODO 没有完成,所以以后的功能可能会更加丰富,例如上面提过的 ignore
的通配符转化等等。