Hexo 构建失败排查: 缓存没清干净, 换个 Node 版本就报错的两个坑
前言
写 Hexo 文章多了之后, 会遇到一个共同的问题: 报错信息看不出到底哪里错了。
比如 hexo s 突然起不来, 或者构建出来的东西和预期不一样。网上的解决办法五花八门, 试一圈下来问题还在。
这篇不讲具体某个错误的怎么修, 而是讲一套固定的排查顺序 —— 先排除掉最常见、最容易被忽略的原因, 再往深处查。按这个顺序走, 大部分问题在第 1、2 步就能定位。
排查总览
先给个全貌, 后面逐条展开:
| 步骤 | 做什么 | 能解决什么 |
|---|---|---|
| 1 | 清干净缓存重装 | 依赖版本残留、node_modules 脏了 |
| 2 | 查依赖树找冲突源 | ERR_REQUIRE_ESM、模块找不到 |
| 3 | 换 Node 版本验证 | 版本错配导致的诡异报错 |
| 4 | 排除插件影响 | 某个插件引发的连锁错误 |
| 5 | 才动配置 | 真正的配置问题 |
顺序很重要。大部分人一开始就去改配置, 结果改了半天, 其实是缓存脏了。
第一步: 清干净缓存重装
为什么必须先做这步
Node 生态有个很坑的地方: 改了配置但不重装, 行为不会变。
node_modules 里装的是旧版本, 缓存里存的是旧的中间结果。这两个不清掉, 你后面所有的排查都是在验证一个错误的环境。
而且如果你之前在 Node 18 下装过依赖, 现在换到 Node 20, 那些原生模块(native module)是按旧版本编译的, 直接拿来用大概率出问题。
标准操作
1 | # 1. 清缓存和生成产物 |
注意 package-lock.json 也要删。它的作用是锁定依赖版本, 但如果你要解决的问题正是”依赖版本不对”, 那这份锁定文件就是问题的固化 —— 必须删掉让它重新解析。
判断: 这步有没有用
做完这一步就好了, 说明问题出在依赖残留。以后遇到构建问题, 直接从这步开始, 能省很多时间。
第二步: 查依赖树找冲突源
如果第一步做完还是报错, 说明是真实的依赖冲突, 得往下查。
找出某个包到底装了几个版本
这是排查依赖冲突最有用的一条命令:
1 | npm ls strip-ansi |
输出会明确告诉你哪些包依赖了它、装的是什么版本:
1 | zsyyblog@ |
看到同一个包同时存在 7.x 和 6.x, 就知道问题在哪了。
ERR_REQUIRE_ESM 怎么定位
如果报这个错:
1 | Error [ERR_REQUIRE_ESM]: require() of ES Module ... not supported |
排查步骤:
1 | # 1. 看报错里的路径, 记下具体是哪个包 |
关键看 "type" 字段:
"type": "module"—— ESM, 不能被require()- 没有
"type"或"type": "commonjs"—— CommonJS, 可以被require()
解决办法: 强制降级传递依赖
如果确认是某个包的新版本把老插件搞崩了, 在项目根目录强制装一个旧版本:
1 | npm install <包名>@<兼容版本> --save-exact |
--save-exact 会把版本号精确锁定(不带 ^), 这样它会作为直接依赖被放在项目根目录, 所有传递依赖都会优先找到它。
Hexo 升级时最常见的组合是:
1 | npm install strip-ansi@6.0.1 --save-exact |
第三步: 换 Node 版本验证
为什么换版本能定位问题
有些报错很奇怪, 同一个代码在 A 机器上正常, 在 B 机器上就炸。这类问题九成是 Node 版本差异。
Hexo 各版本对 Node 的要求:
| Hexo 版本 | Node.js 最低要求 |
|---|---|
| 6.2+ | 12.13.0 |
| 7.0+ | 14.0.0 |
| 7.x 实际推荐 | 18.0.0 |
| 8.0+ | 20.19.0 |
如果你的 Hexo 8 项目跑在 Node 18 上, 很多报错都是版本不对导致的, 而不是配置错误。
用 nvm 管理版本
安装 nvm:
1 | # Linux / macOS |
常用命令:
1 | nvm install 20 # 安装 Node 20 |
Windows 上推荐用 fnm, 体验和 nvm 一致。
换版本后必须重装依赖
这是最容易漏的一步:
1 | nvm use 20 |
因为原生模块是针对特定 Node 版本编译的, 换了 Node 不重装, 大概率会报 NODE_MODULE_VERSION 不匹配。
判断: 是不是版本问题
做法很简单: 换到另一个 Node 大版本, 重新完整安装, 看问题是否消失。
- 消失 → 确定是版本问题, 把版本固定下来
- 还在 → 版本不是主因, 继续第四步
把版本固定下来
确认可用后, 在 package.json 里声明, 避免以后重装又变:
1 | { |
装了 nvm 的话, 还可以配一个 .nvmrc 文件, 内容就是版本号:
1 | echo "22" > .nvmrc |
第四步: 排除插件影响
前三步做完还报错, 大概率是某个插件的问题。
二分法定位
最朴素但最有效的办法: 逐个禁用插件。
先在 package.json 里把可疑插件注释掉, 重新安装构建:
1 | # 禁用后重装 |
如果好了, 就是这个插件的问题。再装回来。
更快的办法: 看报错来源
多数情况下报错信息本身就指向了来源, 比如:
1 | Error: Cannot read properties of undefined (reading 'cover') |
1 | npm ls <报错里的包名> |
1 | # 直接在源码里搜 |
临时绕过
如果确认是插件 bug 但急着发文章, 可以用垫片绕过, 而不是改插件源码。
比如老插件调用的全局函数在新版里被搬走了:
1 | // 在 _config.butterfly.yml 的 inject.head 里加 |
用 || 做存在性判断, 这样即使主题以后又把函数放回去了, 这段代码也不会冲突。
第五步: 动配置
到这一步基本可以确定是配置问题了。
Hexo 配置的排查要点:
配置层级要看清
Hexo 的配置有主题配置和站点配置两套, 同时还存在 _config.yml(站点)和 _config.butterfly.yml(主题)的区别。
常见误区: 把站点配置写到了主题配置里, 或者反过来。先确认你改的文件是哪个。
缩进和类型
YAML 对缩进敏感, 这几个错误很常见:
1 | # 错: tab 缩进(YAML 不支持 tab) |
插件的配置节点可能缺失
老插件升级后, 配置格式可能变了。报错里出现 undefined 时, 优先怀疑配置节点缺失。
一个通用的排查习惯
最后说一个我觉得最有用的习惯 —— 每次排查都记录下来。
我自己的做法是, 每解决一个新报错, 就写成一篇博客:
- 报错现象是什么
- 根因是什么
- 怎么解决的
- 参考链接
这样做有三个好处:
- 下次遇到同类问题, 直接搜自己的文章, 不用重新推导
- 一年后回头看, 这些文章正好是最有搜索价值的踩坑记录
- 排查过程被迫理清一遍, 记忆反而更牢
排查本身是隐性的, 写出来才是显性的知识。
小结
一套固定的排查顺序, 记住这五步:
- 清缓存重装 —— 排除依赖残留(最常见)
- 查依赖树 ——
npm ls <包名>找冲突源(第二常见) - 换 Node 版本 —— 排除版本错配
- 排除插件 —— 二分法禁用 + 看报错来源
- 最后动配置 —— YAML 缩进、类型、节点缺失
核心原则: 从最常见的原因查起, 不要一上来就改配置。
绝大多数构建问题在第 1、2 步就解决了, 而大部分人恰恰是从第 5 步开始的 —— 于是改了半天配置, 问题根本不在那里。
参考链接:
💡 准备购买云服务器 / 域名来搭建或部署站点?
通过下面的链接下单,通常能领到新用户专属优惠,也能小额支持本站持续更新:
阿里云(返现) |
腾讯云 2核2G 99元/年 |
腾讯云 云产品特惠












