最近有个项目(就叫他 P 项目)做了一次 UI 视觉统一。
之前是个小项目用的是默认主题 theme-d
,这次需求还针对性的发布了一套 theme-p
主题。
然后出事故了,更新了主题之后我们的 dialog
显示异常了。
使用控制台查看样式
通过查看样式我们发现都是 UI 的样式,并没有我们手动覆盖的样式。
但是这里有一个异常点有四个生效的样式,正常情况是只会有一个。但是这里我忽略了这个问题,我以为只是有多余的引入,或者没有 externals
、peerDependencies
导致有多个。
看上去样式是生效了只不过效果不对,我就怀疑 theme-p
有问题,但是在文档站显示是正常的。
那我们只能想办法去排查这个错误样式是谁引入进来的。
通过控制变量法
因为样式在页面中都显示 style,没有办法从文件名切入,所以这里我先采用了控制变量法。
main.ts
代码全部注释掉main.ts
初始一个新的页面,页面中只渲染 dialog。- 查看效果,dialog 效果同
theme-p
文档站。 main.ts
放开原始代码。- 查看效果,dialog 效果诡异。这个时候判断问题出在
main.ts
中。 main.ts
注释掉一半,观察效果。- 如果效果异常,重复步骤6,再注释掉一半。
- 当效果正常时,复原一半。
- 只到最后只保留下一行有问题的代码
- 进入到文件中,重复步骤6。
最后就能定位到错误代码行。你以为故事就结束了?这里诡异的是我定位到了好几个位置
- 第一次我定位到三方依赖中(没完全定位,估计是被缓存忽悠了)
- 第二次定位到了
import {dialog} from 'ui';
中 - 另一个同事定位到了我们的业务组件库中(ui-p)。这里也很重要,但是他介入定位比较晚,不然我们排查速度还能更快一点。
这里其实对于解决问题的帮助不太大。而且我们项目依赖嵌套严重,导致耗时严重。
大胆猜测
在我两次定位之后,我知道这样是无法分析出问题了,然后我给了几个大胆的猜测。
- 没有
externals
,所以载入了新的样式,导致样式权重异常。这里的特征是产物中会有 css 代码 - 有
externals
,所以载入了新的样式,导致样式权重异常。这里的特征是会有明确的require()
- 有地方
import 'ul.css'
- 没有按需引入
在我给出猜测的时候我已经有了预感,就是因为 ui-p
用的是默认主题,并且做了 externals
,加上我们做了异步组件,所以导致主题冲突。
加上另一个同事分析到了在 ui-p
中,所以我们接下来就是验证是否是 ui-p
的问题。
断点调试
是的你没听错,样式也可以“断点调试”。
- 我们在
node_modules
先给dialog.css
加了一行代码body{background: red}
。 - 然后通过
Chrome-Devetools
中的search
来查找到body{background: red}
所在的文件 - 然后对代码进行断点调试
- 之后可以看到堆栈信息,发现堆栈中有
ui-p
控制变量
把所有 ui-p 组件都干掉,发现 dialog 也正常了
解决 ui-p
和主应用主题不同问题
- 升级
ui-p
为theme-p
主题 - 还原
p
为theme-d
主题 - 移除
ui-p
ui-p
做命名空间
各个方案都有问题,我们选择了命名空间。
你以为到这里就结束了吗?并没有,我将做完命名空间的包放入项目中。还!是!有!问!题!
完了,不止一个 ui-p
,接下来就重复上述的操作咯。
但是这次排查出来结果比较离谱,显示是 common.js 载入。这使我怀疑上了另一个位置 splitChunks
异常
修改 splitChunks
策略
因为使用了 all
所以导致 async
和 initial
被合并了。这个使用 initial
其实会异常的大,因为里面有 async
的代码.
所以我们只需要改成 initial
重新编译即可。✿✿ヽ(°▽°)ノ✿ 成功了,我果然是最靓的仔。
这个时候成功条件变为了两个,那我们需要看看是不是只是 splitChunks 的问题,万幸的是必须两个都完成,才可以解决问题(我的时间没有浪费 🐶)
复盘
- 做命名空间是必须的
splitChunks
应该不是必须的,只不过 dialog 并不在我的 async 中,所以我是正常的。- 排查方法还需要继续调研。上述方案比较低效
还有什么方法可以查看引入 css 的地方嘛?
这里问了几个同事,但是大家并没有做过,也希望知道的老铁可以留言哈
- webpack 是否可以?
- babel 是否可以?
- cli 的 --report 是否可以?
- 控制台的断点调试是否可以?
- 压缩前的代码是否有一些描述?
externals
,这是我能想到的一个位置。- 默认的会把代码包含在产物中
externals
会变成require()
语句。
externals 排查
yarn build --target lib --name myLib --report
通过把调整构建目标,打出了 lib 版本的资源,的确是查到了。
但是看到之后我迷糊了,因为又是 ui-p
。这里我就彻底蒙了,因为我们项目是 monorepo
的,所以我在想是不是依赖的问题,但是我最后还是没找到问题点。
项目&截图
我把我在群里的汇报截图贴过来,感兴趣可以看一下,项目的话暂时不提供复现 demo 了。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。