8小时外的成长 记一次脑图组件在 vue-cli2 项目中不兼容问题的处理

陈恒捷 · 2022年04月10日 · 2045 次阅读

起因

收到同学反馈,之前创建的 vue 脑图开源项目,在结合 vue-cli2 创建的项目使用时,会出问题无法使用:

https://github.com/chenhengjie123/vue-testcase-minder-editor/issues/3

由于之前我都是基于 vue-cli3 创建的项目来使用的,没有这个问题,且之前其实也有同学反馈过,但因为没有足够详细的可重现步骤无法定位。这次这位同学写得很详细,本地也终于可以重现了,而且也确认了下,这位同学用的这个项目已经做了不少功能,不好直接升级到 vue-cli3 ,所以趁着这个周末研究一下。

问题逐步定位

  • 问题 1:Module build failed: BrowserslistError: Unknown browser query dead
error  in ./node_modules/vue-testcase-minder-editor/lib/VueTestcaseMinderEditor.css

Module build failed: BrowserslistError: Unknown browser query `dead`
    at /Users/zhongxin/VueProject/vue2/demo1/node_modules/browserslist/index.js:164:11
...

一开始的定位方式,就是搜一下自己项目哪里用到了 browserslist 且配置了 dead 有关的配置,结果发现在 package.json 里面确实有:

https://github.com/chenhengjie123/vue-testcase-minder-editor/blob/affde62733eec810bf03775be5daa61153313c78/package.json

一开始先用排除法确认下是不是这里的问题,于是去掉了 not dead 部分,测试了一下,确实问题消失了。但这个就是最佳方案吗?为何之前 cli3 创建的项目就没问题?于是上 google 搜了一下,发现也有不少项目存在,最终找到官方的一个 issue :

https://github.com/browserslist/browserslist/issues/266

里面内容很多,我大致看了下,作者有提到一个消息:

@Graphap fix the source of the problem, not result. You need to update Browserslist in all components. By removing not dead you did not fix the problem. In your system different companies still use different browsers. It will create problems in different places.

大致意思是去掉 not dead 只是消除了出问题这个现象,并不是解决根本问题。你需要升级所有组件里面的 Browserslist 版本才能解决。从这里面可以看出,前面我这个试验方案虽然能用,但不是官方推荐的最佳方案,而官方所说的升级项目全部组件里面的 Browserslist 这个操作成本很高。所以继续看。

然后看着看着,发现后面有人说 bootstrap 4.1.2 存在这个问题,然后 4.1.3 解决了。作为同样是外部依赖库,它的解决方案很可能是最适合我的,赶紧看看:

https://github.com/twbs/bootstrap/releases/tag/v4.1.3

Fixed: Moved the browserslist config from our package.json to a separate file to avoid unintended inherited browser settings across npm projects.

很清晰的说明,把 browserslist 配置从 package.json 挪到一个独立的文件中,避免跨 npm 项目意外继承浏览器设置。那具体是啥文件呢?继续找这个 tag 相比上一次 tag 的所有改动 commit :

https://github.com/twbs/bootstrap/compare/v4.1.2...v4.1.3

然后找到了具体的改动 commit :https://github.com/twbs/bootstrap/commit/6cf8700fd9fd096855d6510ceef9c1ff225f8e40 。实际就是把这段配置挪到了一个 独立的 .browserslistrc 文件中。

最后照样画葫芦,解决了这个问题:

https://github.com/chenhengjie123/vue-testcase-minder-editor/commit/dbae36c4a0fc2a90a9f1f99cfdef1d6263a83877

  • 问题 2:Module parse failed: Unexpected token (95:251947)
error  in ./node_modules/vue-testcase-minder-editor/lib/VueTestcaseMinderEditor.umd.min.js

Module parse failed: Unexpected token (95:251947)
You may need an appropriate loader to handle this file type.
(Source code omitted for this binary file)

英文提示翻译过来就是:

您可能需要适当的加载程序来处理此文件类型。
(此二进制文件省略了源代码)

有点奇怪,难道 js 打包格式有问题?但 cli3 没任何问题呀?先试试搞个 loader 单独处理脑图组件的 js 文件:

diff --git a/build/webpack.base.conf.js b/build/webpack.base.conf.js
index 412ad48..4ac7aa5 100644
--- a/build/webpack.base.conf.js
+++ b/build/webpack.base.conf.js
@@ -40,6 +40,12 @@ module.exports = {
         loader: 'babel-loader',
         include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
       },
+      {
+        // 针对 vue-testcase-minder-editor 做一些单独处理
+        test: /\.js$/,
+        loader: 'babel-loader',
+        include: [resolve('node_modules/vue-testcase-minder-editor')]
+      },
       {
         test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
         loader: 'url-loader',

好了,错误信息有点不一样了:

 WARNING  Compiled with 2 warnings                                                                                   5:02:36 PM

 warning  in ./src/main.js

10:8-31 "export 'default' (imported as 'VueTestcaseMinderEditor') was not found in '../lib/VueTestcaseMinderEditor.umd.js'

 warning  in ./src/main.js

15:21-44 "export 'default' (imported as 'VueTestcaseMinderEditor') was not found in '../lib/VueTestcaseMinderEditor.umd.js'

warning 信息先不管,看看实际运行是否正常:

空白页面,console 一样一堆报错,说明还是有问题,继续处理。

(此处省去好几周由于比较忙只是断断续续处理)

端午假期终于有空了,继续弄。这时候由于时间也过去比较久了,所以打开了一下思路:既然说的是编译错误,那不妨先看看具体是什么位置编译错误?

由于原来用的 min.js 是压缩过格式的,很难看清,所以手动调整下,把 ./node_modules/vue-testcase-minder-editor/lib/VueTestcaseMinderEditor.umd.min.js 的文件内容,手动改为脑图组件编译后 lib 里面的非 min 文件。调整后报错信息的行号变了:

 error  in ./node_modules/vue-testcase-minder-editor/lib/VueTestcaseMinderEditor.umd.min.js

Module parse failed: Unexpected token (132701:4)
You may need an appropriate loader to handle this file type.
(Source code omitted for this binary file)

 @ ./src/main.js 6:0-65
 @ multi (webpack)-dev-server/client?http://localhost:8080 webpack/hot/dev-server ./src/main.js

这时候去看 js 文件对应行的内容:

132693 /* harmony default export */ var insertBoxvue_type_script_lang_js_ = ({
132694   name: 'insertBox',
132695   data() {
132696     return {
132697 
132698     }
132699   },
132700   computed: {
132701     ...Object(vuex_esm["b" /* mapGetters */])('caseEditorStore', [
132702       'getMinder'
132703     ]),
132704     disabled1() {
132705       var minder = this.getMinder;
132706       var bool = false;
132707       if (minder.queryCommandState) {
132708         bool = minder.queryCommandState('AppendChildNode') === -1;
132709       }
132710       return bool
132711     },

132701 行有一个 ...Object 的写法,这里 ... 是 es6 引入的扩展运算符(Object rest spread),正常转译时应该会转义掉,但这里不知道为啥并没有被转译。

这里的原文其实是 vuex 的 ...mapGetter 写法。于是网上搜了下,找到了一篇比较老的文章:https://blog.csdn.net/weixin_34279061/article/details/94166155 ,基本意思是因为 babel 编译配置里没有针对扩展运算符进行转译导致。因此加了下对应的编译插件:babel-plugin-transform-object-rest-spread ,但试着给项目根目录的 babel.config.js 里加上对应的 plugins 配置,也没效果。而且经过查阅,脑图项目用的 vue-cli 里面 @vue/cli-plugin-babel/preset 这个预配置里是带有这个转译插件的 (官方文档:https://github.com/vuejs/vue-docs-zh-cn/blob/master/vue-babel-preset-app/README.md,里面提到 object rest spread 在 preset-env 里面已支持),用其他 vue-cli 项目试了下,扩展运算符是可以正常转译的。不知道是哪里配置有问题,导致扩展运算符这个转译没生效。。。

PS:关于转译的相关概念,可以参照:https://zh.javascript.info/polyfills#zhuan-yi-qi-transpilers ,此处不再详述。虽然现在前端有很多封装好的 cli 可以直接生成预配置好 webpack 、babel 等的工程,但了解下还是没坏处的。

然后灵机一闪,既然通过配置不行,那我干脆对生成后的 js 再单独用 babel-cli 对产物单独转义一下扩展运算符,是否可以?

第一步,安装 babel-cli ,以及 babel 转义扩展运算符的插件

npm install --save-dev --registry=https://registry.npm.taobao.org babel-cli babel-plugin-transform-object-rest-spread

第二步,调整 lib 打包命令,末尾增加 && mv lib/VueTestcaseMinderEditor.umd.min.js lib/VueTestcaseMinderEditor.umd.min.js.bak && babel --plugins transform-object-rest-spread lib/VueTestcaseMinderEditor.umd.min.js.bak > lib/VueTestcaseMinderEditor.umd.min.js

然后把打包出来的文件内容,复制粘贴到之前的 ./node_modules/vue-testcase-minder-editor/lib/VueTestcaseMinderEditor.umd.min.js ,再次启动 vue2 项目,没有报错了。

OK,问题解决,提交!

https://github.com/chenhengjie123/vue-testcase-minder-editor/commit/808b1ab0e5f42169afd29851adaa35007436fe4b

最后,还有一个奇怪的问题,为啥 cli3.x 的就没问题呢?最后,在 cli3.x 的文档里找到了一句说明

Vue CLI 使用了 Babel 7 中的新配置格式 babel.config.js。和 .babelrc 或 package.json 中的 babel 字段不同,这个配置文件不会使用基于文件位置的方案,而是会一致地运用到项目根目录以下的所有文件,包括 node_modules 内部的依赖。我们推荐在 Vue CLI 项目中始终使用 babel.config.js 取代其它格式。

估计是因为 node_modules 里的依赖都会被转译,转译过程中会把扩展运算符也转译掉,所以就没有问题。

总结

1、解决问题还是要顺着日志去看。直接把日志信息放到搜索引擎里找,是一个很有效的办法。
2、一个报错的解决方案可能会有很多种,不要急着解决,多看看其他项目是怎么解决的,特别是知名项目,避免解决一个问题引起其他副作用。
3、自己对 webpack babel 等的了解还不够深入,后续还需要进一步熟悉,避免后续在这些地方栽跟头。。。

这里还遗留了一个问题,就是为何扩展运算符转译插件不生效,后续作为继续深入 webpack babel 的机制的任务,继续定位处理。

如果有前端大佬看出了问题所在,也诚邀指点一下。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册