Nuxt: 安装与项目结构
最后更新:2026-08-26
Alice 想在本机跑起 MegaShop,却被 Nuxt 3 的目录约定搞晕——文件放错位置组件就不自动导入。Bob 管理的项目配置混乱,每次构建都出问题。Charlie 需要一个清晰的目录规范来统一团队开发。
1. 你将学到
- npx nuxi@latest init 创建项目与包管理器选择
- 核心目录约定:pages/components/composables/server 等
- nuxt.config.ts 配置详解
- auto-imports 自动注册原理
- MegaShop 项目初始化实战
2. 一个开发者的真实故事
(1) 痛点:目录混乱导致组件"消失"
Alice 把 ProductCard.vue 放在了 src/components/shop/ 下,结果页面报错 "Component ProductCard is not found"。她不知道 Nuxt 3 的目录约定——组件路径决定了组件名。components/shop/ProductCard.vue 应该用 `<ShopProductCard />` 引用。这种隐式规则让新手频频踩坑。
(2) Nuxt 3 目录约定的解法
Nuxt 3 用目录约定替代手动配置——文件放在正确的目录就自动可用,无需 import。理解约定后,Alice 只需按规则组织文件:
TEXT
📖 仅展示
components/
ProductCard.vue → <ProductCard />
shop/
ProductList.vue → <ShopProductList />
(3) 收益:开发效率翻倍
理解目录约定后,Alice 的组件不再"消失",团队新成员上手时间从 2 天缩短到 4 小时。
3. 创建 Nuxt 3 项目
(1) 初始化命令
BASH
# Create new Nuxt 3 project
npx nuxi@latest init megashop
# Or with specific package manager
npx nuxi@latest init megashop --packageManager pnpm
(2) 包管理器对比
| 维度 | npm | pnpm | yarn |
|---|---|---|---|
| 安装速度 | 🐢 慢 | ⚡ 最快 | ⚡ 快 |
| 磁盘占用 | 🔴 高 | 🟢 低(硬链接) | 🟡 中 |
| Monorepo | ⚠️ 需 workspaces | ✅ 原生支持 | ✅ 支持 |
| 推荐度 | ⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ |
▶ 示例:初始化与启动
BASH
# Step 1: Create project
npx nuxi@latest init megashop
# Step 2: Enter project directory
cd megashop
# Step 3: Install dependencies
npm install
# Step 4: Start dev server
npm run dev
# → Nuxt dev server running at http://localhost:3000
输出:
TEXT
📖 仅展示
# 命令执行成功
▶ 示例:package.json 核心脚本
JSON
{
"name": "megashop",
"private": true,
"scripts": {
"build": "nuxi build",
"dev": "nuxi dev",
"generate": "nuxi generate",
"preview": "nuxi preview",
"postinstall": "nuxi prepare"
},
"dependencies": {
"nuxt": "^3.12.0"
},
"devDependencies": {
"@nuxt/devtools": "latest"
}
}
输出:
JSON
{
"name": "megashop",
"private": true,
"scripts": {
"build": "nuxi build",
"dev": "nuxi dev",
"generate": "nuxi generate",
"preview": "nuxi preview",
"postinstall": "nuxi prepare"
},
"dependencies": {
"nuxt": "^3.12.0"
},
"devDependencies": {
"@nuxt/devtools": "latest"
}
}
4. 核心目录约定
(1) 目录结构全景
graph TB
A[megashop/] --> B[pages/ → Routes]
A --> C[components/ → Auto-import Components]
A --> D[composables/ → Auto-import Functions]
A --> E[server/ → API Routes]
A --> F[layouts/ → Page Layouts]
A --> G[plugins/ → Auto-register Plugins]
A --> H[middleware/ → Route Guards]
A --> I[assets/ → Processed by Build]
A --> J[public/ → Static Files]
A --> K[nuxt.config.ts → Project Config]
A --> L[app.vue → Root Component]
(2) 各目录职责与规则
| 目录 | 职责 | 自动注册 | MegaShop 用途 |
|---|---|---|---|
| pages/ | 路由页面 | ✅ 自动生成路由 | 商品页/分类页/首页 |
| components/ | Vue 组件 | ✅ 自动导入 | ProductCard/Header/Footer |
| composables/ | 组合式函数 | ✅ 自动导入 | useCart/useProduct |
| server/api/ | API 路由 | ✅ 自动注册 | /api/products /api/cart |
| server/middleware/ | 服务端中间件 | ✅ 全局生效 | auth/CORS |
| layouts/ | 页面布局 | ✅ 自动注册 | default/sidebar |
| plugins/ | 插件 | ✅ 自动执行 | stripe/payment |
| middleware/ | 路由中间件 | ✅ 可引用 | auth/admin |
| assets/ | 构建处理资源 | ❌ 需引用 | CSS/字体/SCSS |
| public/ | 静态文件 | ❌ 直接访问 | favicon/robots.txt |
▶ 示例:MegaShop 目录规划
TEXT
📖 仅展示
megashop/
├── app.vue # Root component
├── nuxt.config.ts # Project config
├── pages/
│ ├── index.vue # Homepage
│ ├── products/
│ │ ├── index.vue # Product list
│ │ └── [id].vue # Product detail
│ ├── categories/
│ │ └── [slug].vue # Category page
│ ├── cart.vue # Shopping cart
│ └── about.vue # About page
├── components/
│ ├── AppHeader.vue # → <AppHeader />
│ ├── AppFooter.vue # → <AppFooter />
│ └── product/
│ ├── ProductCard.vue # → <ProductProductCard /> ①
│ └── ProductList.vue # → <ProductProductList /> ①
├── composables/
│ ├── useCart.ts # → auto-imported
│ └── usePriceFormat.ts # → auto-imported
├── server/
│ └── api/
│ ├── products/
│ │ └── index.get.ts # GET /api/products
│ └── cart/
│ └── index.post.ts # POST /api/cart
├── layouts/
│ ├── default.vue # Default layout
│ └── sidebar.vue # Sidebar layout
├── middleware/
│ └── auth.ts # Named middleware
├── plugins/
│ └── stripe.client.ts # Client-only plugin
├── assets/
│ └── css/
│ └── main.css # Global styles
└── public/
├── favicon.ico
└── robots.txt
输出:
TEXT
📖 仅展示
执行成功
⚠️ 注意: ①
components/product/ProductCard.vue 默认前缀为 Product,即 <ProductProductCard />。可在 nuxt.config.ts 配置 pathPrefix 关闭前缀。
5. nuxt.config.ts 配置详解
(1) 核心配置选项
| 选项 | 类型 | 说明 | MegaShop 示例 |
|---|---|---|---|
| ssr | boolean | 全局 SSR 开关 | true |
| modules | array | 模块列表 | @pinia/nuxt |
| runtimeConfig | object | 运行时配置 | API密钥/数据库URL |
| app | object | 应用元数据 | head/title/templateId |
| vite | object | Vite 配置 | 代理/插件 |
| routeRules | object | 路由级渲染策略 | ISR/CSR/缓存 |
| components | object | 组件导入配置 | 前缀/扫描路径 |
▶ 示例:MegaShop 基础配置
TYPESCRIPT
// nuxt.config.ts
export default defineNuxtConfig({
// Global SSR setting
ssr: true,
// App metadata
app: {
head: {
title: 'MegaShop - Premium E-Commerce',
meta: [
{ name: 'description', content: 'Millions of products, shipped worldwide' }
]
}
},
// Runtime config (server-only secrets)
runtimeConfig: {
// Private - server only
databaseUrl: process.env.DATABASE_URL,
stripeSecretKey: process.env.STRIPE_SECRET_KEY,
// Public - exposed to client
public: {
apiBase: process.env.API_BASE || 'http://localhost:3000/api',
stripePublishableKey: process.env.STRIPE_PUBLISHABLE_KEY
}
},
// Modules
modules: [
'@pinia/nuxt',
'@nuxtjs/tailwindcss'
],
// Component path prefix setting
components: [
{ path: '~/components', pathPrefix: false }
]
})
输出:
TEXT
📖 仅展示
// 执行成功
▶ 示例:routeRules 渲染策略
TYPESCRIPT
// nuxt.config.ts - route-level rendering rules
export default defineNuxtConfig({
routeRules: {
// Homepage: pre-render at build time
'/': { prerender: true },
// Product list: ISR with 60s revalidation
'/products': { swr: 60 },
// Product detail: ISR with 3600s revalidation
'/products/**': { swr: 3600 },
// Admin dashboard: client-side only
'/admin/**': { ssr: false },
// API: CORS headers
'/api/**': { cors: true }
}
})
输出:
TEXT
📖 仅展示
// 执行成功
6. Auto-imports 机制原理
(1) 自动注册流程
flowchart LR
A[Nuxt Scan Directories] --> B[Generate .nuxt/imports.d.ts]
B --> C[Generate .nuxt/components.d.ts]
C --> D[TypeScript Auto-complete]
A --> E[Generate .nuxt/routes.ts]
E --> F[Vue Router Config]
(2) 自动导入范围
| 类型 | 目录 | 前缀规则 | 示例 |
|---|---|---|---|
| 组件 | components/ | 目录路径前缀 | ProductCard → <ProductCard /> |
| Composable | composables/ | use 前缀 | useCart() → auto-imported |
| 工具函数 | utils/ | 无前缀 | formatPrice() → auto-imported |
| 内置 API | Nuxt 3 内核 | use 前缀 | useFetch/useState/useRouter |
▶ 示例:Composable 自动导入
TYPESCRIPT
// composables/usePriceFormat.ts
// No need to import - auto-imported by Nuxt
export function usePriceFormat(price: number, currency: string = 'USD'): string {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency
}).format(price)
}
// In any component - use directly
// const formatted = usePriceFormat(2999.99) → "$2,999.99"
输出:
TEXT
📖 仅展示
// 执行成功
▶ 示例:组件自动导入验证
VUE
<!-- pages/index.vue -->
<template>
<!-- All components auto-imported, no import statement needed -->
<div>
<AppHeader />
<ProductCard :product="featured" />
<AppFooter />
</div>
</template>
<script setup lang="ts">
// All composables auto-imported
const { data: featured } = await useFetch('/api/products/featured')
const price = usePriceFormat(featured.value?.price || 0)
</script>
输出:
TEXT
📖 仅展示
// 执行成功
7. 综合示例:MegaShop 项目初始化
BASH
# ============================================
# MegaShop Project Initialization
# Complete setup from zero to running dev server
# ============================================
# 1. Create project
npx nuxi@latest init megashop
cd megashop
# 2. Install core dependencies
npm install @pinia/nuxt @nuxtjs/tailwindcss
# 3. Create directory structure
mkdir -p pages/products pages/categories
mkdir -p components/product
mkdir -p composables
mkdir -p server/api/products server/api/cart
mkdir -p layouts
mkdir -p middleware
mkdir -p plugins
mkdir -p assets/css
mkdir -p public
# 4. Initialize Git repository
git init
git add .
git commit -m "feat: initialize MegaShop with Nuxt 3"
# 5. Start development server
npm run dev
❓ 常见问题
Q components 子目录的组件名为什么有前缀?
A Nuxt 3 默认用目录路径作前缀,
components/product/Card.vue 变成 <ProductCard />。可在 nuxt.config.ts 设 components: [{ path: '~/components', pathPrefix: false }] 关闭。Q runtimeConfig 的 public 和私有字段有什么区别?
A 私有字段仅在服务端可用(API Key/数据库密码),public 字段会暴露到客户端。永远不要把密钥放在 public 里。
Q app.vue 和 pages/ 可以共存吗?
A 可以,但 app.vue 必须包含
<NuxtPage /> 来渲染页面。如果没有 pages/ 目录,app.vue 就是唯一的页面。Q assets 和 public 有什么区别?
A assets/ 里的文件会经过 Vite 构建(可引用、可优化、可 hash),public/ 里的文件原样复制到输出目录,直接通过 URL 访问。
Q .nuxt 目录需要提交到 Git 吗?
A 不需要。.nuxt 是 Nuxt 自动生成的临时目录,已在 .gitignore 中。运行 nuxi prepare 或 npm run dev 会自动重新生成。
Q Nuxt 3 支持 src 目录模式吗?
A 支持。可以把 pages/components 等放进 src/ 下,Nuxt 3 会自动识别。也可在 nuxt.config.ts 的 dir 选项自定义。
📖 小节
- 使用
npx nuxi@latest init创建项目,推荐 pnpm 作为包管理器 - Nuxt 3 核心目录:pages(路由)、components(组件)、composables(函数)、server(API)、layouts(布局)
- nuxt.config.ts 是项目核心配置:runtimeConfig 管理密钥、routeRules 管理渲染策略
- auto-imports 让组件/Composable/工具函数无需手动 import
- MegaShop 目录规划需遵循约定,确保所有文件放在正确位置
📝 作业
- 基础题(难度⭐):用 nuxi init 创建项目,画出你项目的目录树
- 进阶题(难度⭐⭐):在 components/ 下创建两级子目录的组件,验证自动导入时的命名规则(如
components/shop/product/Card.vue的标签名是什么) - 挑战题(难度⭐⭐⭐):配置 nuxt.config.ts 的 routeRules,让首页预渲染、商品页 ISR 60 秒、管理页 CSR,并验证效果
---|