从0到1使用Vue3+Nuxt.js搭建服务端渲染(SSR)的避坑指南,结合最新实践整理的关键细节和解决方案:
一、项目初始化与目录结构
-
目录规范
- Nuxt3默认无
src
目录,需将Vue3项目的views
目录迁移至pages
,components
保留原样(自动全局注册) - 避坑重点:
public
目录禁止存放index.html
(会覆盖SSR入口)- 静态资源(图片/CSS)必须放在
assets
目录,引用时使用~/assets/
路径 - 服务端专用代码(如数据库连接)应置于
server
目录,避免客户端打包
- Nuxt3默认无
-
环境配置
# 强制要求Node.js ≥18.x,推荐pnpm避免依赖冲突 npx nuxi@latest init nuxt-ssr && cd nuxt-ssr pnpm install @nuxtjs/tailwindcss @element-plus/nuxt -D
- TS支持:优先阅读Nuxt英文文档配置,中文文档可能未同步更新
二、Vue3与Nuxt3特性适配
- 响应式陷阱
- 服务端数据:使用
useAsyncData
而非ref/reactive
,避免客户端重复请求// ✅ 正确示例(服务端获取) const { data } = await useAsyncData('articles', () => $fetch('/api/posts'))
- 全局状态:优先用Pinia替代Vuex,需配置
@pinia/nuxt
模块并启用SSR兼容
- 服务端数据:使用
- 生命周期差异
onMounted
仅在客户端执行,服务端渲染阶段用onServerPrefetch
预取数据- 内存泄漏:在
onBeforeUnmount
中清理定时器/事件监听,避免SSR服务内存累积onBeforeUnmount(() => { clearInterval(timer) window.removeEventListener('resize', handleResize) })
三、路由与中间件开发
-
路由规则
- 文件路由:
pages/user/[id].vue
自动生成/user/:id
动态路由,无需router.js
1 - 404处理:创建
pages/[...slug].vue
捕获未匹配路由,需禁用Vue Router的*
通配符<!-- pages/[...slug].vue --> <template> <Error404 /> </template>
- 文件路由:
-
中间件配置
- 鉴权流:全局中间件(
auth.global.ts
)+ 路由级中间件组合// middleware/auth.global.ts export default defineNuxtRouteMiddleware((to) => { const { isLoggedIn } = useAuthStore() if (!isLoggedIn && to.path !== '/login') { return navigateTo('/login') } })
- 鉴权流:全局中间件(
四、状态管理与性能优化
-
SSR数据流
- Cookies同步:使用
useCookie
在服务端/客户端同步状态const token = useCookie('token', { maxAge: 3600 })
- Cookies同步:使用
-
渲染性能
- 首屏优化:用
<ClientOnly>
包裹非关键组件,延迟加载第三方库<template> <Banner :data="banner" /> <ClientOnly> <HeavyChartLibrary /> </ClientOnly> </template>
- CDN加速:配置
nuxt.config.ts
的nitro.preset
为cloudflare
或vercel
- 首屏优化:用
五、错误处理与调试
-
全局错误捕获
- 服务端500错误:在
/src-ssr/index.js
拦截渲染异常,返回静态错误页app.get('*', (req, res) => { ssr.renderToString({ req, res }, (err, html) => { if (err) res.status(500).send(renderErrorPage()) }) })
- 服务端500错误:在
-
内存泄漏排查
六、部署与监控
-
容器化部署
# Dockerfile(启用NUXT_PUBLIC_RUNTIME_CONFIG) FROM node:18-alpine ENV NUXT_PUBLIC_API_BASE=https://api.example.com RUN pnpm build && pnpm prune --prod CMD ["node", ".output/server/index.mjs"]
-
监控告警
- Sentry集成:通过
@nuxtjs/sentry
模块捕获客户端/服务端异常 - 性能指标:配置Prometheus + Grafana监控SSR渲染耗时/QPS
- Sentry集成:通过
终极避坑清单
- 插件注册:检查所有
Vue.use()
调用,避免服务端重复初始化 - 静态资源:
public/
仅放无需处理的文件(如robots.txt
) - API代理:用
nitro.devProxy
替代@nuxtjs/proxy
,减少配置复杂度 - 版本锁定:固定
@nuxt/kit
和vue
版本,防止自动升级导致兼容问题
通过以上方案可规避90%的SSR开发陷阱,建议结合Chrome Performance面板和console.memory
持续优化内存占用。