VuePress 打包报错 ReferenceError document is not defined 的原因与解决方案
在使用 VuePress 搭建文档网站的过程中,我们经常会想引入一些交互性的插件,比如 cursor-effects
提供的趣味鼠标效果。然而在构建(build)时却可能遇到如下报错:
ReferenceError: document is not defined
这篇文章将深入分析这个问题的根本原因,并提供一种优雅的解决方案。
🚨 问题现象
在开发环境 (vuepress dev
) 中一切正常,但当执行打包命令 vuepress build
时却报错:
ReferenceError: document is not defined
通常,这种报错会出现在你直接在代码中调用了 document
或其他浏览器 API 的情况下,例如:
import 'cursor-effects'
new springyEmojiCursor() // 报错行
🧠 原因分析
VuePress 在打包时采用的是 服务端渲染(Server-Side Rendering, SSR),构建过程是由 Node.js 运行的。而 Node.js 是运行在服务端的环境,不存在 document
、window
、navigator
等浏览器特有的对象。
所以,如果你在构建时执行了依赖 DOM 的代码(比如直接初始化动画效果或操作 DOM),就会导致构建失败。
✅ 解决方案
解决思路非常明确:确保所有依赖浏览器环境的代码只在客户端执行,也就是说,只在页面真正加载后、浏览器环境已就绪时再执行。
情况 1:在页面组件中引入插件
如果你只想在某个具体页面或组件中使用,比如 Home.vue
,可以这样做:
import { onMounted } from 'vue'
onMounted(() => {
import('cursor-effects').then((m) => {
new m.springyEmojiCursor({ emoji: '🔥' })
})
})
因为 onMounted
只在客户端执行,构建时不会触发这段代码,自然不会报错。
情况 2:全局使用插件
如果希望整个文档站点都启用这个效果,应在 VuePress 提供的 client.ts
中注册。
VuePress 2 提供了一个增强入口文件:docs/.vuepress/client.ts
,我们可以在这里使用 defineClientConfig
来定义全局客户端配置:
// docs/.vuepress/client.ts
import { onMounted } from 'vue'
import { defineClientConfig } from 'vuepress/client'
export default defineClientConfig({
setup() {
onMounted(() => {
// 可安全使用浏览器 API
document.querySelector('#app')
import('cursor-effects').then(function (m) {
new m.springyEmojiCursor({ emoji: "🤣" })
})
})
},
})
说明:
defineClientConfig
:VuePress 提供的客户端配置函数,类似于你在 Vue 应用中使用的根组件设置。setup()
:可使用组合式 API(如onMounted
、ref
等)官方文档 。onMounted()
:确保 DOM 已加载,此时使用document
是安全的。import()
:使用动态导入的方式,确保只有在浏览器中执行。
💡 小贴士
- 永远不要在顶层作用域中直接使用
document
、window
等浏览器 API; - 使用
onMounted()
包裹你的 DOM 操作逻辑; - 如果你用的是第三方依赖,确保它不会在 SSR 构建时执行副作用代码。
更新日志
2025/6/16 07:14
查看所有更新日志
23359
-new article于