@nuxt/docs 4.1.2 → 4.1.3
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/1.getting-started/01.introduction.md +6 -6
- package/1.getting-started/02.installation.md +2 -1
- package/1.getting-started/03.configuration.md +36 -36
- package/1.getting-started/04.views.md +9 -9
- package/1.getting-started/05.assets.md +15 -9
- package/1.getting-started/06.styling.md +58 -48
- package/1.getting-started/07.routing.md +17 -17
- package/1.getting-started/08.seo-meta.md +59 -46
- package/1.getting-started/09.transitions.md +49 -44
- package/1.getting-started/10.data-fetching.md +104 -81
- package/1.getting-started/11.state-management.md +26 -19
- package/1.getting-started/12.error-handling.md +22 -20
- package/1.getting-started/13.server.md +8 -8
- package/1.getting-started/14.layers.md +22 -16
- package/1.getting-started/15.prerendering.md +32 -32
- package/1.getting-started/16.deployment.md +10 -10
- package/1.getting-started/17.testing.md +44 -44
- package/1.getting-started/18.upgrade.md +53 -71
- package/2.guide/0.index.md +7 -7
- package/2.guide/{2.directory-structure → 1.directory-structure}/.navigation.yml +1 -1
- package/2.guide/{2.directory-structure → 1.directory-structure}/0.nuxt.md +3 -3
- package/2.guide/1.directory-structure/0.output.md +18 -0
- package/2.guide/{2.directory-structure → 1.directory-structure}/1.app/.navigation.yml +1 -1
- package/2.guide/{2.directory-structure → 1.directory-structure}/1.app/1.assets.md +4 -4
- package/2.guide/{2.directory-structure → 1.directory-structure}/1.app/1.components.md +45 -28
- package/2.guide/{2.directory-structure → 1.directory-structure}/1.app/1.composables.md +13 -13
- package/2.guide/{2.directory-structure → 1.directory-structure}/1.app/1.layouts.md +19 -15
- package/2.guide/{2.directory-structure → 1.directory-structure}/1.app/1.middleware.md +31 -25
- package/2.guide/{2.directory-structure → 1.directory-structure}/1.app/1.pages.md +39 -37
- package/2.guide/{2.directory-structure → 1.directory-structure}/1.app/1.plugins.md +25 -25
- package/2.guide/{2.directory-structure → 1.directory-structure}/1.app/1.utils.md +7 -7
- package/2.guide/{2.directory-structure → 1.directory-structure}/1.app/3.app-config.md +18 -18
- package/2.guide/{2.directory-structure → 1.directory-structure}/1.app/3.app.md +7 -7
- package/2.guide/{2.directory-structure → 1.directory-structure}/1.app/3.error.md +6 -6
- package/2.guide/{2.directory-structure → 1.directory-structure}/1.content.md +7 -4
- package/2.guide/{2.directory-structure → 1.directory-structure}/1.modules.md +8 -8
- package/2.guide/{2.directory-structure → 1.directory-structure}/1.node_modules.md +2 -2
- package/2.guide/{2.directory-structure → 1.directory-structure}/1.public.md +2 -2
- package/2.guide/{2.directory-structure → 1.directory-structure}/1.server.md +35 -35
- package/2.guide/{2.directory-structure → 1.directory-structure}/1.shared.md +7 -7
- package/2.guide/{2.directory-structure → 1.directory-structure}/2.env.md +8 -8
- package/2.guide/{2.directory-structure → 1.directory-structure}/2.gitignore.md +1 -1
- package/2.guide/{2.directory-structure → 1.directory-structure}/2.nuxtignore.md +5 -4
- package/2.guide/{2.directory-structure → 1.directory-structure}/2.nuxtrc.md +4 -4
- package/2.guide/{2.directory-structure → 1.directory-structure}/3.nuxt-config.md +3 -3
- package/2.guide/{2.directory-structure → 1.directory-structure}/3.package.md +1 -1
- package/2.guide/{2.directory-structure → 1.directory-structure}/3.tsconfig.md +3 -3
- package/2.guide/{1.concepts → 2.concepts}/1.auto-imports.md +22 -22
- package/2.guide/{1.concepts → 2.concepts}/10.nuxt-lifecycle.md +17 -17
- package/2.guide/{1.concepts → 2.concepts}/2.vuejs-development.md +13 -13
- package/2.guide/{1.concepts → 2.concepts}/3.rendering.md +24 -22
- package/2.guide/{1.concepts → 2.concepts}/4.server-engine.md +6 -6
- package/2.guide/{1.concepts → 2.concepts}/5.modules.md +5 -5
- package/2.guide/{1.concepts → 2.concepts}/7.esm.md +17 -15
- package/2.guide/{1.concepts → 2.concepts}/8.typescript.md +12 -12
- package/2.guide/3.going-further/1.events.md +3 -3
- package/2.guide/3.going-further/1.experimental-features.md +246 -85
- package/2.guide/3.going-further/1.features.md +44 -9
- package/2.guide/3.going-further/1.internals.md +25 -25
- package/2.guide/3.going-further/10.runtime-config.md +12 -12
- package/2.guide/3.going-further/11.nightly-release-channel.md +1 -1
- package/2.guide/3.going-further/2.hooks.md +14 -14
- package/2.guide/3.going-further/3.modules.md +96 -94
- package/2.guide/3.going-further/4.kit.md +7 -7
- package/2.guide/3.going-further/6.nuxt-app.md +8 -8
- package/2.guide/3.going-further/7.layers.md +62 -53
- package/2.guide/3.going-further/9.debugging.md +2 -2
- package/2.guide/4.recipes/1.custom-routing.md +30 -30
- package/2.guide/4.recipes/2.vite-plugin.md +4 -4
- package/2.guide/4.recipes/3.custom-usefetch.md +13 -13
- package/2.guide/4.recipes/4.sessions-and-authentication.md +35 -21
- package/2.guide/5.best-practices/hydration.md +4 -4
- package/2.guide/5.best-practices/performance.md +17 -17
- package/3.api/1.components/1.client-only.md +6 -3
- package/3.api/1.components/1.nuxt-client-fallback.md +10 -7
- package/3.api/1.components/10.nuxt-picture.md +1 -1
- package/3.api/1.components/11.teleports.md +5 -2
- package/3.api/1.components/12.nuxt-route-announcer.md +9 -9
- package/3.api/1.components/13.nuxt-time.md +44 -17
- package/3.api/1.components/2.nuxt-page.md +6 -6
- package/3.api/1.components/3.nuxt-layout.md +15 -10
- package/3.api/1.components/4.nuxt-link.md +42 -22
- package/3.api/1.components/5.nuxt-loading-indicator.md +3 -3
- package/3.api/1.components/6.nuxt-error-boundary.md +12 -10
- package/3.api/2.composables/on-prehydrate.md +2 -2
- package/3.api/2.composables/use-app-config.md +1 -1
- package/3.api/2.composables/use-async-data.md +20 -20
- package/3.api/2.composables/use-cookie.md +29 -21
- package/3.api/2.composables/use-error.md +2 -2
- package/3.api/2.composables/use-fetch.md +58 -32
- package/3.api/2.composables/use-head-safe.md +7 -7
- package/3.api/2.composables/use-head.md +5 -5
- package/3.api/2.composables/use-hydration.md +6 -6
- package/3.api/2.composables/use-lazy-async-data.md +4 -4
- package/3.api/2.composables/use-lazy-fetch.md +4 -4
- package/3.api/2.composables/use-loading-indicator.md +12 -12
- package/3.api/2.composables/use-nuxt-app.md +22 -22
- package/3.api/2.composables/use-nuxt-data.md +8 -8
- package/3.api/2.composables/use-preview-mode.md +15 -18
- package/3.api/2.composables/use-request-event.md +1 -1
- package/3.api/2.composables/use-request-fetch.md +3 -3
- package/3.api/2.composables/use-request-header.md +1 -1
- package/3.api/2.composables/use-request-headers.md +4 -4
- package/3.api/2.composables/use-request-url.md +1 -1
- package/3.api/2.composables/use-response-header.md +9 -10
- package/3.api/2.composables/use-route-announcer.md +4 -4
- package/3.api/2.composables/use-route.md +1 -1
- package/3.api/2.composables/use-router.md +10 -8
- package/3.api/2.composables/use-runtime-config.md +11 -11
- package/3.api/2.composables/use-runtime-hook.md +2 -2
- package/3.api/2.composables/use-seo-meta.md +4 -4
- package/3.api/2.composables/use-server-seo-meta.md +6 -6
- package/3.api/2.composables/use-state.md +5 -5
- package/3.api/3.utils/$fetch.md +10 -8
- package/3.api/3.utils/abort-navigation.md +3 -3
- package/3.api/3.utils/add-route-middleware.md +5 -5
- package/3.api/3.utils/call-once.md +6 -6
- package/3.api/3.utils/clear-error.md +3 -3
- package/3.api/3.utils/clear-nuxt-data.md +3 -3
- package/3.api/3.utils/clear-nuxt-state.md +3 -3
- package/3.api/3.utils/create-error.md +2 -2
- package/3.api/3.utils/define-lazy-hydration-component.md +13 -13
- package/3.api/3.utils/define-nuxt-component.md +5 -5
- package/3.api/3.utils/define-nuxt-plugin.md +13 -13
- package/3.api/3.utils/define-nuxt-route-middleware.md +5 -5
- package/3.api/3.utils/define-page-meta.md +23 -23
- package/3.api/3.utils/define-route-rules.md +7 -7
- package/3.api/3.utils/navigate-to.md +11 -11
- package/3.api/3.utils/prefetch-components.md +1 -1
- package/3.api/3.utils/preload-components.md +1 -1
- package/3.api/3.utils/preload-route-components.md +2 -2
- package/3.api/3.utils/prerender-routes.md +3 -3
- package/3.api/3.utils/refresh-cookie.md +4 -4
- package/3.api/3.utils/refresh-nuxt-data.md +12 -7
- package/3.api/3.utils/reload-nuxt-app.md +3 -3
- package/3.api/3.utils/set-page-layout.md +1 -1
- package/3.api/3.utils/set-response-status.md +3 -3
- package/3.api/3.utils/show-error.md +5 -5
- package/3.api/3.utils/update-app-config.md +4 -3
- package/3.api/4.commands/add.md +1 -1
- package/3.api/4.commands/analyze.md +2 -1
- package/3.api/4.commands/build.md +2 -1
- package/3.api/4.commands/dev.md +5 -4
- package/3.api/4.commands/generate.md +3 -2
- package/3.api/4.commands/init.md +3 -2
- package/3.api/4.commands/module.md +4 -4
- package/3.api/4.commands/prepare.md +7 -2
- package/3.api/4.commands/preview.md +5 -4
- package/3.api/4.commands/test.md +40 -0
- package/3.api/4.commands/typecheck.md +5 -3
- package/3.api/4.commands/upgrade.md +3 -3
- package/3.api/5.kit/1.modules.md +36 -36
- package/3.api/5.kit/10.runtime-config.md +1 -1
- package/3.api/5.kit/10.templates.md +8 -6
- package/3.api/5.kit/11.nitro.md +62 -62
- package/3.api/5.kit/12.resolving.md +2 -2
- package/3.api/5.kit/14.builder.md +1 -0
- package/3.api/5.kit/15.examples.md +2 -2
- package/3.api/5.kit/16.layers.md +26 -26
- package/3.api/5.kit/3.compatibility.md +14 -14
- package/3.api/5.kit/4.autoimports.md +13 -13
- package/3.api/5.kit/5.components.md +7 -7
- package/3.api/5.kit/6.context.md +3 -3
- package/3.api/5.kit/7.pages.md +7 -7
- package/3.api/5.kit/8.layout.md +2 -2
- package/3.api/5.kit/9.plugins.md +5 -4
- package/3.api/6.advanced/1.hooks.md +3 -3
- package/3.api/6.advanced/2.import-meta.md +3 -3
- package/3.api/6.nuxt-config.md +300 -865
- package/3.api/index.md +7 -7
- package/5.community/2.getting-help.md +1 -1
- package/5.community/3.reporting-bugs.md +1 -1
- package/5.community/4.contribution.md +11 -11
- package/5.community/5.framework-contribution.md +4 -4
- package/5.community/6.roadmap.md +1 -1
- package/6.bridge/1.overview.md +13 -13
- package/6.bridge/10.configuration.md +2 -1
- package/6.bridge/2.typescript.md +3 -3
- package/6.bridge/3.bridge-composition-api.md +8 -8
- package/6.bridge/4.plugins-and-middleware.md +9 -9
- package/6.bridge/5.nuxt3-compatible-api.md +20 -17
- package/6.bridge/6.meta.md +20 -19
- package/6.bridge/7.runtime-config.md +1 -1
- package/6.bridge/8.nitro.md +3 -3
- package/6.bridge/9.vite.md +4 -4
- package/7.migration/1.overview.md +2 -2
- package/7.migration/10.bundling.md +1 -1
- package/7.migration/11.server.md +3 -3
- package/7.migration/2.configuration.md +23 -21
- package/7.migration/20.module-authors.md +7 -7
- package/7.migration/3.auto-imports.md +3 -3
- package/7.migration/4.meta.md +21 -18
- package/7.migration/5.plugins-and-middleware.md +8 -8
- package/7.migration/6.pages-and-layouts.md +28 -24
- package/7.migration/7.component-options.md +18 -18
- package/7.migration/8.runtime-config.md +7 -7
- package/package.json +1 -1
- package/2.guide/2.directory-structure/0.output.md +0 -18
- /package/2.guide/{1.concepts → 2.concepts}/.navigation.yml +0 -0
- /package/2.guide/{1.concepts → 2.concepts}/9.code-style.md +0 -0
|
@@ -5,9 +5,9 @@ description: Nuxt provides a powerful system that allows you to extend the defau
|
|
|
5
5
|
|
|
6
6
|
Nuxt layers are a powerful feature that you can use to share and reuse partial Nuxt applications within a monorepo, or from a git repository or npm package. The layers structure is almost identical to a standard Nuxt application, which makes them easy to author and maintain.
|
|
7
7
|
|
|
8
|
-
:read-more{to="/docs/getting-started/layers"}
|
|
8
|
+
:read-more{to="/docs/4.x/getting-started/layers"}
|
|
9
9
|
|
|
10
|
-
A minimal Nuxt layer directory should contain a [`nuxt.config.ts`](/docs/guide/directory-structure/nuxt-config) file to indicate it is a layer.
|
|
10
|
+
A minimal Nuxt layer directory should contain a [`nuxt.config.ts`](/docs/4.x/guide/directory-structure/nuxt-config) file to indicate it is a layer.
|
|
11
11
|
|
|
12
12
|
```ts [base/nuxt.config.ts]
|
|
13
13
|
export default defineNuxtConfig({})
|
|
@@ -15,16 +15,16 @@ export default defineNuxtConfig({})
|
|
|
15
15
|
|
|
16
16
|
Additionally, certain other files in the layer directory will be auto-scanned and used by Nuxt for the project extending this layer.
|
|
17
17
|
|
|
18
|
-
- [`app/components/*`](/docs/guide/directory-structure/app/components) - Extend the default components
|
|
19
|
-
- [`app/composables/*`](/docs/guide/directory-structure/app/composables) - Extend the default composables
|
|
20
|
-
- [`app/layouts/*`](/docs/guide/directory-structure/app/layouts) - Extend the default layouts
|
|
21
|
-
- [`app/middleware/*`](/docs/guide/directory-structure/app/middleware) - Extend the default middleware
|
|
22
|
-
- [`app/pages/*`](/docs/guide/directory-structure/app/pages) - Extend the default pages
|
|
23
|
-
- [`app/plugins/*`](/docs/guide/directory-structure/plugins) - Extend the default plugins
|
|
24
|
-
- [`app/utils/*`](/docs/guide/directory-structure/app/utils) - Extend the default utils
|
|
25
|
-
- [`app/app.config.ts`](/docs/guide/directory-structure/app-config) - Extend the default app config
|
|
26
|
-
- [`server/*`](/docs/guide/directory-structure/server) - Extend the default server endpoints & middleware
|
|
27
|
-
- [`nuxt.config.ts`](/docs/guide/directory-structure/nuxt-config)- Extend the default nuxt config
|
|
18
|
+
- [`app/components/*`](/docs/4.x/guide/directory-structure/app/components) - Extend the default components
|
|
19
|
+
- [`app/composables/*`](/docs/4.x/guide/directory-structure/app/composables) - Extend the default composables
|
|
20
|
+
- [`app/layouts/*`](/docs/4.x/guide/directory-structure/app/layouts) - Extend the default layouts
|
|
21
|
+
- [`app/middleware/*`](/docs/4.x/guide/directory-structure/app/middleware) - Extend the default middleware
|
|
22
|
+
- [`app/pages/*`](/docs/4.x/guide/directory-structure/app/pages) - Extend the default pages
|
|
23
|
+
- [`app/plugins/*`](/docs/4.x/guide/directory-structure/plugins) - Extend the default plugins
|
|
24
|
+
- [`app/utils/*`](/docs/4.x/guide/directory-structure/app/utils) - Extend the default utils
|
|
25
|
+
- [`app/app.config.ts`](/docs/4.x/guide/directory-structure/app-config) - Extend the default app config
|
|
26
|
+
- [`server/*`](/docs/4.x/guide/directory-structure/server) - Extend the default server endpoints & middleware
|
|
27
|
+
- [`nuxt.config.ts`](/docs/4.x/guide/directory-structure/nuxt-config)- Extend the default nuxt config
|
|
28
28
|
|
|
29
29
|
## Basic Example
|
|
30
30
|
|
|
@@ -33,35 +33,35 @@ Additionally, certain other files in the layer directory will be auto-scanned an
|
|
|
33
33
|
```ts [nuxt.config.ts]
|
|
34
34
|
export default defineNuxtConfig({
|
|
35
35
|
extends: [
|
|
36
|
-
'./base'
|
|
37
|
-
]
|
|
36
|
+
'./base',
|
|
37
|
+
],
|
|
38
38
|
})
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
```vue [app/app.vue]
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
<template>
|
|
43
|
+
<BaseComponent />
|
|
44
|
+
</template>
|
|
45
45
|
```
|
|
46
46
|
|
|
47
47
|
```ts [base/nuxt.config.ts]
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
48
|
+
export default defineNuxtConfig({
|
|
49
|
+
// Extending from base nuxt.config.ts!
|
|
50
|
+
app: {
|
|
51
|
+
head: {
|
|
52
|
+
title: 'Extending Configs is Fun!',
|
|
53
|
+
meta: [
|
|
54
|
+
{ name: 'description', content: 'I am using the extends feature in Nuxt!' },
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
})
|
|
59
59
|
```
|
|
60
60
|
|
|
61
61
|
```vue [base/app/components/BaseComponent.vue]
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
<template>
|
|
63
|
+
<h1>Extending Components is Fun!</h1>
|
|
64
|
+
</template>
|
|
65
65
|
```
|
|
66
66
|
|
|
67
67
|
::
|
|
@@ -79,10 +79,13 @@ For example:
|
|
|
79
79
|
```ts [nuxt.config.ts]
|
|
80
80
|
export default defineNuxtConfig({
|
|
81
81
|
extends: [
|
|
82
|
-
|
|
83
|
-
'./layers/
|
|
84
|
-
|
|
85
|
-
|
|
82
|
+
// Highest priority (among extends)
|
|
83
|
+
'./layers/base',
|
|
84
|
+
// Medium priority
|
|
85
|
+
'./layers/theme',
|
|
86
|
+
// Lower priority
|
|
87
|
+
'./layers/custom',
|
|
88
|
+
],
|
|
86
89
|
// Your project has the highest priority
|
|
87
90
|
})
|
|
88
91
|
```
|
|
@@ -110,13 +113,19 @@ You can use a git repository to share your Nuxt layer. Some examples:
|
|
|
110
113
|
```ts [nuxt.config.ts]
|
|
111
114
|
export default defineNuxtConfig({
|
|
112
115
|
extends: [
|
|
113
|
-
|
|
114
|
-
'github:username/repoName
|
|
115
|
-
|
|
116
|
-
'github:username/repoName
|
|
117
|
-
|
|
118
|
-
'
|
|
119
|
-
|
|
116
|
+
// GitHub Remote Source
|
|
117
|
+
'github:username/repoName',
|
|
118
|
+
// GitHub Remote Source within /base directory
|
|
119
|
+
'github:username/repoName/base',
|
|
120
|
+
// GitHub Remote Source from dev branch
|
|
121
|
+
'github:username/repoName#dev',
|
|
122
|
+
// GitHub Remote Source from v1.0.0 tag
|
|
123
|
+
'github:username/repoName#v1.0.0',
|
|
124
|
+
// GitLab Remote Source example
|
|
125
|
+
'gitlab:username/repoName',
|
|
126
|
+
// Bitbucket Remote Source example
|
|
127
|
+
'bitbucket:username/repoName',
|
|
128
|
+
],
|
|
120
129
|
})
|
|
121
130
|
```
|
|
122
131
|
|
|
@@ -138,8 +147,8 @@ When using git remote sources, if a layer has npm dependencies and you wish to i
|
|
|
138
147
|
```ts [nuxt.config.ts]
|
|
139
148
|
export default defineNuxtConfig({
|
|
140
149
|
extends: [
|
|
141
|
-
['github:username/repoName', { install: true }]
|
|
142
|
-
]
|
|
150
|
+
['github:username/repoName', { install: true }],
|
|
151
|
+
],
|
|
143
152
|
})
|
|
144
153
|
```
|
|
145
154
|
::
|
|
@@ -156,8 +165,8 @@ export default defineNuxtConfig({
|
|
|
156
165
|
// Node Module with scope
|
|
157
166
|
'@scope/moduleName',
|
|
158
167
|
// or just the module name
|
|
159
|
-
'moduleName'
|
|
160
|
-
]
|
|
168
|
+
'moduleName',
|
|
169
|
+
],
|
|
161
170
|
})
|
|
162
171
|
```
|
|
163
172
|
|
|
@@ -210,16 +219,16 @@ When importing using global aliases (such as `~/` and `@/`) in a layer component
|
|
|
210
219
|
|
|
211
220
|
Also when using relative paths in `nuxt.config` file of a layer, (with exception of nested `extends`) they are resolved relative to user's project instead of the layer. As a workaround, use full resolved paths in `nuxt.config`:
|
|
212
221
|
|
|
213
|
-
```
|
|
214
|
-
import { fileURLToPath } from 'url'
|
|
215
|
-
import { dirname, join } from 'path'
|
|
222
|
+
```ts [nuxt.config.ts]
|
|
223
|
+
import { fileURLToPath } from 'node:url'
|
|
224
|
+
import { dirname, join } from 'node:path'
|
|
216
225
|
|
|
217
226
|
const currentDir = dirname(fileURLToPath(import.meta.url))
|
|
218
227
|
|
|
219
228
|
export default defineNuxtConfig({
|
|
220
229
|
css: [
|
|
221
|
-
join(currentDir, './app/assets/main.css')
|
|
222
|
-
]
|
|
230
|
+
join(currentDir, './app/assets/main.css'),
|
|
231
|
+
],
|
|
223
232
|
})
|
|
224
233
|
```
|
|
225
234
|
|
|
@@ -229,12 +238,12 @@ You can use the internal array `nuxt.options._layers` to support custom multi-la
|
|
|
229
238
|
|
|
230
239
|
```ts [modules/my-module.ts]
|
|
231
240
|
export default defineNuxtModule({
|
|
232
|
-
setup(_options, nuxt) {
|
|
241
|
+
setup (_options, nuxt) {
|
|
233
242
|
for (const layer of nuxt.options._layers) {
|
|
234
243
|
// You can check for a custom directory existence to extend for each layer
|
|
235
244
|
console.log('Custom extension for', layer.cwd, layer.config)
|
|
236
245
|
}
|
|
237
|
-
}
|
|
246
|
+
},
|
|
238
247
|
})
|
|
239
248
|
```
|
|
240
249
|
|
|
@@ -5,11 +5,11 @@ description: "In Nuxt, your routing is defined by the structure of your files in
|
|
|
5
5
|
|
|
6
6
|
## Adding custom routes
|
|
7
7
|
|
|
8
|
-
In Nuxt, your routing is defined by the structure of your files inside the [app/pages directory](/docs/guide/directory-structure/app/pages). However, since it uses [vue-router](https://router.vuejs.org) under the hood, Nuxt offers you several ways to add custom routes in your project.
|
|
8
|
+
In Nuxt, your routing is defined by the structure of your files inside the [app/pages directory](/docs/4.x/guide/directory-structure/app/pages). However, since it uses [vue-router](https://router.vuejs.org) under the hood, Nuxt offers you several ways to add custom routes in your project.
|
|
9
9
|
|
|
10
10
|
### Router Config
|
|
11
11
|
|
|
12
|
-
Using [router options](/docs/guide/recipes/custom-routing#router-options), you can optionally override or extend your routes using a function that accepts the scanned routes and returns customized routes.
|
|
12
|
+
Using [router options](/docs/4.x/guide/recipes/custom-routing#router-options), you can optionally override or extend your routes using a function that accepts the scanned routes and returns customized routes.
|
|
13
13
|
|
|
14
14
|
If it returns `null` or `undefined`, Nuxt will fall back to the default routes (useful to modify input array).
|
|
15
15
|
|
|
@@ -18,18 +18,18 @@ import type { RouterConfig } from '@nuxt/schema'
|
|
|
18
18
|
|
|
19
19
|
export default {
|
|
20
20
|
// https://router.vuejs.org/api/interfaces/routeroptions.html#routes
|
|
21
|
-
routes:
|
|
21
|
+
routes: _routes => [
|
|
22
22
|
{
|
|
23
23
|
name: 'home',
|
|
24
24
|
path: '/',
|
|
25
|
-
component: () => import('~/pages/home.vue')
|
|
26
|
-
}
|
|
25
|
+
component: () => import('~/pages/home.vue'),
|
|
26
|
+
},
|
|
27
27
|
],
|
|
28
28
|
} satisfies RouterConfig
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
::note
|
|
32
|
-
Nuxt will not augment any new routes you return from the `routes` function with metadata defined in `definePageMeta` of the component you provide. If you want that to happen, you should use the `pages:extend` hook which is [called at build-time](/docs/api/advanced/hooks#nuxt-hooks-build-time).
|
|
32
|
+
Nuxt will not augment any new routes you return from the `routes` function with metadata defined in `definePageMeta` of the component you provide. If you want that to happen, you should use the `pages:extend` hook which is [called at build-time](/docs/4.x/api/advanced/hooks#nuxt-hooks-build-time).
|
|
33
33
|
::
|
|
34
34
|
|
|
35
35
|
### Pages Hook
|
|
@@ -48,7 +48,7 @@ export default defineNuxtConfig({
|
|
|
48
48
|
pages.push({
|
|
49
49
|
name: 'profile',
|
|
50
50
|
path: '/profile',
|
|
51
|
-
file: '~/extra-pages/profile.vue'
|
|
51
|
+
file: '~/extra-pages/profile.vue',
|
|
52
52
|
})
|
|
53
53
|
|
|
54
54
|
// remove routes
|
|
@@ -66,8 +66,8 @@ export default defineNuxtConfig({
|
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
removePagesMatching(/\.ts$/, pages)
|
|
69
|
-
}
|
|
70
|
-
}
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
71
|
})
|
|
72
72
|
```
|
|
73
73
|
|
|
@@ -75,17 +75,17 @@ export default defineNuxtConfig({
|
|
|
75
75
|
|
|
76
76
|
If you plan to add a whole set of pages related with a specific functionality, you might want to use a [Nuxt module](/modules).
|
|
77
77
|
|
|
78
|
-
The [Nuxt kit](/docs/guide/going-further/kit) provides a few ways [to add routes](/docs/api/kit/pages):
|
|
79
|
-
- [`extendPages`](/docs/api/kit/pages#extendpages) (callback: pages => void)
|
|
80
|
-
- [`extendRouteRules`](/docs/api/kit/pages#extendrouterules) (route: string, rule: NitroRouteConfig, options: ExtendRouteRulesOptions)
|
|
78
|
+
The [Nuxt kit](/docs/4.x/guide/going-further/kit) provides a few ways [to add routes](/docs/4.x/api/kit/pages):
|
|
79
|
+
- [`extendPages`](/docs/4.x/api/kit/pages#extendpages) (callback: pages => void)
|
|
80
|
+
- [`extendRouteRules`](/docs/4.x/api/kit/pages#extendrouterules) (route: string, rule: NitroRouteConfig, options: ExtendRouteRulesOptions)
|
|
81
81
|
|
|
82
82
|
## Router Options
|
|
83
83
|
|
|
84
|
-
On top of customizing options for [`vue-router`](https://router.vuejs.org/api/interfaces/routeroptions.html), Nuxt offers [additional options](/docs/api/nuxt-config#router) to customize the router.
|
|
84
|
+
On top of customizing options for [`vue-router`](https://router.vuejs.org/api/interfaces/routeroptions.html), Nuxt offers [additional options](/docs/4.x/api/nuxt-config#router) to customize the router.
|
|
85
85
|
|
|
86
86
|
### Using `router.options`
|
|
87
87
|
|
|
88
|
-
This is the recommended way to specify [router options](/docs/api/nuxt-config#router).
|
|
88
|
+
This is the recommended way to specify [router options](/docs/4.x/api/nuxt-config#router).
|
|
89
89
|
|
|
90
90
|
```ts [router.options.ts]
|
|
91
91
|
import type { RouterConfig } from '@nuxt/schema'
|
|
@@ -110,16 +110,16 @@ export default defineNuxtConfig({
|
|
|
110
110
|
// add a route
|
|
111
111
|
files.push({
|
|
112
112
|
path: resolver.resolve('./runtime/router-options'),
|
|
113
|
-
optional: true
|
|
113
|
+
optional: true,
|
|
114
114
|
})
|
|
115
|
-
}
|
|
116
|
-
}
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
117
|
})
|
|
118
118
|
```
|
|
119
119
|
|
|
120
120
|
### Using `nuxt.config`
|
|
121
121
|
|
|
122
|
-
**Note:** Only JSON serializable [options](/docs/api/nuxt-config#router) are configurable:
|
|
122
|
+
**Note:** Only JSON serializable [options](/docs/4.x/api/nuxt-config#router) are configurable:
|
|
123
123
|
|
|
124
124
|
- `linkActiveClass`
|
|
125
125
|
- `linkExactActiveClass`
|
|
@@ -129,40 +129,40 @@ export default defineNuxtConfig({
|
|
|
129
129
|
- `hashMode`
|
|
130
130
|
- `scrollBehaviorType`
|
|
131
131
|
|
|
132
|
-
```
|
|
132
|
+
```ts [nuxt.config]
|
|
133
133
|
export default defineNuxtConfig({
|
|
134
134
|
router: {
|
|
135
|
-
options: {}
|
|
136
|
-
}
|
|
135
|
+
options: {},
|
|
136
|
+
},
|
|
137
137
|
})
|
|
138
138
|
```
|
|
139
139
|
|
|
140
140
|
### Hash Mode (SPA)
|
|
141
141
|
|
|
142
|
-
You can enable hash history in SPA mode using the `hashMode` [config](/docs/api/nuxt-config#router). In this mode, router uses a hash character (#) before the actual URL that is internally passed. When enabled, the **URL is never sent to the server** and **SSR is not supported**.
|
|
142
|
+
You can enable hash history in SPA mode using the `hashMode` [config](/docs/4.x/api/nuxt-config#router). In this mode, router uses a hash character (#) before the actual URL that is internally passed. When enabled, the **URL is never sent to the server** and **SSR is not supported**.
|
|
143
143
|
|
|
144
144
|
```ts [nuxt.config.ts]
|
|
145
145
|
export default defineNuxtConfig({
|
|
146
146
|
ssr: false,
|
|
147
147
|
router: {
|
|
148
148
|
options: {
|
|
149
|
-
hashMode: true
|
|
150
|
-
}
|
|
151
|
-
}
|
|
149
|
+
hashMode: true,
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
152
|
})
|
|
153
153
|
```
|
|
154
154
|
|
|
155
155
|
### Scroll Behavior for hash links
|
|
156
156
|
|
|
157
|
-
You can optionally customize the scroll behavior for hash links. When you set the [config](/docs/api/nuxt-config#router) to be `smooth` and you load a page with a hash link (e.g. `https://example.com/blog/my-article#comments`), you will see that the browser smoothly scrolls to this anchor.
|
|
157
|
+
You can optionally customize the scroll behavior for hash links. When you set the [config](/docs/4.x/api/nuxt-config#router) to be `smooth` and you load a page with a hash link (e.g. `https://example.com/blog/my-article#comments`), you will see that the browser smoothly scrolls to this anchor.
|
|
158
158
|
|
|
159
159
|
```ts [nuxt.config.ts]
|
|
160
160
|
export default defineNuxtConfig({
|
|
161
161
|
router: {
|
|
162
162
|
options: {
|
|
163
|
-
scrollBehaviorType: 'smooth'
|
|
164
|
-
}
|
|
165
|
-
}
|
|
163
|
+
scrollBehaviorType: 'smooth',
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
166
|
})
|
|
167
167
|
```
|
|
168
168
|
|
|
@@ -176,6 +176,6 @@ import { createMemoryHistory } from 'vue-router'
|
|
|
176
176
|
|
|
177
177
|
export default {
|
|
178
178
|
// https://router.vuejs.org/api/interfaces/routeroptions.html
|
|
179
|
-
history: base => import.meta.client ? createMemoryHistory(base) : null /* default */
|
|
179
|
+
history: base => import.meta.client ? createMemoryHistory(base) : null, /* default */
|
|
180
180
|
} satisfies RouterConfig
|
|
181
181
|
```
|
|
@@ -28,7 +28,7 @@ First, we need to install the Vite plugin, for our example, we'll use `@rollup/p
|
|
|
28
28
|
|
|
29
29
|
::
|
|
30
30
|
|
|
31
|
-
Next, we need to import and add it to our [`nuxt.config.ts`](/docs/guide/directory-structure/nuxt-config) file:
|
|
31
|
+
Next, we need to import and add it to our [`nuxt.config.ts`](/docs/4.x/guide/directory-structure/nuxt-config) file:
|
|
32
32
|
|
|
33
33
|
```ts [nuxt.config.ts]
|
|
34
34
|
import yaml from '@rollup/plugin-yaml'
|
|
@@ -36,9 +36,9 @@ import yaml from '@rollup/plugin-yaml'
|
|
|
36
36
|
export default defineNuxtConfig({
|
|
37
37
|
vite: {
|
|
38
38
|
plugins: [
|
|
39
|
-
yaml()
|
|
40
|
-
]
|
|
41
|
-
}
|
|
39
|
+
yaml(),
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
42
|
})
|
|
43
43
|
```
|
|
44
44
|
|
|
@@ -6,13 +6,13 @@ description: How to create a custom fetcher for calling your external API in Nux
|
|
|
6
6
|
|
|
7
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
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`.
|
|
9
|
+
The [`$fetch`](/docs/4.x/api/utils/dollarfetch) utility function (used by the [`useFetch`](/docs/4.x/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
10
|
|
|
11
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
12
|
|
|
13
13
|
## Custom `$fetch`
|
|
14
14
|
|
|
15
|
-
Let's create a custom `$fetch` instance with a [Nuxt plugin](/docs/guide/directory-structure/plugins).
|
|
15
|
+
Let's create a custom `$fetch` instance with a [Nuxt plugin](/docs/4.x/guide/directory-structure/plugins).
|
|
16
16
|
|
|
17
17
|
::note
|
|
18
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).
|
|
@@ -29,24 +29,24 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|
|
29
29
|
|
|
30
30
|
const api = $fetch.create({
|
|
31
31
|
baseURL: 'https://api.nuxt.com',
|
|
32
|
-
onRequest({ request, options, error }) {
|
|
32
|
+
onRequest ({ request, options, error }) {
|
|
33
33
|
if (session.value?.token) {
|
|
34
34
|
// note that this relies on ofetch >= 1.4.0 - you may need to refresh your lockfile
|
|
35
35
|
options.headers.set('Authorization', `Bearer ${session.value?.token}`)
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
|
-
async onResponseError({ response }) {
|
|
38
|
+
async onResponseError ({ response }) {
|
|
39
39
|
if (response.status === 401) {
|
|
40
40
|
await nuxtApp.runWithContext(() => navigateTo('/login'))
|
|
41
41
|
}
|
|
42
|
-
}
|
|
42
|
+
},
|
|
43
43
|
})
|
|
44
44
|
|
|
45
45
|
// Expose to useNuxtApp().$api
|
|
46
46
|
return {
|
|
47
47
|
provide: {
|
|
48
|
-
api
|
|
49
|
-
}
|
|
48
|
+
api,
|
|
49
|
+
},
|
|
50
50
|
}
|
|
51
51
|
})
|
|
52
52
|
```
|
|
@@ -61,7 +61,7 @@ const { data: modules } = await useAsyncData('modules', () => $api('/modules'))
|
|
|
61
61
|
```
|
|
62
62
|
|
|
63
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).
|
|
64
|
+
Wrapping with [`useAsyncData`](/docs/4.x/api/composables/use-async-data) **avoid double data fetching when doing server-side rendering** (server & client on hydration).
|
|
65
65
|
::
|
|
66
66
|
|
|
67
67
|
## Custom `useFetch`/`useAsyncData`
|
|
@@ -71,13 +71,13 @@ Now that `$api` has the logic we want, let's create a `useAPI` composable to rep
|
|
|
71
71
|
```ts [app/composables/useAPI.ts]
|
|
72
72
|
import type { UseFetchOptions } from 'nuxt/app'
|
|
73
73
|
|
|
74
|
-
export function useAPI<T>(
|
|
74
|
+
export function useAPI<T> (
|
|
75
75
|
url: string | (() => string),
|
|
76
76
|
options?: UseFetchOptions<T>,
|
|
77
77
|
) {
|
|
78
78
|
return useFetch(url, {
|
|
79
79
|
...options,
|
|
80
|
-
$fetch: useNuxtApp().$api as typeof $fetch
|
|
80
|
+
$fetch: useNuxtApp().$api as typeof $fetch,
|
|
81
81
|
})
|
|
82
82
|
}
|
|
83
83
|
```
|
|
@@ -101,13 +101,13 @@ interface CustomError {
|
|
|
101
101
|
statusCode: number
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
export function useAPI<T>(
|
|
104
|
+
export function useAPI<T> (
|
|
105
105
|
url: string | (() => string),
|
|
106
106
|
options?: UseFetchOptions<T>,
|
|
107
107
|
) {
|
|
108
108
|
return useFetch<T, FetchError<CustomError>>(url, {
|
|
109
109
|
...options,
|
|
110
|
-
$fetch: useNuxtApp().$api
|
|
110
|
+
$fetch: useNuxtApp().$api,
|
|
111
111
|
})
|
|
112
112
|
}
|
|
113
113
|
```
|
|
@@ -116,7 +116,7 @@ export function useAPI<T>(
|
|
|
116
116
|
This example demonstrates how to use a custom `useFetch`, but the same structure is identical for a custom `useAsyncData`.
|
|
117
117
|
::
|
|
118
118
|
|
|
119
|
-
:link-example{to="/docs/examples/advanced/use-custom-fetch-composable"}
|
|
119
|
+
:link-example{to="/docs/4.x/examples/advanced/use-custom-fetch-composable"}
|
|
120
120
|
|
|
121
121
|
:video-accordion{title="Watch a video about custom $fetch and Repository Pattern in Nuxt" videoId="jXH8Tr-exhI"}
|
|
122
122
|
|
|
@@ -48,7 +48,7 @@ import { z } from 'zod'
|
|
|
48
48
|
|
|
49
49
|
const bodySchema = z.object({
|
|
50
50
|
email: z.string().email(),
|
|
51
|
-
password: z.string().min(8)
|
|
51
|
+
password: z.string().min(8),
|
|
52
52
|
})
|
|
53
53
|
|
|
54
54
|
export default defineEventHandler(async (event) => {
|
|
@@ -59,14 +59,14 @@ export default defineEventHandler(async (event) => {
|
|
|
59
59
|
// this server util is auto-imported by the auth-utils module
|
|
60
60
|
await setUserSession(event, {
|
|
61
61
|
user: {
|
|
62
|
-
name: 'John Doe'
|
|
63
|
-
}
|
|
62
|
+
name: 'John Doe',
|
|
63
|
+
},
|
|
64
64
|
})
|
|
65
65
|
return {}
|
|
66
66
|
}
|
|
67
67
|
throw createError({
|
|
68
68
|
statusCode: 401,
|
|
69
|
-
message: 'Bad credentials'
|
|
69
|
+
message: 'Bad credentials',
|
|
70
70
|
})
|
|
71
71
|
})
|
|
72
72
|
```
|
|
@@ -98,25 +98,37 @@ const credentials = reactive({
|
|
|
98
98
|
email: '',
|
|
99
99
|
password: '',
|
|
100
100
|
})
|
|
101
|
-
async function login() {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
101
|
+
async function login () {
|
|
102
|
+
try {
|
|
103
|
+
await $fetch('/api/login', {
|
|
104
|
+
method: 'POST',
|
|
105
|
+
body: credentials,
|
|
106
|
+
})
|
|
107
|
+
|
|
107
108
|
// Refresh the session on client-side and redirect to the home page
|
|
108
109
|
await refreshSession()
|
|
109
110
|
await navigateTo('/')
|
|
110
|
-
}
|
|
111
|
-
|
|
111
|
+
} catch {
|
|
112
|
+
alert('Bad credentials')
|
|
113
|
+
}
|
|
112
114
|
}
|
|
113
115
|
</script>
|
|
114
116
|
|
|
115
117
|
<template>
|
|
116
118
|
<form @submit.prevent="login">
|
|
117
|
-
<input
|
|
118
|
-
|
|
119
|
-
|
|
119
|
+
<input
|
|
120
|
+
v-model="credentials.email"
|
|
121
|
+
type="email"
|
|
122
|
+
placeholder="Email"
|
|
123
|
+
>
|
|
124
|
+
<input
|
|
125
|
+
v-model="credentials.password"
|
|
126
|
+
type="password"
|
|
127
|
+
placeholder="Password"
|
|
128
|
+
>
|
|
129
|
+
<button type="submit">
|
|
130
|
+
Login
|
|
131
|
+
</button>
|
|
120
132
|
</form>
|
|
121
133
|
</template>
|
|
122
134
|
```
|
|
@@ -138,12 +150,12 @@ export default defineEventHandler(async (event) => {
|
|
|
138
150
|
// TODO: Fetch some stats based on the user
|
|
139
151
|
|
|
140
152
|
return {}
|
|
141
|
-
})
|
|
153
|
+
})
|
|
142
154
|
```
|
|
143
155
|
|
|
144
156
|
## Protect App Routes
|
|
145
157
|
|
|
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/app/middleware) to protect the route on the client side and redirect users to the login page.
|
|
158
|
+
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/4.x/guide/directory-structure/app/middleware) to protect the route on the client side and redirect users to the login page.
|
|
147
159
|
|
|
148
160
|
`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
161
|
|
|
@@ -164,17 +176,17 @@ export default defineNuxtRouteMiddleware(() => {
|
|
|
164
176
|
|
|
165
177
|
Now that we have our app middleware to protect our routes, we can use it on our home page that display our authenticated user information. If the user is not authenticated, they will be redirected to the login page.
|
|
166
178
|
|
|
167
|
-
We'll use [`definePageMeta`](/docs/api/utils/define-page-meta) to apply the middleware to the route that we want to protect.
|
|
179
|
+
We'll use [`definePageMeta`](/docs/4.x/api/utils/define-page-meta) to apply the middleware to the route that we want to protect.
|
|
168
180
|
|
|
169
181
|
```vue [app/pages/index.vue]
|
|
170
182
|
<script setup lang="ts">
|
|
171
183
|
definePageMeta({
|
|
172
184
|
middleware: ['authenticated'],
|
|
173
185
|
})
|
|
174
|
-
|
|
186
|
+
|
|
175
187
|
const { user, clear: clearSession } = useUserSession()
|
|
176
188
|
|
|
177
|
-
async function logout() {
|
|
189
|
+
async function logout () {
|
|
178
190
|
await clearSession()
|
|
179
191
|
await navigateTo('/login')
|
|
180
192
|
}
|
|
@@ -183,7 +195,9 @@ async function logout() {
|
|
|
183
195
|
<template>
|
|
184
196
|
<div>
|
|
185
197
|
<h1>Welcome {{ user.name }}</h1>
|
|
186
|
-
<button @click="logout">
|
|
198
|
+
<button @click="logout">
|
|
199
|
+
Logout
|
|
200
|
+
</button>
|
|
187
201
|
</div>
|
|
188
202
|
</template>
|
|
189
203
|
```
|
|
@@ -47,7 +47,7 @@ const userTheme = localStorage.getItem('theme') || 'light'
|
|
|
47
47
|
</script>
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
**Solution**: You can use [`useCookie`](/docs/api/composables/use-cookie):
|
|
50
|
+
**Solution**: You can use [`useCookie`](/docs/4.x/api/composables/use-cookie):
|
|
51
51
|
|
|
52
52
|
```html
|
|
53
53
|
<template>
|
|
@@ -144,7 +144,7 @@ const greeting = hour < 12 ? 'Good morning' : 'Good afternoon'
|
|
|
144
144
|
</script>
|
|
145
145
|
```
|
|
146
146
|
|
|
147
|
-
**Solution**: Use [`NuxtTime`](/docs/api/components/nuxt-time) component or handle it client-side:
|
|
147
|
+
**Solution**: Use [`NuxtTime`](/docs/4.x/api/components/nuxt-time) component or handle it client-side:
|
|
148
148
|
|
|
149
149
|
```html
|
|
150
150
|
<template>
|
|
@@ -178,8 +178,8 @@ onMounted(() => {
|
|
|
178
178
|
|
|
179
179
|
## In summary
|
|
180
180
|
|
|
181
|
-
1. **Use SSR-friendly composables**: [`useFetch`](/docs/api/composables/use-fetch), [`useAsyncData`](/docs/api/composables/use-async-data), [`useState`](/docs/api/composables/use-state)
|
|
182
|
-
2. **Wrap client-only code**: Use [`ClientOnly`](/docs/api/components/client-only) component for browser-specific content
|
|
181
|
+
1. **Use SSR-friendly composables**: [`useFetch`](/docs/4.x/api/composables/use-fetch), [`useAsyncData`](/docs/4.x/api/composables/use-async-data), [`useState`](/docs/4.x/api/composables/use-state)
|
|
182
|
+
2. **Wrap client-only code**: Use [`ClientOnly`](/docs/4.x/api/components/client-only) component for browser-specific content
|
|
183
183
|
3. **Consistent data sources**: Ensure server and client uses the same data
|
|
184
184
|
4. **Avoid side effects in setup**: Move browser-dependent code to `onMounted`
|
|
185
185
|
|