前言
最近测试报过来一个离谱的 bug
,问题如下:
iOS 系统中,所有链接都需要点击两次才能跳转!
相信所有写过代码的人都知道,这个 bug
有多么严重。于是咱们就基于此 bug
,开启修复之旅。
正文
📱强烈建议公司一定要给开发配专用的测试机,这真的很影响调研的进度!
首次
在遇到这个问题的第一件事,就是定位问题,是所有的链接都有这个问题?还是只有部分按钮有这个问题?
定位问题点
于是我写了以下代码:
<a href="www.baidu.com">百度</a>
<a href="/products">内链</a>
<button on:click={e => location.href = 'www.baidu.com'}>点击链接</button>
<button on:click={e => goto('/products')}>点击链接</button>
上面分别测试:
- 外链
- 内链
- 按钮外链
- 按钮内链
经过测试有了第一步确认内容:
- 按钮跳转(
goto
/location.href
)都没有问题 - 外链跳转没有问题
- 内链跳转需要点击两次
基于上面的测试,可以确定的是,只有 a 标签上 href 的内链才会出现 iOS 需要点击两次的情况。
定位问题原因
由于公司使用的框架是 svelte
,第一时间想到了 svelte
的预加载出了问题。
于是写了以下代码:
<a href="products" data-sveltekit-preload-data={false}>内链</a>
经过测试,关闭预加载确实能解决点击两次的问题。
但这并不解决问题,因为:
- 一个是这会大大损失
svelte
为数不多的优点 - 二是我不能在所有的
a
标签上添加一个属性吧?
寻找解决方案
相信大家在遇到问题的第一时间,百度 + 掘金 等平台就开始全速运行了~
经过几分钟发现不太好找才会上国外找。
但 svelte
有一个问题,就是国内的参考资料极少。因此第一时间便优先的国外的资源。
stackoverflow
搜索:找到相似的问题,但并不完全相似,且没有可行的解决方案reddit
搜索:和 stackvoerflow 是同一个问题google
搜索:也是类似的情况,找不到解决方案
都这一步都没有找到解决方案的问题,一般就很难在搜索引擎上找到了,只能是扒源码或者 github
提问。由于没有太多时间扒源码去看,因此直接在 Discord
和 github
上进行了提问。
由于 github
的提问已删除,所以这里就简单给大家看下 Discord
的提问:
但最终并没有解决问题。
二次
框架版本升级
经过上面的问题,再结合 Discord
的回复,以及我们使用的 svelteKit
框架的版本,当时怀疑是这个版本的 svelteKit
的问题(1.x),于是决定先升级 svelteKit
确定抛开框架问题。
基于官网的升级方案:kit.svelte.dev/docs/migrat…
升级了项目的 svelteKit
的版本,但此时仍没有解决问题。
全局关闭预加载
既然上面都没解决问题,目前的解决方案就是关闭预加载。官网可以看到全局调整的方案,但并没有说明如何关闭:
经过测试可以确定,可以通过 data-sveltekit-preload-data={false}
关闭预加载。
于是有了以下代码:
<script>
onMount(() => {
if (isIOS()) {
const bodyEl = document.querySelector('body')
bodyEl.setAttribute('data-sveltekit-preload-data', "false")
}
})
</script>
三次
但上面方案还是一种 hard-code
方案,我们并没有找到问题的原因,因此还是需要复现问题,提供给 github
的 issues
,让维护者确定问题以及解决方案。
于是开始进行最小化可复现单元的实践。
尝试新项目复现
这里就是创建一个新项目,复现问题,上传至 github
上提供给维护者测试。
- 创建项目
- 复制老项目的
app.html
保持一致 - 新建两个页面,并创建内链跳转链接
- 测试:问题并未复现
- 在需要跳转的
ts
文件中添加接口请求(jsonplaceholder.typicode.com/posts) - 测试:问题并未复现
到这一步就感觉不对了,问题不能复现证明是有其他代码在影响 preload
,可能并不是 svelte
本身的问题。
确定项目问题
经过上面的问题,已经感觉到距离问题本身越来越近了。于是将上面写的两个页面复制到原项目中,发现依然有问题,那么就可以确定问题出现在项目的其他位置,而并不是预加载本身。
定位问题原因
于是进行了以下操作:
- 注释掉所有的
app.html / app.css / layout.ts / layout.svelte
等全局内容 - 测试是否复现问题:问题未复现
- 逐个打开注释内容,直到问题复现
最终定位到同事新写的 AI
嵌入的代码,在 layout.ts
中:
export const load = (async (url) => {
const icon = 'xxx';
// 加载ai助手;
new CozeWebSDK.WebChatClient({
config: {
bot_id: 'xxx',
},
componentProps: {
title: 'xxx',
icon,
},
el: document.getElementById('aiDemo'),
});
// ...
return { ... };
}) satisfies LayoutLoad;
这段代码其实可以理解为 Vue、React
的路由拦截,但多了一个监听功能,如果不引用 url
则监听一次,如果引用则每次都运行。
因此每次点击时,都新 new
了一个 WebChatClient
...
在配合上预加载,于是出现了最开始我们遇到的问题。
解决方案
找到问题原因,解决就很简单了。将此段代码移动到 layout.svelte
的 onMount
中,只执行一次。
onMount(async (url) => {
const icon = 'xxx';
// 加载ai助手;
new CozeWebSDK.WebChatClient({
config: {
bot_id: 'xxx',
},
componentProps: {
title: 'xxx',
icon,
},
el: document.getElementById('aiDemo'),
});
})
复盘
通过上面的解决过程,会发现,其中做了很多无用功,且耽误了很多时间。因此整理了这次解决途中出现的问题,以及我们应该使用的解决问题流程。
出现的问题
第一时间怀疑框架的问题
这里其实有好几个原因,综合让我第一时间怀疑框架的问题:
svelte
过于新(如果使用的是vue
、react
,那么我第一时间就会怀疑是代码本身的问题)svelte
相关资源过少,导致没有人出过类似的问题,怀疑是框架本身svelte
框架本身的不信任(由于部分框架维护者的原因,对svelte
框架本身并不信任)
实际上一个正在商用的框架,是不会出现这么重大的问题而不被发现的,因此还是要对框架保持基础的信任
过早的考虑 hard-code 解决方案
其实这点本身没错,但问题是项目本身还没有上线,因此不必如此着急的考虑 hard-code
的方案,可以存在脑海,确定解决不了再考虑 hard-code
的问题。
github 提问方式有问题
在 github
上提问,理论上我们应该提供给维护者一个可复现的最小代码段或者项目,否则维护者没有时间和你交流问题(提问的艺术)。
当前,你在 Discord
中可以这么做,因为 Discord
更倾向于一个社区,而 issues
有一定区别。
解决问题流程
定位问题原因
通过在项目中逐步打断点,确认问题具体出现的位置。并确定是否找到最终原因,如果确定则直接根据原因修改,如果不确定,通过最小可复现项目复现。
通过最小可复现项目复现问题
确定在最小可复现项目中是否可以复现,如果可以则提供给 issues
提问,如果不可以则代表未定位到核心原因,再到项目中查找真实问题原因
根据上面内容查找真实问题原因方法
将项目中所有可能有影响的位置全部关闭,确定到没有问题的时候,逐个开启项目中的各个功能点,直到问题再次出现