@nuxt/docs 0.0.0 → 3.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.navigation.yml +2 -0
- package/1.getting-started/.navigation.yml +3 -0
- package/1.getting-started/01.introduction.md +81 -0
- package/1.getting-started/02.installation.md +109 -0
- package/1.getting-started/03.configuration.md +226 -0
- package/1.getting-started/04.views.md +163 -0
- package/1.getting-started/05.assets.md +48 -0
- package/1.getting-started/06.styling.md +565 -0
- package/1.getting-started/07.routing.md +149 -0
- package/1.getting-started/08.seo-meta.md +360 -0
- package/1.getting-started/09.transitions.md +473 -0
- package/1.getting-started/10.data-fetching.md +795 -0
- package/1.getting-started/11.state-management.md +223 -0
- package/1.getting-started/12.error-handling.md +233 -0
- package/1.getting-started/13.server.md +94 -0
- package/1.getting-started/14.layers.md +92 -0
- package/1.getting-started/15.prerendering.md +194 -0
- package/1.getting-started/16.deployment.md +130 -0
- package/1.getting-started/17.testing.md +728 -0
- package/1.getting-started/18.upgrade.md +997 -0
- package/2.guide/.navigation.yml +2 -0
- package/2.guide/0.index.md +22 -0
- package/2.guide/1.concepts/.navigation.yml +3 -0
- package/2.guide/1.concepts/1.auto-imports.md +205 -0
- package/2.guide/1.concepts/10.nuxt-lifecycle.md +141 -0
- package/2.guide/1.concepts/2.vuejs-development.md +103 -0
- package/2.guide/1.concepts/3.rendering.md +255 -0
- package/2.guide/1.concepts/4.server-engine.md +62 -0
- package/2.guide/1.concepts/5.modules.md +48 -0
- package/2.guide/1.concepts/7.esm.md +299 -0
- package/2.guide/1.concepts/8.typescript.md +97 -0
- package/2.guide/1.concepts/9.code-style.md +22 -0
- package/2.guide/2.directory-structure/.navigation.yml +3 -0
- package/2.guide/2.directory-structure/0.nuxt.md +20 -0
- package/2.guide/2.directory-structure/0.output.md +18 -0
- package/2.guide/2.directory-structure/1.assets.md +16 -0
- package/2.guide/2.directory-structure/1.components.md +608 -0
- package/2.guide/2.directory-structure/1.composables.md +121 -0
- package/2.guide/2.directory-structure/1.content.md +64 -0
- package/2.guide/2.directory-structure/1.layouts.md +180 -0
- package/2.guide/2.directory-structure/1.middleware.md +209 -0
- package/2.guide/2.directory-structure/1.modules.md +66 -0
- package/2.guide/2.directory-structure/1.node_modules.md +12 -0
- package/2.guide/2.directory-structure/1.pages.md +440 -0
- package/2.guide/2.directory-structure/1.plugins.md +299 -0
- package/2.guide/2.directory-structure/1.public.md +27 -0
- package/2.guide/2.directory-structure/1.server.md +546 -0
- package/2.guide/2.directory-structure/1.shared.md +104 -0
- package/2.guide/2.directory-structure/1.utils.md +49 -0
- package/2.guide/2.directory-structure/2.env.md +75 -0
- package/2.guide/2.directory-structure/2.gitignore.md +37 -0
- package/2.guide/2.directory-structure/2.nuxtignore.md +36 -0
- package/2.guide/2.directory-structure/2.nuxtrc.md +50 -0
- package/2.guide/2.directory-structure/3.app-config.md +177 -0
- package/2.guide/2.directory-structure/3.app.md +72 -0
- package/2.guide/2.directory-structure/3.error.md +55 -0
- package/2.guide/2.directory-structure/3.nuxt-config.md +34 -0
- package/2.guide/2.directory-structure/3.package.md +32 -0
- package/2.guide/2.directory-structure/3.tsconfig.md +24 -0
- package/2.guide/3.going-further/.navigation.yml +3 -0
- package/2.guide/3.going-further/1.experimental-features.md +689 -0
- package/2.guide/3.going-further/1.features.md +103 -0
- package/2.guide/3.going-further/1.internals.md +81 -0
- package/2.guide/3.going-further/10.runtime-config.md +174 -0
- package/2.guide/3.going-further/11.nightly-release-channel.md +68 -0
- package/2.guide/3.going-further/2.hooks.md +98 -0
- package/2.guide/3.going-further/3.modules.md +811 -0
- package/2.guide/3.going-further/4.kit.md +51 -0
- package/2.guide/3.going-further/6.nuxt-app.md +64 -0
- package/2.guide/3.going-further/7.layers.md +227 -0
- package/2.guide/3.going-further/9.debugging.md +115 -0
- package/2.guide/3.going-further/index.md +4 -0
- package/2.guide/4.recipes/.navigation.yml +3 -0
- package/2.guide/4.recipes/1.custom-routing.md +181 -0
- package/2.guide/4.recipes/2.vite-plugin.md +65 -0
- package/2.guide/4.recipes/3.custom-usefetch.md +125 -0
- package/2.guide/4.recipes/4.sessions-and-authentication.md +203 -0
- package/3.api/.navigation.yml +3 -0
- package/3.api/1.components/.navigation.yml +3 -0
- package/3.api/1.components/1.client-only.md +76 -0
- package/3.api/1.components/1.dev-only.md +51 -0
- package/3.api/1.components/1.nuxt-client-fallback.md +80 -0
- package/3.api/1.components/10.nuxt-picture.md +27 -0
- package/3.api/1.components/11.teleports.md +40 -0
- package/3.api/1.components/12.nuxt-route-announcer.md +56 -0
- package/3.api/1.components/13.nuxt-time.md +173 -0
- package/3.api/1.components/2.nuxt-page.md +154 -0
- package/3.api/1.components/3.nuxt-layout.md +156 -0
- package/3.api/1.components/4.nuxt-link.md +322 -0
- package/3.api/1.components/5.nuxt-loading-indicator.md +50 -0
- package/3.api/1.components/6.nuxt-error-boundary.md +65 -0
- package/3.api/1.components/7.nuxt-welcome.md +25 -0
- package/3.api/1.components/8.nuxt-island.md +70 -0
- package/3.api/1.components/9.nuxt-img.md +43 -0
- package/3.api/2.composables/.navigation.yml +3 -0
- package/3.api/2.composables/on-prehydrate.md +60 -0
- package/3.api/2.composables/use-app-config.md +19 -0
- package/3.api/2.composables/use-async-data.md +212 -0
- package/3.api/2.composables/use-cookie.md +233 -0
- package/3.api/2.composables/use-error.md +32 -0
- package/3.api/2.composables/use-fetch.md +217 -0
- package/3.api/2.composables/use-head-safe.md +55 -0
- package/3.api/2.composables/use-head.md +69 -0
- package/3.api/2.composables/use-hydration.md +68 -0
- package/3.api/2.composables/use-lazy-async-data.md +47 -0
- package/3.api/2.composables/use-lazy-fetch.md +55 -0
- package/3.api/2.composables/use-loading-indicator.md +77 -0
- package/3.api/2.composables/use-nuxt-app.md +294 -0
- package/3.api/2.composables/use-nuxt-data.md +112 -0
- package/3.api/2.composables/use-preview-mode.md +118 -0
- package/3.api/2.composables/use-request-event.md +23 -0
- package/3.api/2.composables/use-request-fetch.md +52 -0
- package/3.api/2.composables/use-request-header.md +34 -0
- package/3.api/2.composables/use-request-headers.md +37 -0
- package/3.api/2.composables/use-request-url.md +41 -0
- package/3.api/2.composables/use-response-header.md +48 -0
- package/3.api/2.composables/use-route-announcer.md +60 -0
- package/3.api/2.composables/use-route.md +52 -0
- package/3.api/2.composables/use-router.md +92 -0
- package/3.api/2.composables/use-runtime-config.md +142 -0
- package/3.api/2.composables/use-runtime-hook.md +43 -0
- package/3.api/2.composables/use-seo-meta.md +80 -0
- package/3.api/2.composables/use-server-seo-meta.md +27 -0
- package/3.api/2.composables/use-state.md +48 -0
- package/3.api/3.utils/$fetch.md +98 -0
- package/3.api/3.utils/.navigation.yml +3 -0
- package/3.api/3.utils/abort-navigation.md +73 -0
- package/3.api/3.utils/add-route-middleware.md +88 -0
- package/3.api/3.utils/call-once.md +92 -0
- package/3.api/3.utils/clear-error.md +29 -0
- package/3.api/3.utils/clear-nuxt-data.md +23 -0
- package/3.api/3.utils/clear-nuxt-state.md +23 -0
- package/3.api/3.utils/create-error.md +55 -0
- package/3.api/3.utils/define-nuxt-component.md +53 -0
- package/3.api/3.utils/define-nuxt-route-middleware.md +67 -0
- package/3.api/3.utils/define-page-meta.md +234 -0
- package/3.api/3.utils/define-route-rules.md +52 -0
- package/3.api/3.utils/navigate-to.md +230 -0
- package/3.api/3.utils/on-before-route-leave.md +11 -0
- package/3.api/3.utils/on-before-route-update.md +11 -0
- package/3.api/3.utils/on-nuxt-ready.md +25 -0
- package/3.api/3.utils/prefetch-components.md +28 -0
- package/3.api/3.utils/preload-components.md +23 -0
- package/3.api/3.utils/preload-route-components.md +41 -0
- package/3.api/3.utils/prerender-routes.md +46 -0
- package/3.api/3.utils/refresh-cookie.md +46 -0
- package/3.api/3.utils/refresh-nuxt-data.md +91 -0
- package/3.api/3.utils/reload-nuxt-app.md +74 -0
- package/3.api/3.utils/set-page-layout.md +24 -0
- package/3.api/3.utils/set-response-status.md +36 -0
- package/3.api/3.utils/show-error.md +31 -0
- package/3.api/3.utils/update-app-config.md +27 -0
- package/3.api/4.commands/.navigation.yml +3 -0
- package/3.api/4.commands/add.md +112 -0
- package/3.api/4.commands/analyze.md +41 -0
- package/3.api/4.commands/build-module.md +42 -0
- package/3.api/4.commands/build.md +46 -0
- package/3.api/4.commands/cleanup.md +38 -0
- package/3.api/4.commands/dev.md +59 -0
- package/3.api/4.commands/devtools.md +38 -0
- package/3.api/4.commands/generate.md +41 -0
- package/3.api/4.commands/info.md +33 -0
- package/3.api/4.commands/init.md +46 -0
- package/3.api/4.commands/module.md +84 -0
- package/3.api/4.commands/prepare.md +36 -0
- package/3.api/4.commands/preview.md +43 -0
- package/3.api/4.commands/typecheck.md +42 -0
- package/3.api/4.commands/upgrade.md +37 -0
- package/3.api/5.kit/.navigation.yml +3 -0
- package/3.api/5.kit/1.modules.md +172 -0
- package/3.api/5.kit/10.runtime-config.md +27 -0
- package/3.api/5.kit/10.templates.md +283 -0
- package/3.api/5.kit/11.nitro.md +409 -0
- package/3.api/5.kit/12.resolving.md +268 -0
- package/3.api/5.kit/13.logging.md +65 -0
- package/3.api/5.kit/14.builder.md +491 -0
- package/3.api/5.kit/15.examples.md +41 -0
- package/3.api/5.kit/2.programmatic.md +125 -0
- package/3.api/5.kit/3.compatibility.md +230 -0
- package/3.api/5.kit/4.autoimports.md +144 -0
- package/3.api/5.kit/5.components.md +127 -0
- package/3.api/5.kit/6.context.md +130 -0
- package/3.api/5.kit/7.pages.md +295 -0
- package/3.api/5.kit/8.layout.md +80 -0
- package/3.api/5.kit/9.plugins.md +263 -0
- package/3.api/6.advanced/.navigation.yml +1 -0
- package/3.api/6.advanced/1.hooks.md +105 -0
- package/3.api/6.advanced/2.import-meta.md +60 -0
- package/3.api/6.nuxt-config.md +12 -0
- package/3.api/index.md +31 -0
- package/5.community/.navigation.yml +3 -0
- package/5.community/2.getting-help.md +48 -0
- package/5.community/3.reporting-bugs.md +50 -0
- package/5.community/4.contribution.md +205 -0
- package/5.community/5.framework-contribution.md +142 -0
- package/5.community/6.roadmap.md +79 -0
- package/5.community/7.changelog.md +92 -0
- package/6.bridge/.navigation.yml +3 -0
- package/6.bridge/1.overview.md +137 -0
- package/6.bridge/10.configuration.md +96 -0
- package/6.bridge/2.typescript.md +46 -0
- package/6.bridge/3.bridge-composition-api.md +132 -0
- package/6.bridge/4.plugins-and-middleware.md +65 -0
- package/6.bridge/5.nuxt3-compatible-api.md +204 -0
- package/6.bridge/6.meta.md +117 -0
- package/6.bridge/7.runtime-config.md +38 -0
- package/6.bridge/8.nitro.md +102 -0
- package/6.bridge/9.vite.md +37 -0
- package/7.migration/.navigation.yml +3 -0
- package/7.migration/1.overview.md +24 -0
- package/7.migration/10.bundling.md +28 -0
- package/7.migration/11.server.md +17 -0
- package/7.migration/2.configuration.md +240 -0
- package/7.migration/20.module-authors.md +94 -0
- package/7.migration/3.auto-imports.md +18 -0
- package/7.migration/4.meta.md +127 -0
- package/7.migration/5.plugins-and-middleware.md +80 -0
- package/7.migration/6.pages-and-layouts.md +233 -0
- package/7.migration/7.component-options.md +156 -0
- package/7.migration/8.runtime-config.md +58 -0
- package/LICENSE +21 -0
- package/README.md +11 -0
- package/package.json +16 -4
- package/dist/.gitkeep +0 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
navigation.title: 'Vite Plugins'
|
|
3
|
+
title: Using Vite Plugins in Nuxt
|
|
4
|
+
description: Learn how to integrate Vite plugins into your Nuxt project.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
While Nuxt modules offer extensive functionality, sometimes a specific Vite plugin might meet your needs more directly.
|
|
8
|
+
|
|
9
|
+
First, we need to install the Vite plugin, for our example, we'll use `@rollup/plugin-yaml`:
|
|
10
|
+
|
|
11
|
+
::code-group{sync="pm"}
|
|
12
|
+
|
|
13
|
+
```bash [npm]
|
|
14
|
+
npm install @rollup/plugin-yaml
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```bash [yarn]
|
|
18
|
+
yarn add @rollup/plugin-yaml
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
```bash [pnpm]
|
|
22
|
+
pnpm add @rollup/plugin-yaml
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
```bash [bun]
|
|
26
|
+
bun add @rollup/plugin-yaml
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
::
|
|
30
|
+
|
|
31
|
+
Next, we need to import and add it to our [`nuxt.config.ts`](/docs/guide/directory-structure/nuxt-config) file:
|
|
32
|
+
|
|
33
|
+
```ts [nuxt.config.ts]
|
|
34
|
+
import yaml from '@rollup/plugin-yaml'
|
|
35
|
+
|
|
36
|
+
export default defineNuxtConfig({
|
|
37
|
+
vite: {
|
|
38
|
+
plugins: [
|
|
39
|
+
yaml()
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Now we installed and configured our Vite plugin, we can start using YAML files directly in our project.
|
|
46
|
+
|
|
47
|
+
For example, we can have a `config.yaml` that stores configuration data and import this data in our Nuxt components:
|
|
48
|
+
|
|
49
|
+
::code-group
|
|
50
|
+
|
|
51
|
+
```yaml [data/hello.yaml]
|
|
52
|
+
greeting: "Hello, Nuxt with Vite!"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
```vue [components/Hello.vue]
|
|
56
|
+
<script setup>
|
|
57
|
+
import config from '~/data/hello.yaml'
|
|
58
|
+
</script>
|
|
59
|
+
|
|
60
|
+
<template>
|
|
61
|
+
<h1>{{ config.greeting }}</h1>
|
|
62
|
+
</template>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
::
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
---
|
|
2
|
+
navigation.title: 'Custom useFetch'
|
|
3
|
+
title: Custom useFetch in Nuxt
|
|
4
|
+
description: How to create a custom fetcher for calling your external API in Nuxt.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
When working with Nuxt, you might be making the frontend and fetching an external API, and you might want to set some default options for fetching from your API.
|
|
8
|
+
|
|
9
|
+
The [`$fetch`](/docs/api/utils/dollarfetch) utility function (used by the [`useFetch`](/docs/api/composables/use-fetch) composable) is intentionally not globally configurable. This is important so that fetching behavior throughout your application remains consistent, and other integrations (like modules) can rely on the behavior of core utilities like `$fetch`.
|
|
10
|
+
|
|
11
|
+
However, Nuxt provides a way to create a custom fetcher for your API (or multiple fetchers if you have multiple APIs to call).
|
|
12
|
+
|
|
13
|
+
## Custom `$fetch`
|
|
14
|
+
|
|
15
|
+
Let's create a custom `$fetch` instance with a [Nuxt plugin](/docs/guide/directory-structure/plugins).
|
|
16
|
+
|
|
17
|
+
::note
|
|
18
|
+
`$fetch` is a configured instance of [ofetch](https://github.com/unjs/ofetch) which supports adding the base URL of your Nuxt server as well as direct function calls during SSR (avoiding HTTP roundtrips).
|
|
19
|
+
::
|
|
20
|
+
|
|
21
|
+
Let's pretend here that:
|
|
22
|
+
- The main API is https://api.nuxt.com
|
|
23
|
+
- We are storing the JWT token in a session with [nuxt-auth-utils](https://github.com/atinux/nuxt-auth-utils)
|
|
24
|
+
- If the API responds with a `401` status code, we redirect the user to the `/login` page
|
|
25
|
+
|
|
26
|
+
```ts [plugins/api.ts]
|
|
27
|
+
export default defineNuxtPlugin((nuxtApp) => {
|
|
28
|
+
const { session } = useUserSession()
|
|
29
|
+
|
|
30
|
+
const api = $fetch.create({
|
|
31
|
+
baseURL: 'https://api.nuxt.com',
|
|
32
|
+
onRequest({ request, options, error }) {
|
|
33
|
+
if (session.value?.token) {
|
|
34
|
+
// note that this relies on ofetch >= 1.4.0 - you may need to refresh your lockfile
|
|
35
|
+
options.headers.set('Authorization', `Bearer ${session.value?.token}`)
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
async onResponseError({ response }) {
|
|
39
|
+
if (response.status === 401) {
|
|
40
|
+
await nuxtApp.runWithContext(() => navigateTo('/login'))
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
// Expose to useNuxtApp().$api
|
|
46
|
+
return {
|
|
47
|
+
provide: {
|
|
48
|
+
api
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
With this Nuxt plugin, `$api` is exposed from `useNuxtApp()` to make API calls directly from the Vue components:
|
|
55
|
+
|
|
56
|
+
```vue [app.vue]
|
|
57
|
+
<script setup>
|
|
58
|
+
const { $api } = useNuxtApp()
|
|
59
|
+
const { data: modules } = await useAsyncData('modules', () => $api('/modules'))
|
|
60
|
+
</script>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
::callout
|
|
64
|
+
Wrapping with [`useAsyncData`](/docs/api/composables/use-async-data) **avoid double data fetching when doing server-side rendering** (server & client on hydration).
|
|
65
|
+
::
|
|
66
|
+
|
|
67
|
+
## Custom `useFetch`/`useAsyncData`
|
|
68
|
+
|
|
69
|
+
Now that `$api` has the logic we want, let's create a `useAPI` composable to replace the usage of `useAsyncData` + `$api`:
|
|
70
|
+
|
|
71
|
+
```ts [composables/useAPI.ts]
|
|
72
|
+
import type { UseFetchOptions } from 'nuxt/app'
|
|
73
|
+
|
|
74
|
+
export function useAPI<T>(
|
|
75
|
+
url: string | (() => string),
|
|
76
|
+
options?: UseFetchOptions<T>,
|
|
77
|
+
) {
|
|
78
|
+
return useFetch(url, {
|
|
79
|
+
...options,
|
|
80
|
+
$fetch: useNuxtApp().$api as typeof $fetch
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Let's use the new composable and have a nice and clean component:
|
|
86
|
+
|
|
87
|
+
```vue [app.vue]
|
|
88
|
+
<script setup>
|
|
89
|
+
const { data: modules } = await useAPI('/modules')
|
|
90
|
+
</script>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
If you want to customize the type of any error returned, you can also do so:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
import type { FetchError } from 'ofetch'
|
|
97
|
+
import type { UseFetchOptions } from 'nuxt/app'
|
|
98
|
+
|
|
99
|
+
interface CustomError {
|
|
100
|
+
message: string
|
|
101
|
+
statusCode: number
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function useAPI<T>(
|
|
105
|
+
url: string | (() => string),
|
|
106
|
+
options?: UseFetchOptions<T>,
|
|
107
|
+
) {
|
|
108
|
+
return useFetch<T, FetchError<CustomError>>(url, {
|
|
109
|
+
...options,
|
|
110
|
+
$fetch: useNuxtApp().$api
|
|
111
|
+
})
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
::note
|
|
116
|
+
This example demonstrates how to use a custom `useFetch`, but the same structure is identical for a custom `useAsyncData`.
|
|
117
|
+
::
|
|
118
|
+
|
|
119
|
+
:link-example{to="/docs/examples/advanced/use-custom-fetch-composable"}
|
|
120
|
+
|
|
121
|
+
:video-accordion{title="Watch a video about custom $fetch and Repository Pattern in Nuxt" videoId="jXH8Tr-exhI"}
|
|
122
|
+
|
|
123
|
+
::note
|
|
124
|
+
We are currently discussing to find a cleaner way to let you create a custom fetcher, see https://github.com/nuxt/nuxt/issues/14736.
|
|
125
|
+
::
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 'Sessions and Authentication'
|
|
3
|
+
description: "Authentication is an extremely common requirement in web apps. This recipe will show you how to implement basic user registration and authentication in your Nuxt app."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Introduction
|
|
7
|
+
|
|
8
|
+
In this recipe we'll be setting up authentication in a full-stack Nuxt app using [Nuxt Auth Utils](https://github.com/Atinux/nuxt-auth-utils) which provides convenient utilities for managing client-side and server-side session data.
|
|
9
|
+
|
|
10
|
+
The module uses secured & sealed cookies to store session data, so you don't need to setup a database to store session data.
|
|
11
|
+
|
|
12
|
+
## Install nuxt-auth-utils
|
|
13
|
+
|
|
14
|
+
Install the `nuxt-auth-utils` module using the `nuxi` CLI.
|
|
15
|
+
|
|
16
|
+
```bash [Terminal]
|
|
17
|
+
npx nuxi@latest module add auth-utils
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
::callout
|
|
21
|
+
This command will install `nuxt-auth-utils` as dependency and push it in the `modules` section of our `nuxt.config.ts`
|
|
22
|
+
::
|
|
23
|
+
|
|
24
|
+
## Cookie Encryption Key
|
|
25
|
+
|
|
26
|
+
As `nuxt-auth-utils` uses sealed cookies to store session data, session cookies are encrypted using a secret key from the `NUXT_SESSION_PASSWORD` environment variable.
|
|
27
|
+
|
|
28
|
+
::note
|
|
29
|
+
If not set, this environment variable will be added to your `.env` automatically when running in development mode.
|
|
30
|
+
::
|
|
31
|
+
|
|
32
|
+
```ini [.env]
|
|
33
|
+
NUXT_SESSION_PASSWORD=a-random-password-with-at-least-32-characters
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
::important
|
|
37
|
+
You'll need to add this environment variable to your production environment before deploying.
|
|
38
|
+
::
|
|
39
|
+
|
|
40
|
+
## Login API Route
|
|
41
|
+
|
|
42
|
+
For this recipe, we'll create a simple API route to sign-in a user based on static data.
|
|
43
|
+
|
|
44
|
+
Let's create a `/api/login` API route that will accept a POST request with the email and password in the request body.
|
|
45
|
+
|
|
46
|
+
```ts [server/api/login.post.ts]
|
|
47
|
+
import { z } from 'zod'
|
|
48
|
+
|
|
49
|
+
const bodySchema = z.object({
|
|
50
|
+
email: z.string().email(),
|
|
51
|
+
password: z.string().min(8)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
export default defineEventHandler(async (event) => {
|
|
55
|
+
const { email, password } = await readValidatedBody(event, bodySchema.parse)
|
|
56
|
+
|
|
57
|
+
if (email === 'admin@admin.com' && password === 'iamtheadmin') {
|
|
58
|
+
// set the user session in the cookie
|
|
59
|
+
// this server util is auto-imported by the auth-utils module
|
|
60
|
+
await setUserSession(event, {
|
|
61
|
+
user: {
|
|
62
|
+
name: 'John Doe'
|
|
63
|
+
}
|
|
64
|
+
})
|
|
65
|
+
return {}
|
|
66
|
+
}
|
|
67
|
+
throw createError({
|
|
68
|
+
statusCode: 401,
|
|
69
|
+
message: 'Bad credentials'
|
|
70
|
+
})
|
|
71
|
+
})
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
::callout
|
|
75
|
+
Make sure to install the `zod` dependency in your project (`npm i zod`).
|
|
76
|
+
::
|
|
77
|
+
|
|
78
|
+
::tip{to="https://github.com/atinux/nuxt-auth-utils#server-utils"}
|
|
79
|
+
Read more about the `setUserSession` server helper exposed by `nuxt-auth-utils`.
|
|
80
|
+
::
|
|
81
|
+
|
|
82
|
+
## Login Page
|
|
83
|
+
|
|
84
|
+
The module exposes a Vue composable to know if a user is authenticated in our application:
|
|
85
|
+
|
|
86
|
+
```vue
|
|
87
|
+
<script setup>
|
|
88
|
+
const { loggedIn, session, user, clear, fetch } = useUserSession()
|
|
89
|
+
</script>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Let's create a login page with a form to submit the login data to our `/api/login` route.
|
|
93
|
+
|
|
94
|
+
```vue [pages/login.vue]
|
|
95
|
+
<script setup lang="ts">
|
|
96
|
+
const { loggedIn, user, fetch: refreshSession } = useUserSession()
|
|
97
|
+
const credentials = reactive({
|
|
98
|
+
email: '',
|
|
99
|
+
password: '',
|
|
100
|
+
})
|
|
101
|
+
async function login() {
|
|
102
|
+
$fetch('/api/login', {
|
|
103
|
+
method: 'POST',
|
|
104
|
+
body: credentials
|
|
105
|
+
})
|
|
106
|
+
.then(async () => {
|
|
107
|
+
// Refresh the session on client-side and redirect to the home page
|
|
108
|
+
await refreshSession()
|
|
109
|
+
await navigateTo('/')
|
|
110
|
+
})
|
|
111
|
+
.catch(() => alert('Bad credentials'))
|
|
112
|
+
}
|
|
113
|
+
</script>
|
|
114
|
+
|
|
115
|
+
<template>
|
|
116
|
+
<form @submit.prevent="login">
|
|
117
|
+
<input v-model="credentials.email" type="email" placeholder="Email" />
|
|
118
|
+
<input v-model="credentials.password" type="password" placeholder="Password" />
|
|
119
|
+
<button type="submit">Login</button>
|
|
120
|
+
</form>
|
|
121
|
+
</template>
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Protect API Routes
|
|
125
|
+
|
|
126
|
+
Protecting server routes is key to making sure your data is safe. Client-side middleware is helpful for the user, but without server-side protection your data can still be accessed. It is critical to protect any routes with sensitive data, we should return a 401 error if the user is not logged in on those.
|
|
127
|
+
|
|
128
|
+
The `auth-utils` module provides the `requireUserSession` utility function to help make sure that users are logged in and have an active session.
|
|
129
|
+
|
|
130
|
+
Let's create an example of a `/api/user/stats` route that only authenticated users can access.
|
|
131
|
+
|
|
132
|
+
```ts [server/api/user/stats.get.ts]
|
|
133
|
+
export default defineEventHandler(async (event) => {
|
|
134
|
+
// make sure the user is logged in
|
|
135
|
+
// This will throw a 401 error if the request doesn't come from a valid user session
|
|
136
|
+
const { user } = await requireUserSession(event)
|
|
137
|
+
|
|
138
|
+
// TODO: Fetch some stats based on the user
|
|
139
|
+
|
|
140
|
+
return {}
|
|
141
|
+
});
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Protect App Routes
|
|
145
|
+
|
|
146
|
+
Our data is safe with the server-side route in place, but without doing anything else, unauthenticated users would probably get some odd data when trying to access the `/users` page. We should create a [client-side middleware](https://nuxt.com/docs/guide/directory-structure/middleware) to protect the route on the client side and redirect users to the login page.
|
|
147
|
+
|
|
148
|
+
`nuxt-auth-utils` provides a convenient `useUserSession` composable which we'll use to check if the user is logged in, and redirect them if they are not.
|
|
149
|
+
|
|
150
|
+
We'll create a middleware in the `/middleware` directory. Unlike on the server, client-side middleware is not automatically applied to all endpoints, and we'll need to specify where we want it applied.
|
|
151
|
+
|
|
152
|
+
```typescript [middleware/authenticated.ts]
|
|
153
|
+
export default defineNuxtRouteMiddleware(() => {
|
|
154
|
+
const { loggedIn } = useUserSession()
|
|
155
|
+
|
|
156
|
+
// redirect the user to the login screen if they're not authenticated
|
|
157
|
+
if (!loggedIn.value) {
|
|
158
|
+
return navigateTo('/login')
|
|
159
|
+
}
|
|
160
|
+
})
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Home Page
|
|
164
|
+
|
|
165
|
+
Now that we have our app middleware to protect our routes, we can use it on our home page that display our authenticated user informations. If the user is not authenticated, they will be redirected to the login page.
|
|
166
|
+
|
|
167
|
+
We'll use [`definePageMeta`](/docs/api/utils/define-page-meta) to apply the middleware to the route that we want to protect.
|
|
168
|
+
|
|
169
|
+
```vue [pages/index.vue]
|
|
170
|
+
<script setup lang="ts">
|
|
171
|
+
definePageMeta({
|
|
172
|
+
middleware: ['authenticated'],
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
const { user, clear: clearSession } = useUserSession()
|
|
176
|
+
|
|
177
|
+
async function logout() {
|
|
178
|
+
await clearSession()
|
|
179
|
+
await navigateTo('/login')
|
|
180
|
+
}
|
|
181
|
+
</script>
|
|
182
|
+
|
|
183
|
+
<template>
|
|
184
|
+
<div>
|
|
185
|
+
<h1>Welcome {{ user.name }}</h1>
|
|
186
|
+
<button @click="logout">Logout</button>
|
|
187
|
+
</div>
|
|
188
|
+
</template>
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
We also added a logout button to clear the session and redirect the user to the login page.
|
|
192
|
+
|
|
193
|
+
## Conclusion
|
|
194
|
+
|
|
195
|
+
We've successfully set up a very basic user authentication and session management in our Nuxt app. We've also protected sensitive routes on the server and client side to ensure that only authenticated users can access them.
|
|
196
|
+
|
|
197
|
+
As next steps, you can:
|
|
198
|
+
- Add authentication using the [20+ supported OAuth providers](https://github.com/atinux/nuxt-auth-utils?tab=readme-ov-file#supported-oauth-providers)
|
|
199
|
+
- Add a database to store users, see [Nitro SQL Database](https://nitro.build/guide/database) or [NuxtHub SQL Database](https://hub.nuxt.com/docs/features/database)
|
|
200
|
+
- Let user signup with email & password using [password hashing](https://github.com/atinux/nuxt-auth-utils?tab=readme-ov-file#password-hashing)
|
|
201
|
+
- Add support for [WebAuthn / Passkeys](https://github.com/atinux/nuxt-auth-utils?tab=readme-ov-file#webauthn-passkey)
|
|
202
|
+
|
|
203
|
+
Checkout the open source [atidone repository](https://github.com/atinux/atidone) for a full example of a Nuxt app with OAuth authentication, database and CRUD operations.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: '<ClientOnly>'
|
|
3
|
+
description: Render components only in client-side with the <ClientOnly> component.
|
|
4
|
+
links:
|
|
5
|
+
- label: Source
|
|
6
|
+
icon: i-simple-icons-github
|
|
7
|
+
to: https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/client-only.ts
|
|
8
|
+
size: xs
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
The `<ClientOnly>` component is used for purposely rendering a component only on client side.
|
|
12
|
+
|
|
13
|
+
::note
|
|
14
|
+
The content of the default slot will be tree-shaken out of the server build. (This does mean that any CSS used by components within it may not be inlined when rendering the initial HTML.)
|
|
15
|
+
::
|
|
16
|
+
|
|
17
|
+
## Props
|
|
18
|
+
|
|
19
|
+
- `placeholderTag` | `fallbackTag`: specify a tag to be rendered server-side.
|
|
20
|
+
- `placeholder` | `fallback`: specify a content to be rendered server-side.
|
|
21
|
+
|
|
22
|
+
```vue
|
|
23
|
+
<template>
|
|
24
|
+
<div>
|
|
25
|
+
<Sidebar />
|
|
26
|
+
<!-- The <Comment> component will only be rendered on client-side -->
|
|
27
|
+
<ClientOnly fallback-tag="span" fallback="Loading comments...">
|
|
28
|
+
<Comment />
|
|
29
|
+
</ClientOnly>
|
|
30
|
+
</div>
|
|
31
|
+
</template>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Slots
|
|
35
|
+
|
|
36
|
+
- `#fallback`: specify a content to be rendered on the server and displayed until `<ClientOnly>` is mounted in the browser.
|
|
37
|
+
|
|
38
|
+
```vue [pages/example.vue]
|
|
39
|
+
<template>
|
|
40
|
+
<div>
|
|
41
|
+
<Sidebar />
|
|
42
|
+
<!-- This renders the "span" element on the server side -->
|
|
43
|
+
<ClientOnly fallbackTag="span">
|
|
44
|
+
<!-- this component will only be rendered on client side -->
|
|
45
|
+
<Comments />
|
|
46
|
+
<template #fallback>
|
|
47
|
+
<!-- this will be rendered on server side -->
|
|
48
|
+
<p>Loading comments...</p>
|
|
49
|
+
</template>
|
|
50
|
+
</ClientOnly>
|
|
51
|
+
</div>
|
|
52
|
+
</template>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Examples
|
|
56
|
+
|
|
57
|
+
### Accessing HTML Elements
|
|
58
|
+
|
|
59
|
+
Components inside `<ClientOnly>` are rendered only after being mounted. To access the rendered elements in the DOM, you can watch a template ref:
|
|
60
|
+
|
|
61
|
+
```vue [pages/example.vue]
|
|
62
|
+
<script setup lang="ts">
|
|
63
|
+
const nuxtWelcomeRef = useTemplateRef('nuxtWelcomeRef')
|
|
64
|
+
|
|
65
|
+
// The watch will be triggered when the component is available
|
|
66
|
+
watch(nuxtWelcomeRef, () => {
|
|
67
|
+
console.log('<NuxtWelcome /> mounted')
|
|
68
|
+
}, { once: true })
|
|
69
|
+
</script>
|
|
70
|
+
|
|
71
|
+
<template>
|
|
72
|
+
<ClientOnly>
|
|
73
|
+
<NuxtWelcome ref="nuxtWelcomeRef" />
|
|
74
|
+
</ClientOnly>
|
|
75
|
+
</template>
|
|
76
|
+
```
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: '<DevOnly>'
|
|
3
|
+
description: Render components only during development with the <DevOnly> component.
|
|
4
|
+
links:
|
|
5
|
+
- label: Source
|
|
6
|
+
icon: i-simple-icons-github
|
|
7
|
+
to: https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/dev-only.ts
|
|
8
|
+
size: xs
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
Nuxt provides the `<DevOnly>` component to render a component only during development.
|
|
12
|
+
|
|
13
|
+
The content will not be included in production builds.
|
|
14
|
+
|
|
15
|
+
```vue [pages/example.vue]
|
|
16
|
+
<template>
|
|
17
|
+
<div>
|
|
18
|
+
<Sidebar />
|
|
19
|
+
<DevOnly>
|
|
20
|
+
<!-- this component will only be rendered during development -->
|
|
21
|
+
<LazyDebugBar />
|
|
22
|
+
|
|
23
|
+
<!-- if you ever require to have a replacement during production -->
|
|
24
|
+
<!-- be sure to test these using `nuxt preview` -->
|
|
25
|
+
<template #fallback>
|
|
26
|
+
<div><!-- empty div for flex.justify-between --></div>
|
|
27
|
+
</template>
|
|
28
|
+
</DevOnly>
|
|
29
|
+
</div>
|
|
30
|
+
</template>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Slots
|
|
34
|
+
|
|
35
|
+
- `#fallback`: if you ever require to have a replacement during production.
|
|
36
|
+
|
|
37
|
+
```vue
|
|
38
|
+
<template>
|
|
39
|
+
<div>
|
|
40
|
+
<Sidebar />
|
|
41
|
+
<DevOnly>
|
|
42
|
+
<!-- this component will only be rendered during development -->
|
|
43
|
+
<LazyDebugBar />
|
|
44
|
+
<!-- be sure to test these using `nuxt preview` -->
|
|
45
|
+
<template #fallback>
|
|
46
|
+
<div><!-- empty div for flex.justify-between --></div>
|
|
47
|
+
</template>
|
|
48
|
+
</DevOnly>
|
|
49
|
+
</div>
|
|
50
|
+
</template>
|
|
51
|
+
```
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "<NuxtClientFallback>"
|
|
3
|
+
description: "Nuxt provides the <NuxtClientFallback> component to render its content on the client if any of its children trigger an error in SSR"
|
|
4
|
+
links:
|
|
5
|
+
- label: Source (client)
|
|
6
|
+
icon: i-simple-icons-github
|
|
7
|
+
to: https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/client-fallback.client.ts
|
|
8
|
+
size: xs
|
|
9
|
+
- label: Source (server)
|
|
10
|
+
icon: i-simple-icons-github
|
|
11
|
+
to: https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/client-fallback.server.ts
|
|
12
|
+
size: xs
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
Nuxt provides the `<NuxtClientFallback>` component to render its content on the client if any of its children trigger an error in SSR.
|
|
16
|
+
|
|
17
|
+
::note{to="/docs/guide/going-further/experimental-features#clientfallback"}
|
|
18
|
+
This component is experimental and in order to use it you must enable the `experimental.clientFallback` option in your `nuxt.config`.
|
|
19
|
+
::
|
|
20
|
+
|
|
21
|
+
```vue [pages/example.vue]
|
|
22
|
+
<template>
|
|
23
|
+
<div>
|
|
24
|
+
<Sidebar />
|
|
25
|
+
<!-- this component will be rendered on client-side -->
|
|
26
|
+
<NuxtClientFallback fallback-tag="span">
|
|
27
|
+
<Comments />
|
|
28
|
+
<BrokeInSSR />
|
|
29
|
+
</NuxtClientFallback>
|
|
30
|
+
</div>
|
|
31
|
+
</template>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Events
|
|
35
|
+
|
|
36
|
+
- `@ssr-error`: Event emitted when a child triggers an error in SSR. Note that this will only be triggered on the server.
|
|
37
|
+
|
|
38
|
+
```vue
|
|
39
|
+
<template>
|
|
40
|
+
<NuxtClientFallback @ssr-error="logSomeError">
|
|
41
|
+
<!-- ... -->
|
|
42
|
+
</NuxtClientFallback>
|
|
43
|
+
</template>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Props
|
|
47
|
+
|
|
48
|
+
- `placeholderTag` | `fallbackTag`: Specify a fallback tag to be rendered if the slot fails to render on the server.
|
|
49
|
+
- **type**: `string`
|
|
50
|
+
- **default**: `div`
|
|
51
|
+
- `placeholder` | `fallback`: Specify fallback content to be rendered if the slot fails to render.
|
|
52
|
+
- **type**: `string`
|
|
53
|
+
- `keepFallback`: Keep the fallback content if it failed to render server-side.
|
|
54
|
+
- **type**: `boolean`
|
|
55
|
+
- **default**: `false`
|
|
56
|
+
|
|
57
|
+
```vue
|
|
58
|
+
<template>
|
|
59
|
+
<!-- render <span>Hello world</span> server-side if the default slot fails to render -->
|
|
60
|
+
<NuxtClientFallback fallback-tag="span" fallback="Hello world">
|
|
61
|
+
<BrokeInSsr />
|
|
62
|
+
</NuxtClientFallback>
|
|
63
|
+
</template>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Slots
|
|
67
|
+
|
|
68
|
+
- `#fallback`: specify content to be displayed server-side if the slot fails to render.
|
|
69
|
+
|
|
70
|
+
```vue
|
|
71
|
+
<template>
|
|
72
|
+
<NuxtClientFallback>
|
|
73
|
+
<!-- ... -->
|
|
74
|
+
<template #fallback>
|
|
75
|
+
<!-- this will be rendered on server side if the default slot fails to render in ssr -->
|
|
76
|
+
<p>Hello world</p>
|
|
77
|
+
</template>
|
|
78
|
+
</NuxtClientFallback>
|
|
79
|
+
</template>
|
|
80
|
+
```
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "<NuxtPicture>"
|
|
3
|
+
description: "Nuxt provides a <NuxtPicture> component to handle automatic image optimization."
|
|
4
|
+
links:
|
|
5
|
+
- label: Source
|
|
6
|
+
icon: i-simple-icons-github
|
|
7
|
+
to: https://github.com/nuxt/image/blob/main/src/runtime/components/NuxtPicture.vue
|
|
8
|
+
size: xs
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
`<NuxtPicture>` is a drop-in replacement for the native `<picture>` tag.
|
|
12
|
+
|
|
13
|
+
Usage of `<NuxtPicture>` is almost identical to [`<NuxtImg>`](/docs/api/components/nuxt-img) but it also allows serving modern formats like `webp` when possible.
|
|
14
|
+
|
|
15
|
+
Learn more about the [`<picture>` tag on MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture).
|
|
16
|
+
|
|
17
|
+
## Setup
|
|
18
|
+
|
|
19
|
+
In order to use `<NuxtPicture>` you should install and enable the Nuxt Image module:
|
|
20
|
+
|
|
21
|
+
```bash [Terminal]
|
|
22
|
+
npx nuxi@latest module add image
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
::read-more{to="https://image.nuxt.com/usage/nuxt-picture" target="_blank"}
|
|
26
|
+
Read more about the `<NuxtPicture>` component.
|
|
27
|
+
::
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: '<Teleport>'
|
|
3
|
+
description: The <Teleport> component teleports a component to a different location in the DOM.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
::warning
|
|
7
|
+
The `to` target of [`<Teleport>`](https://vuejs.org/guide/built-ins/teleport.html) expects a CSS selector string or an actual DOM node. Nuxt currently has SSR support for teleports to `#teleports` only, with client-side support for other targets using a `<ClientOnly>` wrapper.
|
|
8
|
+
::
|
|
9
|
+
|
|
10
|
+
## Body Teleport
|
|
11
|
+
|
|
12
|
+
```vue
|
|
13
|
+
<template>
|
|
14
|
+
<button @click="open = true">
|
|
15
|
+
Open Modal
|
|
16
|
+
</button>
|
|
17
|
+
<Teleport to="#teleports">
|
|
18
|
+
<div v-if="open" class="modal">
|
|
19
|
+
<p>Hello from the modal!</p>
|
|
20
|
+
<button @click="open = false">
|
|
21
|
+
Close
|
|
22
|
+
</button>
|
|
23
|
+
</div>
|
|
24
|
+
</Teleport>
|
|
25
|
+
</template>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Client-side Teleport
|
|
29
|
+
|
|
30
|
+
```vue
|
|
31
|
+
<template>
|
|
32
|
+
<ClientOnly>
|
|
33
|
+
<Teleport to="#some-selector">
|
|
34
|
+
<!-- content -->
|
|
35
|
+
</Teleport>
|
|
36
|
+
</ClientOnly>
|
|
37
|
+
</template>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
:link-example{to="/docs/examples/advanced/teleport"}
|