Open closertb opened 8 months ago
在做商品前端之前,我是本地生活前端基础设施WAP平台的全栈开发者。我对接的客户是本地生活的前端,区别于业务前端的是,自己即是产品、也是开发、测试、运维。
商品前端作为业务开发,其工作更细,更强调团队,除了要和产品、服务端、测试密切配合;还需要关注上下游链路、依赖更多,制约更多。
而除了上述差别,还有就是更关注用户体验、关注客诉、关注线上问题。以下便是我2023年遇到的奇葩、棘手,让人个人成长但不多的业务问题集锦top4, 分享与各位共勉:
某天要下班提包走的瞬间,突然产品拉群,运维反馈说XX商户套餐添加菜品操作页面白屏(其实是一致loading,页面假死),并发了个视频。
白屏
发错了,是下面这个
我们迅速根据商家信息去查了接口调用日志,发现请求正常,响应正常未超时,前端系统日志也正常,未上报任何报错信息。
几个人对视频又观察分析,发现商户小程序选菜页面正常,只是H5应用选菜页面打开才会白屏(本质上是整个app崩溃了,页面都没法退出)。然后又和运维交流了一下,说商户安卓手机能正常操作,只有苹果手机有问题(型号:IP15 PRO)。我们测试迅速在我们的测试商户复现,未成功复现。于是又联系运维,要了商户的临时登录帮助复现,也未复现(复现的机型是IP 13)。这就更蒙了,难道只有苹果高端机才有问题?
然后找到一位土豪同事,用他刚上手的水果试了一下,果然复现了,难道这真的是富贵病???
但机智的我突然开窍,会不会是这个分类表情符造成的?我们迅速在测试账号复现了该分类,并成功验证这个猜想,确实是分类表情符被截断造成。当晚我们给商户的建议是:改一下表情符出现的位置,或者减少数量。
第二天,另一个测试在一台IP 13也复现了,但APP版本一样,唯一不一样的,是系统的版本,他的更新。然后我们又升级了一台,果然是系统升级造成。至于为什么小程序没问题,因为小程序用的是UC内核容器,而H5用的是原生webview容器,即safari内核。
这难道了我,以前只知道去github给仓库作者提issue,这给苹果系统提issue,还是大姑娘上轿-头一回。
大姑娘上轿
在google了苹果bug反馈机制后,迅速写了一个demo,并提了一个issue,一周后,打开测试机看到一条系统更新推送,看到了是关于safari的,果断升级,发现问题已解。
某天bug写的起劲,钉钉消息不断弹出,大事不妙,果然,前线运维反馈APP菜品列表滑动卡顿,并录了视频。
习惯性打开测试商户看了下,800个菜,滑动正常,问了下对面,只有100来个菜,这不应该啊。问了对方机型,华为Mate60(没听错,就是那个遥遥领先),那就更不可能啊。毕竟我手上这个vivo老年机,不能说很流畅,但真的不至于卡。又找了几个手机(包括一个Mate50),运行都很正常,然后、然后、就挂起了。
然后隔了几天,另一个同事查问题,发现在一加手机上也很卡。但奇怪的是,出问题当天,我们就用过这手机,测试出来很流畅,而且是两个人一起测过。很快我们发现了不同端,APP由于有发版,测试版自动升级成了正式版。然后我们又找了两台测试机,装了app正式包,发现都有卡顿问题。于是我们把问题抛给了APP。
后面APP不断本地回滚版本测试,发现一年前的版本运行起来都卡。然后解释之所以正式包卡,测试包不卡,是因为UC内核不一样,正式版的内核有优化(这算哪门子的优化)。然后我们就只有从自身找原因,通过代码不断回滚测试,发现9月前的版本运行流畅,9月后的版本就不行了,然后同事发现是因为在虚拟列表的列表单元组件deriveDataFromProps增加了动态计算工作量,当然,这个bug并不是这一个同事造成的,他只是把坑挖的更明显(后面,我们发现,这个迭代,另一个同事正在这个坑里刨,上线后,估计就是P5故障了)。
因为快速滑动,虚拟列表不断地卸载挂载,照成大量的计算与setState,从而导致卡顿。其实更好的做法,是在数据提前计算好传给列表单元,而不是挂载时动态计算。调整后,卡顿问题迅速得到了解决,上线后,我们也收到了运维的正向反馈:
这一次问题处理,我意识到了百分百还原问题现场的重要性,不要以我以为的思想来判定问题。
我以为
2023财年,最硬核输出可能就是wa-form了,这是KPI下硬挤出来的产物(两个憨憨熬夜一周),但不是废物,因为它确实解决了我们B端场景的联动校验问题,没有Formily那么多概念,但却有formily 70%的能力(大概)。
这个库在第一版时,直接在我们扩品类的业务项目上落地,出现了很多bug。但有一个bug,至今也没找到原因,大概的现象就是: 当我们在这个表单上,持续的触发联动校验,会突然的出现联动校验假死(和操作时间无关,没法稳定复现);但更神奇的是,只会在一个测试机(水果13)出现,安卓机,其他人的苹果都不能复现,开发模式也不能。
但更神奇的事情是,出现这个bug连上safari开始debug时,联动校验又恢复了。所以这神秘的面纱,我们至今没有揭开。
当时我们也是经过评估,认为这个bug线上出现概率不大,确认可以不解决直接上线。
一说起webpack的构建拆包,你可能马上就想到要用SplitChunk插件加个配置,这玩意多简单,最多分出个样式问题(由于加载时序造成的同权重样式优先级变化)。但我今年遇到了神奇的,还不止一次,我拆包后,发现大多数页面能运行,但部分页面的某个功能一点,页面就白屏了,一检查,还是那熟悉的味道:Cannot read properties of undefined。
Cannot read properties of undefined
更神奇的是,这种bug只会在生产模式出现,开发模式是不能复现的。
在做移动端的拆包优化时,遇到过这问题,也是临近上线才发现,当时时间紧没研究问题,后面就紧急把配置回滚。但今年老板紧追页面加载体验问题,这PC端一个页面4.2M的包,不做拆包就只有贱指325了。是时候动一下手指,加一波配置,原以为经过九九八十一难后,这次一定会成功,但在内灰时,赶巧被测试发现,点某个小功能又白屏了,啥也不说,马上配置回滚,紧急再重新内灰。
325
临近财年底,手上业务没那么重,就认真研究了下,这不,有点效果!!!放假前给webpack官方提了一个Issue, 让他过不好年(大意了,别人不是中国人), 但过了一天,那熟悉的味道又来了,大概意思:同学你好,你的问题我收到了,你能提供一个最小单元的复现示例吗
同学你好,你的问题我收到了,你能提供一个最小单元的复现示例吗
满怀信心去新建一个项目,以为能复现,但事实证明,这可能不是官方的bug。但更残酷的事实是:过不好年的,可能是我。
过不好年的,可能是我
但这个示例还是有用的,经过将示例项目和业务项目构建结果对比,发现业务项目会多出这样一段结果:
/******/ /* webpack/runtime/runtimeId */ /******/ (() => { /******/ __webpack_require__.j = 335; /******/ })();
经过大年初一初二初三不断抽时间看源码,发现了蛛丝马迹:
webpack/runtime/runtimeId
// webpack/lib/RuntimePlugin.js compilation.hooks.runtimeRequirementInTree .for(RuntimeGlobals.runtimeId) .tap("RuntimePlugin", chunk => { compilation.addRuntimeModule(chunk, new RuntimeIdRuntimeModule()); return true; });
// RuntimeIdRuntimeModule 定义, webpack/lib/runtime/RuntimeIdRuntimeModule.js class RuntimeIdRuntimeModule extends RuntimeModule { constructor() { super("runtimeId"); }
/** * @returns {string} runtime code */ generate() { const { chunkGraph, chunk } = this; const runtime = chunk.runtime; if (typeof runtime !== "string") throw new Error("RuntimeIdRuntimeModule must be in a single runtime"); const id = chunkGraph.getRuntimeId(runtime); return `${RuntimeGlobals.runtimeId} = ${JSON.stringify(id)};`; }
}
2. 所以要触发钩子调用,就得RuntimeGlobals.runtimeId变化,触发条件 ```js runtimeConditionExpression({ chunkGraph, runtimeCondition, runtime, runtimeRequirements }) { if (runtimeCondition === undefined) return "true"; if (typeof runtimeCondition === "boolean") return `${runtimeCondition}`; /** @type {Set<string>} */ const positiveRuntimeIds = new Set(); forEachRuntime(runtimeCondition, runtime => positiveRuntimeIds.add(`${chunkGraph.getRuntimeId(runtime)}`) ); /** @type {Set<string>} */ const negativeRuntimeIds = new Set(); forEachRuntime(subtractRuntime(runtime, runtimeCondition), runtime => negativeRuntimeIds.add(`${chunkGraph.getRuntimeId(runtime)}`) ); // 这里有新增RuntimeGlobals.runtimeId runtimeRequirements.add(RuntimeGlobals.runtimeId); return compileBooleanMatcher.fromLists( Array.from(positiveRuntimeIds), Array.from(negativeRuntimeIds) )(RuntimeGlobals.runtimeId); }
所以,只有在 runtimeCondition 存在且不为boolean时,才会触发RuntimeGlobals.runtimeId添加。
boolean为true时,代表所有chunk都需要;
boolean为false时,代表所有chunk都不需要,可以shaking掉;
{ "sideEffects": [ "es/**/style/*", "es/**/*.less", "es/theme/*", "es/index.js", "lib/**/style/*", "lib/**/*.less", "lib/theme/*", "lib/index.js" ], }
最直接的解决策略就是改库的sideEffects配置,因为这个库的index.js有一段关于样式的副作用代码,所以调整还包括了库整体架构的调整。终于,终于,在大年初五,我开始心无旁骛的过年了。
你以为这就完了,并没有,webpack针对于大项目的构建确实是有bug的,只能说未完待续(issue 还在持续掰扯)。
但愿2024 不要再有这么多奇奇怪怪的线上问题,毕竟我已早过而立之年,再不学学大模型、AIGC,就真的要面临提前退休,回家种地的境地了。
🙏🏻🙏🏻🙏🏻!!!
角色的转变
在做商品前端之前,我是本地生活前端基础设施WAP平台的全栈开发者。我对接的客户是本地生活的前端,区别于业务前端的是,自己即是产品、也是开发、测试、运维。
商品前端作为业务开发,其工作更细,更强调团队,除了要和产品、服务端、测试密切配合;还需要关注上下游链路、依赖更多,制约更多。
而除了上述差别,还有就是更关注用户体验、关注客诉、关注线上问题。以下便是我2023年遇到的奇葩、棘手,让人个人成长但不多的业务问题集锦top4, 分享与各位共勉:
一个表情符造成的崩溃
某天要下班提包走的瞬间,突然产品拉群,运维反馈说XX商户套餐添加菜品操作页面
白屏
(其实是一致loading,页面假死),并发了个视频。发错了,是下面这个
我们迅速根据商家信息去查了接口调用日志,发现请求正常,响应正常未超时,前端系统日志也正常,未上报任何报错信息。
几个人对视频又观察分析,发现商户小程序选菜页面正常,只是H5应用选菜页面打开才会白屏(本质上是整个app崩溃了,页面都没法退出)。然后又和运维交流了一下,说商户安卓手机能正常操作,只有苹果手机有问题(型号:IP15 PRO)。我们测试迅速在我们的测试商户复现,未成功复现。于是又联系运维,要了商户的临时登录帮助复现,也未复现(复现的机型是IP 13)。这就更蒙了,难道只有苹果高端机才有问题?
然后找到一位土豪同事,用他刚上手的水果试了一下,果然复现了,难道这真的是富贵病???
但机智的我突然开窍,会不会是这个分类表情符造成的?我们迅速在测试账号复现了该分类,并成功验证这个猜想,确实是分类表情符被截断造成。当晚我们给商户的建议是:改一下表情符出现的位置,或者减少数量。
第二天,另一个测试在一台IP 13也复现了,但APP版本一样,唯一不一样的,是系统的版本,他的更新。然后我们又升级了一台,果然是系统升级造成。至于为什么小程序没问题,因为小程序用的是UC内核容器,而H5用的是原生webview容器,即safari内核。
这难道了我,以前只知道去github给仓库作者提issue,这给苹果系统提issue,还是
大姑娘上轿
-头一回。在google了苹果bug反馈机制后,迅速写了一个demo,并提了一个issue,一周后,打开测试机看到一条系统更新推送,看到了是关于safari的,果断升级,发现问题已解。
UC内核打造的出其不意
某天bug写的起劲,钉钉消息不断弹出,大事不妙,果然,前线运维反馈APP菜品列表滑动卡顿,并录了视频。
习惯性打开测试商户看了下,800个菜,滑动正常,问了下对面,只有100来个菜,这不应该啊。问了对方机型,华为Mate60(没听错,就是那个遥遥领先),那就更不可能啊。毕竟我手上这个vivo老年机,不能说很流畅,但真的不至于卡。又找了几个手机(包括一个Mate50),运行都很正常,然后、然后、就挂起了。
然后隔了几天,另一个同事查问题,发现在一加手机上也很卡。但奇怪的是,出问题当天,我们就用过这手机,测试出来很流畅,而且是两个人一起测过。很快我们发现了不同端,APP由于有发版,测试版自动升级成了正式版。然后我们又找了两台测试机,装了app正式包,发现都有卡顿问题。于是我们把问题抛给了APP。
后面APP不断本地回滚版本测试,发现一年前的版本运行起来都卡。然后解释之所以正式包卡,测试包不卡,是因为UC内核不一样,正式版的内核有优化(这算哪门子的优化)。然后我们就只有从自身找原因,通过代码不断回滚测试,发现9月前的版本运行流畅,9月后的版本就不行了,然后同事发现是因为在虚拟列表的列表单元组件deriveDataFromProps增加了动态计算工作量,当然,这个bug并不是这一个同事造成的,他只是把坑挖的更明显(后面,我们发现,这个迭代,另一个同事正在这个坑里刨,上线后,估计就是P5故障了)。
因为快速滑动,虚拟列表不断地卸载挂载,照成大量的计算与setState,从而导致卡顿。其实更好的做法,是在数据提前计算好传给列表单元,而不是挂载时动态计算。调整后,卡顿问题迅速得到了解决,上线后,我们也收到了运维的正向反馈:
这一次问题处理,我意识到了百分百还原问题现场的重要性,不要以
我以为
的思想来判定问题。偶现的bug,奔溃的调试
2023财年,最硬核输出可能就是wa-form了,这是KPI下硬挤出来的产物(两个憨憨熬夜一周),但不是废物,因为它确实解决了我们B端场景的联动校验问题,没有Formily那么多概念,但却有formily 70%的能力(大概)。
这个库在第一版时,直接在我们扩品类的业务项目上落地,出现了很多bug。但有一个bug,至今也没找到原因,大概的现象就是: 当我们在这个表单上,持续的触发联动校验,会突然的出现联动校验假死(和操作时间无关,没法稳定复现);但更神奇的是,只会在一个测试机(水果13)出现,安卓机,其他人的苹果都不能复现,开发模式也不能。
但更神奇的事情是,出现这个bug连上safari开始debug时,联动校验又恢复了。所以这神秘的面纱,我们至今没有揭开。
当时我们也是经过评估,认为这个bug线上出现概率不大,确认可以不解决直接上线。
分包也能分出线上问题
一说起webpack的构建拆包,你可能马上就想到要用SplitChunk插件加个配置,这玩意多简单,最多分出个样式问题(由于加载时序造成的同权重样式优先级变化)。但我今年遇到了神奇的,还不止一次,我拆包后,发现大多数页面能运行,但部分页面的某个功能一点,页面就白屏了,一检查,还是那熟悉的味道:
Cannot read properties of undefined
。更神奇的是,这种bug只会在生产模式出现,开发模式是不能复现的。
在做移动端的拆包优化时,遇到过这问题,也是临近上线才发现,当时时间紧没研究问题,后面就紧急把配置回滚。但今年老板紧追页面加载体验问题,这PC端一个页面4.2M的包,不做拆包就只有贱指
325
了。是时候动一下手指,加一波配置,原以为经过九九八十一难后,这次一定会成功,但在内灰时,赶巧被测试发现,点某个小功能又白屏了,啥也不说,马上配置回滚,紧急再重新内灰。临近财年底,手上业务没那么重,就认真研究了下,这不,有点效果!!!放假前给webpack官方提了一个Issue, 让他过不好年(大意了,别人不是中国人), 但过了一天,那熟悉的味道又来了,大概意思:
同学你好,你的问题我收到了,你能提供一个最小单元的复现示例吗
满怀信心去新建一个项目,以为能复现,但事实证明,这可能不是官方的bug。但更残酷的事实是:
过不好年的,可能是我
。但这个示例还是有用的,经过将示例项目和业务项目构建结果对比,发现业务项目会多出这样一段结果:
经过大年初一初二初三不断抽时间看源码,发现了蛛丝马迹:
webpack/runtime/runtimeId
的webpack钩子定义在// RuntimeIdRuntimeModule 定义, webpack/lib/runtime/RuntimeIdRuntimeModule.js class RuntimeIdRuntimeModule extends RuntimeModule { constructor() { super("runtimeId"); }
}
所以,只有在 runtimeCondition 存在且不为boolean时,才会触发RuntimeGlobals.runtimeId添加。
boolean为true时,代表所有chunk都需要;
boolean为false时,代表所有chunk都不需要,可以shaking掉;
最直接的解决策略就是改库的sideEffects配置,因为这个库的index.js有一段关于样式的副作用代码,所以调整还包括了库整体架构的调整。终于,终于,在大年初五,我开始心无旁骛的过年了。
你以为这就完了,并没有,webpack针对于大项目的构建确实是有bug的,只能说未完待续(issue 还在持续掰扯)。
新年愿望
但愿2024 不要再有这么多奇奇怪怪的线上问题,毕竟我已早过而立之年,再不学学大模型、AIGC,就真的要面临提前退休,回家种地的境地了。
🙏🏻🙏🏻🙏🏻!!!