工夫回到一周前,过后刚开发完公司A我的项目的一个新的版本,期待着测试实现就进行公布。此时的我也筹备从间断多日的缓和开发状态中走进去,认为能够稍稍放松一下。而那时的我还不晓得,我行将面临一个弱小的Bug选手,更不晓得我要跟这个Bug来来回回进行屡次的格斗。当然,咱们能看到这篇文章也就阐明了我最终解决了这个Bug,而且这个过程也是相当的精彩的。什么?你不置信,那就让我来带你进入这个“跌宕起伏”的经验中吧。

情谊提醒:接下来的文章兴许有一点长,然而心愿你可能保持读上来。我置信我在解决这个Bug的过程中的一些思路会给你带来一些思考。当然也心愿你在这个过程中可能像我一样学习到一些新的常识,为当前排查相似的Bug积攒一些教训。好啦,话不多说,让咱们开始吧。

我的项目介绍

先来简略介绍一下A我的项目,这是一个基于Vue框架的我的项目,我的项目应用的也是Vue CLI这个开发工具。这个我的项目是须要集成在别的APP中的,也就是页面须要在APP中进浏览和操作。这个我的项目在我接手之前曾经开发过一段时间了。所以我的项目中的一些依赖库和工具库版本绝对比拟低,这也给我后续的调试以及解决Bug的过程减少了一些艰难。

BUG初现

过后开发实现之后,就交给咱们这边的测试和另一个城市的相干同学去验收这次开发的性能。在咱们这边所有都很失常,测试这边也没有反馈有什么问题。然而在另一个城市的同学小C的iPhone手机上却发现了白屏,关上页面之后什么内容也没有。

发现了这个问题之后,我再次跟咱们这边的测试同学确认了一下,看看咱们这边测试的iOS零碎的iPhone手机有没有这个问题。通过测试的测试,发现咱们这边的几台iPhone手机都没有问题。而后就问了小C他应用的测试手机的零碎版本是多少,过后感觉应该跟iOS的零碎版本有关系。

小C反馈说他的iPhone是6S Plus,而后零碎的版本是11.1.2。我问了咱们这边测试应用的iPhone版本都是多少,测试反馈说零碎的版本都是12以上的。所以到这里,我确定了这个白屏Bug的呈现必定跟iPhone手机的零碎有关系

重现BUG之路

尽管确定了问题呈现的环境,然而因为我身边没有零碎是11的iPhone手机,所以想让这个问题重现就变成了一个难题。询问了身边的共事,大家的零碎版本也都广泛高于12,所以借用他人的手机进行调试这个办法临时也不可行。

在平时的开发中,如果网页在iOS零碎的APP中有一些问题的话,咱们个别都会通过Safari浏览器进行调试。然而因为这次呈现问题的iPhone手机不在我这里,并且我这边也没有雷同零碎的手机。所以想通过真机进行调试就不太可能了。那怎么办呢?这个问题必定是要解决的,我也置信方法总比艰难多

想要进行调试,最简略的方法就是让我有一个零碎是11的iPhone手机。所以我就搜寻看看有没有什么方法能够给iPhone手机装置11的零碎。一搜寻还真的有,过程也不算是很简单。然而其中有一个步骤是须要到一些论坛或者第三方的助手网站下载跟本人手机型号相匹配的iOS零碎,这个步骤让我有点感觉不平安。毕竟不是官网的,不可能保障安全性。而且也未必有版本是11的零碎。所以这个计划就临时作罢

在我搜寻的过程中,我发现有网友说能够应用Xcode装置相应零碎版本的iPhone模拟器来进行调试。哎,你说我怎么没有想到这个方法呢?这的确是一个不错的方法。因为之前跟公司的共事学习过Swift,也理解过Xcode的一些操作。忽然感叹,真是技多不压身,你不晓得你什么时候就会用上你学过的常识。所以有条件的话,还是多学习一些常识。额,有点跑题了。

装置Xcode

我关上公司的电脑,开始装置Xcode,然而发现公司的电脑系统版本太低,装置Xcode须要降级零碎,所以没方法,先降级零碎吧。因为降级的工夫比拟长,我想到本人家中的Mac电脑上是有装置过Xcode,所以决定先回家。留下公司的电脑缓缓降级。

回到家,二话不说就开始筹备调试,然而发现我的Xcode下面的iPhone模拟器的零碎版本也都是12以上的,查了一下材料,Xcode是能够装置不同零碎版本的模拟器的,于是我就装置了零碎版本是11的模拟器。这个过程须要咱们关上Xcode的偏好设置,而后在Components选项中,抉择下载你要装置的对应零碎版本的模拟器。

装置胜利之后,运行iPhone 6S Plus模拟器,应用模拟器的Safari关上h5的页面地址,果然是白屏。

小样,终于把这个问题给复现了,这样就间隔解决这个Bug不远了。我关上MacSafari浏览器,进入开发者模式,发现了如下所示的报错

我搜寻了一下这个谬误,发现是因为我的项目中应用了...ES6扩大运算符,而后iOS 11零碎不反对这个这个运算符。这么容易就找到问题了,开心。想到这个问题还是比拟好解决的,能够通过应用Babel的一些插件,很容易就能够将这个问题解决掉。而后我就开心的睡觉去了,心想这个问题也不是什么大问题,今天解决一下就好了。

装置Safari Technology Preview

第二天到公司,我就在我的项目中的babel的配置文件中增加了相应的插件

{  ...  // 省略原来的配置内容  "plugins": ["@babel/plugin-proposal-object-rest-spread"]}

而后公布到测试环境中。通知了小C同学再次测试一下,我也在等着解决这个Bug的好消息。然而,呈现的却不是好消息,小C给我回复说还是不能够。什么,不可能呀,我就马上用公司的电脑再次进行测试。当我用公司电脑的Safari调试零碎是iOS 11iPhone 6S PLus模拟器的时候,却发现呈现了上面这个状况:审核正告:“data-custom”太新,无奈在此查看的页面上运行

我就又搜寻了一下为什么会呈现这个问题,终于让我找到了答案,Safari浏览器的Web Inspector工程师也说这是一个Bug,不过他们曾经修复了,在下个公布的版本中就能够失常应用新的Safari浏览器去调试比拟老的iOS零碎的模拟器了。晓得当初这个版本的Safari调试不了模仿的iOS 11零碎的页面。我有点丧气,总不能我当初回家把我的电脑拿过去吧?????当我想着该如何解决的时候,我发现了下面那个答复中提到了Safari Technology PreviewSafari技术预览

我看这个名字感觉有点心愿,而后就搜寻了一下Safari Technology Preview是什么。而后就发现它绝对于Safari就跟Chromium绝对于Chrome是一样,都相当于是开发版本的浏览器。

这时,我感觉能够应用Safari Technology Preview进行调试。所以就下载了Safari Technology Preview,当我关上Safari Technology Preview而后进入开发者模式后,发现的确能够调试iOS 11零碎的页面。而后我就看了一下为什么还是白屏的问题。发现呈现的谬误还是上次的问题:

也就是说这个问题还没有解决掉,因为打包后的代码是没有SourceMap的,所以要想看更具体的报错信息,须要在本地进行调试。本地的环境中是有SourceMap的,能够定位到更具体的错误信息,我在本地运行了我的项目,而后我关上了控制台的谬误详情,发现是应用的一个第三方的库呈现了问题。

那么到这里为止,能够阐明下面咱们应用的Babel插件没有解决这个第三方的库,所以当初咱们的问题就变成了:如何解决第三方库中呈现的...扩大运算符没有被编译为ES5语法的问题

将第三方库中的ES6语法进行编译

查看Vue CLI中相干的配置办法

这时我又认真的看了一下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默认解决的是ES6module类型的库,所以这里就又呈现了新的问题。

第一种办法遇到了妨碍,先暂停一下。我筹备持续尝试上面两种办法。然而因为前面两种办法对原来的我的项目改变有点大,所以我间接通过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过程就像是降级打怪一样,一直失败,一直尝试,只有不放弃,终有胜利的那一天。如果你保持看到了这里,那阐明你也很棒呀。在当今这个信息爆炸的时代里,可能保持看完一篇很长的文章曾经很不错了。

一点反思与思考:这个过程中我也发现了本人对BabelVue CLI其实没有那么纯熟,如果我对它们比拟纯熟的话,那我解决这个Bug应该会破费更少的工夫。当然,当初把它们学习好也不算晚。要抱着学习的态度,这次解决这个Bug的过程,就是我当前解决其它相似Bug的教训。还有在解决Bug的这个过程中要有急躁,当然在尝试之后也要学会放弃谬误的方向

写这篇文章也破费了我不少的工夫,如果你有所播种或者感悟,无妨点赞,转发,珍藏走一波,这个要求应该不算过分吧?????

如果你对本篇文章有什么意见和倡议,都能够间接在文章上面留言,也能够在这里提出来。也欢送大家关注我的公众号关山不难越,学习更多实用的前端常识,让咱们一起致力提高吧。