Butterfly 5.2 升级到 5.7: getScript 找不到, 说说组件加载不出来怎么解
前言
上一篇文章写了 Hexo 7 → 8 的升级, 这次接着记录 Butterfly 主题的升级。
本地是 5.2.2, 当前最新是 5.7.0。中间跨了 5.3、5.4、5.5、5.6、5.7 五个版本, 官方更新日志里有大量性能优化和 bug 修复, 值得升级。
但升级过程中踩到了几个坑, 其中一个是跨大版本的破坏性变更, 老插件直接罢工。这篇把过程和解决办法记下来。
先看升级收益
翻了一遍 5.6 的更新日志, 对博客体验提升比较明显的有这些:
- TOC 目录滚动从 throttle 轮询换成 IntersectionObserver, 大幅减少滚动事件的计算量
- 滚动处理器换成
btf.rafThrottle, 跟随浏览器渲染帧率 - 平滑滚动从线性插值改成 easeOutQuart 缓动, 观感更自然
- 新增
scriptCache/cssCache机制, 防止脚本和样式重复加载 - Mermaid 手势系统用 AbortController 重写, 修复了 Chrome 下滚动图表乱跳
- 修复
flink.js和button.js缺少 HTML 转义导致的 XSS 漏洞
性能优化是实打实的, 文章多了之后尤其明显。
障碍一: ReferenceError: getScript is not defined
这是最典型的报错, 说说组件加载不出来(比如”说说”模块)。
报错现象
1 | ReferenceError: getScript is not defined |
页面上对应组件的位置空白, 控制台一片红。
根因: 全局函数搬进了命名空间
Butterfly 3.x 时代, getScript 是直接挂在 window 上的:
1 | window.getScript = ... |
所以任何地方都能直接调。
从 5.x 开始, 这类函数被收进了 window.btf 命名空间:
1 | window.btf.getScript = ... |
而我用的那个第三方插件(信封/说说相关), 它注入的内联脚本里调的还是裸函数:
1 | getScript('/js/xxx.js', callback) |
这个裸调用现在自然就找不到了。
解决办法: 加一段惰性垫片
不想改插件源码的话, 可以在 inject.head 里加一段垫片代码。关键在于”惰性” —— 调用的时候才去取 btf, 这样就不依赖脚本的加载顺序:
1 | window.getScript = window.getScript || function(u, a) { |
六行代码, 一个插件都不用改。
具体做法是在 _config.butterfly.yml 的 inject.head 下面加:
1 | inject: |
这个思路挺通用的 —— 遇到”全局函数搬家”导致的报错, 都可以用同样的方式兜一层。
障碍二: 构建直接崩, 报 cover undefined
报错现象
1 | TypeError: Cannot read properties of undefined (reading 'cover') |
hexo g 直接中止, 构建不出来。
根因: 插件配置节点缺失
hexo-butterfly-envelope 从 1.0.13+ 开始, 把四张图片收进了 custom_pic 这个子节点里, 而代码内部不做任何存在性检查就往下读。
我的旧配置里没有这一节, 于是读 undefined.custom_pic, 构建直接崩。
解决办法: 补齐配置节点
按插件要求补上配置就行:
1 | envelope: |
补的时候顺手发现, 它的默认值还指向一个已经废弃的镜像地址, 一并改成了自己的图床。
教训: 老插件升级后如果直接崩, 先去看它的 changelog, 大概率是配置格式变了。
障碍三: unknown block tag: timenode
报错现象
1 | ERROR Failed to render tag: unknown block tag: timenode |
文章渲染失败, 但不是全部文章, 只有用了特定标签的那几篇。
根因: 同名标签, 少注册了一个
Butterfly 5 自己带了一个 timeline 标签, 但只注册了这一个。
而我用的第三方版本除了 timeline, 还注册了 timenode。我的文章里用了 30 次 timenode, 于是就报错了。
解决办法: 保留第三方版本
让第三方的标签插件覆盖官方的, 这样两个标签都能用。
这个问题的本质是同名标签的注册冲突 —— 如果你升级后遇到”某个标签突然不认识了”, 先想想是不是两个插件抢同一个标签名。
升级前: 先验证挂载点
这次升级前我做了件事, 差点白做。
我原本的判断是: 跨 5 个版本, 那些插件依赖的模板挂载点肯定早被删了, 升级必然失败。
于是我把 5.7.0 的包解开, 直接 grep 那几个挂载点:
1 | # 解包后 grep 挂载点 |
结果如下:
| 挂载点 | 3.7.1 | 5.7.0 |
|---|---|---|
| recent-posts | 5 个布局文件 | 6 个 |
| sticky_layout | 1 | 1 |
| aside-content | 1 | 1 |
| card-widget | 11 | 13 |
四个挂载点在新版里一个不少, 而且 card-widget 还多了 2 个。
所以我那条”最重的理由”—— 证据不支持。改口之后, 升级才真正开始。
这一步花的时间不长, 但避免了”因为一个不成立的判断而放弃升级”。预感值得说出来, 但只有证据能定案。
完整升级流程
1 | # 1. 备份 + Git 基线 |
建议的版本锁定
升级完记得把版本锁进 package.json, 避免以后重装得到不同环境:
1 | { |
小结
这次跨越 5 个小版本, 全过程只撞到 3 个真实障碍, 比预期少很多:
getScript搬家 —— 用惰性垫片兜住, 不改插件源码- 配置节点缺失 —— 补配置即可
- 同名标签冲突 —— 让第三方版本覆盖官方
三个问题的共同点是: **都不是主题本身的 bug, 而是”老插件跟不上新主题”**。
所以升级前做的那件事 —— grep 挂载点验证 —— 比事后一个一个试错要高效得多。
参考链接:
💡 准备购买云服务器 / 域名来搭建或部署站点?
通过下面的链接下单,通常能领到新用户专属优惠,也能小额支持本站持续更新:
阿里云(返现) |
腾讯云 2核2G 99元/年 |
腾讯云 云产品特惠












