nuxt3目录结构详解

在 Nuxt.js 3 中,一个应用程序的文件夹结构具有一定的规范性。以下是 Nuxt.js 3 的文件夹结构及其用途的详细解释:

.nuxt 目录

Nuxt 使用.nuxt/目录在开发中生成您的Vue应用程序。

你不应该碰里面的任何文件,因为整个目录将在运行nuxt dev时重新创建。

.output 目录

Nuxt在为生产构建应用程序时创建.output目录。

你不应该碰里面的任何文件,因为整个目录将在运行nuxt build时重新创建。

使用此目录将Nuxt应用程序部署到生产环境。

assets 目录

assets/ 目录用于添加构建工具(webpack或Vite)将处理的所有网站资产。

该目录通常包含以下类型的文件:

  • Stylesheets (CSS, SASS, etc.)
  • Fonts
  • Images 它不会从public/目录中提供。

如果你想从服务器上提供资产,我们建议看一下public/目录

Components 目录

components/目录是您放置所有Vue组件的地方,然后可以在您的页面或其他组件中导入这些组件(了解更多)

Nuxt自动导入你的components目录中的任何组件(以及你可能正在使用的任何模块注册的组件)。

| components/
--| TheHeader.vue
--| TheFooter.vue
layouts/default.vue

Custom directories

默认情况下,只扫描~/components目录。如果要添加其他目录,或更改在该目录的子文件夹中扫描组件的方式,可以向配置中添加其他目录:

nuxt.config.ts

export default defineNuxtConfig({
  components: [
    { path: '~/components/special-components', prefix: 'Special' },
    '~/components'
  ]
})

Component extensions

默认情况下,在nuxt.config.ts的扩展键中指定了扩展名的任何文件都被视为组件。如果需要限制应注册为组件的文件扩展名,可以使用组件目录声明的扩展形式及其扩展键:

export default defineNuxtModule({
  components: [
    {
      path: '~/components',
+     extensions: ['.vue'],
    }
  ]
})

Component Names

如果你在嵌套目录中有一个组件,例如:

| components/
--| base/
----| foo/
------| Button.vue

然后组件的名称将基于它自己的路径、目录和文件名,删除重复的段。因此,组件的名称将是:

为了清晰起见,我们建议组件的文件名与其名称相匹配。(所以,在上面的例子中,你可以将Button.vue重命名为BaseFooButton.vue)

如果你想只根据组件的名称而不是路径自动导入组件,那么你需要使用配置对象的扩展形式将pathPrefix选项设置为false:

nuxt.config.ts

export default defineNuxtConfig({
  components: [
    {
      path: '~/components/',
+     pathPrefix: false,
    },
  ],
});

这将使用与在Nuxt 2中使用的相同策略注册组件。例如,~/components/Some/MyComponent.vue将可用为 而不是

Dynamic Components

如果你想使用Vue 语法,那么你将需要使用Vue提供的resolveComponent辅助方法。

例如:



如果你正在使用resolveComponent来处理动态组件,请确保除了组件名称之外不插入任何内容,组件名称必须是字符串而不是变量。

或者,尽管不推荐,您可以全局注册所有组件,这将为所有组件创建异步块,并使它们在整个应用程序中可用。

export default defineNuxtConfig({
    components: {
+     global: true,
+     dirs: ['~/components']
    },
  })

您还可以通过将某些组件放在 ~/components/global目录中来选择性地全局注册它们。

global选项也可以为每个组件目录设置。

Dynamic Imports

要动态导入一个组件(也称为惰性加载组件),你所需要做的就是在组件名称前添加Lazy前缀。

layouts/default.vue

如果不总是需要该组件,这尤其有用。通过使用Lazy前缀,你可以延迟加载组件代码,直到合适的时刻,这有助于优化你的JavaScript包大小。

pages/index.vue



Direct Imports

如果你想要或需要绕过Nuxt的自动导入功能,你也可以显式地从#components导入组件。

pages/index.vue




ClientOnly Component

Nuxt 提供了组件,目的是只在客户端呈现一个组件。若要只在客户端导入组件,请在客户端插件中注册该组件。

pages/example.vue

使用槽位作为回退,直到挂载到客户端。

pages/example.vue

.client Components

如果组件只能在客户端呈现,则可以添加.client 后缀到您的组件。

| components/
--| Comments.client.vue
pages/example.vue

此功能仅适用于Nuxt自动导入和 #components导入。从它们的实际路径显式导入这些组件并不会将它们转换为仅针对客户端的组件。

.client 组件只有在被挂载后才被渲染。要使用onMounted()访问呈现的模板,在 onMounted() 钩子的回调中添加await nextTick()

.server Components

.server 组件既可以单独使用,也可以与.client组件配对使用。

Standalone server components

Standalone server components will always be rendered on the server. When their props update, this will result in a network request that will update the rendered HTML in-place.

Server components are currently experimental and in order to use them, you need to enable the 'component islands' feature in your nuxt.config:

nuxt.config.ts

export default defineNuxtConfig({
  experimental: {
    componentIslands: true
  }
})

Now you can register server-only components with the .server suffix and use them anywhere in your application automatically.

| components/
--| HighlightedMarkdown.server.vue
pages/example.vue

Slots are not supported by server components in their current state of development.

Paired with a .client component

在这种情况下,.server + .client 组件是组件的两部分,可以在高级用例中用于服务器端和客户端组件的独立实现。

| components/
--| Comments.client.vue
--| Comments.server.vue
pages/example.vue

组件的客户端部分能够为服务器呈现的HTML'hydrate'是很重要的。也就是说,它应该在初始加载时呈现相同的HTML,否则您将遇到水合不匹配的情况。

DevOnly Component

Nuxt提供了 组件,只在开发过程中渲染组件。

这些内容将不包含在生产构建和 tree-shaken中。

pages/example.vue

Library Authors

制作具有自动摇树和组件注册功能的Vue组件库非常简单

你可以使用components:dirs钩子来扩展目录列表,而不需要在Nuxt模块中进行用户配置。

想象一个这样的目录结构:

| node_modules/
---| awesome-ui/
------| components/
---------| Alert.vue
---------| Button.vue
------| nuxt.js
| pages/
---| index.vue
| nuxt.config.js

然后在awesome-ui/nuxt.js 中你可以使用components:dirs钩子:

import { defineNuxtModule } from '@nuxt/kit'
import { fileURLToPath } from 'node:url'

export default defineNuxtModule({
  hooks: {
    'components:dirs'(dirs) {
      // Add ./components dir to the list
      dirs.push({
        path: fileURLToPath(new URL('./components', import.meta.url)),
        prefix: 'awesome'
      })
    }
  }
})

就是这样!现在在你的项目中,你可以在你的nuxt.config文件中导入你的UI库作为Nuxt模块:

export default {
  modules: ['awesome-ui/nuxt']
}

并直接在我们的pages/index.vue中使用模块组件(前缀为`awesome-):

It will automatically import the components only if used and also support HMR when updating your components in node_modules/awesome-ui/components/.

Composables 目录

Nuxt 3使用composables/目录使用auto-imports自动将Vue组合导入到应用中!

在底层,Nuxt自动生成文件.nuxt/imports.d.ts来声明类型。

注意,为了让Nuxt生成类型,你必须运行nuxi prepare, nuxi devnuxi build。如果你在没有运行开发服务器的情况下创建了一个可组合对象,TypeScript会抛出一个错误,比如Cannot find name 'useBar'.

Usage

Method 1: Using named export

composables/useFoo.ts

export const useFoo = () => {
  return useState('foo', () => 'bar')
}

Method 2: Using default export

composables/use-foo.ts or composables/useFoo.ts

// It will be available as useFoo() (camelCase of file name without extension)
export default function () {
  return useState('foo', () => 'bar')
}

用法: 你现在可以在 .js, .ts.vue 文件中使用自动导入组合

app.vue



示例

Nested Composables

你可以在使用自动导入的另一个可组合对象中使用一个可组合对象:

composables/test.ts

export const useFoo = () => {
  const nuxtApp = useNuxtApp()
  const bar = useBar()
}

访问插件注入

你可以从可组合文件中访问plugin injections

composables/test.ts

export const useHello = () => {
  const nuxtApp = useNuxtApp()
  return nuxtApp.$hello
}

如何扫描文件

Nuxt只扫描 composables/ 目录的顶层文件,例如:

composables
 | - index.ts // scanned
 | - useFoo.ts // scanned
 | - nested
 | --- utils.ts // not scanned

只有composables/index.tscomposables/useFoo.ts会被搜索导入。

为了让自动导入工作于嵌套模块,你可以重新导出它们(推荐)或配置扫描器包含嵌套目录:

示例:composables/index.ts中重新导出您需要的组合的文件:

composables/index.ts

// Enables auto import for this export
export { utils } from './nested/utils.ts'

示例: 扫描composables/文件夹内的嵌套目录:

nuxt.config.ts

export default defineNuxtConfig({
  imports: {
    dirs: [
      // Scan top-level modules
      'composables',
      // ... or scan modules nested one level deep with a specific name and file extension
      'composables/*/index.{ts,js,mjs,mts}',
      // ... or scan all modules within given directory
      'composables/**'
    ]
  }
})

Content 目录

Nuxt Content模块读取项目中的content/ 目录并解析.md, .yml, .csv and .json文件为您的应用程序创建一个基于文件的CMS。

  • 使用内置组件渲染您的内容。
  • 使用类似mongodb的API查询您的内容。
  • 使用带有MDC语法的Markdown文件中的Vue组件。
  • 自动生成导航。

开始

安装

在项目中安装 @nuxt/content模块:

yarn add --dev @nuxt/content
或
npm install --save-dev @nuxt/content
或
pnpm add -D @nuxt/content

Then, add @nuxt/content to the modules section of nuxt.config.ts:

nuxt.config.ts

export default defineNuxtConfig({
  modules: [
    '@nuxt/content'
  ],
  content: {
    // https://content.nuxtjs.org/api/configuration
  }
})

创建内容

Place your markdown files inside the content/ directory in the root directory of your project:

content/index.md

# Hello Content

模块自动加载并解析它们。

渲染页面

要呈现内容页面,使用 ContentDoc组件添加一个catch-all路由:

pages/[...slug].vue

Layouts 目录

Nuxt提供了一个可定制的布局框架,可以在整个应用程序中使用,非常适合将常见的UI或代码模式提取到可重用的布局组件中。

布局放在layouts/目录中,使用时将通过异步导入自动加载。布局是通过添加到您的app.vue,或者设置一个layout属性作为页面元数据的一部分(如果你使用~/pages集成),或者手动指定它作为的一个prop。(注意: 布局名称被规范化为串格式,因此 someLayout 变成some-layout。)

如果你的应用只有一个布局,我们建议使用app.vue

不像其他组件,你的布局必须有一个根元素,以允许Nuxt在布局变化之间应用过渡-这个根元素不能是

启用默认布局

Add a ~/layouts/default.vue:

layouts/default.vue

在布局文件中,布局的内容将加载在中,而不是使用特殊的组件。

如果你使用app.vue你还需要添加 :

app.vue

设置另一种布局

-| layouts/
---| default.vue
---| custom.vue

你可以像这样直接覆盖默认布局:

app.vue



或者,你可以像这样覆盖默认的每页布局:

pages/index.vue


app.vue

layouts/custom.vue

layouts/default.vue


了解更多关于定义页面元数据的信息。

动态更改布局

还可以为布局使用ref或computed属性。



在每页的基础上重写布局

如果您正在使用~/pages集成,您可以通过设置layout: false,然后在页面内使用组件来获得完全控制。

pages/index.vue



layouts/custom.vue


Middleware 目录

Nuxt提供了一个可定制的路由中间件框架,可以在整个应用程序中使用,非常适合在导航到特定路由之前提取想要运行的代码。

路由中间件运行在Nuxt应用程序的Vue部分中。尽管名称相似,但它们与服务器中间件完全不同,服务器中间件运行在应用程序的Nitro服务器部分中。

路由中间件有三种:

  1. 匿名(或内联)路由中间件,直接在使用它们的页面中定义。
  2. 命名路由中间件,放置在middleware/ 目录中,在页面上使用时会通过异步导入自动加载。(注意:路由中间件名称被规范化为串串形式,因此someMiddleware 变成 some-middleware。)
  3. 全局路由中间件,放置在 middleware/目录中(带有.global后缀),并将在每次路由更改时自动运行。

前两种路由中间件可以definePageMeta中定义

格式

路由中间件是导航守卫,它接收当前路由和下一个路由作为参数。

export default defineNuxtRouteMiddleware((to, from) => {
  if (to.params.id === '1') {
    return abortNavigation()
  }
  return navigateTo('/')
})

Nuxt提供了两个全局可用的辅助函数,它们可以直接从中间件返回:

  1. navigateTo (to: RouteLocationRaw | undefined | null, options?: { replace: boolean, redirectCode: number, external: boolean ) - 在插件或中间件中重定向到给定的路由。也可以直接调用它来执行页面导航。
  2. abortNavigation (err?: string | Error) - 终止导航,并显示一条可选的错误消息。

不像vue-router中的导航守卫,第三个next()参数不会被传递,重定向或路由取消是通过从中间件返回值来处理的。可能的返回值有:

  • nothing - 不会阻塞导航,并且会移动到下一个中间件功能(如果有的话),或者完成路由导航
  • return navigateTo('/') or return navigateTo({ path: '/' }) - 重定向到给定的路径,并将重定向代码设置为302 Found,如果重定向发生在服务器端
  • return navigateTo('/', { redirectCode: 301 }) - 重定向到给定的路径,并将重定向代码设置为301 Moved permanent,如果重定向发生在服务器端
  • return abortNavigation() - 停止当前导航
  • return abortNavigation(error) - 拒绝有错误的当前导航

我们建议使用上面的帮助函数来执行重定向或停止导航。vue-router中描述的其他可能的返回值可能可以工作,但将来可能会有破坏性的更改。

动态添加中间件

可以使用addRouteMiddleware()辅助函数手动添加全局或命名路由中间件,例如从插件中添加。

export default defineNuxtPlugin(() => {
  addRouteMiddleware('global-test', () => {
    console.log('这个全局中间件是在一个插件中添加的,将在每次路由更改时运行')
  }, { global: true })

  addRouteMiddleware('named-test', () => {
    console.log('这个命名中间件是在插件中添加的,它将覆盖任何同名的现有中间件')
  })
})

示例:命名路由中间件

-| middleware/
---| auth.ts

在页面文件中,可以引用这个路由中间件

现在,在导航到该页面完成之前, auth 路由中间件将运行。

Node modules 目录

包管理器(npmyarnpnpm)创建node_modules/目录来存储项目的依赖项。

Pages 目录

Nuxt提供了一个基于文件的路由,在您的web应用程序中使用Vue Router在底层创建路由。

这个目录是 可选的 ,这意味着如果你只使用app.vuevue-router不会被包括在内(除非你在nuxt.config中设置了pages: true或者有一个app/router.options.ts),减少应用程序的包大小。

使用

页面是Vue组件,可以使用 .vue, .js, .jsx, .ts or .tsx扩展名

pages/index.vue

// https://vuejs.org/guide/extras/render-function.html
export default defineComponent({
  render () {
    return h('h1', 'Index page')
  }
})
// https://nuxt.com/docs/examples/advanced/jsx
// https://vuejs.org/guide/extras/render-function.html#jsx-tsx
export default defineComponent({
  render () {
    return 

Index page

} })

The pages/index.vue file will be mapped to the / route of your application.

如果你正在使用app.vue,确保使用组件来显示当前页面:

app.vue

Pages必须有一个根元素,以允许页面之间的路由transitions。(HTML注释也被认为是元素。)

这意味着当路由被服务器渲染或静态生成时,您将能够正确地看到它的内容,但是当您在客户端导航期间导航到该路由时,路由之间的转换将失败,您将看到路由将不会被渲染。

下面是一些例子来说明只有一个根元素的页面是什么样子的:

pages/working.vue

pages/bad-1.vue


pages/bad-2.vue

动态 Routes

如果您将任何内容放在方括号内,它将被转换为dynamic route参数。您可以在文件名或目录中混合和匹配多个参数,甚至是非动态文本。

If you want a parameter to be optional, you must enclose it in double square brackets - for example, ~/pages/[[slug]]/index.vue or ~/pages/[[slug]].vue will match both / and /test. 如果您希望参数是 可选的 ,则必须将其括在双方括号中——例如,~/pages/[[slug]]/index.vue~/pages/[[slug]].vue将同时匹配 //test

示例

-| pages/
---| index.vue
---| users-[group]/
-----| [id].vue

根据上面的例子,你可以通过$route对象访问组件中的 group/id:

pages/users-[group]/[id].vue

导航到/users-admins/123将呈现:

admins - 123

如果你想使用Composition API访问路由,有一个全局的useRoute函数,它将允许你访问路由,就像选项API中的this.$route一样。

Catch-all Route

If you need a catch-all route, you create it by using a file named like [...slug].vue. This will match all routes under that path.

pages/[...slug].vue

导航到/hello/world将呈现:

["hello", "world"]

嵌套 Routes

可以使用 来显示嵌套路由

示例:

-| pages/
---| parent/
------| child.vue
---| parent.vue

这个文件树将生成这些路由:

[
  {
    path: '/parent',
    component: '~/pages/parent.vue',
    name: 'parent',
    children: [
      {
        path: 'child',
        component: '~/pages/parent/child.vue',
        name: 'parent-child'
      }
    ]
  }
]

要显示child.vue组件,你必须在pages/parent.vue中插入组件:

pages/parent.vue

Child Route Keys

如果你想要更多的控制组件被重新渲染(例如,对于transitions),你可以通过pageKey道具传递一个字符串或函数,或者你可以通过definePageMeta定义一个key值:

pages/parent.vue

换个:

pages/child.vue

Page Metadata

你可能想在你的应用程序中为每个路由定义元数据。你可以使用definePageMeta宏来实现这一点,它将在

这些数据可以通过route.meta对象在应用程序的其余部分中访问。

如果使用嵌套路由,那么来自所有这些路由的页面元数据将被合并到单个对象中。有关路由元的更多信息,请参见vue-router docs

类似于definetriggersdefineProps(参见Vue docs), definePageMeta是一个编译器宏。它将被编译掉,因此您不能在组件中引用它。相反,传递给它的元数据将从组件中提升出来。因此,页面元对象不能引用组件(或组件上定义的值)。但是,它可以引用导入的绑定。

Special Metadata

当然,你可以在整个应用程序中定义元数据供自己使用。但是一些用definePageMeta定义的元数据有一个特定的目的:

alias

您可以定义页面别名。它们允许您从不同的路径访问同一个页面。它可以是字符串,也可以是vue-router文档中定义的字符串数组(https://router.vuejs.org/guide/essentials/redirect-and-alias.html#alias)。

keepalive

如果你在你的definePageMeta中设置KeepAlive: true, Nuxt将自动包装你的页面Vue 组件。例如,如果您希望跨路由更改保持页面状态,那么在具有动态子路由的父路由中这样做可能很有用。

当你的目标是为父路由保留状态时,使用以下语法:。你也可以设置传递给' '的道具(查看完整列表这里)。

你可以为这个属性设置一个默认值在你的nuxt.config

key

See above.

layout

您可以定义用于呈现路由的布局。这可以是false(禁用任何布局),一个字符串或一个ref/computed,如果你想让它以某种方式响应。关于布局的更多信息

layoutTransition and pageTransition

你可以为包装页面和布局的组件定义转换属性,或者传递false来禁用该路由的包装。您可以在这里看到可传递的选项列表,或者阅读关于过渡如何工作的更多信息

你可以为这些属性设置默认值在你的nuxt.config

middleware

可以在加载此页面之前定义要应用的中间件。它将与任何匹配的父/子路由中使用的所有其他中间件合并。它可以是字符串、函数(遵循全局前保护模式的匿名/内联中间件函数)或字符串/函数数组。关于命名中间件的更多信息

name

您可以为该页的路由定义一个名称。

path

如果您有一个比文件名更复杂的模式,您可以定义一个路径匹配器。更多信息请参见vue-router文档

Typing Custom Metadata

如果要为页面添加自定义元数据,您可能希望以类型安全的方式这样做。可以增加definePageMeta接受的对象的类型:

index.d.ts

declare module '#app' {
  interface PageMeta {
    pageType?: string
  }
}

// 在扩充类型时,确保导入/导出某些内容总是很重要的
export {}

页面导航

要在应用程序的页面之间导航,你应该使用组件。

该组件包含在Nuxt中,因此您不必像导入其他组件那样导入它。

一个简单的链接到你的pages文件夹中的index.vue页面:

Router 选项

可以自定义vue-router选项

Using app/router.options

这是指定路由器选项的推荐方法。

app/router.options.ts

import type { RouterConfig } from '@nuxt/schema'

// https://router.vuejs.org/api/interfaces/routeroptions.html
export default  {
}
自定义 Routes

您可以选择使用一个接受扫描路由并返回定制路由的函数来覆盖路由。 如果返回nullundefined, Nuxt将退回到默认路由。(用于修改输入数组)

app/router.options.ts

import type { RouterConfig } from '@nuxt/schema'

// https://router.vuejs.org/api/interfaces/routeroptions.html
export default  {
  routes: (_routes) => [
    {
      name: 'home',
      path: '/',
      component: () => import('~/pages/home.vue')
    }
  ],
}
自定义历史记录(高级)

您可以选择使用接受基url并返回历史模式的函数来覆盖历史模式。 如果返回null or undefined, Nuxt将退回到默认的历史记录。

app/router.options.ts

import type { RouterConfig } from '@nuxt/schema'
import { createMemoryHistory } from 'vue-router'

// https://router.vuejs.org/api/interfaces/routeroptions.html
export default  {
  history: base => process.client ? createMemoryHistory(base) : null /* default */
}

使用 nuxt.config

注意: 只有JSON可序列化选项是可配置的:

  • linkActiveClass
  • linkExactActiveClass
  • end
  • sensitive
  • strict
  • hashMode
nuxt.config.ts

export default defineNuxtConfig({
  router: {
    // https://router.vuejs.org/api/interfaces/routeroptions.html
    options: {}
  }
})

Hash 模式 (SPA)

您可以在SPA模式下启用哈希历史。在这种模式下,路由器在内部传递的实际URL之前使用一个哈希字符(#)。当启用时,URL永远不会发送到服务器SSR不支持

nuxt.config.ts

export default defineNuxtConfig({
  ssr: false,
  router: {
    options: {
      hashMode: true
    }
  }
})

Programmatic Navigation

Nuxt 3允许通过navigateTo() 实用方法进行编程导航。使用此实用工具方法,您将能够在应用程序中以编程方式导航用户。这对于从用户获取输入并在整个应用程序中动态导航用户非常有用。在本例中,我们有一个名为navigateTo()的简单方法,当用户提交搜索表单时调用它。

注意: 确保在navigateTo 上总是await,或者通过从函数返回来链接它的结果。

Plugins 目录

Nuxt自动读取您的plugins目录中的文件,并在创建Vue应用程序时加载它们。你可以在文件名中使用.server.client后缀来只在服务器端或客户端加载插件。

plugins/目录下的所有插件都是自动注册的,所以你不应该将它们单独添加到你的nuxt.config目录中。

注册了哪些文件

只有在plugins/目录的顶层的文件(或任何子目录中的索引文件)才会被注册为插件。

例如:

plugins
 | - myPlugin.ts
 | - myOtherPlugin
 | --- supportingFile.ts
 | --- componentToRegister.vue
 | --- index.ts

只有myPlugin.tsmyOtherPlugin/index.ts会被注册。

创建组件

传递给插件的唯一参数是 nuxtApp.

export default defineNuxtPlugin(nuxtApp => {
  // Doing something with nuxtApp
})

插件注册令

您可以通过在文件名前面加上一个数字来控制插件注册的顺序。

例如:

plugins/
 | - 1.myPlugin.ts
 | - 2.myOtherPlugin.ts

在本例中,2.myOtherPlugin.ts将能够访问1.myPlugin.ts注入的任何内容。

这在一个插件依赖于另一个插件的情况下非常有用。

在插件中使用可组合文件

你可以在 Nuxt plugins中使用composables:

export default defineNuxtPlugin((NuxtApp) => {
  const foo = useFoo()
})

然而,请记住有一些限制和区别:

  • 如果一个可组合的插件依赖于后来注册的另一个插件,它可能无法工作
  • 原因: 插件按顺序调用,先于所有其他插件。你可以使用一个依赖于另一个尚未被调用的插件的可组合。
  • 如果一个可组合文件依赖于Vue.js的生命周期,它将无法工作
  • 原因: 通常情况下,Vue.js组合组件被绑定到当前组件实例,而插件只被绑定到nuxtApp实例。

自动提供辅助函数

如果你想在NuxtApp实例上提供一个帮助器,请在provide键下从插件中返回它。例如:

export default defineNuxtPlugin(() => {
  return {
    provide: {
      hello: (msg: string) => `Hello ${msg}!`
    }
  }
})

在另一个文件中,你可以这样做:



输入插件

如果你从插件中返回你的helper,它们会自动被输入;你会发现它们为返回的useNuxtApp()和在你的模板中键入。

如果你 需要 在另一个插件中使用提供的帮助程序,你可以调用useNuxtApp()来获得类型化版本。但通常情况下,应该避免这样做,除非您确定插件的顺序。

Advanced

对于高级用例,你可以像这样声明注入属性的类型:

index.d.ts

declare module '#app' {
  interface NuxtApp {
    $hello (msg: string): string
  }
}

declare module '@vue/runtime-core' {
  interface ComponentCustomProperties {
    $hello (msg: string): string
  }
}

export { }

Vue 插件

如果你想使用Vue插件,比如vue-gtag来添加谷歌Analytics标签,你可以使用Nuxt插件来做到这一点。

首先,安装你想要的插件。

yarn add --dev vue-gtag-next

然后创建一个插件文件plugins/vue-gtag.client.js

import VueGtag from 'vue-gtag-next'

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.use(VueGtag, {
    property: {
      id: 'GA_MEASUREMENT_ID'
    }
  })
})

Vue Diectives

类似地,您可以在插件中注册自定义Vue指令。例如,在 plugins/directive.ts中:

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.directive('focus', {
    mounted (el) {
      el.focus()
    },
    getSSRProps (binding, vnode) {
      // you can provide SSR-specific props here
      return {}
    }
  })
})

Public 目录

public/目录直接服务于服务器根目录,包含必须保留其名称的公共文件(例如:robots.txt)或可能不会更改(例如:favicon.ico)。

Server 目录

Nuxt自动扫描~/server/api, ~/server/routes, 和 ~/server/middleware目录中的文件,以注册具有HMR支持的API和服务器处理程序。

每个文件都应该导出一个用defineEventHandler()定义的默认函数。

处理程序可以直接返回JSON数据,一个Promise或使用event.node.res.end()发送响应。

Read more in Nitro Route Handling Docs.

实例

创建一个新文件server/api/hello.ts:

server/api/hello.ts

export default defineEventHandler((event) => {
  return {
    api: 'works'
  }
})

你现在可以使用await $fetch('/api/hello')通用地调用这个API。

Server 路由

~/server/api中的文件在它们的路由中会自动以/api作为前缀。 对于添加没有/api前缀的服务器路由,您可以将它们放到 ~/server/routes目录中。

示例:

server/routes/hello.ts

export default defineEventHandler(() => 'Hello World!')

对于上面的例子, /hello路由可以在http://localhost:3000/hello 上访问。

Server 中间件

Nuxt将自动读入~/server/middleware中的任何文件,为项目创建服务器中间件。

中间件处理程序将在每个请求上运行,然后再运行任何其他服务器路由,以添加或检查标头、记录请求或扩展事件的请求对象。

中间件处理程序不应返回任何内容(也不应关闭或响应请求),而只检查或扩展请求上下文或抛出错误。

示例:

server/middleware/log.ts

export default defineEventHandler((event) => {
  console.log('New request: ' + event.node.req.url)
})
server/middleware/auth.ts

export default defineEventHandler((event) => {
  event.context.auth = { user: 123 }
})

Server 插件

Nuxt将自动读取~/server/plugins目录中的任何文件,并将它们注册为Nitro插件。这允许扩展Nitro的运行时行为并与生命周期事件挂钩。

示例:

server/plugins/nitroPlugin.ts

export default defineNitroPlugin((nitroApp) => {
  console.log('Nitro plugin', nitroApp)
})

Read more in Nitro Plugins.

Server 工具

服务器路由是由unjs/h3提供的,它附带了一组方便的助手。

Read more in Available H3 Request Helpers.

您可以自己在~/server/utils目录中添加更多的helper。

使用示例

匹配路由参数

服务器路由可以在文件名的括号内使用动态参数,比如/api/hello/[name].ts并通过event.context.params访问。

示例:

server/api/hello/[name].ts

export default defineEventHandler((event) => `Hello, ${event.context.params.name}!`)

你现在可以使用 await $fetch('/api/hello/nuxt')调用这个API,并得到Hello, nuxt!

匹配 HTTP Method

句柄文件名可以用.get, .post, .put, .delete作为后缀,…匹配请求的HTTP方法

server/api/test.get.ts

export default defineEventHandler(() => 'Test get handler')
server/api/test.post.ts

export default defineEventHandler(() => 'Test post handler')

Given the example above, fetching /test with:

  • GET method: Returns Test get handler
  • POST method: Returns Test post handler
  • Any other method: Returns 405 error

Catch-all Route

全覆盖路由有助于处理备用路由。例如,创建一个名为~/server/api/foo/[...].ts 的文件,将为所有不匹配任何路由处理程序的请求注册一个catch-all路由,例如/api/foo/bar/baz

示例:

server/api/foo/[...].ts

export default defineEventHandler(() => `Default foo handler`)
server/api/[...].ts

export default defineEventHandler(() => `Default api handler`)

用Body处理请求

server/api/submit.post.ts

export default defineEventHandler(async (event) => {
    const body = await readBody(event)
    return { body }
})

你现在可以使用$fetch('/api/submit', { method: 'post', body: { test: 123 } })通用地调用这个API。

我们在文件名中使用submit.post.ts只是为了匹配能够接受请求体的POST方法的请求。当在GET请求中使用readBody时,readBody将抛出405 Method Not Allowed HTTP错误。

处理带有Query参数的请求

Sample query /api/query?param1=a¶m2=b

server/api/query.get.ts

export default defineEventHandler((event) => {
  const query = getQuery(event)
  return { a: query.param1, b: query.param2 }
})

错误处理

如果没有抛出错误,则返回状态代码200 OK。任何未捕获的错误将返回一个500 Internal Server ErrorHTTP错误。

要返回其他错误代码,请抛出带有 createError的异常。

server/api/validation/[id].ts

export default defineEventHandler((event) => {
  const id = parseInt(event.context.params.id) as number
  if (!Number.isInteger(id)) {
    throw createError({
      statusCode: 400,
      statusMessage: 'ID should be an integer',
    })
  }
  return 'All good'
})

返回其他状态码

要返回其他状态码,可以使用setResponseStatus

For example, to return 202 Accepted

server/api/validation/[id].ts

export default defineEventHandler((event) => {
  setResponseStatus(event, 202)
})

访问 Runtime Config

server/api/foo.ts

export default defineEventHandler((event) => {
  const config = useRuntimeConfig()
  return { key: config.KEY }
})

访问 Request Cookies

export default defineEventHandler((event) => {
  const cookies = parseCookies(event)
  return { cookies }
})

高级用法示例

Nitro 配置

您可以在nuxt.config中使用nitro键直接设置nitro配置

这是一个高级选项。自定义配置可能会影响生产部署,因为当Nitro在Nuxt的小版本中升级时,配置接口可能会随着时间的推移而改变。

nuxt.config.ts

export default defineNuxtConfig({
  // https://nitro.unjs.io/config
  nitro: {}
})

使用嵌套路由器

server/api/hello/[...slug].ts

import { createRouter, defineEventHandler, useBase } from 'h3'

const router = createRouter()

router.get('/test', defineEventHandler(() => 'Hello World'))

export default useBase('/api/hello', router.handler)

发送 Streams (实验性)

注意: 这是一个实验特性,只在Node.js环境中可用。

server/api/foo.get.ts

import fs from 'node:fs'
import { sendStream } from 'h3'

export default defineEventHandler((event) => {
  return sendStream(event, fs.createReadStream('/path/to/file'))
})

返回一个legacy处理程序或中间件

server/api/legacy.ts

export default (req, res) => {
  res.end('Legacy handler')
}

使用unjs/h3可以支持遗留处理程序,但建议尽可能避免使用遗留处理程序。

server/middleware/legacy.ts

export default (req, res, next) => {
  console.log('Legacy middleware')
  next()
}

不要将next()回调与async或返回Promise的legacy中间件结合使用!

Server 存储

Nitro提供了一个跨平台存储层。为了配置额外的存储挂载点,你可以使用nitro.storage

示例:使用Redis
nuxt.config.ts

export default defineNuxtConfig({
  nitro: {
    storage: {
      'redis': {
        driver: 'redis',
        /* redis connector options */
        port: 6379, // Redis port
        host: "127.0.0.1", // Redis host
        username: "", // needs Redis >= 6
        password: "",
        db: 0, // Defaults to 0
        tls: {} // tls/ssl
      }
    }
  }
})

创建一个新文件 server/api/test.post.ts:

server/api/test.post.ts

export default defineEventHandler(async (event) => {
  const body = await readBody(event)
  await useStorage().setItem('redis:test', body)
  return 'Data is set'
})

创建一个新文件 server/api/test.get.ts:

server/api/test.get.ts

export default defineEventHandler(async (event) => {
  const data = await useStorage().getItem('redis:test')
  return data
})

创建一个新文件 app.vue:

app.vue



Utils 目录

Nuxt 3 使用 utils/ 目录在整个应用程序中使用auto-imports自动导入辅助函数和其他实用程序!

utils/ 目录的主要目的是允许在Vue组合函数和其他自动导入的实用函数之间进行语义区分。utils/ 自动导入的工作方式和被扫描的方式与组合文件/目录相同。你可以在文档的那个部分看到例子和更多关于它们如何工作的信息。

.env文件

Nuxt CLI在开发模式下以及运行nuxi buildnuxi generate时内置了dotenv支持。

除了任何进程环境变量外,如果您的项目根目录中有一个.env文件,它将在构建、开发和生成时自动加载,并且在nuxt.config文件和模块中设置的任何环境变量都将可访问。

如果您想使用不同的文件 - 例如,使用.env.local.env.production - 您可以在使用nuxi时传递--dotenv标志来实现。例如:

npx nuxi dev --dotenv .env.local

与上面一样,这仅适用于开发模式以及运行nuxi buildnuxi generate

在开发模式下更新.env文件时,Nuxt实例会自动重新启动以将新值应用于process.env

请注意,从.env文件中删除变量或完全删除.env文件将不会取消已设置的值。

但是,在构建服务器之后,您需要在运行服务器时自己设置环境变量。此时将不会读取您的.env文件。如何设置环境变量因每个环境而异。在Linux服务器上,您可以使用终端DATABASE_HOST=mydatabaseconnectionstring node .output/server/index.mjs传递环境变量作为参数。或者您可以使用source .env && node .output/server/index.mjs引用您的env文件。

请注意,对于纯静态站点,在项目预渲染之后无法设置运行时配置。

如果您想在构建时使用环境变量但不关心以后更新这些变量(或者只需要在应用程序内部以反应方式更新它们),则appConfig可能是更好的选择。您可以在您的nuxt.config中定义appConfig(使用环境变量),也可以在您的项目中的~/app.config.ts文件中定义appConfig

.gitignore 文件

一个.gitignore的文件指定了git应该忽略的未跟踪文件。在git文档中了解更多信息。

我们建议有一个 .gitignore的文件,包含至少以下条目:

.gitignore

# Nuxt dev/build outputs
.output
.nuxt
# Node dependencies
node_modules
# System files
*.log

nuxtignore 文件

在构建阶段,.nuxtignore文件可以让Nuxt忽略项目根目录(rootDir)中的layouts, pages, components, composablesmiddleware文件。.nuxtignore文件遵循与.gitignore.eslintignore文件相同的规范,其中每一行都是一个glob模式,指示应该忽略哪些文件。

注意: 你也可以在你的nuxt.config中配置ignoreOptionsignorePrefixignore

示例

.nuxtignore

# ignore layout foo.vue
layouts/foo.vue
# ignore layout files whose name ends with -ignore.vue
layouts/*-ignore.vue

# ignore page bar.vue
pages/bar.vue
# ignore page inside ignore folder
pages/ignore/*.vue

# ignore route middleware files under foo folder except foo/bar.js
middleware/foo/*.js
!middleware/foo/bar.js

App Config File

Nuxt 3提供了一个app.config配置文件公开应用程序中的响应性配置,能够在生命周期内的运行时更新它,或者使用nuxt插件并使用HMR(热模块替换)编辑它。

你可以使用app.config.ts文件 轻松提供运行时应用配置。它可以有.ts, .js, or .mjs 的扩展。

app.config.ts

export default defineAppConfig({
  foo: 'bar'
})

不要把任何秘密的值在app.config文件。它公开给用户客户端。

定义应用程序配置

To expose config and environment variables to the rest of your app, you will need to define configuration in app.config file. 要将配置和环境变量暴露给应用程序的其余部分,你需要在'app.config 文件配置。

示例:

app.config.ts

export default defineAppConfig({
  theme: {
    primaryColor: '#ababab'
  }
})

当添加'theme'到app.config, Nuxt使用Vite或webpack来捆绑代码。我们可以使用useAppConfig在服务器和浏览器中通用地访问theme

const appConfig = useAppConfig()

console.log(appConfig.theme)

手动输入App配置

Nuxt尝试从提供的应用程序配置自动生成一个typescript接口。

也可以手动输入app config:

index.d.ts

declare module '@nuxt/schema' {
  interface AppConfigInput {
    /** Theme configuration */
    theme?: {
      /** Primary app color */
      primaryColor?: string
    }
  }
}

// 在扩充类型时,确保导入/导出某些内容总是很重要的
export {}

app.vue 文件

app.vue文件是Nuxt 3应用程序中的主要组件。

最小的使用

在Nuxt 3中,pages/目录是可选的。如果不存在,Nuxt将不包含vue-router依赖项。这在处理着陆页面或不需要路由的应用程序时非常有用。

app.vue

使用Pages

如果你有一个pages/目录,使用组件来显示当前页面:

app.vue

因为Nuxt 3在使用suspense,所以它不能被设置为根元素。

记住那个 app.vue 作为Nuxt应用程序的主要组件。你添加的任何东西(JS和CSS)都是全局的,包含在每个页面中。

如果你想在页面之间自定义页面结构,请查看layouts/目录。

nuxt.Config.ts 文件

Nuxt可以用一个nuxt.config文件轻松配置,该文件可以有js, ts or mjs扩展名。

export default defineNuxtConfig({
  // My Nuxt config
})

defineNuxtConfig 辅助函数是全局可用的,无需导入。

如果你喜欢,你可以显式地从nuxt/config导入defineNuxtConfig:

import { defineNuxtConfig } from 'nuxt/config'

export default defineNuxtConfig({
  // My Nuxt config
})

为了确保您的配置是最新的,当检测到主配置文件env, nuxtignore and nuxtrc dotfile 中的更改时,Nuxt将完全重新启动。

package.json 文件

package.json文件包含应用程序的所有依赖项和脚本。

tsconfig.json 配置文件

Nuxt自动生成一个.nuxt/tsconfig.json文件,包含你在Nuxt项目中使用的解析别名,以及其他合理的默认值。你可以通过在你的项目的根目录中创建一个tsconfig.json获益,它包含以下内容:

{
  "extends": "./.nuxt/tsconfig.json"
}

根据需要,可以自定义该文件的内容。但是,建议不要覆盖target modulemoduleResolution。此外,请注意,如果你需要自定义你的“路径”,这将覆盖自动生成的路径别名。相反,我们建议你将任何路径别名添加到你的nuxt.conf中的alias属性中,在那里它们将被拾取并添加到自动生成的tsconfig中。

最后修改:2023 年 08 月 27 日
如果觉得我的文章对你有用,请随意赞赏