BUG: Safari10 Cannot declare a let variable twice: 'e'.
上线后,吃饭、午休、会议,查看线上错误日志,吓一跳,300+个错误 SyntaxError: Cannot declare a let variable twice: 'e'.
于是拉上小伙伴(我刚接手 C 端业务)退出会议,着手定位问题。
解决方法
// 修改 webpack(version: 4.5) 配置文件
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const config = {
// ...
minimizer: [
new UglifyJSPlugin({
cache: true,
parallel: true,
sourceMap: true,
uglifyOptions: {
safari10: true,
},
}),
],
// ...
}
答案在上面了,看官如果还有兴趣的话请继续。
由于日志中没有错误的行列信息,无法使用 sourcemap 定位到源码位置。 只能看到报错的文件路径: https://xxx/xxx/main.[hash].js。 还好,错误信息非常明确,不就是一个作用域内 let e
两次嘛,没 sourcemap 我也能找到源码位置。
第一回合
- 将有文件的线上 main.[hash].js 文件下载下来。
- 搜索关键字
let e=
。 嗯,只有 10 个结果,很好 - 查看 同一个函数作用域下出现两次
let e=
的位置 - 嗯,只有一处
getLocationCity{let e='xx',if(...){let e='yy'}}
, 哇抓到 bug 了,so easy~ - 在源码中找到
getLocationCity
的位置,代码命名没问题,猜测 uglifyJS 压缩混淆代码时重命名出的问题。 - 修改源码,本地编译,检查压缩混淆后
getLocationCity
下的变量命名没问题了。 - 提交代码,beta 构建,product 构建,准备发布。
- 不对,最近没改这块源码,有问题。。
第二回合
- 回头仔细分析日志
- 发现两条线索: 1、错误开始时间与最近一次发布时间吻合;2、所有错误的都是 IOS10(userAgent)
- 猜测是最近一次发布导致的兼容性问题
- 为对比新增的
let e=
,从 Jenkins 构建记录日志中找到上上次发布的 main.[hash].js 文件 URL,下载、对比 - 发现新增的
let e=
位置,h(e){for(let e='...'){...}}
并没有。(此时小伙伴用模拟器 ios10 重现了问题,错误会导致页面卡死,报错达 500+次,心里开始慌了) - 精简找到的 h 函数,在 chrome console 中执行无错误,确认是 ios10 兼容问题,与 uglifyJS 无关(此时回头看前面找到的
getLocationCity{let e='xx',if(...){let e='yy'}}
并无语法问题,因为let
作用范围是块级作用域,因代码压缩了没仔细分析,误以为是 uglifyJS 的 bug) - 于是只好 google
ios 10 SyntaxError: Cannot declare a let variable twice: 'e'.
- ヾ(。`Д´。)我擦,google 结果第一条就是相关内容,于是顺藤摸瓜找到解决方法(不完美)
minimizer: [
new UglifyJSPlugin({
uglifyOptions: {
mangle: {
safari10: true,
},
},
},
}),
],
- 此时解决方法有两个:1、小伙伴的临时方法:将 for 改成 foreach;2、如上修改 uglify 配置
- 最终决定修改配置,原因:解决根本问题,uglifyJS 改动可以验证(大部分生产问题修复都会遇到这样的场景,方法 1 的风险往往更低)
- 修改配置后,本地构建,对比检查 for 中的变量 e 被重命名成 a 了
- 提交代码、PR、打包构建、发布。
- 观察日志系统,错误数量停止增长。问题解决。继续会议。
第三回合
- 会议后,我们 leader review PR,提醒“你这样改可能覆盖 webpack 4.5 uglifyJS 的默认配置,并且 uglifyJS 插件官方文档 中 safari10 与 mangle 是同级的”。
- 对比 WebpackOptionsDefaulter 文件,发现默认配置中还有 sourcemap,cache 相关。
- 检查构建文件,确认没有输出 sourcemap 文件。
- copy 默认配置,添加
safari10: true
(如上文答案) - 本地构建,检查 sourcemap、变量命名,正常
- 结束,彻底解决。
思考
- 直接 google 搜索错误信息可以更快地找到解决方法。(这次未及时搜索是因为错误信息实在太清晰,一看就明白,但它是有误导性的)
- 仔细分析日志可以提前预知到是兼容性问题,方便重现问题,搜索也可以提高精准度
- 修改代码/配置应该仔细分析影响范围及验证,这次覆盖配置项是因为项目刚升级到 webpack 4.5(leader 升级的),我和小伙伴都还不熟悉新的配置。不过还是仔细验证了编译输出的文件,配置不完美但并没有实际损失。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

上一篇: Effective C++ 笔记(6)
下一篇: 谈谈自己对于 AOP 的了解
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论