时间回到一周前,当时刚开发完公司A项目的一个新的版本,等待着测试完成就进行发布。此时的我也准备从连续多日的紧张开发状态中走出来,觉得能够稍稍放松一下。而那时的我还不知道,我即将面临一个强大的Bug选手,更不知道我要跟这个Bug来来回回进行屡次的搏斗。固然,咱们能看到这篇文章也就说明了我最终解决了这个Bug,并且这个过程也是至关的精彩的。什么?你不相信,那就让我来带你进入这个“跌宕起伏”的经历中吧。javascript
友情提示:接下来的文章也许有一点长,可是但愿你可以坚持读下去。我相信我在解决这个Bug的过程当中的一些思路会给你带来一些思考。固然也但愿你在这个过程当中可以像我同样学习到一些新的知识,为之后排查相似的Bug积累一些经验。好啦,话很少说,让咱们开始吧。前端
先来简单介绍一下A项目,这是一个基于Vue
框架的项目,项目使用的也是Vue CLI
这个开发工具。这个项目是须要集成在别的APP中的,也就是页面须要在APP中进浏览和操做。这个项目在我接手以前已经开发过一段时间了。因此项目中的一些依赖库和工具库版本相对比较低,这也给我后续的调试以及解决Bug的过程增长了一些困难。vue
当时开发完成以后,就交给咱们这边的测试和另外一个城市的相关同窗去验收此次开发的功能。在咱们这边一切都很正常,测试这边也没有反馈有什么问题。可是在另外一个城市的同窗小C的iPhone手机上却发现了白屏,打开页面以后什么内容也没有。java
发现了这个问题以后,我再次跟咱们这边的测试同窗确认了一下,看看咱们这边测试的iOS系统的iPhone手机有没有这个问题。通过测试的测试,发现咱们这边的几台iPhone手机都没有问题。而后就问了小C他使用的测试手机的系统版本是多少,当时感受应该跟iOS
的系统版本有关系。node
小C反馈说他的iPhone是6S Plus
,而后系统的版本是11.1.2
。我问了咱们这边测试使用的iPhone版本都是多少,测试反馈说系统的版本都是12
以上的。因此到这里,我肯定了这个白屏Bug的出现确定跟iPhone手机的系统有关系。webpack
虽然肯定了问题出现的环境,可是由于我身边没有系统是11
的iPhone手机,因此想让这个问题重现就变成了一个难题。询问了身边的同事,你们的系统版本也都广泛高于12
,因此借用别人的手机进行调试这个方法暂时也不可行。git
在平时的开发中,若是网页在iOS
系统的APP中有一些问题的话,咱们通常都会经过Safari
浏览器进行调试。可是由于此次出现问题的iPhone手机不在我这里,而且我这边也没有相同系统的手机。因此想经过真机进行调试就不太可能了。那怎么办呢?这个问题确定是要解决的,我也相信办法总比困难多。github
想要进行调试,最简单的办法就是让我有一个系统是11
的iPhone手机。因此我就搜索看看有没有什么办法能够给iPhone手机安装11
的系统。一搜索还真的有,过程也不算是很复杂。可是其中有一个步骤是须要到一些论坛或者第三方的助手网站下载跟本身手机型号相匹配的iOS
系统,这个步骤让我有点感受不安全。毕竟不是官方的,不可以保证安全性。并且也未必有版本是11
的系统。因此这个方案就暂时做罢。web
在我搜索的过程当中,我发现有网友说可使用Xcode
安装相应系统版本的iPhone模拟器
来进行调试。哎,你说我怎么没有想到这个办法呢?这确实是一个不错的办法。由于以前跟公司的同事学习过Swift
,也了解过Xcode
的一些操做。忽然感慨,真是技多不压身,你不知道你何时就会用上你学过的知识。因此有条件的话,仍是多学习一些知识。额,有点跑题了。npm
我打开公司的电脑,开始安装Xcode
,可是发现公司的电脑系统版本过低,安装Xcode
须要升级系统,因此没办法,先升级系统吧。由于升级的时间比较长,我想到本身家中的Mac电脑上是有安装过Xcode
,因此决定先回家。留下公司的电脑慢慢升级。
回到家,二话不说就开始准备调试,可是发现个人Xcode
上面的iPhone模拟器的系统版本也都是12
以上的,查了一下资料,Xcode
是能够安装不一样系统版本的模拟器的,因而我就安装了系统版本是11
的模拟器。这个过程须要咱们打开Xcode
的偏好设置,而后在Components
选项中,选择下载你要安装的对应系统版本的模拟器。
安装成功以后,运行iPhone 6S Plus
模拟器,使用模拟器的Safari
打开h5的页面地址,果真是白屏。
小样,终于把这个问题给复现了,这样就距离解决这个Bug不远了。我打开Mac
的Safari
浏览器,进入开发者模式,发现了以下所示的报错
我搜索了一下这个错误,发现是由于项目中使用了...
ES6扩展运算符,而后iOS 11
系统不支持这个这个运算符。这么容易就找到问题了,开心。想到这个问题仍是比较好解决的,能够经过使用Babel
的一些插件,很容易就能够将这个问题解决掉。而后我就开心的睡觉去了,心想这个问题也不是什么大问题,明天处理一下就行了。
次日到公司,我就在项目中的babel
的配置文件中添加了相应的插件
{ ... // 省略原来的配置内容 "plugins": ["@babel/plugin-proposal-object-rest-spread"] }
而后发布到测试环境中。告诉了小C同窗再次测试一下,我也在等着解决这个Bug的好消息。可是,出现的却不是好消息,小C给我回复说仍是不能够。什么,不可能呀,我就立刻用公司的电脑再次进行测试。当我用公司电脑的Safari
调试系统是iOS 11
的iPhone 6S PLus
模拟器的时候,却发现出现了下面这个状况:审核警告:“data-custom”太新,没法在此检查的页面上运行
我就又搜索了一下为何会出现这个问题,终于让我找到了答案,Safari
浏览器的Web Inspector
工程师也说这是一个Bug,不过他们已经修复了,在下个发布的版本中就能够正常使用新的Safari
浏览器去调试比较老的iOS
系统的模拟器了。知道如今这个版本的Safari
调试不了模拟的iOS 11
系统的页面。我有点沮丧,总不能我如今回家把个人电脑拿过来吧😂?当我想着该如何解决的时候,我发现了上面那个回答中提到了Safari Technology Preview
,Safari
技术预览。
我看这个名字感受有点但愿,而后就搜索了一下Safari Technology Preview
是什么。而后就发现它相对于Safari
就跟Chromium
相对于Chrome
是同样,都至关因而开发版本的浏览器。
这时,我以为可使用Safari Technology Preview
进行调试。因此就下载了Safari Technology Preview
,当我打开Safari Technology Preview
而后进入开发者模式后,发现确实能够调试iOS 11
系统的页面。而后我就看了一下为何仍是白屏的问题。发现出现的错误仍是上次的问题:
也就是说这个问题尚未解决掉,由于打包后的代码是没有SourceMap
的,因此要想看更详细的报错信息,须要在本地进行调试。本地的环境中是有SourceMap
的,能够定位到更详细的错误信息,我在本地运行了项目,而后我打开了控制台的错误详情,发现是使用的一个第三方的库出现了问题。
那么到这里为止,能够说明上面咱们使用的Babel
插件没有处理这个第三方的库,因此如今咱们的问题就变成了:如何解决第三方库中出现的...
扩展运算符没有被编译为ES5语法的问题。
这时我又仔细的看了一下Vue CLI
的相关文档,发现确实在浏览器的兼容性这个章节中,提到了一些处理的方法。原来咱们在项目中写的代码默认会帮咱们转换为ES5的语法的,可是若是项目中依赖的第三方库须要polyfill
的话,那须要咱们手动进行配置。一看到这里,我感受黎明就要来了。
我就开始尝试这三种方法。我发现第一种方法是比较简单的,也很好配置。因而我就尝试了第一种方法。在项目的vue.config.js
中添加以下的配置:
... // 省略的配置 transpileDependencies: [ 'module-name/library-name' // 出现问题的那个库 ], ... // 省略的配置
从新运行项目,当我将要为即将到来的成功欢呼鼓掌时,控制台忽然报告了以下的错误:Uncaught TypeError: Cannot assign to read only property 'exports' of object '#<Object>'
这个报错是在Chrome
浏览器的控制台出现的,由于项目在本地从新运行以后会首先打开Chrome
浏览器。真是的,一个问题尚未解决,又出来了一个新的问题。而后再次查询资料后发现,原来是由于这个第三方的库是一个CommonJS
类型的库,而Babel
默认处理的是ES6
的module
类型的库,因此这里就又出现了新的问题。
第一种方法遇到了阻碍,先暂停一下。我准备继续尝试下面两种方法。可是由于后面两种方法对原来的项目改动有点大,因此我直接经过Vue CLI
建立了一个新的项目,在package.json
中加入项目中使用的那个第三方包的依赖,使用公司的包管理工具安装了依赖。而后运行项目,打开控制台确实发现了相同的错误。可是打开详情之后,发现出错的路径跟我原来项目不一致。而后我此次抱着试一试的心态,继续使用了第一种方法尝试看看可不能够。而后复制了出错路径的包名称,在vue.config.js
文件中的对应位置添加了以下的配置代码:
... // 省略的配置 transpileDependencies: [ 'module-name-new/library-name-new' // 出现问题的那个库 ], ... // 省略的配置
而后从新运行项目,发现竟然能够了。啊,竟然能够了。为何我在原来的项目中这样却不能够呢?我看了一下原来项目的依赖以及如今新的测试项目的依赖,发现它们的vue
, babel
版本差了好多。我猜想多是由于这个缘由。可是如今确定不能够贸然升级这些依赖的版本,由于为了解决这个问题再次带来新的问题就得不偿失了。
还有一个问题就是为何一样的第三方库,在原来的项目中和如今的项目中报错的路径不同。并且看着像是使用了两个不同的第三方库。这里先留个悬念,我会在后面的文章中进行解释。
接下来,我开始在测试项目中继续尝试剩下的两种方法,对于第二种方法,由于老项目中使用的presets
是没有polyfills
这个配置选项的,到如今为止出问题的这个第三方库我不知道除了这个...
对象扩展操做符以外还有没有别的依赖。因此这个方法我暂时也放弃了。
对于第三个方法,我以为能够尝试,首先我将测试项目中的一些关键依赖进行了手动降级,而后按照上面的第三个方法的步骤在测试项目中使用。可是发现测试项目运行以后,提示须要安装core-js
,安装core-js
以后还报错,再次提示须要安装es.module.regex.match
等等不少依赖,继续查资料,发现须要把配置中的 useBuiltIns
修改,可是由于我接手的这个项目是老项目,依赖比较多,不肯定修改useBuiltIns
这个配置选项后会不会出现新的问题。因此也不敢贸然修改这个配置选项,因此也暂时放弃了这个方法。
我后来想了一下,对于...
扩展运算符来讲,这是一个新的语法。是不可以经过一些polyfills
去解决的。须要Babel
对这个语法进行编译,而后才能够在低版本的系统中使用,因此解决的办法仍是要让Babel
对这个库再次进行编译。
当进行到了这里的时候,彷佛没有了出路。一时间我感受我要被这个Bug战胜了,我彷佛听到了它无情的嘲笑,“小伙子,是否是被我折磨的没有脾气啦;放弃吧,你是没办法打倒个人。哈哈哈。。。”
可是,它看错我了,Bug越是难解决,我对它就越有兴趣。因此我决定好好理一下思路,准备再次扬帆起航。
我发现第一种办法实际上是起做用的,只不过是由于一个是CommonJS
类型的,一个须要是ES6 module
类型的。因此我决定从这个地方入手,因而我决定查查相关的资料,看看Babel
有没有办法能够即可以处理CommonJS
模块,又可以处理ES6 module
模块呢?终于,功夫不负有心人,我发现了Babel
里面有这么一个配置sourceType
,若是把sourceType
设置为unambiguous
就能够解决这个问题。
这样Babel
就会根据模块文件中有没有import/export
来决定使用哪一种解析模块的方式。因而我再次使用了第一种方法,在vue.config.js
中添加了transpileDependencies
选项的配置,而后在项目中的Babel
配置文件中添加了以下的配置:
module.exports = { ... // 省略的配置 sourceType: 'unambiguous', ... // 省略的配置 };
发现的确能够,这一刻成功的喜悦再次降临。而后我再次打包,再次把代码部署到测试环境,赶紧让小C同窗再次测试一下,发现的确能够。欧耶,终于解决这个问题了。我终于能够松一口气了,哈哈哈。。。小样,这怎么会可贵到我呢?
可是,当我仔细阅读将这个选项设置为unambiguous
时,我发现了一些问题。由于这样的话会有一些风险,由于就算不使用import/export
语句的这些模块也多是彻底有效的ES6 module
,因此这样的话就有可能会出现一些意外的状况。怎么办,我彷佛在一不留神的时候又被Bug卡住了脖子。
我以为老天老是给我开玩笑,当我从一个坑里跳出来,觉得没有危险的时候。前面忽然又多出来一个坑,我一不留心就又掉了进去。我感受既然都走到了这里,确定要继续走下去,必定有办法能够优化我如今遇到的问题。我就很仔细的再次看了一下Babel
的配置说明文档,这个时候就心想若是我对Babel
再熟悉一些就行了。不要紧,继续努力。终于,我彷佛看到了什么了不起的配置选项。
我在Config Merging options
里发现了overrides
选项,这个配置选项不正是我须要的吗?我能够利用这个配置选项将我须要的第三方包使用unambiguous
的处理方式,而后其余的第三方库都按照以前的方式处理不就能够了。哈哈哈,我真是个天才,我内心这样对本身说😂。
因此只须要在项目的babel.config.js
中写下以下的配置就能够了:
module.exports = { ... // 省略的配置 overrides: [ { include: './node_modules/module-name/library-name/name.common.js', // 使用的第三方库 sourceType: 'unambiguous' } ], ... // 省略的配置 };
对了,还有一件事情尚未说,那就是上文提到的关于为何使用公司本身的包管理工具下载下来的node_modules
包的名称跟使用官方的npm
包管理工具下载的包的名称不一致的问题。缘由是公司使用的包管理工具是cnpm
的一个修改版本。又由于cnpm
为了提升下载的速度,使用了cnpm/npminstall
,因此才会出现下载的包名比较混乱的状况,详情能够看这里。
到此完结撒花,总结一下:出现白屏的缘由是由于使用的第三方库的包中使用了...
扩展运算符,而后由于第三方的包默认是没有被Babel
处理过的,因此在不支持...
的iOS 11
系统上就出现了白屏。解决的方式就是经过给vue.config.js
的配置文件中transpileDependencies
配置选项中添加上出问题的包的名称就能够了。固然若是项目比较老,可能还须要像文章上面写的那样的处理方式。
解决这个Bug过程就像是升级打怪同样,不断失败,不断尝试,只要不放弃,终有成功的那一天。若是你坚持看到了这里,那说明你也很棒呀。在当今这个信息爆炸的时代里,可以坚持看完一篇很长的文章已经很不错了。
一点反思与思考:这个过程当中我也发现了本身对Babel
和Vue CLI
其实没有那么熟练,若是我对它们比较熟练的话,那我解决这个Bug应该会花费更少的时间。固然,如今把它们学习好也不算晚。要抱着学习的态度,此次解决这个Bug的过程,就是我之后解决其它相似Bug的经验。还有在解决Bug的这个过程当中要有耐心,固然在尝试以后也要学会放弃错误的方向。
写这篇文章也花费了我很多的时间,若是你有所收获或者感悟,不妨点赞,转发,收藏走一波,这个要求应该不算过度吧😂?
若是你对本篇文章有什么意见和建议,均可以直接在文章下面留言,也能够在这里提出来。也欢迎你们关注个人公众号关山不难越,学习更多实用的前端知识,让咱们一块儿努力进步吧。