Vue 生态
前言
Vue.js 自 2014 年由尤雨溪发布以来,已从一个轻量级前端框架演变为一个拥有完整工具链和丰富周边生态的渐进式框架。Vue 的核心设计哲学——渐进式、易上手、高性能——吸引了全球数百万开发者。本文档从 Nuxt 3 全栈框架、Vite 插件开发、VueUse 工具库源码、生态工具链、框架对比以及生产部署等维度,系统性地梳理 Vue 生态的全貌。
一、Nuxt 3:全栈 Vue 框架
1.1 文件路由系统
Nuxt 3 采用约定优于配置的设计理念,基于文件系统的路由(File-based Routing)是其核心特性之一。开发者只需在 pages/ 目录下创建 .vue 文件,Nuxt 便会自动生成对应的路由配置。
基本路由规则:
pages/index.vue→/pages/about.vue→/aboutpages/blog/index.vue→/blogpages/blog/[id].vue→/blog/:id(动态路由)pages/blog/[id]/comment.vue→/blog/:id/comment(嵌套动态路由)pages/category/[...slug].vue→ 通配路由,匹配/category/a/b/c
路由参数获取:
Nuxt 3 提供了 useRoute 组合函数来获取当前路由信息:
<script setup>
const route = useRoute();
// 动态路由参数
console.log(route.params.id);
// 查询参数
console.log(route.query.page);
</script>导航守卫:
通过 useRouter 和中间件(Middleware)机制实现导航控制。在 middleware/ 目录下创建文件,Nuxt 会自动注册:
// middleware/auth.ts
export default defineNuxtRouteMiddleware((to, from) => {
const token = useCookie('token');
if (!token.value && to.path !== '/login') {
return navigateTo('/login');
}
});1.2 SSR 与 SSG
Nuxt 3 的核心竞争力在于其灵活的多渲染模式支持:
服务端渲染(SSR):
默认模式下,Nuxt 3 在服务端执行 Vue 组件的渲染,生成完整的 HTML 返回给浏览器。这种模式的优势在于:
- SEO 友好:搜索引擎爬虫可以直接抓取完整的页面内容。
- 首屏性能:用户无需等待 JavaScript 下载和执行即可看到页面内容。
- 社交分享:社交平台的内容抓取器能正确提取页面元信息。
渲染流程如下:
- 浏览器请求页面 → 2. Nitro 服务端接收请求 → 3. 执行 Vue 组件,获取数据 → 4. 生成 HTML 字符串 → 5. 注入客户端 hydration 脚本 → 6. 返回完整 HTML → 7. 浏览器显示内容并下载 JS → 8. Vue 接管页面进行交互(水合/hydration)
静态站点生成(SSG):
适用于内容型网站(博客、文档站、营销页面)。在构建时预渲染所有页面,部署时只需静态文件即可:
# 生成静态站点
npx nuxi generate
# 输出目录: .output/public/混合渲染:
Nuxt 3 允许在同一个项目中为不同路由配置不同的渲染模式,这是通过 Route Rules 实现的:
// nuxt.config.ts
export default defineNuxtConfig({
routeRules: {
'/': { prerender: true }, // SSG
'/blog/**': { prerender: true }, // SSG
'/dashboard/**': { ssr: false }, // SPA
'/api/**': { proxy: '/api' }, // API 代理
}
});1.3 自动导入
Nuxt 3 内置了自动导入(Auto-imports)功能,开发者无需手动引入常用的组合式 API:
- Vue API:
ref、reactive、computed、watch等 - Nuxt API:
useState、useFetch、useCookie、useRouter、useRoute等 - 自定义组合函数:
composables/目录下导出的函数自动可用 - 组件:
components/目录下的组件自动注册,支持嵌套目录
<script setup>
// 无需 import,自动可用
const count = ref(0);
const { data, pending, error } = await useFetch('/api/posts');
</script>1.4 模块系统
Nuxt 3 的模块系统是其生态扩展的核心机制。模块可以封装配置、组件、插件、中间件等,实现功能的即插即用。
常用官方模块:
@nuxt/content— 基于文件的 CMS,支持 Markdown/JSON/CSV@nuxt/image— 图片优化,支持响应式图片和格式转换@nuxt/fonts— 字体优化加载@nuxt/scripts— 第三方脚本优化管理nuxt-icon— 图标组件@pinia/nuxt— Pinia 状态管理集成
使用模块:
// nuxt.config.ts
export default defineNuxtConfig({
modules: [
'@nuxt/content',
'@pinia/nuxt',
'~/modules/my-custom-module'
]
});创建自定义模块:
// modules/my-module/index.ts
import { defineNuxtModule, createResolver, addComponent, addImports } from '@nuxt/kit';
export default defineNuxtModule({
meta: {
name: 'my-module',
configKey: 'myModule'
},
defaults: {
prefix: 'My'
},
setup(options, nuxt) {
const resolver = createResolver(import.meta.url);
// 注册组件
addComponent({
name: `${options.prefix}Button`,
filePath: resolver.resolve('./runtime/MyButton.vue')
});
// 注册可自动导入的组合函数
addImports({
name: 'useMyFeature',
as: 'useMyFeature',
from: resolver.resolve('./runtime/composables')
});
}
});1.5 Nitro 引擎
Nitro 是 Nuxt 3 底层的服务端引擎,负责处理请求、构建和部署。它是独立于 Vue 的通用服务端运行时,具备以下特性:
- 跨平台运行时:支持 Node.js、Bun、Deno、Cloudflare Workers、Vercel Edge 等
- 文件系统路由:
server/api/和server/routes/自动注册为 API 路由 - 自动导入:
server/utils/目录下的函数自动可用 - 静态文件服务:
public/目录直接对外提供静态文件 - 无服务器兼容:可部署到 AWS Lambda、Vercel、Netlify 等 Serverless 平台
// server/api/posts.ts
export default defineEventHandler(async (event) => {
const query = getQuery(event);
const body = await readBody(event);
return {
posts: await getPostsFromDatabase(),
page: query.page || 1
};
});二、Vite 插件开发
2.1 插件钩子
Vite 插件基于 Rollup 插件接口,并扩展了 Vite 特有的钩子。理解这些钩子的执行时机是开发高质量插件的基础。
通用钩子(与 Rollup 共享):
| 钩子函数 | 执行时机 | 用途 |
|---|---|---|
options | 构建开始前 | 修改或替换插件选项 |
buildStart | 构建开始时 | 初始化资源加载 |
resolveId | 解析模块 ID 时 | 自定义模块解析逻辑 |
load | 加载模块时 | 返回自定义模块内容 |
transform | 转换模块时 | 对模块源码进行转换 |
moduleParsed | 模块解析完成后 | 访问解析后的模块信息 |
buildEnd | 构建完成时 | 清理资源 |
closeBundle | 打包关闭后 | 最终清理 |
Vite 独有钩子:
| 钩子函数 | 执行时机 | 用途 |
|---|---|---|
config | 解析 Vite 配置前 | 修改配置 |
configResolved | Vite 配置解析后 | 读取最终配置 |
configureServer | Vite Dev Server 启动时 | 添加自定义中间件 |
handleHotUpdate | HMR 发生时 | 自定义热更新行为 |
插件的结构:
// vite-plugin-my-transform.ts
import type { Plugin } from 'vite';
export function myTransformPlugin(): Plugin {
return {
name: 'vite-plugin-my-transform',
// Vite 配置钩子
config(config, { command }) {
if (command === 'build') {
return {
define: {
__BUILD_TIME__: JSON.stringify(Date.now())
}
};
}
},
// 模块转换钩子
transform(code, id) {
if (id.endsWith('.vue')) {
return code.replace(/__VERSION__/g, '1.0.0');
}
}
};
}2.2 虚拟模块
虚拟模块是 Vite 插件中非常强大的功能,它允许插件凭空生成模块内容,供应用代码导入。虚拟模块 ID 通常以 virtual: 开头,以区别于真实文件系统中的模块。
// vite-plugin-virtual-module.ts
import type { Plugin, ResolvedConfig } from 'vite';
const VIRTUAL_MODULE_ID = 'virtual:config';
export function virtualConfigPlugin(): Plugin {
let config: ResolvedConfig;
return {
name: 'vite-plugin-virtual-config',
resolveId(id) {
if (id === VIRTUAL_MODULE_ID) {
return '\0' + VIRTUAL_MODULE_ID;
}
},
load(id) {
if (id === '\0' + VIRTUAL_MODULE_ID) {
return `
export const appConfig = {
appName: 'MyApp',
version: '1.0.0',
buildTime: ${Date.now()},
mode: '${config?.env?.MODE || 'development'}'
};
`;
}
},
configResolved(resolvedConfig) {
config = resolvedConfig;
}
};
}应用代码中直接导入:
import { appConfig } from 'virtual:config';
console.log(appConfig.appName);\0 前缀是 Vite/Rollup 内部标记虚拟模块的约定方式,确保虚拟模块不会被文件系统模块解析器误处理。
2.3 代码转换
代码转换是 Vite 插件最常用的功能之一,通过 transform 钩子实现。每个模块在加载后都会被传递给注册的插件链进行转换。
function envInjectPlugin(): Plugin {
return {
name: 'vite-plugin-env-inject',
enforce: 'pre', // 在其他插件之前执行
transform(code, id) {
// 只处理 .js 和 .vue 文件
if (!/\.(js|vue|ts)$/.test(id)) return null;
// 替换环境变量占位符
const envVarRegex = /__ENV__(\w+)__ENV__/g;
const transformedCode = code.replace(envVarRegex, (match, varName) => {
return JSON.stringify(process.env[varName] || '');
});
return {
code: transformedCode,
map: null
};
}
};
}转换链的执行顺序:
enforce: 'pre'插件的transform- Vite 核心转换(Vue SFC、TypeScript 编译等)
enforce: undefined(默认)插件的transformenforce: 'post'插件的transform
2.4 Rollup 兼容性
Vite 的插件系统与 Rollup 高度兼容,这意味着大多数 Rollup 插件可以直接在 Vite 中使用。但需要注意以下几点:
兼容性清单:
- 使用标准 Rollup 钩子的插件一般可以无缝迁移
- 涉及 Rollup 输出阶段的钩子(如
renderChunk、generateBundle)仅在 Vite 的生产构建阶段生效 - 使用环境中特定 API(如
fs模块)的插件需要确保在浏览器环境中不会意外执行 - Vite 独有钩子(如
configureServer)在 Rollup 中不存在,需要条件判断
示例:在 Vite 中使用 Rollup 插件:
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import alias from '@rollup/plugin-alias';
import resolve from '@rollup/plugin-node-resolve';
export default defineConfig({
plugins: [
vue(),
alias({
entries: {
'@': '/src'
}
}),
resolve({
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json']
})
]
});三、VueUse 源码分析
3.1 设计理念
VueUse 是一个基于 Vue 3 组合式 API 的工具函数库,其核心思想是将浏览器的各种 API、状态管理、异步操作等封装为可复用的组合函数。截至最新版本,VueUse 提供了超过 200 个工具函数,涵盖浏览器 API、动画、状态管理、传感器、网络等多个领域。
VueUse 的设计遵循以下原则:
- 轻量化:按需导入,Tree-shaking 友好
- 响应式:所有返回值都是 Vue 响应式数据
- 类型安全:完整的 TypeScript 类型定义
- 兼容性:与 Vue 3 和 Nuxt 3 无缝集成
3.2 useMouse:鼠标位置追踪
useMouse 是最具代表性的 VueUse 工具函数之一,它演示了如何将浏览器的 DOM 事件与 Vue 响应式系统结合:
// 源码简化版
import { ref } from 'vue';
import { useEventListener } from '@vueuse/core';
export function useMouse(options = {}) {
const {
type = 'page', // page | client | screen
touch = true,
resetOnTouchEnds = false,
initialValue = { x: 0, y: 0 }
} = options;
const x = ref(initialValue.x);
const y = ref(initialValue.y);
useEventListener(window, 'mousemove', (event) => {
if (type === 'page') {
x.value = event.pageX;
y.value = event.pageY;
} else if (type === 'client') {
x.value = event.clientX;
y.value = event.clientY;
} else if (type === 'screen') {
x.value = event.screenX;
y.value = event.screenY;
}
});
return { x, y };
}核心机制分析:
- 响应式状态:使用
ref创建可变的响应式坐标值 - 事件绑定:通过
useEventListener自动管理事件绑定和清理 - 选项模式:通过 options 对象提供灵活的配置,包含默认值
- 返回值解构:返回响应式引用,保持与 Vue 组合式 API 一致的使用体验
useEventListener 内部使用 watchEffect 和 onUnmounted 自动注册和移除事件监听器,无需手动清理。
3.3 useLocalStorage:持久化响应式状态
useLocalStorage 将 localStorage 的读写封装为 Vue 响应式数据,实现了状态持久化与响应式的统一:
// 源码简化版
import { ref, watch } from 'vue';
export function useLocalStorage(key, initialValue, options = {}) {
const {
serializer = JSON,
deep = true,
listenToStorageChanges = true
} = options;
// 读取初始值
const raw = localStorage.getItem(key);
const data = ref(raw !== null ? serializer.parse(raw) : initialValue);
// 监听数据变化,写入 localStorage
watch(
data,
(newValue) => {
if (newValue === null || newValue === undefined) {
localStorage.removeItem(key);
} else {
localStorage.setItem(key, serializer.stringify(newValue));
}
},
{ deep }
);
// 监听其他标签页的存储变化
if (listenToStorageChanges) {
useEventListener(window, 'storage', (event) => {
if (event.key === key) {
data.value = event.newValue
? serializer.parse(event.newValue)
: initialValue;
}
});
}
return data;
}关键设计点:
- 延迟解析:首次读取时解析
localStorage中已有的值 - 自动同步:通过
watch监听响应式数据变化,自动写回localStorage - 跨标签页同步:监听
storage事件,实现多标签页间的数据同步 - 可序列化:默认使用
JSON.stringify/JSON.parse,支持自定义序列化器
3.4 useDebounce:防抖工具
useDebounce 展示了 VueUse 如何将通用的异步控制模式与 Vue 响应式结合:
// 源码简化版
import { ref, watch } from 'vue';
export function useDebounce(value, delay = 200) {
const debounced = ref(value);
let timer = null;
watch(value, (newVal) => {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
debounced.value = newVal;
}, delay);
});
return debounced;
}使用方式:
<script setup>
const searchQuery = ref('');
const debouncedQuery = useDebounce(searchQuery, 300);
watch(debouncedQuery, (query) => {
// 300ms 防抖后发起搜索
fetchSearchResults(query);
});
</script>VueUse 还提供了 useThrottle、useThrottleFn、useDebounceFn 等变体,覆盖不同的使用场景。值得注意的是,VueUse 的防抖实现直接作用于响应式数据,而非函数调用,这与传统的 Lodash debounce 有所不同。
四、Vue 生态工具链
4.1 Vite(构建工具)
Vite 是 Vue 生态的标配构建工具,由尤雨溪创建。它利用浏览器原生 ES Module 实现了极速的冷启动和热更新。
核心优势:
- 开发服务器:基于 ESM 的按需编译,无需打包整个应用即可启动
- HMR:模块热替换,编辑代码后实时更新页面,保持应用状态
- 构建优化:基于 Rollup 的生产构建,支持代码分割、CSS 压缩、Tree-shaking
- 通用性:不仅支持 Vue,还支持 React、Svelte、Solid 等框架
// vite.config.ts
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import AutoImport from 'unplugin-auto-import/vite';
import Components from 'unplugin-vue-components/vite';
export default defineConfig({
plugins: [
vue(),
AutoImport({
imports: ['vue', 'vue-router', 'pinia']
}),
Components({
dirs: ['src/components']
})
],
server: {
port: 3000,
proxy: {
'/api': 'http://localhost:8080'
}
}
});4.2 Vue CLI(已进入维护模式)
Vue CLI 是 Vue 生态中最早的官方脚手架工具,基于 Webpack。虽然官方现在推荐使用 Vite,但大量现存项目仍在使用 Vue CLI。
核心功能:
- 零配置启动 Vue 项目
- 插件系统(
@vue/cli-plugin-router、@vue/cli-plugin-vuex等) - UI 管理界面(
vue ui) - 多环境配置(
.env.production、.env.development)
迁移到 Vite:
对于现有 Vue CLI 项目,可以逐步迁移到 Vite。主要的迁移内容包括:
- 将
vue.config.js配置迁移到vite.config.ts - Webpack 别名由
@配置为 Vite 的resolve.alias - 环境变量从
process.env.VUE_APP_*改为import.meta.env.VITE_* - 样式预处理器的配置方式不同
4.3 Pinia(状态管理)
Pinia 是 Vue 3 官方推荐的状态管理库,是 Vuex 的继任者。它与 Vue 3 的组合式 API 深度集成,同时支持选项式 API。
核心概念:
- Store:状态容器,相当于 Vuex 的 module
- State:状态数据,自动响应式
- Getter:计算属性,用于派生状态
- Action:操作方法,支持同步和异步
// stores/counter.ts
import { defineStore } from 'pinia';
export const useCounterStore = defineStore('counter', () => {
// state
const count = ref(0);
const name = ref('Counter');
// getters
const doubleCount = computed(() => count.value * 2);
// actions
function increment() {
count.value++;
}
async function fetchAndSet() {
const data = await fetch('/api/count').then(res => res.json());
count.value = data.count;
}
return { count, name, doubleCount, increment, fetchAndSet };
});与 Vuex 的区别:
| 特性 | Pinia | Vuex 4 |
|---|---|---|
| TypeScript 支持 | 原生支持 | 需要额外类型定义 |
| 模块化 | 自动按 store 分隔 | 需手动注册 module |
| 数据变更 | 直接修改 state | 需通过 mutation |
| 体积 | ~1KB | 约 10KB |
| DevTools 支持 | 完整支持 | 完整支持 |
4.4 Vue Router(路由管理)
Vue Router 是 Vue 生态的官方路由管理库,目前最新稳定版本为 v4,与 Vue 3 搭配使用。
核心功能:
// router/index.ts
import { createRouter, createWebHistory } from 'vue-router';
const routes = [
{
path: '/',
component: () => import('@/pages/Home.vue'),
name: 'home'
},
{
path: '/blog/:id',
component: () => import('@/pages/Post.vue'),
name: 'post',
props: true
},
{
path: '/dashboard',
component: () => import('@/layouts/Dashboard.vue'),
meta: { requiresAuth: true },
children: [
{ path: '', component: () => import('@/pages/DashboardHome.vue') },
{ path: 'settings', component: () => import('@/pages/Settings.vue') }
]
}
];
const router = createRouter({
history: createWebHistory(),
routes
});
// 全局导航守卫
router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth && !isAuthenticated()) {
next('/login');
} else {
next();
}
});
export default router;4.5 Vue DevTools
Vue DevTools 是 Vue 应用的调试利器,提供以下核心功能:
- 组件树:查看组件层次结构和 props/state 状态
- Timeline:追踪事件、路由变化和性能瓶颈
- Pinia 检查器:实时查看和修改 Store 状态
- 性能分析:识别组件渲染的耗时和频率
- 路由调试:查看当前路由和导航历史
Vue DevTools 提供了浏览器扩展和独立应用两种使用方式。Vue 3 的 DevTools 实现了全新的架构,支持 Vite 插件集成,无需浏览器扩展也能使用。
五、Nuxt 3 vs Next.js 对比
5.1 核心技术对比
| 维度 | Nuxt 3 | Next.js |
|---|---|---|
| 底层框架 | Vue 3 | React |
| 渲染模式 | SSR / SSG / SPA / 混合 | SSR / SSG / ISR / SPA |
| 服务端引擎 | Nitro(可部署到任意平台) | Node.js 或 Edge Runtime |
| 路由方式 | 文件系统路由 | 文件系统路由(App Router / Pages Router) |
| 数据获取 | useFetch / useAsyncData / $fetch | fetch() / server functions |
| 插件生态 | 1000+ Nuxt 模块 | 丰富的 React 生态 |
| TypeScript | 一流支持 | 一流支持 |
| 包体积 | 约 10MB + | 约 50MB + |
| 增量静态再生 | 通过 routeRules 实现 | ISR(Incremental Static Regeneration) |
5.2 数据获取方式对比
Nuxt 3:
<script setup>
// 服务端和客户端均可执行
const { data, pending, error, refresh } = await useFetch('/api/posts', {
key: 'posts',
pick: ['title', 'content'], // 选择性提取字段
transform: (data) => data.posts
});
// useAsyncData 更灵活
const { data: posts } = await useAsyncData('posts', () => {
return $fetch('/api/posts');
});
</script>Next.js:
// App Router (Server Component)
export default async function PostsPage() {
const posts = await fetch('https://api.example.com/posts', {
next: { revalidate: 3600 } // ISR
}).then(res => res.json());
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}5.3 部署生态对比
Nuxt 3 的 Nitro 引擎支持丰富的部署目标:
- Node.js 服务器:直接运行
node .output/server/index.mjs - Vercel:自动适配
@vercel/nitro预设 - Netlify:通过
@netlify/functions部署 - Cloudflare Pages:Edge SSR 支持
- Docker:内置 Dockerfile 支持
- AWS Lambda:通过预设适配
Next.js 的部署目标:
- Vercel:官方首选平台,功能最完整
- 独立输出:
next build && next start - Docker:需要自行编写 Dockerfile
- AWS:通过 Serverless Next.js 组件适配
5.4 适用场景建议
选择 Nuxt 3 的场景:
- 团队熟悉 Vue 技术栈
- 需要快速原型开发
- 项目要求灵活的多渲染模式
- 需要部署到多样化的平台(尤其是非 Node.js 环境)
- 轻量级应用,关注包体积
选择 Next.js 的场景:
- 团队熟悉 React 技术栈
- 需要 App Router 的 Server Components 能力
- 需要成熟的 ISR 增量静态再生
- 项目需要大规模 React 生态支持
- 优先部署 Vercel 平台
六、生产部署最佳实践
6.1 性能优化
加载性能:
- 代码分割:利用 Vite 的自动代码分割,结合路由懒加载
- 图片优化:使用
@nuxt/image或vite-imagetools进行图片压缩和格式转换 - HTTP/2 服务端推送:Nitro 自动优化静态资源加载
- CSS 优化:PurgeCSS 移除未使用的 CSS,关键 CSS 内联
- 字体优化:使用
@nuxt/fonts优化 Google Fonts 加载
运行时性能:
- 虚拟滚动:处理长列表时使用
vue-virtual-scroller - 响应式数据优化:合理使用
shallowRef/shallowReactive避免深层响应式开销 - 计算属性缓存:用
computed代替方法调用 - 组件卸载清理:在
onUnmounted中清理定时器和事件监听
6.2 SEO 与元数据
- 使用
useHead组合函数动态管理页面元信息 - 结构化数据(JSON-LD)注入
- 生成
sitemap.xml和robots.txt - Open Graph / Twitter Card 元标签
useHead({
title: '博客首页',
meta: [
{ name: 'description', content: '我的个人博客' },
{ property: 'og:title', content: '博客首页' },
{ property: 'og:description', content: '我的个人博客' }
],
link: [
{ rel: 'canonical', href: 'https://example.com' }
]
});6.3 安全最佳实践
- Content Security Policy(CSP):通过 Nitro 配置安全头
- 输入验证:服务端和客户端双重验证
- CSRF 防护:使用
useCookie的sameSite属性 - XSS 防护:Vue 默认转义模板绑定,避免使用
v-html - 依赖审计:定期运行
npm audit检查已知漏洞 - 环境变量安全:敏感信息使用
NUXT_SECRET_*前缀,仅在服务端可用
6.4 监控与错误追踪
日志管理:
- Nuxt 3 内置
useLogger进行结构化日志输出 - 可集成 Sentry、Datadog 等 APM 工具
性能监控:
- Web Vitals 采集(LCP、FID、CLS)
- Nitro Server Timing API 用于服务端性能追踪
- Vue DevTools 性能面板用于开发阶段分析
错误处理:
// 全局错误处理
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.hook('vue:error', (error, instance, info) => {
console.error('Vue Error:', error, info);
// 上报到 Sentry 等错误追踪服务
});
nuxtApp.hook('app:error', (error) => {
console.error('App Error:', error);
});
});6.5 CI/CD 流程
# .github/workflows/deploy.yml 示例
name: Deploy
on:
push:
branches: [main]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npm run build
- run: npm run generate # 静态站点生成
- uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: .output/public6.6 Docker 部署
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-alpine AS runner
WORKDIR /app
COPY --from=builder /app/.output ./
EXPOSE 3000
CMD ["node", "./server/index.mjs"]附录:Demo 演示
以下演示展示了一个基于 Nuxt 3 构建的静态博客应用,包含文件路由、Vite 插件转换和虚拟模块的模拟实现。