伴鱼技术团队

Technology changes the world

伴鱼开放平台 上线了! 源于实践的解决方案,助力企业成就未来!

Babel6升级到Babel7中遇到的问题及处理方式

现在我们直接使用官方推荐的 Babel升级工具 来升级现有项目试试

1. 使用Babel升级工具

1
2
3
4
5
6
# 不安装,直接使用npx来执行
npx babel-upgrade --write

# 或是安裝 babel-upgrade 在 global 並執行
yarn global add babel-upgrade
babel-upgrade --write

至此我们可以看到 package.json 中移除了旧版本的依赖,自动新增了新版名称,.babelrc 文件的配置也会自动修改,但是不会删除已有的插件,比如原来的 transform-decorators-legacy

1
2
3
# 移除旧版本依赖后,重新安装依赖
rm -rf node_modules
yarn install

执行这个命令之后就可以看到报错 Cannot find module babel-plugin-syntax-jsx

2. 处理 Cannot find module babel-plugin-syntax-jsx 异常

avatar

1
2
3
4
5
6
7
编译失败 ❌

./src/utils/polyfill.js
Thread Loader (Worker 0)
[BABEL] ./src/utils/polyfill.js: Cannot find module 'babel-plugin-syntax-jsx' (While processing: "./node_modules/babel-plugin-transform-vue-jsx/index.js")
at Generator.next (<anonymous>)
at Generator.next (<anonymous>)

原因是在babel-plugin-transform-vue-jsx中使用的包是babel-plugin-syntax-jsx,而babel-upgrade将这个包升级成了@babel/plugin-syntax-jsx
avatar

推荐架构

解决方案

1
2
yarn remove @babel/plugin-syntax-jsx
yarn add -D babel-plugin-syntax-jsx

处理完成,重新启动项目,又报错Can’t resolve ‘babel-polyfill’

3. 处理 Can’t resolve ‘babel-polyfill’

avatar

1
2
3
4
编译失败 ❌

./src/utils/polyfill.js
Module not found: Can't resolve 'babel-polyfill' in './src/utils'

原因是babel-polyfill已经升级成了@babel/polyfill,需要将项目中的引入依赖换成@babel/polyfill

yarn start 启动项目之后,编辑器没有报任何异常,可以正常访问,这个时候打开教室端H5页面,发现页面蓝屏了

avatar

4. 处理蓝屏问题

打开控制台,没有任何报错,打开终端,也没有编译报错,看了一下Network,没有网络请求。通过console.log缩小范围,发现代码走到了Indicator.open()方法就不往下走了,通过debugger发现,应该是mintui内部报错了,通过try catch捕获了错误,没有错误堆栈,但是代码不往下执行。

avatar

avatar

原因是H5项目中使用了babel-plugin-component插件对MintUi按需加载,但是又在下面引入了@babel/plugin-transform-modules-commonjs插件。

avatar

按需加载依赖的是ES Module中import的静态导入,而@babel/plugin-transform-modules-commonjs会将import 转换成require,导致按需加载失败。

先将@babel/plugin-transform-modules-commonjs插件注释,然后重新编译。

avatar

打开页面,页面正常显示,没有任何问题。

avatar

本来以为这样事情就解决了,但是重新编译编辑器端之后发现,编译报错。

avatar

原因是ES Module没有经过转换,而在ES Module的规范在export default是必须写的,如果不写需要使用 import * as name from ‘name’,这种方式导入。改项目中的代码明显不现实,所以只能把@babel/plugin-transform-modules-commonjs插件加入进来。

但是启动H5的项目之后又会不能显示。最后的解决方案是:将之前的babel-plugin-transform-es2015-modules-commonjs插件也添加进去,这个插件是可以和babel-plugin-component一起使用的,而@babel/plugin-transform-modules-commonjs会和babel-plugin-component冲突。

重新编译之后,项目可以正常启动,但是使用babel-upgrade升级的babel版本,默认都是7.0版本,不是最新的版本,所以还需要将这些包手动升级到最新版本

5. 手动升级依赖到最新版本

avatar

1
2
3
4
5
yarn remove babel-core

yarn add -D @babel/cli @babel/core @babel/plugin-proposal-class-properties @babel/plugin-proposal-json-strings @babel/plugin-syntax-dynamic-import @babel/plugin-syntax-import-meta @babel/plugin-transform-for-of @babel/plugin-transform-modules-commonjs @babel/plugin-transform-runtime @babel/preset-env @babel/register

yarn add @babel/polyfill

6. 添加内部依赖

由于我们的项目使用了一个内部的依赖包@ipalfish/cls-base-components,添加此依赖包,启动之后发生报错:

avatar

打开这个npm包内部,这个包没有Babel编译,需要单独配置Babel编译,但是在 .babelrc 文件配置的编译规则,在node_modules里面不生效

avatar

avatar

在Babel7中配置文件的规则与Babel6有所不同,主要是:

  • 【全局配置】全局配置 babel.config.js 里的配置默认对整个项目生效,包括node_modules。除非通过 exclude 配置进行剔除。

  • 【全局配置】全局配置中如果没有配置 babelrcRoots 字段,那么babel 默认情况下不会加载任何子package中的相对配置(如.babelrc文件)。除非在全局配置中通过 babelrcRoots 字段进行配置。

  • 【全局配置】babel 全局配置文件所在的位置就决定了你的项目根目录在哪里,默认就是执行babel的当前工作目录,例如上面的例子,你在根目录执行babel,babel才能找到babel.config.js,从而确定该monorepo的根目录,进而将配置对整个项目生效

  • 【相对配置】相对配置可被加载的前提是在 babel.config.js 中配置了 babelrcRoots. 如 babelrcRoots: [‘.’, ‘./frontend’],这表示要对当前根目录和frontend这个子package开启 .babelrc 的加载。(注意: 项目根目录除了可以拥有一个 babel.config.js,同时也可以拥有一个 .babelrc 相对配置)

  • 【相对配置】相对配置加载的边界是当前package的最顶层。假设上文案例中要编译 frontend/src/index.js 那么,该文件编译时可以加载 frontend 下的 .babelrc 配置,但无法向上检索总项目根目录下的 .babelrc

总结

总的来说就是:

  • babel.config.js 是对整个项目(父子package) 都生效的配置,但要注意babel的执行工作目录。

  • .babelrc 是对待编译文件生效的配置,子package若想加载.babelrc是需要babel配置babelrcRoots才可以(父package自身的babelrc是默认可用的)— 这在babel6不是这样的。

  • 任何package中的babelrc寻找策略是: 只会向上寻找到本包的 package.json 那一级。

  • node_modules下面的模块一般都是编译好的,请剔除掉对他们的编译。如有需要,可以把个例加到 babelrcRoots 中。

最好的解决方案就是,将.babelrc文件换成babel.config.js文件。

欢迎关注我的其它发布渠道