- 作者:老汪软件技巧
- 发表时间:2024-09-01 21:04
- 浏览量:
系列
前言
作为一名 Vue Developer,我习惯使用 Vue 组件 和 组合式 API 以及 渐进式的生态 来构建各类单页面应用(SPA),也喜欢在业余时间捣鼓开源项目和技术博客。随着项目各类需求的迭代和升级,我开始探索学习服务端渲染(SSR)和 静态站点生成(SSG)的场景和技术。
而在这探索和学习中,Nuxt 基于 Vue 的元框架,天然对 Vue 开发者的友好性,吸引了我的关注。它不仅支持多种渲染模式,集成了路由管理、状态管理、SEO优化,还提供了更丰富的生态(图层、插件、中间件、模块)以及支持多种部署环境(Github Pages、Nodejs、Cloudflare、Netlify、Vercel)
单页应用 SPA
单页应用是一种 Web 应用架构,其中应用的所有交互和内容都在一个 HTML 页面中进行,只有必要的部分才会动态加载或更新。
缺点
服务端渲染 SSR
服务端渲染(Server-Side Rendering)是在服务器端生成完整的 HTML 页面,然后将这些页面发送到客户端。
缺点
静态站点生成 SSG
静态站点生成是在构建时生成所有页面的静态 HTML 文件,这些文件在用户请求时直接提供。
缺点
初识 Nuxt概述简介
Nuxt 是一个基于 Vue 的元框架,专注于构建现代化的 Web 应用。它提供了一系列功能和工具,旨在简化开发过程,提高应用性能,并支持多种渲染模式。无论是服务端渲染、静态站点生成、还是单页面应用都能提供出色的支持,并具有如下特点:
应用场景
企业级应用
企业级应用通常需要高性能、可扩展和可维护的解决方案。Nuxt 的服务端渲染功能可以提高应用的首屏加载速度和 SEO 性能,同时也可以支持复杂的业务逻辑和大规模的应用结构。
例: 公司官网、企业门户网站、内部管理系统、客户管理系统
内容管理系统需要高效的内容发布和管理功能。Nuxt 的静态站点生成功能适合生成静态的内容页面,提高加载速度和减少服务器负担。
例: 博客、新闻网站、技术文档网站 (由 @nuxt/content 模块实现)
电子商务网站
电子商务网站需要快速的页面加载速度和良好的用户体验。Nuxt 可以通过 SSR 提高页面加载性能,并通过静态生成技术预渲染产品页面以提高访问速度。
例: 在线商店、产品目录、电子商务平台
......
关键概念
在不断学习 Nuxt 旅途中,了解了 Nuxt 通过 图层(Layers)、插件(Plugins)、中间件(Middleware)、模块(Modules)等概念,为开发者提供了一个高度灵活和可扩展的开发环境,所以就图层、插件、中间件、模块、服务端渲染、以及运行时配置,做进一步说明和讲解。
图层 Layers
图层是一个包含 Nuxt 配置、模块和其他资源的目录。每个图层可以包含自己的 nuxt.config.js 配置文件、模块、插件等。这种结构使得不同的图层可以独立开发和管理。
具有如下作用
通过将应用拆分为多个图层,可以实现更好的模块化,每个图层专注于应用的一个特定方面。图层之间可以继承和覆盖配置,使得共享配置可以集中管理,同时允许对特定图层定制化设置。通过图层可以在多个项目中复用相同模块和配置,提高开发效率和一致性,图层可以是 npm 包
其他说明
图层内文件将被 Nuxt 自动扫描并在项目中使用,而无需手到导入。这意味着,图层内的目录和文件等同于你在项目的手动编写开发一样。当然就近原则,项目中同名组件、布局、页面等覆盖于图层中同名文件内容。如果以 JavaScript 的作用域中变量去理解项目所引用的图层内容,还挺 "适用"。每个 Nuxt 项目都可以视为图层,并根据需要加载不同图层,也可以被其他图层加载
应用场景
多主题支持:
通过图层,你可以为应用创建多个主题,每个主题作为一个独立的图层,并根据用户的选择或配置动态加载不同的主题图层。多租户应用:
在多租户应用中,不同租户可能需要不同的配置或功能。你可以为每个租户创建一个图层,这些图层可以包含特定的路由、组件和服务端逻辑。插件系统:
开发一个可扩展的插件系统,每个插件作为一个独立的图层,实现特定功能,如身份验证、支付集成、数据分析等。渐进式迁移:
如果你正在将一个大型遗留项目迁移到 Nuxt,可以将不同的部分逐步迁移到图层中,确保平稳过渡。
参考文档
官方文档:/docs/guide/…视频讲解:…插件 Plugins
Nuxt 插件是一个功能强大的机制,它允许开发者在 Vue 应用初始化时执行自定义代码,以扩展或定制应用的行为,如果是服务端插件则允许开发者配置身份验证和授权、数据上的预处理以及处理请求拦截、重定向、日志记录等功能。
Nuxt 插件是分 客户端插件 和 服务端插件 两类:
客户端插件 (Nuxt4 目录结构: ~/app/plugins/xxx.ts)
// 例. 全局注册 Ant Design Vue 组件
import Antd from 'ant-design-vue'
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(Antd)
})
// 例. 全局注册指令
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.directive('action', {
mounted (el) {
//...
},
})
})
官方文档:/docs/guide/…
服务端插件 (Nuxt4 目录结构: ~/server/plugins/xxx.ts)
// 例. 返回 html 页面时,注入 信息
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('render:html', (html) => {
html.head.push('')
})
})
Nitro Plugin 文档:nitro.unjs.io/guide/plugi…
中间件 Middleware
在 Nuxt 框架中,中间件也分 客户端路由中间件 和 服务端路由中间件。 客户端路由中间件通常用于 Vue 路由的权限验证和重定向,而服务端路由中间件则通常用于来自客户端API请求认证和授权,以及数据和异常的预处理。
客户端路由中间件 (Nuxt4 目录结构: ~/app/middleware/xxx.ts)
// 例. Vue 路由拦截处理 => ~/app/middleware/auth.ts
export default defineNuxtRouteMiddleware((to, from) => {
if (to.params.id === '1') {
return abortNavigation() // 阻止路由访问
}
if (to.path == '/index') {
return navigateTo('/') // 路由重定向
}
})
<template>
<div class="container">
Render Page Content
div>
template>
<script setup lang="ts">
definePageMeta({
middleware: 'auth' // 使用中间件
})
script>
官方文档 /docs/guide/…
推荐视频 …
服务端路由中间件 (Nuxt4 目录结构: ~/server/middleware/xxx.ts)
// 例. Api Token 校验
export default defineEventHandler((event) => {
const token = getRequestHeader(event, 'token')
if (!token) {
throw createError({
statusCode: 403,
statusMessage: 'Token expired',
})
}
})
官方文档
模块 Modules
Nuxt 模块是一个扩展和定制 Nuxt 应用的核心机制,它可以为你的项目导入组件库,集成第三方服务、自动化配置等,而无需你手动编写所有代码。
模块与插件区别
模块主要作用如下
常用的官方和社区模块
如何使用模块?(以 Ant Design Vue 为例)
添加依赖项 @ant-design-vue/nuxt
npx nuxi@latest module add ant-design-vue
完善 nuxt.config.ts 配置选项
export default defineNuxtConfig({
modules: [
'@ant-design-vue/nuxt'
],
antd:{
// Options
}
})
项目中使用组件,无需手动导入
<template>
<AButton @click="doClick">
按钮
AButton>
template>
<script lang="ts" setup>
const doClick = () => {
message.info("按钮已触发");
}
script>
社区现有模块:/modules
开发模块文档:/docs/guide/…
服务端渲染 SSR
在 Nuxt SSR 模式下,客户端向服务器发出请求后,服务器会先执行相关的逻辑(如获取数据、渲染模板等),生成完整的 HTML 页面,并将其返回给客户端。客户端接收到页面后,立即展示给用户,同时在后台加载并激活 Vue 代码以进行后续的交互。
具体流程如下:
请求阶段:用户在浏览器中访问页面时,浏览器会向服务器发出请求。服务器渲染:服务器接收到请求,执行数据获取、模板渲染,生成 HTML 页面。返回 HTML:服务器将生成的 HTML 页面返回给浏览器。浏览器展示:浏览器接收到 HTML 后,立即展示页面内容。客户端激活:接下来 Vue 客户端脚本会加载激活,使页面具备交互能力。
这里服务端获取数据传输给客户端,Nuxt 称之为预渲染页面的有效负载,它一般是随着 html 页面一起返回。那么怎么样的数据获取才是真正的有效负载呢?
运行时配置 Runtime
在 Nuxt 中,运行时配置是指在应用运行时,动态设置或调整配置参数的功能。运行时配置通常用于设置环境相关的变量,例如 API 密钥、数据库连接字符串、或根据不同的部署环境(如开发、生产、测试等)切换配置。
推荐视频:…
运行时配置的用途
环境区分:根据不同的环境(开发、生产等)设置不同的选项,如 API 的基础 URL。安全性:将敏感信息(密钥、数据库配置)存储在环境变量中,而不是代码硬编码。灵活性:在不需要重新构建应用的情况下,可以动态调整某些配置参数。
运行时配置的示例
设置运行时配置
export default defineNuxtConfig({
runtimeConfig: {
public: {
apiBase: '/api' // 服务端和客户端都可用, 默认 '/api'
},
apiSecret: 'key', // 仅服务端可用, 默认 'key'
}
})
项目中使用运行时配置
<template>
<div class="container">
<div class="look-base-url">
{{ config.public.apiBase }}
div>
<div class="look-user-data">
{{ data }}
div>
div>
template>
<script setup lang="ts">
const config = useRuntimeConfig()
const { data } = await useFetch('/api/user', {
method: 'post',
body: {
apiSecret: import.meta.server
? config.apiSecret // 仅在服务端渲染时有值
: ''
}
})
script>
如果构建了 node-server 模式下的前端项目,如何设定运行不同部署环境下的变量
# 测试环境 (apiBase: `/test/api`, apiSecret: `test-key`)
NUXT_PUBLIC_API_BASE=/test/api NUXT_API_SECRET=test-key node .output/server/index.mjs
# 正式环境 (apiBase: `/prod/api`, apiSecret: `prod-key`)
NUXT_PUBLIC_API_BASE=/prod/api NUXT_API_SECRET=prod-key node .output/server/index.mjs
如果是构建了 node-server 模式下的前端项目,我们一般是通过 PM2 来设定变量和后台运行
// ecosystem.config.cjs
module.exports = {
apps: [
{
name: "NuxtApp", // 表示 PM2 运行实例的唯一名称
autorestart: true, // 默认为 true, 发生异常的情况下自动重启
exec_mode: "cluster", // 多核 CPU 上运行多个实例
instances: "max", // max表示最大的 应用启动实例个数,仅在 cluster 模式有效
script: ".output/server/index.mjs", // 应用程序的启动脚本
// 生产环境运行时变量
env_production: {
NUXT_PUBLIC_API_BASE: "/prod/api",
NUXT_API_SECRET: "prod-key",
},
// 测试环境运行时变量
env_test: {
NUXT_PUBLIC_API_BASE: "/test/api",
NUXT_API_SECRET: "test-key",
},
},
],
};
# 运行 测试环境
pm2 start ecosystem.config.cjs --env test
# 运行 正式环境
pm2 start ecosystem.config.cjs --env production
与 Vue 相比搭建 Template 模版
使用 Nuxt 搭建模版相比于直接使用 Vue 搭建,具有以下几个优势:
Nuxt 提供了服务端渲染的能力,可以减少首屏加载时间,并能提供非常好的SEO优化。另外还可以借助于 来实现组件纯服务端渲染的能力,为一些涉及密钥等安全的页面提供保障。
Nuxt 提供了服务端引擎的能力,可以灵活地管理和扩展项目的服务端逻辑(API 路由的定义和代理等),同时允许为不同的部署环境构建输出 (传统服务器、无服务器环境、静态站点等)。
Nuxt 提供了强大的布局系统,可以轻松管理不同的页面布局,支持在页面中通过 definePageMeta 中的 layout 定义不同的布局适配,同时还支持 setPageLayout API 动态更改当前页面的布局。
Nuxt 提供文件系统路由可以自动生成页面路由,减少了手动配置的工作量。这在构建具有大量页面的后台管理系统时尤为便利。而在适配技术文档的模版上,Nuxt官方也提供了 @nuxt/content 功能上更胜于 vitepress 的模块,很轻松地实现由 Markdown 文件编写的技术文档网站。
Nuxt 内置了许多功能,如中间件、插件机制、模块系统等,这些功能可以极大地简化开发流程,使得开发各类模版更加高效。(如 开发后台管理系统模块,Nuxt有许多开箱即用的模块:Auth 模块、Axios 模块、PWA 模块、API 请求、缓存等)
Nuxt 提供了图层这一强大的共享和复用机制,允许你将应用的不同部分(如核心功能、主题等)拆分到独立的图层中。这种分离使得代码更加模块化和易于维护。同时也支持复用来自 npm 包的第三方图层而在使用中无需手动导入 ,这解决了我在搭建后台管理系统模版时碰到的困惑,即升级或修复后台管理系统时,如何同步已使用这个后台管理系统的更新。
渲染 Rendering 多样性
在之前的章节中,我们已经对单页应用(SPA)、服务端渲染(SSR)和 静态站点生成(SSG)的各个特点和应用场景都做了详细的说明。但 Nuxt 能为我们做的却远不止如此,它还提供了混合渲染 (为不同的路由做适配),为复杂的业务场景做适配。
export default defineNuxtConfig({
routeRules: {
// 在构建时预渲染
'/': { prerender: true },
// 仅在客户端渲染呈现
'/spa/**': { ssr: false },
// 在 10 秒内重用这个缓存的响应
'/ten/**': { cache: { maxAge: 10 } },
// 在客户端不在发起远程 script 脚本的请求,仅 script 内联脚本可执行
'/no-js/**': { experimentalNoScripts: true },
// 页面按需生成,在后台重新验证,缓存直至 API 响应发生变化
'/products': { swr: true },
// 页面按需生成,在后台重新验证,缓存 1 小时(3600 秒)
'/products/**': { swr: 3600 },
// 页面按需生成,在后台重新验证,在 CDN 上缓存 1 小时(3600 秒),功能与 swr 类似
'/blog': { isr: 3600 },
// 页面在下次部署之前按需生成一次,缓存在 CDN 上
'/blog/**': { isr: true },
// 启用跨源资源共享(CORS)功能
'/api/**': { cors: true },
// 重定向处理
'/old-page': { redirect: '/new-page' },
// 返回响应时添加自定义 HTTP 头部 `x-magic-of`,其值为 `nuxt and vercel`
'/headers': { headers: { 'x-magic-of': 'nuxt and vercel' } },
}
})
SWR(Stale-While-Revalidate)
概念:是一种缓存策略,主要用于客户端数据获取和更新。它允许在数据过期(stale)后立即返回缓存的数据,同时在后台重新验证并获取新的数据。当新的数据被获取并更新缓存后,客户端会重新渲染组件。
缓存优先:后台重新验证:ISR(Incremental Static Regeneration)
概念:是一种用于静态网站生成的技术,可以在不重新构建整个网站的情况下,逐步更新静态页面。ISR 允许在构建后对特定页面进行增量更新,而不是重新生成整个站点。
服务器端缓存:ISR 主要用于服务器端缓存和更新。定期更新:在一定时间间隔重新生成静态页面。生成后的内容会被缓存,直到下一个更新周期。依赖平台:与 SWR 不同的是,它往往依赖平台(像 Vercel、Netlify),提供平台级性能。性能优化:提高站点性能,减少重新生成整个站点的需要。
官方文档:
推荐视频:…
Demo 演示:/danielroe/n…
部署 Environment 灵活性
Nuxt 在部署环境和运行环境变量配置上非常灵活,在之前的章节中也有说明。
前端 Engineering 安全性
虽然前端应用的安全性在很大程度上依赖于良好的实践和策略 (如 内容安全策略CSP、Vue 模版转义、CSRF 防护),但 Nuxt 提供了一些强大的功能来进一步确保前端应用的安全性。
相关参考官方文档
/
nitro.unjs.io/guide
视频系列
@TheAlexLic…