博客装修记:再见了,所有的 jQuery
国庆假期即将结束,回想起来以前中学(尤其是高中)时候,总是会有老师在群里发通知说『假期结束,是时候收心了,回校当天检查所有作业,并进行月考』之类很恐怖的话。现在大学了,这种东西已经消失,当然也舒服很多。
人一高兴起来,就想折腾点什么。正好,早就看这个博客主题要加载的东西不太顺眼了,就看个页面而已,又是jQuery又是Bootstrap的,因此趁着这个机会,直接把它删掉算了。
改造结果:特别舒适,总加载量至少少了100KB1. 前言
博客所用的主题是Waxy,具体来说,是以2020.11.23版本(建站时能用到的最新版)作为基础,对其进行了二次修改,添加了自己所需要的功能,比如每日推荐,以及指向枫林书屋最新更新章节的卡片,都是原主题所没有的。
这个版本的Waxy上面不少功能,比如说图片灯箱,图片懒加载,等等,都依赖了第三方库。而这些第三方库(以及主题本体)都依赖了jQuery和Bootstrap。于是这就引入了两个问题:jQuery曾经爆出来几次CVE,虽然可能无关,但总是心里有些发毛;Bootstrap(这里指js)则是在大马拉小车,加载了一整个文件,实际调用到的只有寥寥几个方法,完全就是在浪费流量。所以,一直想找机会把这些依赖清理一遍,减少攻击面的同时也省流量。
这个主题在2020年有过几次更新之后,除了中途修一次Bug,就一直沉寂着,直到几个月前,才有了后续更新。这次跨越六年的大更带来了很多好处,比如作者重写了代码,扔掉了对jQuery和Bootstrap的依赖,然而作者也重写了样式,整个页面大变样,这样一来就不是很喜欢了,而且我也不想贸然更换样式(反面例子就是B站,几年搞一次样式修改,每次都要重新习惯)。于是这才下定决定,不再跟随上游更新,直接按照目前的版本继续改下去算了。
2. 动手
要是放在以前,估计没什么动力来整这活,然而前几天DeepSeek搞活动,安装并登录DSH Desktop就可以领六块钱赛博鸡蛋,有效期七天,不限用途。照做之后,果然领到了:
那可是六块钱啊白送的鸡蛋,再加上国庆节期间全天谷价,DS V41F便宜得要死,那当然是直接蹬起来了。
2.1 评估与方案
前期其实人工排查过,这个主题对于Bootstrap的依赖还是挺深的,对jQuery的依赖也较为分散。考虑到毕竟这是要公开发布的,因此不太敢让他直接动手改,而是先出文档,人工审阅后再动手。对于大项目来说,估计这也是一个好习惯,至少能省一点事后排查的麻烦。
spec没有什么硬性格式要求,写清楚就好根据DS给出来的评估调查来看,主题的实际情况和我想象的差不多:引入的第三方库里头,很多都属于『引入一个库但只使用了一小部分功能』,比如说jQuery全主题仅20处调用、Bootstrap.js仅用到2个组件,然而每次加载页面都要全量加载这两个库。甚至,还发现很神奇的情况:主题在调用一个clipboard.min.js库,但实际上并没有任何地方在使用!推测可能是早期Prism.js(代码高亮)的复制功能需要外挂此库,但现在已经没有必要了,依赖项却一直存在。这两个情况,也正好印证了上面提到的浪费流量问题。
当时这么设计,可能是为了开发的便利,毕竟前端库的存在自然有他的道理,不论是优雅降级还是拿来就用的趁手工具。但现在已经是6202年了,很多功能已经可以通过原生js来实现,所以也没必要再拖着这么大一个库了。因为这个修改版主题只有笔者一个人用,未来要加什么功能心里都有数,所以更好的解决方案是,直接用原生js重写所需功能,同时保持一定的优雅降级:例如,在js未启用的时候,图片灯箱会自动降级到『点击图片就跳转到图片文件』功能,不影响阅读。
还有一些零零碎碎的情况,也在调查中一并被发现,最后得出来这么一份结论:

有了初步的方案,接下来就是做一些取舍了。
2.2 取舍与决定
原本的计划很直接:去掉jq,也去掉bootstrap。从分析的结果来看,前者问题不大,针对存量调用点用原生js重写,后续加新功能就直接从原生js起步就好;但后者有些问题:注意到上面我的用词特地写出来是Bootstrap.js,这主要是因为Bootstrap分两部分,js和css,前者确实是大马拉小车,但后者不同,在主题里多个部位都有使用,虽然也能通过某种方式重写引用,然后彻底扔掉css,但由于牵一发而动全身的问题不好排查,因此暂时决定保留。
另外还有一个小问题:这个精简版主题显然是不能再继续引用公共CDN上的资源了(毕竟是定制版文件)。不过其实问题不大,因为运行这么久,一直都是从服务器加载,主要是考虑到公共CDN未必能快(Chrome 86/Firefox 85之后,均已经放弃了跨域站点加载同域资源时的缓存复用行为),再加上曾经出现过公共CDN被投毒的案例,因此在自己的站点已经在使用CDN的情况下,没有太大的必要再去追求使用公共CDN。
明确了以上限制与权衡之后,就可以直接动手了。其实也就是一句话的事情,剩下的让DS自己在那跑就是了。趁此机会,顺带到校门口的糖水店去喝了碗糖水,牛奶西米露配芝麻糊汤圆,8块钱,感觉比点外卖便宜(沟槽的外卖收我六块钱配送费,虽然不是不能理解骑手的辛苦,但就这个价格,还不如自己吱嘎吱嘎摇个自行车出去喝算了)。
2.3 部署与排错
最终修改了七个文件,分别是主题中对应引用的模板,以及最后精简出来的js/css文件。其中js内包含重写了的灯箱逻辑和懒加载逻辑,大小32.1KB(压缩后8.3KB),CSS则是合入重写的灯箱外观样式,大小42.1KB(压缩后12.4KB),综合算起来,比原来使用jQuery+Bootstarp的时候节省了至少100KB的传输体积,按目前站点的流量看,一天就能节省约20MB的传输量,虽然不多,也是进步,最主要是代码变得更清爽了,加载往返请求也少了。
接下来就是把修改好的代码部署到服务器上,用SFTP就好,之后去Cloudflare后台清个缓存,舒服。部署之后上去一看,很好啊,点哪哪有反应,样式没有崩坏,看DevTools确实少了传输体积,手机端也没问题。时间已经是晚上十二点,想着核查没问题就去睡觉了,然而就在关闭Chrome前一秒,突然发现了一个问题:我高清图标呢?
正常情况下应该如图所示,出故障时只有最右侧那种图标默认情况下,Chrome会在HTML里面寻找图标标头来作为按钮图标,比如本站的是:
<link rel="icon" href="/favicon.ico" type="image/x-icon" sizes="any"/>
<link rel="icon" type="image/png" sizes="64x64" href="/icon-64.png">
<link rel="icon" type="image/png" sizes="128x128" href="/icon-128.png">
<link rel="icon" type="image/png" sizes="192x192" href="/icon-192.png">在找不到图片的情况下,才会回退到使用分辨率较低的favicon.ico来作为图标。出现图标丢失的情况,就说明,部署上去的版本里,HTML头缺少了这些元素。
这才想起来一个很严重的问题:修改是在本地开发版上改的,和生产环境不同步。生产环境里面有一些修改没有在开发版体现(例如高清图标,注释水印)或者故意被移除(例如GA/Umami统计代码,防盗代码,以及页脚的第三方统计图片).直接覆盖上传的话,上述功能就会一起失效。
幸好,站点一开始就考虑到了这种数据丢失的情况,尤其是年初炸了一次站之后,各种备份措施都大大加强,例如现在,服务器上跑着Restic多后端自动备份呢,直接从本地库导出一份就好:
export RESTIC_REPOSITORY=/path/to/repo
export RESTIC_PASSWORD=密码
restic restore <SNAPSHOT_ID>:/path/to/website --target rt/
cd rt/usr/themes/waxy然后就可以对照着备份,把功能代码都添加回去,重新部署一次,就可以了。
3. 写在最后
这次代码精简有惊无险地完成了,虽然不算大工程,但修改深度较大,所以不确定是否有什么小角落没有覆盖到。如果您在浏览中发现有出错的地方,欢迎在这里反馈,或直接邮件联系,谢谢。
(完)
折腾博客总是从简单到繁杂再到简单