Vue SSR应用渲染失败求助:生产环境构建报document未定义错误
Vue SSR Production Build Fails with "ReferenceError: document is not defined"
我正在学习创建Vue SSR应用,遵循官方指南。我的npm scripts配置如下:
"clean": "rimraf ./dist", "start": "node .", "build:client": "NODE_ENV=production webpack --config webpack/client.js --progress --hide-modules", "build:server": "NODE_ENV=production webpack --config webpack/server.js --progress --hide-modules", "build": "yarn clean; yarn build:client; yarn build:server"
执行npm run build; npm run start后应用运行失败,访问localhost:8000时出现如下错误:
ReferenceError: document is not defined at promises.push.installedCssChunks.(anonymous function).Promise.then.installedCssChunks.(anonymous function) (webpack/bootstrap:52:0) at new Promise (<anonymous>) at Function.requireEnsure [as e] (webpack/bootstrap:49:0) at component (src/router.js:10:36) at /Users/admin.hoa.nguyen/Demos/vue-ssr/node_modules/vue-router/dist/vue-router.common.js:1778:17 at /Users/admin.hoa.nguyen/Demos/vue-ssr/node_modules/vue-router/dist/vue-router.common.js:1805:66 at Array.map (<anonymous>) at /Users/admin.hoa.nguyen/Demos/vue-ssr/node_modules/vue-router/dist/vue-router.common.js:1805:38 at Array.map (<anonymous>) at flatMapComponents (/Users/admin.hoa.nguyen/Demos/vue-ssr/node_modules/vue-router/dist/vue-router.common.js:1804:26)
但将服务端构建的NODE_ENV改为development时,应用可正常运行。
问题原因
这个错误的核心是服务端渲染过程中代码尝试访问了浏览器专属的document对象。生产环境下webpack的代码分割/异步加载逻辑(比如你路由里的异步组件)会触发CSS加载相关的代码,而这些代码默认会尝试用document插入样式——但服务端根本没有浏览器环境的DOM对象,所以报错。开发环境服务端构建时,webpack的优化逻辑没那么激进,或者相关代码被跳过了,所以没触发这个问题。
解决方案
1. 给服务端webpack配置明确标记服务端环境
在你的webpack/server.js里添加DefinePlugin,告诉Vue和相关插件当前是服务端环境,它们会自动禁用浏览器特有的逻辑:
const webpack = require('webpack'); module.exports = { // ... 其他配置 plugins: [ new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV), 'process.env.VUE_ENV': '"server"' // 关键:标记服务端环境 }) ] };
2. 优化Vue组件的服务端渲染配置
修改vue-loader的配置,开启optimizeSSR选项,禁用服务端渲染时的DOM相关操作:
// 同样在webpack/server.js的module.rules里 { test: /\.vue$/, loader: 'vue-loader', options: { optimizeSSR: true // 阻止组件在服务端执行DOM操作 } }
3. 处理异步组件的CSS加载
如果你的异步组件里有CSS,生产环境下要避免在服务端加载这些样式。可以:
- 用
extract-text-webpack-plugin(Vue 2)把客户端的CSS提取到单独文件,服务端打包时不处理CSS的DOM插入逻辑; - 或者在组件里通过
process.env.VUE_ENV判断,只在客户端执行样式相关操作:
<script> export default { mounted() { // 只在客户端执行需要document的逻辑 if (process.env.VUE_ENV === 'client') { // 比如动态加载样式等操作 } } } </script>
4. 检查路由的异步组件定义
错误指向src/router.js第10行的组件加载,确保你的异步组件是标准的Vue SSR兼容写法:
// 正确的异步组件写法(支持服务端渲染) const Home = () => import('./views/Home.vue') const router = new VueRouter({ routes: [ { path: '/', component: Home } ] })
5. 确保服务端入口是无状态的
服务端入口文件要每次请求都创建新的Vue、Router实例,不要用单例,避免交叉请求污染:
// src/entry-server.js import Vue from 'vue' import App from './App.vue' import createRouter from './router' export default function createApp(context) { const router = createRouter() const app = new Vue({ router, context, render: h => h(App) }) return { app, router } }
额外排查点
- 如果用了第三方依赖,检查是否有库在服务端执行时访问
document,可以用webpack-node-externals把node_modules排除在服务端打包之外,避免打包浏览器专属库; - 确认
build:server脚本的环境变量是否正确传递(Windows系统建议用cross-env来设置NODE_ENV,避免环境变量不生效的问题)。
内容的提问来源于stack exchange,提问作者Harry Nguyen
相关产品推荐
相关产品推荐

