1. 介绍
同步下和平赛场相关优化,包括工程、性能、用户体验等方面。业务价值包括:
- 项目稳定,源源不断需求发布的情况下,现网bug数目由之前 >=4 降到 <= 1
- 性能提升,横版首屏由之前 3600ms+ 降到 2200ms
- 代码更健壮,代码规范问题 1000+ 降到 0
- 用户体验更流畅、顺滑
2. 工程
工程相关的包括提高代码质量、全量使用 tailwindcss
、横版升级等。
这方面的业务价值就是提升了业务稳定性,相比之前,现网缺陷少了很多,代码质量上也有了提升。比起性能,工程上不好用数字表示,但个人感觉这个更重要,尤其是重构过大大小小的x山之后。
2.1. 代码质量
和平赛场很大一部分前端工作都交给了外部开发者,如何保证他们的代码质量是关键。
目前采取了以下手段:
- 任务分配上
- 分出去的都是相对简单的、非核心主流程的
- 有明确的技术方案和实现路径
- 尽量是业务中已有类似的代码,照猫画虎就能完成的
- 加强代码审查
- 代码提测前CR一次,合主干前再CR一次,复杂点的需求两三天就要CR一次,再复杂的不会交出去
- 这里的CR节奏与其他项目并不完全一样,其他项目可能只CR到主干一次,很多问题发现不了。和平赛场这里还是继续坚持更频繁的CR
- 核心目的是尽早发现完题、尽早解决问题
- 充分利用工具
- 工具是最客观的、不知疲倦的、最高效的
- 支持保存文件自动格式化,新增代码提交前格式化检查
- 开发了 MR Lint 工具、定时全量 Lint 工具
- 引入了
import/order
、tailwindcss/classnames-order
等更严格的规则 - 工具 + 人治结合,保证代码质量、代码统一性
- 核心代码物理隔离
- 历史规律看,只有物理隔离才能保证代码稳定可靠,否则他们一定会入侵他们可以接触到的代码(时间早晚问题),分分钟给你搞乱,而涉及大量文件的CR你可能根本关注不到
- 和平赛场的核心逻辑、核心组件都沉淀到
Press Next
中,Press Next
比业务库代码要求更严格(如 TS 开启严格模式),且有单独的CR和发布管理
- 提供常用组件、常用逻辑的使用方式指引
- 严格遵守流程
- 遵守开发、自测、测试、预发布、正式发布、现网验证等流程
- 现网发布必审批,组件库发布必审批
通过以上方法,尽量让代码可控,避免发现问题太晚。


对代码规范的理解:
- 自洽,自己配的规则自己要遵守,不要满屏飘红
- 统一,用一致的方式解决同一类问题,即便后面升级也方便脚本统一处理
- 安全,ESLint 中的一些规则可以提前发现问题,比如
no-undef
、no-dupe-class-members
、vue/no-lone-template
,另一个方面,合并代码时冲突也大大减少 - 效率,利用好工具可以提升开发效率
2.2. tailwindcss
tailwindcss
是CSS原子化的工具。
为什么用 tailwindcss
?官网给了几个理由:

对于我们项目而言,还有更深层次的原因:
- 由于前端开发与UI开发分离,许多时候前端删掉了某些DOM结构,却不知道删掉对应的样式文件,造成性能问题
- 类名写的很乱,即便一个按钮也有无数种写法,难以维护。用
tailwindcss
之后,大部分情况下只有一个标准答案,会限制开发人员的“胡乱发挥” - 更重要的,更易沉淀,更易抽离,尤其是相对复杂的组件,也对应上面提到的核心代码隔离
对于有些人认为的 tailwindcss
会让模板变成很长,造成难以维护。我是这样看待的:
- 写的太少,不了解
tailwindcss
,对于不熟的东西有天然的恐惧 - 没有规范,我这边的项目要求
tailwindcss
的类名一行一个,并增加ESLint
的排序校验,保证所有人写出来的都一样 - 不懂数据驱动,如果发现完全一模一样的很长的类名,是不是忘记了
v-for

个人对 tailwindcss
的理解:
- 用工具帮开发者完成书写CSS,这个工具是无数测试用例、无数线上项目验证过的
- 简单、高效,让简单的事情回归简单
社区内使用 tailwindcss
或者其他原子化 CSS 的项目很多,比如 github.com
、x.com
,证明了它的成熟性。
为什么不用 unocss
?主要是考虑是社区生态和活跃度,tailwindcss
生态链更成熟。unocss
那点编译速度的提升不足以弥补它在生态的不足、以及生产环境的不确定性。
2.3. 横版项目 Vue3 升级
横版项目之前还是 Vue2,并且还有一些其他问题:
- 大量冗余的CSS,性能差
- 大量全局样式,影响新增组件表现
- 大常量文件放到项目里,没有异步加载,性能差
这里优化成了 Vue3 + Typescript,并解决了上面的问题。Typescript
带来的质量提升是巨大的,体会不到的人可能是一直使用了隐式 any
。
2.4. 其他
- 将
press-gp-dialog
、press-toast
等组件的dom
内嵌在global-component
中,这样每个页面只需要注入一个全局组件即可。同时,在main.ts
中增加了这些组件调用时的默认selector
。好处是,降低开发成本,减少犯错。 - 开发了插件,检查循环依赖、子包引用主包等引用错误问题,避免潜在的错误

3. 性能
横版由于升级了 Vue3,去掉了冗余样式,性能有比较大的提升,由 3600ms+
提升到了 2200ms
左右。
之前:

现在:

竖版性能部分其实做了很多工作,不过都被不停增长的需求、不同增加的代码体积抵消了,当前首屏时间约为 2200ms
左右,在赛事、商家同等量级、同等复杂度的业务中算是较好的。

竖版性能相关优化具体介绍下。
3.1. tim 异步加载
3.1.1. 实现原理
IM 内部使用 tim-js-sdk 和 tim-wx-sdk,分别用于 H5 和小程序。
H5 和 微信小程序均优化成了异步加载。
H5 的异步加载是用了 little-loader
。
微信小程序的异步加载是用了 require.async 语法,并采用 rollup-plugin-copy
将 node_modules
下的 tim-wx-sdk
拷贝到 views/tim-wx
分包中。具体步骤:
- 分包注册
require.async
分包异步加载- 复制三方库对应文件到分包目录
3.1.2. 效果
使用异步加载,微信小程序主包可以减小 0.53M
。
之前:

异步加载之后:

使用异步加载,H5的体积可以减少 170 KB。
之前:

异步加载之后:

3.2. 分享模板异步加载
3.2.1. 当前痛点
- 引入了
jsapi
,体积太大,文件太多,可读性、可维护性太差。本来是非常简单的东西,加载sdk
、调用全局变量即可,现在变得非常麻烦 - 类型缺失,使用、阅读、开发、调试困难
- 多个全局对象
shareObject
、shareUiObject
没有类型 - 分享类别
shareType
没有类型,都是1234
的魔法字符串 - 对外的API,比如
initShare
没有类型
- 多个全局对象
- 最关键的一点,分享根本不是首屏所需资源,不是必要路径,完全可以异步加载
当前 pmd
体积:

把分享重定向到一个伪文件,即去掉分享后的 pmd
体积:

可见分享模块的体积已经达到了 97.49KB
,亟需优化。
光 jsapi
就有 58.34KB
。

3.2.2. 优化思路
- 去掉
jsapi
- 补充类型提示
- 封装异步加载逻辑,业务不关心
其他:
Toast
,Dialog
改为外部传入,方便切换组件库Toast.show
=>showToast
Dialog.confirm
=>showConfirmDialog
toast
和dialog
文案支持自定义postGetMiniProgramOpenLink
改为外部传入,可以充分自定义。传入的时候,就应该封装好参数,share
内部不关心。configWx
改为外部传入,适应任意业务- 支持隐藏任意分享渠道,传入
hideShareType
参数即可,并把之前内部的账号判断移出share
核心逻辑
3.2.3. 效果
减少 85KB
。
之前:

之后:

3.3. 其他
- 开发了
postcss
插件,减少了press-icon-plus
的样式体积15KB
- 将使用
tim
的页面都放到一个分包中
4. 用户体验
除了产品和其他人员提出的用户体验优化之外,前端主动优化了诸多用户体验部分。
4.1. 登录优化
赛事即将开始时,平台会给参赛人员发携带比赛链接的短信。用户点击短信里的链接,会用浏览器打开。没有登录过或者登录失效时候,会展示登录框,点击其中的微信登录时,会弹一个二维码,用户需要截图并用微信扫码打开,步骤太多。
这里优化成了点击微信登录,就直接拉起小程序对应页面。


此外,之前是固定的 scheme
,这里优化成弹出登录框时,判断当前 url
,获取当前的页面、参数等信息,并动态拼接 scheme
,注入到 config
中。让用户跳转到小程序后,打开的就是短信里的链接,无需再次点击。
下图是这一优化上线后,小程序的访问次数对比。

4.2. 页面切换增加切换效果
就是在页面切换时增加动画效果。左边是使用之前,右边是使用之后。使用后有切换动画,提升了流畅感。


核心原理是借助了 router
的 beforeEach
和 afterEach
钩子,在路由跳转前后改变顶层类名,进而增加 translateX
相关动画。


4.3. PC 端展示优化
背景是 H5 用电脑浏览器打开时,会变形,宽高都会被拉长。现在优化成了在 PC 打开时,依然保持 H5 的样式。
效果对比如下,之前:

之后:

原理为,在 PC 端打开一个 iframe
,其宽高是手机的尺寸,其路径是想要打开的页面路径。
当发现是在PC打开,且不在白名单内时,就跳转到 /web-container?path=xxx
的路由,xxx
就是之前的 window.location.href
。
web-container
页面内是一个 iframe
,会拿到页面的 query.path
,将其作为 iframe
的 src
。
当子应用页面跳转时,调用 window.parent.history.replaceState
,更新 query.path
,这样刷新页面,不会跳转到其他地方。
当发现是手机浏览器打开时,且当前是 web-container
模式,就 router.replace
到真正的页面,即去掉子应用。

4.4. 其他
- 支持兜底路由(404页面重定向到首页)
- 跳转二级页面时,携带已有的信息并展示
- 核心页面增加骨架屏
- 通用 popup-container 关闭区域扩大
- 部分按钮、图标的
active
点击效果 - 赛事统计数字的 rollingText 动效
- 切换
tab
后,更新query
,页面刷新后可以记录位置
5. 总结
和平赛场采取了一系列措施,保证代码质量,并优化了性能和用户体验,后面会继续加强、持续优化。
上面提到的很多点,影响方面并非只有一个,比如使用 tailwindcss
,不止在工程上提升了效率,也防止了CSS的膨胀,提升了性能。
另外,上面的优化措施都有单独封装、沉淀,实际上已有不少其他项目已接入,欢迎有想法的找我交流。