构建排雷指南
博客超过 1000 页后,VuePress v1 原生
npm run build踩坑全记录。
# dev 为什么秒开,build 却总崩
dev build
─── ─────
编译范围 按需(访问哪页编译哪页) 全量(1000+页一次性干完)
SSR渲染 不生成 每页生成服务端 HTML
代码优化 不压缩 压缩/摇树/提取CSS/SourceMap
内存占用 低(几百MB) 高(8GB 都不够)
输出文件 不写磁盘 JSON.stringify(全部内容)
2
3
4
5
6
7
结论:博客体量超过 VuePress v1 原生 build 承载上限,需要工程手段兜底。
# 问题 1:JavaScript heap out of memory
# 现象
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed
# 原因
大量 Markdown 文件被全量加载到内存中编译。两个"大胖子"尤其耗内存:
综合实战图片框架.md(120KB+)JavaScript代码规范.md(95KB+)
Babel 在处理超 500KB 文件时会触发 deoptimised 警告,进一步加剧内存压力。
另外,增强代码(enhanceApp.js 中的安全防护)如果在服务端构建阶段执行(console.log + setInterval),会额外消耗内存。
# 修复
Step 1:package.json 中把 Node 内存上限提到 12GB,并开启 GC 优化:
{
"scripts": {
"build": "export NODE_OPTIONS='--localstorage-file=/tmp/vuepress-localstorage.json --optimize-for-size --max-semi-space-size=64' && node --max_old_space_size=12288 ./node_modules/.bin/vuepress build docs"
}
}
2
3
4
5
| 参数 | 作用 |
|---|---|
--max_old_space_size=12288 | 堆上限 12GB |
--optimize-for-size | V8 编译优化倾向体积而非速度 |
--max-semi-space-size=64 | 限制年轻代空间,触发更频繁的小回收 |
Step 2:每次构建前清理缓存(VuePress 的 .temp 目录不会自动清理):
rm -rf node_modules/.cache docs/.vuepress/.temp node_modules/@vuepress/core/.temp
Step 3:config.ts 中关闭 SourceMap + 限制并行线程 + 启用 evergreen:
// docs/.vuepress/config.ts
module.exports = {
evergreen: true, // 只编译到 ES2015+,砍掉 IE11 polyfill
chainWebpack(config, isServer) {
if (isServer) {
config.plugins.delete('vue-server-renderer-server-plugin')
}
config.devtool(false) // 关闭 SourceMap(省 30% 内存)
config.parallelism(2) // 限制 2 线程(避免 8 核同时编译)
}
}
2
3
4
5
6
7
8
9
10
11
12
Step 4:安全防护代码包进客户端判断,防止 build 阶段执行:
// docs/.vuepress/enhanceApp.js
if (typeof window !== 'undefined') {
// 所有安全防护代码放在这里(console.log / setInterval / copy 拦截等)
}
2
3
4
# 问题 2:SSR 包过大导致 JSON.stringify 溢出
# 现象
RangeError: Invalid string length
at JSON.stringify
at /node_modules/vue-server-renderer/server-plugin.js:139
2
3
# 原因
SSR(服务端渲染)会将 1000+ 页的完整 HTML 全部塞到一个包里,再用 JSON.stringify 序列化。V8 引擎的字符串上限约 256MB,1000 页的渲染后 HTML 轻易怼穿天花板。
# 修复
注意:evergreen: true 单独使用不够,必须同时禁用 SSR。
完整配置:
// docs/.vuepress/config.ts
module.exports = {
// Step 1: 只编译到 ES2015+,减少 polyfill
evergreen: true,
// Step 2: 禁用 SSR 服务端渲染
chainWebpack(config, isServer) {
if (isServer) {
config.plugins.delete('vue-server-renderer-server-plugin')
}
}
}
2
3
4
5
6
7
8
9
10
11
12
代价:首屏 SEO 略差(百度可能抓不到 HTML 内容),但对技术博客影响有限。
# 问题 3:代码块内 SFC 标签被误解析
# 现象
SyntaxError: [@vue/compiler-sfc] Unexpected character '│'. (1:8)
at vue-loader → markdown-loader → docs/17.Apps/03.Web/04.Vue高级进阶/01.基础入门.md
2
# 原因
VuePress 把每个 .md 文件封装成一个 Vue 组件:
<template> <!-- 渲染后的 markdown -->
<script> <!-- 页面逻辑 -->
<style> <!-- 页面样式 -->
2
3
当 markdown 代码围栏里出现 <script>、<template>、<style> 标签时(尤其在 ASCII 绘图中),Vue SFC 编译器会把它们当成组件的第二个 <script> 块来解析,导致语法错乱。
# 修复
用 HTML 实体替换代码围栏内的尖括号标签:
- │ <script setup lang="ts"> │
+ │ <script setup lang="ts"> │
2
同时也适用于 <template> → <template>、</script> → </script> 等。
排查方法:grep 搜索所有 .md 文件中代码围栏内的裸露标签:
grep -n '<script\|</script>\|<template\|</template>\|<style\|</style>' docs/**/*.md
# 问题 4:同级文件编号重复
# 现象
warning: 该文件 "xxx.md" 的序号在同一级别中重复出现,将会被覆盖
# 原因
Vdoing 主题要求同目录下文件编号(NN. 前缀)必须唯一。如果有两个 01. 开头的文件,后一个会覆盖前一个。
# 修复
检查该目录,合并或重命名重复编号的文件:
# 示例:发现两个 01. 前缀文件
01.面试准备.md # 占位符
01.面试问题集锦.md # 257行实文
# 修复:合并内容,保留唯一编号
mv 01.面试问题集锦.md 01.面试准备.md
2
3
4
5
6
# 完整构建命令
# 1. 清理缓存
rm -rf node_modules/.cache docs/.vuepress/.temp node_modules/@vuepress/core/.temp
# 2. 构建(12GB 内存上限 + GC 优化 + SourceMap 关闭)
npm run build
# 3. 部署
npm run deploy
2
3
4
5
6
7
8
# 内存优化清单
| 优化项 | 位置 | 预计节省 |
|---|---|---|
| 关闭 SourceMap | config.ts → chainWebpack | ~30% |
| 限制并行 2 线程 | config.ts → config.parallelism(2) | ~40% |
| Node GC 激进回收 | package.json → NODE_OPTIONS | 减少碎片 |
| 安全代码仅客户端 | enhanceApp.js → if (window) | 消除 SSR 端泄漏 |
| 禁用 SSR | config.ts → 删 server plugin | 消除 JSON.stringify 溢出 |
# 为什么 dev 没这些事
| 维度 | dev | build |
|---|---|---|
| 编译方式 | 懒加载,访问才编译 | 全量一次性 |
| SSR 渲染 | 不执行 | 已禁用(chainWebpack) |
| SourceMap | 生成(方便调试) | 已关闭 |
| 并行线程 | 按需 | 限制 2 线程 |
| 内存峰值 | 几百 MB | 4-12GB |
| 单文件处理 | 按需 | 1000+ 篇全上 |
dev 是"来一桌上一桌",build 是"100 桌一起做"——厨房不炸才怪 ⚡