项目结构解析:Nuxt3目录结构、pages路由约定、components自动导入、public静态资源

好,咱们接着聊。上一章我们把 Nuxt3 装起来了,也跑了个 Hello World。但说实话,那个页面只是个空壳子。真正干活的时候,你得搞清楚 Nuxt3 的项目长什么样,每个文件夹是干嘛的。

我刚开始用 Nuxt3 的时候,看着那一堆文件夹也有点懵。后来踩了几个坑,才慢慢摸清楚它的脾气。今天我就把这块掰开了讲,你跟着走一遍,以后建项目心里就有底了。

Nuxt3 的目录结构:一张图说清楚

你创建一个 Nuxt3 项目后,根目录下大概长这样:

my-nuxt-app/
├── .nuxt/              # 构建产物,别手动改
├── assets/             # 需要编译的静态资源(scss、图片等)
├── components/         # 组件,自动导入
├── composables/        # 组合式函数,自动导入
├── layouts/            # 布局文件
├── middleware/         # 路由中间件
├── pages/              # 页面文件,自动生成路由
├── plugins/            # 插件
├── public/             # 纯静态资源,直接复制
├── server/             # 服务端代码(API、中间件)
├── app.vue             # 根组件
├── nuxt.config.ts      # 配置文件
└── package.json        # 依赖管理

嗯,这里要注意:.nuxt 文件夹是 Nuxt 自动生成的,你千万别手贱去改它。我有个同事曾经试图在里面加代码,结果下次构建全没了,白忙活半天。

pages 路由约定:文件即路由

Nuxt3 最爽的一点,就是 文件即路由。你在 pages/ 下面放一个 about.vue,它就自动生成了 /about 这个路由。不用像 Vue Router 那样手动配,省心不少。

举个例子:

pages/
├── index.vue          # 对应 /
├── about.vue          # 对应 /about
├── blog/
│   ├── index.vue      # 对应 /blog
│   └── [id].vue       # 对应 /blog/:id(动态路由)
└── user/
    └── [id]/
        └── profile.vue # 对应 /user/:id/profile

动态路由用方括号 [] 包起来。比如 [id].vue,你在页面里可以通过 useRoute().params.id 拿到参数。

个人经验: 我习惯把动态路由的参数名起得有意义,比如 [slug].vue 而不是 [id].vue。这样看文件名就知道它要干嘛,团队协作时特别有用。

嵌套路由呢?也很简单。你建一个文件夹,里面放个 index.vue,再放个子页面。比如 blog/index.vueblog/[id].vue,它们天然就是父子关系。

components 自动导入:告别手动 import

这个功能我太爱了。在 Nuxt3 里,你把组件放在 components/ 目录下,它就会自动注册。你在任何页面或布局里直接用组件名就行,不用写 import

比如你有个 components/MyButton.vue

<template>
  <button class="btn">
    <slot />
  </button>
</template>

在页面里直接用:

<template>
  <MyButton>点我</MyButton>
</template>

是不是很爽?但有个坑要注意:组件名必须是大驼峰。你写 my-button.vue 的话,在模板里要用 <MyButton />。Nuxt 会自动把连字符转成驼峰。

我曾经踩过的坑: 有一次我把组件命名为 icon-star.vue,然后在模板里写 <IconStar />,结果死活渲染不出来。后来发现是因为文件名里有两个连字符,Nuxt 解析时出了歧义。建议组件名尽量简洁,比如 StarIcon.vue

如果你有嵌套目录,比如 components/form/Input.vue,那在模板里要用 <FormInput />。Nuxt 会把目录名也拼进去,用驼峰连接。

public 静态资源:直接引用,不编译

public/ 目录放的是纯静态文件。比如 favicon.ico、robots.txt、一些不会变动的图片。这些文件会被直接复制到构建后的根目录,你可以在代码里用绝对路径引用。

举个例子:

public/
├── favicon.ico
├── robots.txt
└── images/
    └── logo.png

在模板里引用:

<img src="/images/logo.png" alt="Logo" />

注意路径前面要加 /,表示从根目录开始找。

关键区别: public/ 里的文件不会被 Webpack 或 Vite 处理。而 assets/ 里的文件会经过编译(比如压缩图片、编译 SCSS)。所以,如果你有需要处理的资源,放 assets/;如果是纯静态的,放 public/

我个人的习惯是:logo、图标、第三方库的静态文件放 public/;自己写的样式、需要压缩的图片放 assets/。这样分工明确,不会乱。

其他重要目录速览

目录 作用 自动导入?
composables/ 组合式函数,比如 useAuth()
layouts/ 布局文件,比如 default.vue
middleware/ 路由守卫,比如权限校验
plugins/ 第三方库或自定义插件 否,需手动注册
server/ 服务端 API 和中间件

这里提一下 composables/。你写一个 composables/useCounter.ts,然后在页面里直接 const counter = useCounter() 就能用。Nuxt 会自动帮你导入。这个模式特别适合封装业务逻辑,我现在的项目里几乎每个页面都会用到。

总结一下

说白了,Nuxt3 的目录结构就是一套约定。你按它的规矩来,它帮你省掉很多配置工作。pages 自动生成路由,components 自动导入,public 直接引用——这三板斧用熟了,开发效率能翻倍。

下一章我们会深入 app.vue 和布局系统,到时候你会看到这些目录是怎么串联起来的。先消化今天的内容,有问题随时翻回来看看。