阅读 743

坑爹的 iOS 9:记一次 H5 白屏踩坑之旅

先说结论:iOS 9 的内置浏览器不支持 ES6 语法,而 babel-loader 中没配置相关规则,webpack 打包时,没有将 ES6 编写的文件转义,导致直接白屏不渲染。

起因

某天,客服群里反馈,App 内嵌的某个活动页,iOS 9 的用户打开白屏,然后测试说 PC 浏览器、自用的手机都能打开,于是理所当然的将锅甩给了原生同事。但随着问题的排查,发现 “锅” 越来越朝 Web 前端方向靠拢……

经过

项目信息:

vue: 2.5.13
webpack: 3.6.0
node: 11.13.0

Google 后说白屏是因为有 ES6 的语法在里面,我就很奇怪,都是统一打包的,而且之前也没有客服反馈这类问题。

查询了 iOS 9.0 的发布时间,目前使用的机型基本集中在 iPhone 5 到 6s plus 之间。

因为系统比较久远了,公司也没有相应的测试机。没有真机实在不好调试,于是回家翻出了我 7 年前买的 5s,庆幸的是,当时没有冒进,系统刚好在 9.3.4。

于是用真机打开页面,果然是白屏,连接 MacBook 用 Safari 调试,body 里除了 <div id="app"></div> 以外,其他什么都没有挂载上去。

于是和 iOS 的同事一起调试,用他们的 Xcode 看看能不能得到更多的信息,结果除了白屏,其他什么报错信息都没有。最最奇怪的是,都是内嵌页,有的能打开,有的却白屏。

然后在掘金中看到这篇文章,《记h5项目中在ios9白屏问题》,上面说是 babel-loader 没有将webpack-dev-server 下的 client/index.js 文件转义,但是还是不能解释为啥有的页面能打开(都用的相同的打包配置),不过给我后来的分析问题提供了思路。

后来,他们又说,正式环境,除了反馈的那个页面,其他页面是都可以打开的,于是基本可以定位到是这次改版的某个地方出问题了。

于是,我回退到上一次发版的状态。将其中一个白屏的页面,单独打包到开发环境,居然能访问,然后切回现在的版本,再打包,果然又白屏了。(我们的 H5 内嵌页因为是大部分是运营活动,而活动和活动之间是没有太大联系的,所以这些活动页都可以拆分成一个个子项目,可单独打包替换)

我在另一个目录下,从 git 重新拉了项目,然后回退到正常的版本,然后就挑那个活动页面,挨个比对,刚开始我以为是 vant 版本问题,后面又以为是 node 版本问题(之前是 node 8.11.4,我为了玩 NestJS,升到了 11.13.0),甚至把 less 改成了 scss(原来的是用 scss 写的)都无果。

正在抓狂之际,Axios 封装的文件里有一行吸引了我:

如上图,红框中的代码,是新增的,因为 PHP 那边要更换秘钥,区分开发和正式环境,于是我写了个公共秘钥文件,防止以后每次跟换秘钥,每一个项目都要全量替换。

然后我又观察那些正常渲染页面的项目,共同点都是走的 Node 接口,于是问题基本定位到了。

把红框的注释掉,然后写死了 key,再打包,居然又可以访问了。

当然,问题肯定不是这个变量的问题,于是重新审视代码:

然后联想到之前 Google 的问题,会不会是这个文件没有被 babel-loader 转义成 ES5?

于是我去 webpack 的打包配置文件,在 plugins 的规则里加上了 resolve('config'),将这个目录添加至转义列表:

Ps: 那个 utils 可不用管,那是我们自己封装的工具文件,正常使用 resolve() 即可。

结果

复原那个 apiKey,重新打包,果然又能访问了。

所以,问题的本质还是 iOS 9 的浏览器不支持 ES6+ 语法( iOS 9 以下的估计也会,但没真机,也不好下结论),表现形式就是直接白屏,任何错误信息都没有(用手机和电脑联调的 Safari 浏览器调试也没有)。

如果遇到类似的问题,可以先检查一下是不是项目的某个目录没有加入转义列表,再去寻找其他答案。

Safari 真不愧是移动端界的 IE。

`