Vue SSR开发踩坑
20.1 Vue SSR配置的常见错误
核心知识点
在配置Vue SSR时,常见的错误包括:
- 构建配置错误:服务端和客户端构建配置不当
- 环境变量配置:环境变量配置错误
- 服务器配置:Node.js服务器配置不当
- 依赖安装:缺少必要的依赖包
实用案例分析
错误场景:构建配置错误
// 错误示例:构建配置不当
// vue.config.js
module.exports = {
// 错误:未配置SSR构建
configureWebpack: {
// 缺少SSR相关配置
}
}正确实现:
// 正确示例:配置SSR构建
// vue.config.js
module.exports = {
configureWebpack: {
// 配置webpack以支持SSR
target: 'node'
},
chainWebpack: config => {
// 配置服务端构建
if (process.env.VUE_ENV === 'server') {
config.entry('app').clear().add('./src/entry-server.js')
config.target('node')
config.output.libraryTarget('commonjs2')
} else {
// 配置客户端构建
config.entry('app').clear().add('./src/entry-client.js')
}
}
}
// 或使用@vue/cli-plugin-ssr
// 安装:npm install @vue/cli-plugin-ssr
// 项目结构
// src/
// ├── entry-client.js
// ├── entry-server.js
// └── main.js
// entry-server.js
export default context => {
return new Promise((resolve, reject) => {
const { app, router, store } = createApp()
const { url } = context
const { fullPath } = router.resolve(url).route
if (fullPath !== url) {
return reject({ url: fullPath })
}
router.push(url)
router.onReady(() => {
const matchedComponents = router.getMatchedComponents()
if (!matchedComponents.length) {
return reject({ code: 404 })
}
Promise.all(matchedComponents.map(Component => {
if (Component.asyncData) {
return Component.asyncData({ store, route: router.currentRoute })
}
})).then(() => {
context.state = store.state
resolve(app)
}).catch(reject)
}, reject)
})
}
// entry-client.js
import { createApp } from './main'
const { app, router, store } = createApp()
if (window.__INITIAL_STATE__) {
store.replaceState(window.__INITIAL_STATE__)
}
router.onReady(() => {
app.mount('#app')
})错误场景:服务器配置不当
// 错误示例:Express服务器配置不当
const express = require('express')
const { createBundleRenderer } = require('vue-server-renderer')
const serverBundle = require('./dist/vue-ssr-server-bundle.json')
const clientManifest = require('./dist/vue-ssr-client-manifest.json')
const app = express()
// 错误:未配置静态文件服务
app.get('*', (req, res) => {
const renderer = createBundleRenderer(serverBundle, {
clientManifest
})
const context = { url: req.url }
renderer.renderToString(context, (err, html) => {
if (err) {
res.status(500).end('Internal Server Error')
return
}
res.end(html)
})
})
app.listen(3000)正确实现:
// 正确示例:Express服务器配置
const express = require('express')
const { createBundleRenderer } = require('vue-server-renderer')
const path = require('path')
const serverBundle = require('./dist/vue-ssr-server-bundle.json')
const clientManifest = require('./dist/vue-ssr-client-manifest.json')
const app = express()
// 正确:配置静态文件服务
app.use('/dist', express.static(path.join(__dirname, 'dist')))
// 正确:创建渲染器
const renderer = createBundleRenderer(serverBundle, {
runInNewContext: false,
template: require('fs').readFileSync(path.join(__dirname, 'index.template.html'), 'utf-8'),
clientManifest
})
app.get('*', (req, res) => {
const context = {
url: req.url,
title: 'Vue SSR App'
}
renderer.renderToString(context, (err, html) => {
if (err) {
if (err.code === 404) {
res.status(404).end('Page not found')
} else {
res.status(500).end('Internal Server Error')
}
return
}
res.end(html)
})
})
app.listen(3000, () => {
console.log('Server started at http://localhost:3000')
})20.2 Vue SSR数据预取的陷阱
核心知识点
在进行Vue SSR数据预取时,常见的陷阱包括:
- 数据预取方法:错误的异步数据预取方法
- 状态管理:服务端和客户端状态不一致
- 错误处理:数据预取错误处理不当
- 性能优化:数据预取导致的性能问题
实用案例分析
错误场景:数据预取方法错误
// 错误示例:错误的异步数据预取方法
// 组件中
<template>
<div>{{ user.name }}</div>
</template>
<script>
export default {
data() {
return {
user: {}
}
},
mounted() {
// 错误:在mounted中获取数据,SSR时不会执行
this.fetchUser()
},
methods: {
async fetchUser() {
const response = await fetch('/api/user')
this.user = await response.json()
}
}
}
</script>正确实现:
// 正确示例:使用正确的异步数据预取方法
// 1. 使用asyncData方法
// 组件中
export default {
data() {
return {
user: {}
}
},
// 正确:使用asyncData方法,SSR时会执行
asyncData({ store, route }) {
return store.dispatch('fetchUser', route.params.id)
}
}
// 2. 使用fetch方法(Nuxt.js风格)
export default {
data() {
return {
user: {}
}
},
async fetch() {
const response = await this.$axios.get('/api/user')
this.user = response.data
}
}
// 3. 在服务端入口中处理
// entry-server.js
export default context => {
return new Promise((resolve, reject) => {
const { app, router, store } = createApp()
const { url } = context
router.push(url)
router.onReady(() => {
const matchedComponents = router.getMatchedComponents()
if (!matchedComponents.length) {
return reject({ code: 404 })
}
// 预取数据
Promise.all(matchedComponents.map(Component => {
if (Component.asyncData) {
return Component.asyncData({ store, route: router.currentRoute })
}
})).then(() => {
// 将状态注入上下文
context.state = store.state
resolve(app)
}).catch(reject)
}, reject)
})
}
// 客户端入口中同步状态
// entry-client.js
const { app, router, store } = createApp()
if (window.__INITIAL_STATE__) {
store.replaceState(window.__INITIAL_STATE__)
}错误场景:服务端和客户端状态不一致
// 错误示例:状态管理不当
// store/index.js
import { createStore } from 'vuex'
export default createStore({
state: {
user: null
},
mutations: {
setUser(state, user) {
state.user = user
}
},
actions: {
async fetchUser({ commit }) {
// 错误:服务端和客户端请求相同数据,导致重复请求
const response = await fetch('/api/user')
const user = await response.json()
commit('setUser', user)
}
}
})正确实现:
// 正确示例:确保服务端和客户端状态一致
// store/index.js
import { createStore } from 'vuex'
export default function createStore() {
return createStore({
state: {
user: null
},
mutations: {
setUser(state, user) {
state.user = user
}
},
actions: {
async fetchUser({ commit, state }) {
// 正确:检查状态是否已存在,避免重复请求
if (state.user) {
return state.user
}
const response = await fetch('/api/user')
const user = await response.json()
commit('setUser', user)
return user
}
}
})
}
// main.js
import { createSSRApp } from 'vue'
import createStore from './store'
export function createApp() {
const app = createSSRApp(App)
const store = createStore()
app.use(store)
return { app, store }
}
// 客户端入口中同步状态
// entry-client.js
const { app, store } = createApp()
if (window.__INITIAL_STATE__) {
// 正确:替换客户端状态为服务端状态
store.replaceState(window.__INITIAL_STATE__)
}20.3 Vue SSR路由处理的使用误区
核心知识点
在处理Vue SSR路由时,常见的误区包括:
- 路由配置:服务端和客户端路由配置不一致
- 路由导航:服务端路由导航处理不当
- 404处理:404页面处理错误
- 路由守卫:路由守卫在服务端和客户端的执行差异
实用案例分析
错误场景:路由配置不一致
// 错误示例:服务端和客户端路由配置不一致
// router/index.js
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
// 错误:创建单例路由,服务端和客户端共享
const router = new Router({
mode: 'history',
routes: [
{ path: '/', component: Home },
{ path: '/about', component: About }
]
})
export default router正确实现:
// 正确示例:服务端和客户端路由配置一致
// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
// 正确:创建路由工厂函数,每次请求都创建新实例
export function createRouter() {
return createRouter({
history: createWebHistory(),
routes: [
{ path: '/', component: () => import('./views/Home.vue') },
{ path: '/about', component: () => import('./views/About.vue') }
]
})
}
// main.js
export function createApp() {
const app = createSSRApp(App)
const router = createRouter()
app.use(router)
return { app, router }
}
// entry-server.js
export default context => {
return new Promise((resolve, reject) => {
const { app, router } = createApp()
const { url } = context
router.push(url)
router.onReady(() => {
const matchedComponents = router.getMatchedComponents()
if (!matchedComponents.length) {
return reject({ code: 404 })
}
resolve(app)
}, reject)
})
}错误场景:路由守卫执行差异
// 错误示例:路由守卫在服务端和客户端执行差异
// router/index.js
export function createRouter() {
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/',
component: Home,
meta: { requiresAuth: true }
}
]
})
router.beforeEach((to, from, next) => {
// 错误:在服务端执行时,localStorage不可用
const token = localStorage.getItem('token')
if (to.meta.requiresAuth && !token) {
next('/login')
} else {
next()
}
})
return router
}正确实现:
// 正确示例:处理路由守卫在服务端和客户端的执行差异
// router/index.js
export function createRouter() {
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/',
component: Home,
meta: { requiresAuth: true }
}
]
})
router.beforeEach((to, from, next) => {
// 正确:检查是否在浏览器环境
if (process.client) {
const token = localStorage.getItem('token')
if (to.meta.requiresAuth && !token) {
next('/login')
} else {
next()
}
} else {
// 服务端处理
// 从请求头或cookie中获取token
const token = to.meta.token // 假设token通过meta传递
if (to.meta.requiresAuth && !token) {
next('/login')
} else {
next()
}
}
})
return router
}
// 或在服务端入口中处理
// entry-server.js
export default context => {
return new Promise((resolve, reject) => {
const { app, router, store } = createApp()
const { url, cookies } = context
// 将cookies传递给store
store.commit('setCookies', cookies)
router.push(url)
router.onReady(() => {
const matchedComponents = router.getMatchedComponents()
if (!matchedComponents.length) {
return reject({ code: 404 })
}
resolve(app)
}, reject)
})
}20.4 Vue SSR状态管理的常见问题
核心知识点
在使用Vue SSR状态管理时,常见的问题包括:
- 状态序列化:状态序列化和反序列化问题
- 状态注入:服务端状态注入不当
- 状态同步:服务端和客户端状态同步错误
- 性能问题:状态管理导致的性能问题
实用案例分析
错误场景:状态序列化问题
// 错误示例:状态序列化错误
// store/index.js
export function createStore() {
return createStore({
state: {
user: {
id: 1,
name: 'Alice',
// 错误:包含不可序列化的数据
updateTime: new Date() // Date对象在序列化时会变成字符串
}
}
})
}正确实现:
// 正确示例:处理状态序列化
// 1. 确保状态可序列化
// store/index.js
export function createStore() {
return createStore({
state: {
user: {
id: 1,
name: 'Alice',
// 正确:使用可序列化的数据类型
updateTime: new Date().toISOString() // 转换为字符串
}
},
getters: {
// 在getter中转换回Date对象
userUpdateTime: state => new Date(state.user.updateTime)
}
})
}
// 2. 自定义序列化和反序列化
// entry-server.js
export default context => {
return new Promise((resolve, reject) => {
const { app, router, store } = createApp()
const { url } = context
router.push(url)
router.onReady(() => {
const matchedComponents = router.getMatchedComponents()
if (!matchedComponents.length) {
return reject({ code: 404 })
}
Promise.all(matchedComponents.map(Component => {
if (Component.asyncData) {
return Component.asyncData({ store, route: router.currentRoute })
}
})).then(() => {
// 正确:序列化状态
context.state = JSON.parse(JSON.stringify(store.state))
resolve(app)
}).catch(reject)
}, reject)
})
}
// 3. 在客户端中恢复状态
// entry-client.js
const { app, store } = createApp()
if (window.__INITIAL_STATE__) {
// 正确:反序列化状态
store.replaceState(window.__INITIAL_STATE__)
}错误场景:状态注入不当
// 错误示例:状态注入不当
// 服务器中
const renderer = createBundleRenderer(serverBundle, {
template: fs.readFileSync('./index.html', 'utf-8')
})
app.get('*', (req, res) => {
const context = { url: req.url }
renderer.renderToString(context, (err, html) => {
if (err) {
res.status(500).end('Internal Server Error')
return
}
// 错误:未注入状态到HTML
res.end(html)
})
})正确实现:
// 正确示例:正确注入状态
// 1. 使用模板注入
// index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
</head>
<body>
<div id="app"><!--vue-ssr-outlet--></div>
<!-- 正确:注入状态 -->
<script>window.__INITIAL_STATE__ = {{ state }}</script>
<script src="/dist/client.js"></script>
</body>
</html>
// 2. 在服务器中设置状态
const renderer = createBundleRenderer(serverBundle, {
template: fs.readFileSync('./index.html', 'utf-8'),
// 正确:配置模板渲染
renderState: (context) => {
return `<script>window.__INITIAL_STATE__ = ${JSON.stringify(context.state)}</script>`
}
})
app.get('*', (req, res) => {
const context = { url: req.url }
renderer.renderToString(context, (err, html) => {
if (err) {
res.status(500).end('Internal Server Error')
return
}
res.end(html)
})
})
// 3. 在客户端中同步状态
// entry-client.js
const { app, store } = createApp()
if (window.__INITIAL_STATE__) {
// 正确:替换客户端状态
store.replaceState(window.__INITIAL_STATE__)
}
router.onReady(() => {
app.mount('#app')
})20.5 Vue SSR性能优化的陷阱
核心知识点
在进行Vue SSR性能优化时,常见的陷阱包括:
- 缓存策略:缓存策略不当
- 预渲染:预渲染配置错误
- 资源优化:静态资源优化不当
- 服务器优化:Node.js服务器性能优化不当
实用案例分析
错误场景:缓存策略不当
// 错误示例:缓存策略不当
// 服务器中
app.get('*', (req, res) => {
const context = { url: req.url }
// 错误:每次请求都重新渲染,未使用缓存
renderer.renderToString(context, (err, html) => {
if (err) {
res.status(500).end('Internal Server Error')
return
}
res.end(html)
})
})正确实现:
// 正确示例:使用合理的缓存策略
// 1. 使用页面缓存
const LRU = require('lru-cache')
const cache = new LRU({
max: 100,
maxAge: 1000 * 60 * 15 // 15分钟
})
app.get('*', (req, res) => {
const url = req.url
// 检查缓存
const cachedHtml = cache.get(url)
if (cachedHtml) {
return res.end(cachedHtml)
}
const context = { url }
renderer.renderToString(context, (err, html) => {
if (err) {
res.status(500).end('Internal Server Error')
return
}
// 设置缓存
cache.set(url, html)
res.end(html)
})
})
// 2. 使用组件缓存
// 组件中
export default {
// 启用组件缓存
serverCacheKey: props => props.id
}
// 3. 使用内存缓存
const memoryFs = require('memory-fs')
const fs = new memoryFs()
fs.writeFileSync('/dist/server-bundle.json', JSON.stringify(serverBundle))
// 4. 优化服务器
// 使用cluster模块
const cluster = require('cluster')
const numCPUs = require('os').cpus().length
if (cluster.isMaster) {
for (let i = 0; i < numCPUs; i++) {
cluster.fork()
}
cluster.on('exit', worker => {
console.log(`Worker ${worker.process.pid} died`)
cluster.fork()
})
} else {
// 启动服务器
const app = express()
// 服务器配置
app.listen(3000)
}错误场景:预渲染配置错误
// 错误示例:预渲染配置不当
// vue.config.js
module.exports = {
// 错误:未配置预渲染
}正确实现:
// 正确示例:配置预渲染
// 1. 使用@vue/preload-webpack-plugin
// 安装:npm install @vue/preload-webpack-plugin
// vue.config.js
const PreloadWebpackPlugin = require('@vue/preload-webpack-plugin')
module.exports = {
configureWebpack: {
plugins: [
new PreloadWebpackPlugin({
rel: 'preload',
as: 'script'
})
]
}
}
// 2. 使用prerender-spa-plugin
// 安装:npm install prerender-spa-plugin
// vue.config.js
const PrerenderSPAPlugin = require('prerender-spa-plugin')
module.exports = {
configureWebpack: {
plugins: [
new PrerenderSPAPlugin({
staticDir: path.join(__dirname, 'dist'),
routes: ['/', '/about', '/contact'],
renderer: new PrerenderSPAPlugin.PuppeteerRenderer({
renderAfterDocumentEvent: 'render-event'
})
})
]
}
}
// 3. 在main.js中触发事件
new Vue({
router,
store,
render: h => h(App),
mounted() {
document.dispatchEvent(new Event('render-event'))
}
}).$mount('#app')20.6 Vue SSR部署的常见错误
核心知识点
在部署Vue SSR应用时,常见的错误包括:
- 服务器配置:生产服务器配置不当
- 构建输出:构建输出文件路径配置错误
- 环境变量:生产环境变量配置错误
- 监控和日志:缺少监控和日志配置
实用案例分析
错误场景:服务器配置不当
// 错误示例:生产服务器配置不当
const express = require('express')
const app = express()
// 错误:未配置生产环境
app.use(express.static('dist'))
app.get('*', (req, res) => {
// 错误:未处理生产环境的错误
renderer.renderToString({ url: req.url }, (err, html) => {
res.end(html)
})
})
app.listen(3000)正确实现:
// 正确示例:生产服务器配置
const express = require('express')
const compression = require('compression')
const helmet = require('helmet')
const morgan = require('morgan')
const app = express()
// 正确:使用生产环境中间件
app.use(compression()) // 启用gzip压缩
app.use(helmet()) // 增强安全性
app.use(morgan('combined')) // 日志记录
// 正确:配置静态文件服务
app.use('/dist', express.static('dist', {
maxAge: '1y' // 静态文件缓存1年
}))
// 正确:处理错误
app.get('*', (req, res) => {
const context = { url: req.url }
renderer.renderToString(context, (err, html) => {
if (err) {
if (err.code === 404) {
res.status(404).end('Page not found')
} else {
console.error(err) // 记录错误
res.status(500).end('Internal Server Error')
}
return
}
res.end(html)
})
})
// 正确:设置端口
const port = process.env.PORT || 3000
app.listen(port, () => {
console.log(`Server running on port ${port}`)
})错误场景:构建输出路径配置错误
// 错误示例:构建输出路径配置错误
// vue.config.js
module.exports = {
outputDir: 'dist',
// 错误:未配置服务端和客户端构建输出
configureWebpack: {
output: {
// 缺少输出路径配置
}
}
}正确实现:
// 正确示例:配置构建输出路径
// vue.config.js
module.exports = {
outputDir: 'dist',
configureWebpack: {
output: {
path: path.resolve(__dirname, 'dist'),
publicPath: '/'
}
},
chainWebpack: config => {
if (process.env.VUE_ENV === 'server') {
// 服务端构建输出
config.output
.path(path.resolve(__dirname, 'dist/server'))
.filename('server-bundle.js')
} else {
// 客户端构建输出
config.output
.path(path.resolve(__dirname, 'dist/client'))
.filename('[name].[hash].js')
}
}
}
// 服务器中正确引用构建文件
const serverBundle = require('./dist/server/server-bundle.json')
const clientManifest = require('./dist/client/vue-ssr-client-manifest.json')
const renderer = createBundleRenderer(serverBundle, {
clientManifest,
template: fs.readFileSync('./index.html', 'utf-8')
})20.7 Vue SSR与第三方库的集成陷阱
核心知识点
在集成Vue SSR与第三方库时,常见的陷阱包括:
- 库的服务端兼容性:第三方库在服务端的兼容性问题
- DOM依赖:库依赖DOM API导致的问题
- 全局状态:第三方库的全局状态导致的问题
- 异步加载:第三方库异步加载导致的问题
实用案例分析
错误场景:库依赖DOM API
// 错误示例:使用依赖DOM的库
// 组件中
import $ from 'jquery'
export default {
mounted() {
// 在客户端工作正常,但在服务端会报错
$('#element').hide()
}
}正确实现:
// 正确示例:处理依赖DOM的库
// 1. 检查环境
// 组件中
export default {
mounted() {
// 正确:检查是否在浏览器环境
if (process.client) {
const $ = require('jquery')
$('#element').hide()
}
}
}
// 2. 使用服务端兼容的库
// 例如,使用axios替代fetch
import axios from 'axios'
export default {
asyncData() {
// axios在服务端和客户端都可使用
return axios.get('/api/data')
}
}
// 3. 使用动态导入
// 组件中
export default {
mounted() {
// 动态导入,只在客户端执行
import('jquery').then($ => {
$('#element').hide()
})
}
}
// 4. 配置webpack以模拟浏览器环境
// webpack.config.js
module.exports = {
configureWebpack: {
node: {
// 模拟浏览器环境变量
fs: 'empty',
net: 'empty',
tls: 'empty'
}
}
}错误场景:第三方库的全局状态
// 错误示例:使用有全局状态的库
// 组件中
import moment from 'moment'
// 错误:修改全局配置,影响所有请求
moment.locale('zh-cn')
export default {
data() {
return {
now: moment().format('YYYY-MM-DD')
}
}
}正确实现:
// 正确示例:处理有全局状态的库
// 1. 不修改全局配置
// 组件中
import moment from 'moment'
export default {
data() {
return {
// 正确:每次使用时指定配置
now: moment().locale('zh-cn').format('YYYY-MM-DD')
}
}
}
// 2. 使用实例化的库
// 例如,使用axios实例
import axios from 'axios'
// 创建实例
const api = axios.create({
baseURL: '/api',
timeout: 10000
})
export default {
asyncData() {
return api.get('/data')
}
}
// 3. 在服务端入口中重置全局状态
// entry-server.js
export default context => {
// 重置全局状态
require('moment').locale('en')
return new Promise((resolve, reject) => {
// 服务端渲染逻辑
})
}20.8 Vue SSR内存管理的误区
核心知识点
在管理Vue SSR内存时,常见的误区包括:
- 内存泄漏:内存泄漏导致的问题
- 资源清理:服务端资源清理不当
- 内存限制:Node.js内存限制配置
- 垃圾回收:垃圾回收优化不当
实用案例分析
错误场景:内存泄漏
// 错误示例:内存泄漏
// 服务器中
const app = express()
const connections = []
app.get('*', (req, res) => {
// 错误:未清理连接
connections.push(res)
renderer.renderToString({ url: req.url }, (err, html) => {
res.end(html)
})
})
app.listen(3000)正确实现:
// 正确示例:内存管理
const app = express()
// 正确:使用runInNewContext: false
const renderer = createBundleRenderer(serverBundle, {
runInNewContext: false // 避免每次请求创建新的V8上下文
})
// 正确:处理连接
app.get('*', (req, res) => {
const context = { url: req.url }
renderer.renderToString(context, (err, html) => {
if (err) {
res.status(500).end('Internal Server Error')
return
}
res.end(html)
// 正确:清理上下文
context = null
})
})
// 正确:设置内存限制
// 启动服务器时:node --max-old-space-size=4096 server.js
// 正确:使用cluster模块
const cluster = require('cluster')
const numCPUs = require('os').cpus().length
if (cluster.isMaster) {
console.log(`Master ${process.pid} is running`)
for (let i = 0; i < numCPUs; i++) {
cluster.fork()
}
cluster.on('exit', (worker) => {
console.log(`Worker ${worker.process.pid} died`)
cluster.fork()
})
} else {
// 启动服务器
app.listen(3000)
console.log(`Worker ${process.pid} started`)
}
// 正确:定期重启工作进程
setInterval(() => {
if (cluster.worker) {
cluster.worker.kill()
}
}, 60 * 60 * 1000) // 每小时重启一次错误场景:资源清理不当
// 错误示例:资源清理不当
// 服务端入口中
import { createApp } from './main'
export default context => {
return new Promise((resolve, reject) => {
const { app, router } = createApp()
// 错误:未清理资源
router.push(context.url)
router.onReady(() => {
resolve(app)
}, reject)
})
}正确实现:
// 正确示例:资源清理
import { createApp } from './main'
export default context => {
return new Promise((resolve, reject) => {
const { app, router, store } = createApp()
const { url } = context
router.push(url)
router.onReady(() => {
const matchedComponents = router.getMatchedComponents()
if (!matchedComponents.length) {
return reject({ code: 404 })
}
Promise.all(matchedComponents.map(Component => {
if (Component.asyncData) {
return Component.asyncData({ store, route: router.currentRoute })
}
})).then(() => {
context.state = store.state
resolve(app)
// 正确:清理资源
// 注意:不要在这里清理app,因为Vue需要它来渲染
}).catch(reject)
}, reject)
})
}
// 正确:在服务器中处理内存使用
setInterval(() => {
const memoryUsage = process.memoryUsage()
console.log('Memory usage:', {
rss: (memoryUsage.rss / 1024 / 1024).toFixed(2) + 'MB',
heapTotal: (memoryUsage.heapTotal / 1024 / 1024).toFixed(2) + 'MB',
heapUsed: (memoryUsage.heapUsed / 1024 / 1024).toFixed(2) + 'MB'
})
// 如果内存使用超过阈值,重启进程
if (memoryUsage.heapUsed > 1024 * 1024 * 1024) { // 1GB
console.log('Memory usage too high, restarting...')
process.exit(1)
}
}, 60000) // 每分钟检查一次