Photo by Alex Kubsch on Unsplash

雪猫社从来都少不了折腾。

先是雪先生要求加的表情包FacePack,然后又为了精确统计浏览量连了GA桑的API。之后,因为小图片不能放大看,又加了点击放大图片(Sakurairo里面更喜欢叫灯箱)的simple-img-modal,还为了显示EXIF加了EXIF读取功能。而驱动这些的,自然是前端脚本。

React,命运之选

最开始雪猫社的这些附加组件都使用了React作为框架,现在回头看,这并不是一个很匹配我们的使用场景的选择,最直接地体现在React框架给我们带来的重达100kb的额外脚本上。这个大小的脚本会严重地拖慢我们的脚本解析速度,带来性能影响。但其实这也是当时无奈的折中之选:与React 16.x同期的Vue 2.6.x 包大小也要90多近100KB,虽然比React可能小20/30k左右,但是我对Vue的响应式方案和Vue 2的组件形式都不是特别地感冒,对Vue一个框架全包的理念很不认同。Angular?嗯,感觉这个包会更重。何况之前在motdeditor这个项目上已经有了React这个框架上进行开发的经验(同时这也是学习现代前端体系的第一个框架)

为了尽量减小React的包大小带来的影响,最主要的尝试就是把React外置。当时也是意外地发现WordPress的古腾堡编辑器使用了React。这样只要用户曾经在雪猫社打开过后台编辑器,就能复用这份缓存脚本。(虽然这样的用户很明显并不多)所以我们后面是覆盖了WordPress内的React包,改为了从jsDelivr引入。至于效果嘛,到底有多少人从jsd引入React呢? 唔,希望雪猫社访客中有已经从某些地方下载了React UMD包的吧!:pcr.一切都会好起来的:

脱离了外置依赖后,我们得到了60kb (minified)左右的包(FacePack+pageview,图片点击放大因为还捆了个exifreader所以大小不是很具有参考性)。说实话感觉还是挺大的(?要知道Sakurairo的entry point优化以后只有47.89k,而它的功能可不止FacePack和pageview(统计浏览量的组件的名字)。:yukicat.嘉然_挠头:

SolidJS:时代变了,大人。

时间到了2022年,两个崭新的库进入了我的视野:SolidJS和Svelte。这两个库常被一起提及,因为他们都通过编译期优化,抛弃了VDOM,做到了很轻的包体大小和更高的运行性能。SolidJS更被认为是“教React做hook”。SolidJS的渲染函数只会运行一次,通过响应式编程设计,精确地进行DOM修改,这都使SolidJS能够到达更高的性能。虽然,根据网上前辈的探索,在少量组件的项目上,Svelte能得到同比更小的包。然而考虑到SolidJS同样也使用JSX语法,并且有类似于React的数据流模式与API,迁移成本相比更低,因此最终还是欣然选择了SolidJS作为新的框架。

作为试点,我首先给FacePack和pageview做了重写。

SolidJS和React的API设计理念有所不同。React的API力求简洁,只公开了几个高阶的函数,而SolidJS开放了不少相较底层的API。例如createComputed、createEffect、createMemo,它们大体很像,但是却有很多细微的区别。SolidJS的组件的prop、派生状态的写法也需要耗费时间理解。组件的prop因为加了get(),所以不能采取解构的写法,必须得用它提供的工具函数来处理。派生状态还有Signal独特的读取值的方式带来的变化就是不能在函数体里面提前把值取出来。结果就是JSX模板里面会写满了函数调用。所以我个人感觉相比下来,React hook还是蛮易学的。

然而,当你需要在组件间共享状态时,你就会发现:我超,Signal这么好用,createSignal()它居然能在组件外使用!!哪里想用这个signal,直接import进来就行了。我一开始还装了个nanostores做全局状态管理,写着写着发现,哪还要什么状态管理,直接两个signal解决所有问题,代码还比nanostores好看。

重写后的包大小也是60多k,看起来没有变化,但是要知道,这个60KB的包里面可是包含了20KB左右的SolidJS runtime的。也就是说,组件部分在我做了重写,以及将JS部分迁移到SolidJS后,比React编写的还少了20KB。:parrots.twins:真的是特别令人惊奇的成绩。不过也有可能是我drop了swr(≈10KB minified)并用floating-ui替换了popper导致的。但是不管怎么说,100KB的React全家桶是真的拿掉了,同时这次重写还顺手修掉了pageview的一些小问题,现在打开主页感觉各种意义上的畅快。:yukicat.嘉然_冲拳:

前端圈风风雨雨,浪涌不息。也许两年后,我们又会和SolidJS说再见呢?