halo,大家好,我是 132,今天给大家打来一篇关于c站重构的总结文章
c站是去年成立的弹幕网站,今年暑假流量暴增,如今已经是【中国第三弹幕网站】了
c站所有代码开源,涉及到很多语言和技术栈,除了一些业务层面的最佳实践,还有一些业务轮子,如 celty,eplayer 等都是来自 c站 的积累产出
毫不夸张的说,这种开源力度,业界找不到任何一家网站啦
c站 github 地址: github.com/cliclitv
shi 就一个字,shi 山就两个字,c站经过一年半的业务积累,中间不断的删减需求,导致 shi 山已经很高
加上流量暴涨,导致 vue ssr 性能瓶颈越发明显
长时间的需求总结,pc 主站扮演的角色与以前大不相同,我们发现大部分用户还是移动端为主,pc 端应该尽可能的减少维护量,但应该更具品牌性
是的你没有看错,减少维护量是重构的重中之重,我们最大程度的删除了主站的需求,最终首页只保留五个模块,内页只保留视频播放和弹幕,去掉搜索页,个人页,ugc页等页面
与此同时,隔壁b站更不断地增加需求:漫画,轻小说,音频,英雄联盟……
pc 端的职能虽然变少了,但是它仍然是非常重要的角色没有之一,我们还叫它——主站
它更多的是用来担当【c站】这一品牌的,我们和其他网站一样,确立了c站品牌色
emmm 就是那个,基佬。紫。
因为其他颜色都被用了,蓝(b站),红(a站),绿(爱奇艺),黄(太阿里)……
所以我们使用了基佬紫,也确定了性向:女性向
总得来说,这次重构,也正式宣告我们和b站的不同:
因为 pc 主站变得小而美了,代码也会变得超级小而美,哈哈,以下:
首先,就应该使用小而美的前端框架,fre,哈哈哈
这可能是 c站的一个优势,就是有自己出品的前端框架,这在其他网站是很少有的,这样的好处就是我们真的可以做的 0 依赖,0 第三方库
fre 是我写的纯 hooks 的 react-like 前端框架,它只有 600 行,却复现了 react Fiber 架构(Concurrent 和 Suspense),它拥有相同的 hooks API 的表现,但它也有一些不同:
由于 fre 经过一年的迭代,它几乎所有行为都是可预测的,测试覆盖率 90+
github 地址: github.com/yisar/fre
已经是时候用在生产环境啦,积累一些业务 bug
这是我在业务中遇到的第一个坑,什么意思呢?
如果 A 和 B 两个组件,同时 setState,同时更新组件的话,那 fre 应该将 A 和 B 放到一个队列里,更新完 A 然后更新 B
如果 A 同步 setState 两次,则 A 只能进入队列一次,批量进行更新
以上,是异步更新队列的两条规则,这在 fre 之前是没有的,直到写了 c站,才暴露出来
偏偏还很重要,所以啊,有时候测试未必可信,业务才是大千世界
有如下代码:
function App () { const [state, setState] = useState(0) return ( <div> {state} <A count={1}/> <button onClick={() => setState(state+1)}>+</button> </div> ) } function A(props){ const [state] = useState(new Array(100000)) return <div>{props.count}</div> } 复制代码
以上代码,重点在于,A 组件初始化了一个 10000 的数组,只要 App 组件 rerender 那么 A 组件一定会 rerender,每次 rerender 都会初始化一个长度很大的数组,偏偏其实 rerender 的时候又用不到
这就引来了一个重复渲染的问题
这也是 vuer 一直黑 react 的地方
我觉得吧,很少有人会在这次 rerender 里面写大量 hook,所以其实从优化角度,可能不明显
但是我看了 vue-next 的源码,发现只是内置了 shouldComponentUpdate 而已,这对我而言非常简单,所以我也实现了一个
目的嘛,能减少一点算一点吧,同时以后不用被黑了,哈哈哈
以上,是关于 fre 在这次 c站业务中的一些重构
use-routes 是我当时为了 hooks 写的前端路由,hooks 说起来好奇怪,一直没有一个广泛流传的路由,虽然有 wouter 这种新星,但是其实国内用的还是少
import { h, render } from 'fre' import { useRoutes, push } from 'use-routes' const routes = { '/': () => ( <div> <p>home</p> <button onClick={() => push('/home/jack')}>Go jack</button> </div> ), '/home/:id': ({ id }) => ( <div> <p>{id}</p> <button onClick={() => push('/')}>Go home</button> </div> ), } const App = () => useRoutes(routes) render(<App />, document.getElementById('root')) 复制代码
use-routes github 地址: github.com/frejs/use-r…
为什么我要用 use-routes 而不是 wouter 呢?
首先,我写 use-routes 的适合,wouter 还没出现,然后,其实很大的一个原因是,fre 没有 context stack,而 wouter 依赖了它
这一点其实很重要,context stack 是 react 很冗余的一部分,虽然它不适合 hooks,但是其实它被用到很多地方
这应该是 fre2 要搞的,立个 flag 先
ep 是c站御用播放器,它很好看,这次重构的同时,也对他进行了更改
将默认配色改为基佬紫,哈哈哈
其实一开始打算使用 vue3 的,但是 vue3 现在真的没法用,我一边改代码一边用都非常痛苦
原因是没有 vue-loader,而 vue 对 jsx 支持太简陋了,我还提了 pr,结果他们说他们有自己的 jsx 解析器
然后就是 celty 了
这最初也是我为了搞定 hooks 路由问题,而写的微前端原型框架,但是感觉不太好搞,先弃坑吧
最后放一下截图哈
其实总结的话,其实这次的业务代码很少,很快就写完了
但是对于 fre 来说,因为这次业务重构,fre 重构的也真的不小
测试用例也全部重新写了::>_<::感谢在这个过程中提供帮助的小伙伴啦!