项目初始化阶段,怎么选模板和配置更省心?
做前端项目时,要是用 Vue2 搭配 Nuxt 开发,既能享受 Vue 的开发体验,又能靠 SSR 解决 SEO 和首屏加载问题,但实际开发里「踩坑」的地方可不少,从项目初始化的配置混乱,到 SEO 优化没达到预期,再到部署时服务器报错,每个环节都可能卡壳,这篇文章就用问答形式,把 Vue2 + Nuxt 开发里最容易栽跟头的环节拆解清楚,教你怎么高效把项目落地~
很多新手刚接触 Nuxt 时,第一步「初始化项目」就容易懵,先解答最基础的 —— 怎么快速搭骨架?
Nuxt 提供了官方脚手架,执行 npx create-nuxt-app 项目名 后,终端会引导你选模板、UI 框架、测试工具这些,要是想快速启动,选「Starter Template」就够;如果需要更完整的目录(比如自带 Vuex 模块、布局模板),选「Full Template」更省心,但别盲目选复杂模板,小项目用 Starter 能减少冗余代码。
选完模板,核心配置文件 nuxt.config.js 得重点盯,举个常见坑:全局样式重复加载,有人把 Element UI、自定义全局 CSS 全丢进 css 数组,结果组件里又重复引入,导致样式冲突,正确做法是:全局通用的样式(reset.css、主题色)放 css 里;组件自己的样式用 <style scoped> 隔离。head 配置动态标题和 meta 时,别直接写死,后期 SEO 优化要动态改,所以先预留好通过异步方法修改的口子。
还有 plugins 配置第三方库(axios、echarts),如果直接 import 后丢进 plugins,服务端渲染时可能报错(因为某些库依赖浏览器环境),这时候要加判断:if (process.client) { import('xxx') },保证只在客户端加载,举个例子,给 axios 加拦截器,得把初始化逻辑包在客户端判断里,不然服务端执行时找不到 window,直接崩掉。
SEO 优化是 Nuxt 强项,实操时要注意什么?
Nuxt 最核心的优势之一是 SSR(服务端渲染),天生对 SEO 友好,但实操细节没做好,搜索引擎还是抓不到内容,先解决「动态设置标题和 meta」的问题 ——
很多页面需要根据接口数据改标题(比如文章详情页,标题是文章名),这时候用 asyncData 或者 fetch 方法,在服务端获取数据后,通过 this.$nuxt.$head 动态设置,举个例子:
async asyncData({ $axios, params }) {
const article = await $axios.get(`/api/article/${params.id}`)
return { article }
},
head() {
return { this.article.title,
meta: [
{ name: 'description', content: this.article.desc }
]
}
}
但要注意,如果接口请求慢,服务端渲染时数据还没返回,标题会是空的,所以得优化接口性能,或者给关键数据加缓存。
SEO 不止标题和描述,还要加「结构化数据(JSON-LD)」,比如电商网站的商品页,把商品名称、价格、评分等信息用 JSON-LD 格式埋进页面,搜索引擎能更精准解析,做法是在 head 里加 script 标签:
head() {
return {
script: [
{
type: 'application/ld+json',
innerHTML: JSON.stringify({
'@context': 'https://schema.org/',
'@type': 'Product',
name: this.article.title,
description: this.article.desc
})
}
]
}
}
还要避开一个雷:路由层级过深,Nuxt 自动生成的路由是根据 pages 目录结构来的,pages/article/_id/comments 这样的多层路由,搜索引擎抓取时容易认为页面权重低,尽量把核心页面放在浅层目录,或者通过路由重定向简化结构。
路由与页面加载逻辑,怎么处理才流畅?
Nuxt 的「自动路由」很方便,但动态路由、页面过渡、懒加载这些细节处理不好,用户体验会打折扣,先看动态路由(比如文章详情页 pages/article/_id.vue):
获取参数得用 this.$route.params.id,但如果在 asyncData 里获取,参数是从上下文对象里拿,asyncData({ params }) { ... },这里容易混淆客户端和服务端的参数获取方式,服务端渲染时,asyncData 的上下文有 params,客户端导航时,this.$route.params 也能拿到,所以两种方式都要兼容测试。
然后是页面过渡动画,Nuxt 支持在 layout 或页面组件里配置 transition,比如想做页面切换时的渐变效果,在 default.vue(全局布局)里加:
export default {
transition: 'page-fade'
}
然后在 assets/css 里写动画样式:
.page-fade-enter-active, .page-fade-leave-active {
transition: opacity .3s;
}
.page-fade-enter, .page-fade-leave-to {
opacity: 0;
}
但要注意,过渡动画别太复杂,不然会拖慢页面切换速度。
还有组件懒加载,减少首屏加载体积,Nuxt 里用 component: () => import('@/components/xxx.vue') 就行,但要注意,懒加载的组件如果在服务端渲染时依赖浏览器 API(比如操作 DOM),得用 <client-only> 包裹,不然服务端会报错,比如引入一个依赖 window 的图表组件:
<client-only> <ChartComponent /> </client-only>
路由守卫(middleware),比如需要权限验证的页面,在 middleware 目录写一个 auth.js:
export default function ({ store, redirect }) {
if (!store.state.user.isLogin) {
return redirect('/login')
}
}
然后在需要验证的页面组件里配置 middleware: 'auth',这里要注意,middleware 会在服务端和客户端都执行,所以判断用户状态时,要确保服务端能拿到正确的会话信息(比如把 token 存在 cookie 里,服务端能解析)。
状态管理(Vuex)在 Nuxt 里有啥特殊玩法?
Nuxt 对 Vuex 做了封装,新手容易搞混模块导入和状态同步逻辑,首先是模块自动导入:只要在 store 目录下新建 .js 文件(user.js),Nuxt 会自动识别为 Vuex 模块,不用手动在 index.js 里 import,但如果模块里有命名空间,得在文件里显式声明 namespaced: true,不然调用 mutations 时容易冲突。
然后是服务端与客户端状态同步,比如用户登录信息,在服务端渲染时获取,要用到 nuxtServerInit 方法(只能在 store/index.js 里定义):
export const actions = {
nuxtServerInit({ commit }, { req }) {
// 从 cookie 里解析用户信息
const token = req.headers.cookie.match(/token=([^;]+)/)?.[1]
if (token) {
commit('user/setToken', token)
}
}
}
这里要注意,nuxtServerInit 只在服务端执行,所以能安全地从请求头里拿 cookie,但如果是客户端操作(比如用户点击登录),得用普通的 action/mutation。
还有个坑:状态污染,服务端渲染时,所有用户共享同一个 Vue 实例,所以如果把用户特定数据存在全局状态里,没及时清空,就会串数据,比如用户 A 的信息被用户 B 看到,解决方法是,在页面组件的 asyncData 或 fetch 里,把用户数据存在组件自己的 data 里,而不是全局 Vuex;或者在每次请求后,重置全局状态里的用户特定数据。
性能优化从哪些细节入手?
Nuxt 项目性能差,多半是 SSR 耗时高、客户端 hydratation 慢、资源体积大这几个原因,先看SSR 性能优化:
服务端渲染时,每个请求都要执行组件的 asyncData 和 fetch,如果接口响应慢,整个渲染时间就会拉长,可以给高频接口加缓存(比如用 Redis 缓存接口返回),或者把一些非关键数据放到客户端请求,避免在服务端做复杂计算(比如大量循环、DOM 操作模拟),这些操作既耗性能,又没意义(因为服务端没有真实 DOM)。
然后是客户端 hydratation 优化,Hydratation 是服务端渲染后,客户端重新渲染并绑定事件的过程,如果页面 DOM 结构复杂,hydratation 时间会很长,可以通过减少不必要的组件嵌套、合理使用 v-if 和 v-show 来简化 DOM,用 keep-alive 缓存页面组件,避免重复渲染:
<nuxt keep-alive />
但要注意,缓存的页面如果有动态数据,要及时更新,不然会显示旧数据。
再讲静态资源处理,Nuxt 默认用 webpack 打包,所以要优化打包配置:
- 图片资源用
vue-loader处理,开启url-loader的 limit,小图片转 base64,减少请求; - 第三方库(lodash)用按需导入,
import { debounce } from 'lodash'代替全量引入; - 开启 CDN 加速,把
node_modules里的大库(Vue、Element UI)通过externals配置,从 CDN 加载,减少打包体积。
打包体积优化,用 webpack-bundle-analyzer 分析包体积,把大的第三方库拆分成单独的 chunk,配置 splitChunks:
// nuxt.config.js
build: {
analyze: true, // 打包后自动打开分析报告
splitChunks: {
chunks: 'all',
minSize: 30000,
maxSize: 0,
minChunks: 1,
maxAsyncRequests: 5,
maxInitialRequests: 3,
automaticNameDelimiter: '~',
name: true,
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
priority: 10,
chunks: 'all'
}
}
}
}
这样能把 node_modules 里的库单独打包,缓存更友好。
部署上线和多端兼容,容易踩哪些雷?
部署 Nuxt 项目分两种场景:服务端渲染(SSR)部署和静态站点生成(SSG,nuxt generate),先讲 SSR 部署:
Nuxt 作为 SSR 项目,需要 Node 服务运行,很多人直接把打包后的 .nuxt 目录丢到服务器,结果启动报错,因为没安装依赖,正确步骤是:服务器装 Node.js,拉取代码后执行 npm install,然后用 nuxt start 启动,或者用 PM2 管理进程(pm2 start npm --name "项目名" -- run start),还要配置 Nginx 反向代理,把 80 端口转发到 Nuxt 启动的 3000 端口(默认),同时处理静态资源(把 dist 目录下的文件作为静态资源目录)。
如果项目是博客、文档这类静态内容多的,用 nuxt generate 生成静态 HTML 更高效,但要注意,动态路由(_id.vue)需要配置 routes 数组,告诉 Nuxt 要生成哪些页面,在 nuxt.config.js 里加:
export default {
generate: {
routes() {
return axios.get('/api/articles').then(res => {
return res.data.map(article => `/article/${article.id}`)
})
}
}
}
不然动态页面不会被生成,访问时会 404。
然后是移动端适配,Nuxt 里用 REM 布局的话,要在 plugins 里加适配逻辑,比如根据设备宽度设置根字体大小:
// plugins/rem.js
if (process.client) {
function setRem() {
const docEl = document.documentElement
const width = docEl.getBoundingClientRect().width
docEl.style.fontSize = (width / 750) * 100 + 'px'
}
window.addEventListener('resize', setRem)
setRem()
}
然后在 nuxt.config.js 里把这个插件引入,注意要在客户端执行。
IE 兼容,Vue2 对 IE 的支持需要 Babel 转译和 polyfill,在 nuxt.config.js 里配置 build.babel:
build: {
babel: {
presets({ isServer }) {
return [
[
'@nuxt/babel-preset-app',
{
targets: isServer ? { node: 'current' } : { ie: 11 }
}
]
]
}
},
polyfill: true // 自动引入必要的 polyfill
}
但要注意,有些新 API(fetch)的 polyfill 得手动加,要测试 IE 下的兼容性,避免白屏。
Vue2 + Nuxt 的组合在 2024 年依然有很多适用场景,尤其是对 SEO 要求高、首屏性能敏感的项目,从初始化时选对模板、配置好核心文件,到 SEO 优化时动态处理元信息,再到路由、状态管理、性能优化和部署的细节把控,每一步都得「避坑」又「增效」,把这些环节吃透,项目开发时才能又快又稳,既满足业务需求,又给用户好体验~要是你在开发中遇到其他具体问题,评论区随时交流~
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网



发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。