// enum.js 混用了 import 和 modules.exports
import { i18next } from 'gm-i18n'
let enum = {
a, b
}
modules.exports = enum
// 引用模块
import { a } from 'enum'
// 提示
// export 'a' was not found
// console 输出
// enum.js:347 Uncaught TypeError: Cannot assign to read only property 'exports' of object '#<Object>'
babel7主要变化
废弃 babel-preset-stage-x
babel团队认为,非标准的特性是不稳定的(通过stage来推进),按照stage来划分需要花很多精力来维护。
对应
stage < 3
的plugin
也修改了命名,从@babel/plugin-transform-*
改为@babel/plugin-proposal-*
proposal
表示这只是一个提案中的非标准特性,随时可能变化,使用前要考虑清楚。废弃 babel-preset-es20xx
使用 babel-preset-env 不需要自己决定去用哪些
preset
,而是由env
自动的根据要支持的环境启用相应的preset
使用 Scoped Packages
更加清晰,易于区分 official package 和 community package
如: babel-core -> @babel/core babel-preset-env -> @babel/preset-env
迁移步骤
这样就很快完成了 babel7 的升级,但是还不够。
preset-stage-0
,升级后实际上很多proposal-plugin
是没用到的(扫下每个插件的文档)babel7
的 config-file 也有一些变化,简单来说,它提供了两种配置babel.config.js
和.babelrc
。babel.config.js
作为整个项目通用的配置,可作用于node_modules
。而.babelrc
只作为所在package
的配置,不会影响到其他package
。 这意味着我们项目根目录下配置的.babelrc
对node_modules
是不起作用的,而我们很多库都依赖babel
的转译。解决:项目根目录新建个 babel.config.js ,同时删掉没用到的 proposal-plugin (package.json中也对应删除),结果如下。
babel-transform-runtime
babel 在转换语法的时候会生成一些helper(如 class 的 classCallCheck 等),@babel/plugin-transform-runtime 这个插件会将所有生成 helper 的地方,统一从
@babel/runtime
引入,减少了冗余代码。在
babel.config.js
中添加@babel/plugin-transform-runtime
,然后 install因为我们的编译包括 node_modules,要忽略
@babel/runtime
本身的处理。node_modules下的包可能使用了多种模块格式,而
babel-plugin-transform-runtime
默认是添加import
语句,在wabpack
中同一模块下,import
语句不能和module.exports
同时使用 (babel文档 webpack相关issue) (PS: 原来可以是因为 babel 默认会将所有的模块转化成 cjs ,再传给 webpack。但是这样无法做 tree-shaking,下文会提到)所以添加配置。
polyfill
polyfill 部分变化不大,继续走 script 引入,不经过 webpack 打包。
tree-shaking
webpack
在production mode
会自动进行tree-shaking
优化,消除未使用到的模块代码,原理是通过 es6 module 的静态分析。需要配置
babel
不转换我们的module
,给 env 加个配置,让webpack
来处理模块。我们的代码中(业务代码、库)可能会混用
import
和modules.exports
,这在webapck
中是不允许的。issue如下代码会报错
解决:统一只使用es6模块。也可以配置babel把模块先转换成cjs格式,但是这样webpack就不能做tree-shaking,不推荐
一般而言,
tree-shaking
对业务代码没多大作用,主要是针对 node_modules 下的库。webpack4 新增了sideEffects
选项,进一步优化了tree-shaking
的结果。可以看下Webpack 中的 sideEffects 到底该怎么用? 简单来说,如果一个模块的export没有被任何文件用到 -> 去掉这个模块代码不会产生任何影响(反例是polyfill)-> 那就可以设置 sideEffects:false对于我们自己发布的库,统一使用 es6 module,并且在
package.json
中加上sideEffects: false
(也可以设置为具体的文件),这样跟着业务代码一起打包,就能通过tree-shaking
去除没用到的模块代码(例如我们的图标库gm-svg
,针对不同的项目去掉没用到的图标)。最终...
最后的
babel.config.js
文件内容如下package.json
新增的依赖如下