@nuxt/docs 4.2.0 → 4.2.2
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 +1 -1
- package/1.getting-started/02.installation.md +3 -3
- package/1.getting-started/03.configuration.md +27 -27
- package/1.getting-started/04.views.md +5 -5
- package/1.getting-started/05.assets.md +8 -8
- package/1.getting-started/06.styling.md +15 -15
- package/1.getting-started/07.routing.md +10 -6
- package/1.getting-started/08.seo-meta.md +3 -3
- package/1.getting-started/09.transitions.md +10 -10
- package/1.getting-started/10.data-fetching.md +16 -16
- package/1.getting-started/11.state-management.md +3 -3
- package/1.getting-started/12.error-handling.md +6 -6
- package/1.getting-started/13.server.md +6 -6
- package/1.getting-started/14.layers.md +32 -13
- package/1.getting-started/16.deployment.md +1 -1
- package/1.getting-started/17.testing.md +35 -4
- package/1.getting-started/18.upgrade.md +42 -34
- package/{2.guide/1.directory-structure → 2.directory-structure}/0.nuxt.md +1 -1
- package/{2.guide/1.directory-structure → 2.directory-structure}/0.output.md +1 -1
- package/{2.guide/1.directory-structure → 2.directory-structure}/1.app/1.assets.md +2 -2
- package/{2.guide/1.directory-structure → 2.directory-structure}/1.app/1.components.md +6 -6
- package/{2.guide/1.directory-structure → 2.directory-structure}/1.app/1.composables.md +2 -2
- package/{2.guide/1.directory-structure → 2.directory-structure}/1.app/1.layouts.md +3 -3
- package/{2.guide/1.directory-structure → 2.directory-structure}/1.app/1.middleware.md +5 -5
- package/{2.guide/1.directory-structure → 2.directory-structure}/1.app/1.pages.md +17 -17
- package/{2.guide/1.directory-structure → 2.directory-structure}/1.app/1.plugins.md +3 -7
- package/{2.guide/1.directory-structure → 2.directory-structure}/1.app/1.utils.md +3 -3
- package/{2.guide/1.directory-structure → 2.directory-structure}/1.app/3.app.md +4 -4
- package/{2.guide/1.directory-structure → 2.directory-structure}/1.app/3.error.md +1 -3
- package/{2.guide/1.directory-structure → 2.directory-structure}/1.content.md +2 -2
- package/{2.guide/1.directory-structure → 2.directory-structure}/1.modules.md +1 -1
- package/{2.guide/1.directory-structure → 2.directory-structure}/1.node_modules.md +2 -2
- package/{2.guide/1.directory-structure → 2.directory-structure}/1.public.md +1 -1
- package/{2.guide/1.directory-structure → 2.directory-structure}/1.server.md +7 -7
- package/{2.guide/1.directory-structure → 2.directory-structure}/1.shared.md +3 -3
- package/{2.guide/1.directory-structure → 2.directory-structure}/2.env.md +2 -2
- package/{2.guide/1.directory-structure → 2.directory-structure}/2.nuxtignore.md +1 -1
- package/{2.guide/1.directory-structure → 2.directory-structure}/2.nuxtrc.md +1 -1
- package/{2.guide/1.directory-structure → 2.directory-structure}/3.nuxt-config.md +1 -1
- package/{2.guide/1.directory-structure → 2.directory-structure}/3.package.md +1 -1
- package/2.directory-structure/3.tsconfig.md +69 -0
- package/2.directory-structure/index.md +61 -0
- package/{2.guide → 3.guide}/0.index.md +4 -7
- package/{2.guide/2.concepts/3.rendering.md → 3.guide/1.concepts/1.rendering.md} +4 -30
- package/{2.guide/2.concepts/2.vuejs-development.md → 3.guide/1.concepts/10.vuejs-development.md} +7 -6
- package/{2.guide/2.concepts/10.nuxt-lifecycle.md → 3.guide/1.concepts/2.nuxt-lifecycle.md} +32 -25
- package/{2.guide/2.concepts/1.auto-imports.md → 3.guide/1.concepts/3.auto-imports.md} +7 -7
- package/{2.guide/2.concepts → 3.guide/1.concepts}/4.server-engine.md +3 -3
- package/{2.guide/2.concepts → 3.guide/1.concepts}/5.modules.md +1 -1
- package/{2.guide/2.concepts → 3.guide/1.concepts}/7.esm.md +3 -2
- package/{2.guide/2.concepts → 3.guide/1.concepts}/8.typescript.md +15 -38
- package/{2.guide/2.concepts → 3.guide/1.concepts}/9.code-style.md +1 -1
- package/{2.guide/5.best-practices → 3.guide/2.best-practices}/hydration.md +1 -1
- package/{2.guide/5.best-practices → 3.guide/2.best-practices}/performance.md +2 -2
- package/3.guide/3.ai/.navigation.yml +3 -0
- package/3.guide/3.ai/1.mcp.md +255 -0
- package/3.guide/3.ai/2.llms-txt.md +65 -0
- package/{2.guide → 3.guide}/4.recipes/1.custom-routing.md +5 -5
- package/{2.guide → 3.guide}/4.recipes/2.vite-plugin.md +1 -1
- package/{2.guide → 3.guide}/4.recipes/3.custom-usefetch.md +1 -1
- package/{2.guide → 3.guide}/4.recipes/4.sessions-and-authentication.md +1 -1
- package/{2.guide/3.going-further → 3.guide/5.going-further}/1.events.md +2 -3
- package/{2.guide/3.going-further → 3.guide/5.going-further}/1.experimental-features.md +10 -10
- package/{2.guide/3.going-further → 3.guide/5.going-further}/1.features.md +1 -1
- package/{2.guide/3.going-further → 3.guide/5.going-further}/1.internals.md +3 -2
- package/{2.guide/3.going-further → 3.guide/5.going-further}/10.runtime-config.md +2 -2
- package/{2.guide/3.going-further → 3.guide/5.going-further}/2.hooks.md +2 -2
- package/{2.guide/3.going-further → 3.guide/5.going-further}/3.modules.md +78 -11
- package/{2.guide/3.going-further → 3.guide/5.going-further}/6.nuxt-app.md +5 -5
- package/{2.guide/3.going-further → 3.guide/5.going-further}/7.layers.md +42 -25
- package/{2.guide/3.going-further → 3.guide/5.going-further}/9.debugging.md +1 -1
- package/{3.api → 4.api}/1.components/10.nuxt-picture.md +1 -1
- package/{3.api → 4.api}/1.components/11.teleports.md +1 -1
- package/{3.api → 4.api}/1.components/12.nuxt-route-announcer.md +1 -3
- package/{3.api → 4.api}/1.components/13.nuxt-time.md +0 -2
- package/{3.api → 4.api}/1.components/2.nuxt-page.md +3 -3
- package/{3.api → 4.api}/1.components/3.nuxt-layout.md +5 -5
- package/{3.api → 4.api}/1.components/4.nuxt-link.md +11 -11
- package/{3.api → 4.api}/1.components/5.nuxt-loading-indicator.md +1 -1
- package/{3.api → 4.api}/1.components/6.nuxt-error-boundary.md +1 -1
- package/{3.api → 4.api}/1.components/7.nuxt-welcome.md +2 -2
- package/{3.api → 4.api}/2.composables/use-app-config.md +1 -1
- package/{3.api → 4.api}/2.composables/use-async-data.md +76 -13
- package/4.api/2.composables/use-cookie.md +183 -0
- package/{3.api → 4.api}/2.composables/use-fetch.md +33 -33
- package/{3.api → 4.api}/2.composables/use-head-safe.md +37 -20
- package/4.api/2.composables/use-head.md +169 -0
- package/{3.api → 4.api}/2.composables/use-hydration.md +24 -18
- package/4.api/2.composables/use-lazy-async-data.md +96 -0
- package/4.api/2.composables/use-lazy-fetch.md +111 -0
- package/{3.api → 4.api}/2.composables/use-nuxt-app.md +7 -7
- package/{3.api → 4.api}/2.composables/use-nuxt-data.md +1 -1
- package/{3.api → 4.api}/2.composables/use-request-fetch.md +1 -1
- package/{3.api → 4.api}/2.composables/use-response-header.md +1 -1
- package/{3.api → 4.api}/2.composables/use-route-announcer.md +0 -2
- package/{3.api → 4.api}/2.composables/use-route.md +2 -2
- package/4.api/2.composables/use-router.md +94 -0
- package/{3.api → 4.api}/2.composables/use-runtime-config.md +1 -1
- package/{3.api → 4.api}/2.composables/use-runtime-hook.md +1 -1
- package/{3.api → 4.api}/2.composables/use-state.md +1 -1
- package/{3.api → 4.api}/3.utils/$fetch.md +1 -1
- package/{3.api → 4.api}/3.utils/abort-navigation.md +3 -3
- package/{3.api → 4.api}/3.utils/add-route-middleware.md +1 -1
- package/{3.api → 4.api}/3.utils/call-once.md +0 -2
- package/{3.api → 4.api}/3.utils/define-lazy-hydration-component.md +4 -4
- package/{3.api → 4.api}/3.utils/define-nuxt-component.md +1 -1
- package/4.api/3.utils/define-nuxt-plugin.md +102 -0
- package/{3.api → 4.api}/3.utils/define-nuxt-route-middleware.md +2 -2
- package/{3.api → 4.api}/3.utils/define-page-meta.md +14 -14
- package/{3.api → 4.api}/3.utils/navigate-to.md +15 -15
- package/{3.api → 4.api}/3.utils/on-before-route-leave.md +1 -1
- package/{3.api → 4.api}/3.utils/on-before-route-update.md +1 -1
- package/{3.api → 4.api}/3.utils/refresh-cookie.md +1 -3
- package/{3.api → 4.api}/3.utils/update-app-config.md +2 -2
- package/{3.api → 4.api}/4.commands/add.md +10 -10
- package/4.api/4.commands/analyze.md +42 -0
- package/4.api/4.commands/build-module.md +42 -0
- package/4.api/4.commands/build.md +47 -0
- package/{3.api → 4.api}/4.commands/cleanup.md +6 -6
- package/4.api/4.commands/dev.md +60 -0
- package/{3.api → 4.api}/4.commands/devtools.md +7 -7
- package/4.api/4.commands/generate.md +42 -0
- package/4.api/4.commands/info.md +33 -0
- package/4.api/4.commands/init.md +50 -0
- package/4.api/4.commands/module.md +84 -0
- package/4.api/4.commands/prepare.md +41 -0
- package/4.api/4.commands/preview.md +44 -0
- package/4.api/4.commands/test.md +40 -0
- package/4.api/4.commands/typecheck.md +44 -0
- package/4.api/4.commands/upgrade.md +37 -0
- package/{3.api → 4.api}/5.kit/1.modules.md +18 -18
- package/{3.api → 4.api}/5.kit/10.templates.md +23 -23
- package/{3.api → 4.api}/5.kit/11.nitro.md +35 -35
- package/{3.api → 4.api}/5.kit/14.builder.md +21 -21
- package/{3.api → 4.api}/5.kit/16.layers.md +12 -12
- package/{3.api → 4.api}/5.kit/2.programmatic.md +2 -2
- package/{3.api → 4.api}/5.kit/4.autoimports.md +18 -18
- package/4.api/5.kit/5.components.md +146 -0
- package/4.api/6.advanced/1.hooks.md +105 -0
- package/{3.api → 4.api}/6.nuxt-config.md +29 -28
- package/5.community/3.reporting-bugs.md +1 -1
- package/5.community/4.contribution.md +1 -1
- package/5.community/5.framework-contribution.md +8 -8
- package/5.community/6.roadmap.md +25 -25
- package/5.community/7.changelog.md +10 -0
- package/6.bridge/1.overview.md +1 -1
- package/6.bridge/2.typescript.md +1 -1
- package/6.bridge/3.bridge-composition-api.md +1 -1
- package/6.bridge/4.plugins-and-middleware.md +2 -2
- package/7.migration/11.server.md +1 -1
- package/7.migration/2.configuration.md +3 -3
- package/7.migration/20.module-authors.md +1 -1
- package/7.migration/3.auto-imports.md +1 -1
- package/7.migration/5.plugins-and-middleware.md +2 -2
- package/7.migration/6.pages-and-layouts.md +6 -6
- package/README.md +1 -1
- package/package.json +1 -1
- package/2.guide/1.directory-structure/3.tsconfig.md +0 -38
- package/3.api/2.composables/use-cookie.md +0 -183
- package/3.api/2.composables/use-head.md +0 -69
- package/3.api/2.composables/use-lazy-async-data.md +0 -47
- package/3.api/2.composables/use-lazy-fetch.md +0 -55
- package/3.api/2.composables/use-router.md +0 -94
- package/3.api/3.utils/define-nuxt-plugin.md +0 -102
- package/3.api/4.commands/analyze.md +0 -42
- package/3.api/4.commands/build-module.md +0 -42
- package/3.api/4.commands/build.md +0 -47
- package/3.api/4.commands/dev.md +0 -60
- package/3.api/4.commands/generate.md +0 -42
- package/3.api/4.commands/info.md +0 -33
- package/3.api/4.commands/init.md +0 -50
- package/3.api/4.commands/module.md +0 -84
- package/3.api/4.commands/prepare.md +0 -41
- package/3.api/4.commands/preview.md +0 -44
- package/3.api/4.commands/test.md +0 -40
- package/3.api/4.commands/typecheck.md +0 -44
- package/3.api/4.commands/upgrade.md +0 -37
- package/3.api/5.kit/5.components.md +0 -146
- package/3.api/6.advanced/1.hooks.md +0 -105
- /package/{2.guide/1.directory-structure → 2.directory-structure}/.navigation.yml +0 -0
- /package/{2.guide/1.directory-structure → 2.directory-structure}/1.app/.navigation.yml +0 -0
- /package/{2.guide/1.directory-structure → 2.directory-structure}/1.app/3.app-config.md +0 -0
- /package/{2.guide/1.directory-structure → 2.directory-structure}/2.gitignore.md +0 -0
- /package/{2.guide → 3.guide}/.navigation.yml +0 -0
- /package/{2.guide/2.concepts → 3.guide/1.concepts}/.navigation.yml +0 -0
- /package/{2.guide/5.best-practices → 3.guide/2.best-practices}/.navigation.yml +0 -0
- /package/{2.guide/5.best-practices → 3.guide/2.best-practices}/plugins.md +0 -0
- /package/{2.guide → 3.guide}/4.recipes/.navigation.yml +0 -0
- /package/{2.guide/3.going-further → 3.guide/5.going-further}/.navigation.yml +0 -0
- /package/{2.guide/3.going-further → 3.guide/5.going-further}/11.nightly-release-channel.md +0 -0
- /package/{2.guide/3.going-further → 3.guide/5.going-further}/4.kit.md +0 -0
- /package/{2.guide/3.going-further → 3.guide/5.going-further}/index.md +0 -0
- /package/{3.api → 4.api}/.navigation.yml +0 -0
- /package/{3.api → 4.api}/1.components/.navigation.yml +0 -0
- /package/{3.api → 4.api}/1.components/1.client-only.md +0 -0
- /package/{3.api → 4.api}/1.components/1.dev-only.md +0 -0
- /package/{3.api → 4.api}/1.components/1.nuxt-client-fallback.md +0 -0
- /package/{3.api → 4.api}/1.components/8.nuxt-island.md +0 -0
- /package/{3.api → 4.api}/1.components/9.nuxt-img.md +0 -0
- /package/{3.api → 4.api}/2.composables/.navigation.yml +0 -0
- /package/{3.api → 4.api}/2.composables/on-prehydrate.md +0 -0
- /package/{3.api → 4.api}/2.composables/use-error.md +0 -0
- /package/{3.api → 4.api}/2.composables/use-loading-indicator.md +0 -0
- /package/{3.api → 4.api}/2.composables/use-preview-mode.md +0 -0
- /package/{3.api → 4.api}/2.composables/use-request-event.md +0 -0
- /package/{3.api → 4.api}/2.composables/use-request-header.md +0 -0
- /package/{3.api → 4.api}/2.composables/use-request-headers.md +0 -0
- /package/{3.api → 4.api}/2.composables/use-request-url.md +0 -0
- /package/{3.api → 4.api}/2.composables/use-seo-meta.md +0 -0
- /package/{3.api → 4.api}/2.composables/use-server-seo-meta.md +0 -0
- /package/{3.api → 4.api}/3.utils/.navigation.yml +0 -0
- /package/{3.api → 4.api}/3.utils/clear-error.md +0 -0
- /package/{3.api → 4.api}/3.utils/clear-nuxt-data.md +0 -0
- /package/{3.api → 4.api}/3.utils/clear-nuxt-state.md +0 -0
- /package/{3.api → 4.api}/3.utils/create-error.md +0 -0
- /package/{3.api → 4.api}/3.utils/define-route-rules.md +0 -0
- /package/{3.api → 4.api}/3.utils/on-nuxt-ready.md +0 -0
- /package/{3.api → 4.api}/3.utils/prefetch-components.md +0 -0
- /package/{3.api → 4.api}/3.utils/preload-components.md +0 -0
- /package/{3.api → 4.api}/3.utils/preload-route-components.md +0 -0
- /package/{3.api → 4.api}/3.utils/prerender-routes.md +0 -0
- /package/{3.api → 4.api}/3.utils/refresh-nuxt-data.md +0 -0
- /package/{3.api → 4.api}/3.utils/reload-nuxt-app.md +0 -0
- /package/{3.api → 4.api}/3.utils/set-page-layout.md +0 -0
- /package/{3.api → 4.api}/3.utils/set-response-status.md +0 -0
- /package/{3.api → 4.api}/3.utils/show-error.md +0 -0
- /package/{3.api → 4.api}/4.commands/.navigation.yml +0 -0
- /package/{3.api → 4.api}/5.kit/.navigation.yml +0 -0
- /package/{3.api → 4.api}/5.kit/10.runtime-config.md +0 -0
- /package/{3.api → 4.api}/5.kit/12.resolving.md +0 -0
- /package/{3.api → 4.api}/5.kit/13.logging.md +0 -0
- /package/{3.api → 4.api}/5.kit/15.examples.md +0 -0
- /package/{3.api → 4.api}/5.kit/3.compatibility.md +0 -0
- /package/{3.api → 4.api}/5.kit/6.context.md +0 -0
- /package/{3.api → 4.api}/5.kit/7.pages.md +0 -0
- /package/{3.api → 4.api}/5.kit/8.layout.md +0 -0
- /package/{3.api → 4.api}/5.kit/9.head.md +0 -0
- /package/{3.api → 4.api}/5.kit/9.plugins.md +0 -0
- /package/{3.api → 4.api}/6.advanced/.navigation.yml +0 -0
- /package/{3.api → 4.api}/6.advanced/2.import-meta.md +0 -0
- /package/{3.api → 4.api}/index.md +0 -0
|
@@ -18,9 +18,9 @@ Within your pages, components, and plugins you can use useAsyncData to get acces
|
|
|
18
18
|
|
|
19
19
|
```vue [app/pages/index.vue]
|
|
20
20
|
<script setup lang="ts">
|
|
21
|
-
const { data, status, error, refresh, clear } = await useAsyncData(
|
|
21
|
+
const { data, status, pending, error, refresh, clear } = await useAsyncData(
|
|
22
22
|
'mountains',
|
|
23
|
-
() => $fetch('https://api.nuxtjs.dev/mountains'),
|
|
23
|
+
(_nuxtApp, { signal }) => $fetch('https://api.nuxtjs.dev/mountains', { signal }),
|
|
24
24
|
)
|
|
25
25
|
</script>
|
|
26
26
|
```
|
|
@@ -30,7 +30,7 @@ If you're using a custom useAsyncData wrapper, do not await it in the composable
|
|
|
30
30
|
::
|
|
31
31
|
|
|
32
32
|
::note
|
|
33
|
-
`data`, `status` and `error` are Vue refs and they should be accessed with `.value` when used within the `<script setup>`, while `refresh`/`execute` and `clear` are plain functions.
|
|
33
|
+
`data`, `status`, `pending` and `error` are Vue refs and they should be accessed with `.value` when used within the `<script setup>`, while `refresh`/`execute` and `clear` are plain functions.
|
|
34
34
|
::
|
|
35
35
|
|
|
36
36
|
### Watch Params
|
|
@@ -42,10 +42,11 @@ The built-in `watch` option allows automatically rerunning the fetcher function
|
|
|
42
42
|
const page = ref(1)
|
|
43
43
|
const { data: posts } = await useAsyncData(
|
|
44
44
|
'posts',
|
|
45
|
-
() => $fetch('https://fakeApi.com/posts', {
|
|
45
|
+
(_nuxtApp, { signal }) => $fetch('https://fakeApi.com/posts', {
|
|
46
46
|
params: {
|
|
47
47
|
page: page.value,
|
|
48
48
|
},
|
|
49
|
+
signal,
|
|
49
50
|
}), {
|
|
50
51
|
watch: [page],
|
|
51
52
|
},
|
|
@@ -70,6 +71,64 @@ const { data: user } = useAsyncData(
|
|
|
70
71
|
</script>
|
|
71
72
|
```
|
|
72
73
|
|
|
74
|
+
### Make your `handler` abortable
|
|
75
|
+
|
|
76
|
+
You can make your `handler` function abortable by using the `signal` provided in the second argument. This is useful for cancelling requests when they are no longer needed, such as when a user navigates away from a page. `$fetch` natively supports abort signals.
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
const { data, error } = await useAsyncData(
|
|
80
|
+
'users',
|
|
81
|
+
(_nuxtApp, { signal }) => $fetch('/api/users', { signal }),
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
refresh() // will actually cancel the $fetch request (if dedupe: cancel)
|
|
85
|
+
refresh() // will actually cancel the $fetch request (if dedupe: cancel)
|
|
86
|
+
refresh()
|
|
87
|
+
|
|
88
|
+
clear() // will cancel the latest pending handler
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
You can also pass an `AbortSignal` to the `refresh`/`execute` function to cancel individual requests manually.
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
const { refresh } = await useAsyncData(
|
|
95
|
+
'users',
|
|
96
|
+
(_nuxtApp, { signal }) => $fetch('/api/users', { signal }),
|
|
97
|
+
)
|
|
98
|
+
let abortController: AbortController | undefined
|
|
99
|
+
|
|
100
|
+
function handleUserAction () {
|
|
101
|
+
abortController = new AbortController()
|
|
102
|
+
refresh({ signal: abortController.signal })
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function handleCancel () {
|
|
106
|
+
abortController?.abort() // aborts the ongoing refresh request
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
If your `handler` function does not support abort signals, you can implement your own abort logic using the `signal` provided.
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
const { data, error } = await useAsyncData(
|
|
114
|
+
'users',
|
|
115
|
+
(_nuxtApp, { signal }) => {
|
|
116
|
+
return new Promise((resolve, reject) => {
|
|
117
|
+
signal?.addEventListener('abort', () => {
|
|
118
|
+
reject(new Error('Request aborted'))
|
|
119
|
+
})
|
|
120
|
+
return Promise.resolve(callback.call(this, yourHandler)).then(resolve, reject)
|
|
121
|
+
})
|
|
122
|
+
},
|
|
123
|
+
)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The handler signal will be aborted when:
|
|
127
|
+
|
|
128
|
+
- A new request is made with `dedupe: 'cancel'`
|
|
129
|
+
- The `clear` function is called
|
|
130
|
+
- The `options.timeout` duration is exceeded
|
|
131
|
+
|
|
73
132
|
::warning
|
|
74
133
|
[`useAsyncData`](/docs/4.x/api/composables/use-async-data) is a reserved function name transformed by the compiler, so you should not name your own function [`useAsyncData`](/docs/4.x/api/composables/use-async-data).
|
|
75
134
|
::
|
|
@@ -116,7 +175,7 @@ You can use `useLazyAsyncData` to have the same behavior as `lazy: true` with `u
|
|
|
116
175
|
|
|
117
176
|
### Shared State and Option Consistency
|
|
118
177
|
|
|
119
|
-
When using the same key for multiple `useAsyncData` calls, they will share the same `data`, `error` and `
|
|
178
|
+
When using the same key for multiple `useAsyncData` calls, they will share the same `data`, `error`, `status` and `pending` refs. This ensures consistency across components but requires option consistency.
|
|
120
179
|
|
|
121
180
|
The following options **must be consistent** across all calls with the same key:
|
|
122
181
|
- `handler` function
|
|
@@ -135,12 +194,12 @@ The following options **can differ** without triggering warnings:
|
|
|
135
194
|
|
|
136
195
|
```ts
|
|
137
196
|
// ❌ This will trigger a development warning
|
|
138
|
-
const { data: users1 } = useAsyncData('users', () => $fetch('/api/users'), { deep: false })
|
|
139
|
-
const { data: users2 } = useAsyncData('users', () => $fetch('/api/users'), { deep: true })
|
|
197
|
+
const { data: users1 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { deep: false })
|
|
198
|
+
const { data: users2 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { deep: true })
|
|
140
199
|
|
|
141
200
|
// ✅ This is allowed
|
|
142
|
-
const { data: users1 } = useAsyncData('users', () => $fetch('/api/users'), { immediate: true })
|
|
143
|
-
const { data: users2 } = useAsyncData('users', () => $fetch('/api/users'), { immediate: false })
|
|
201
|
+
const { data: users1 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { immediate: true })
|
|
202
|
+
const { data: users2 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { immediate: false })
|
|
144
203
|
```
|
|
145
204
|
|
|
146
205
|
::tip
|
|
@@ -159,6 +218,7 @@ Keyed state created using `useAsyncData` can be retrieved across your Nuxt appli
|
|
|
159
218
|
- `pending`: the request is in progress
|
|
160
219
|
- `success`: the request has completed successfully
|
|
161
220
|
- `error`: the request has failed
|
|
221
|
+
- `pending`: a `Ref<boolean>` that is `true` while the request is in progress (that is, while `status.value === 'pending'`).
|
|
162
222
|
- `clear`: a function that can be used to set `data` to `undefined` (or the value of `options.default()` if provided), set `error` to `undefined`, set `status` to `idle`, and mark any currently pending requests as cancelled.
|
|
163
223
|
|
|
164
224
|
By default, Nuxt waits until a `refresh` is finished before it can be executed again.
|
|
@@ -170,14 +230,16 @@ If you have not fetched data on the server (for example, with `server: false`),
|
|
|
170
230
|
## Type
|
|
171
231
|
|
|
172
232
|
```ts [Signature]
|
|
233
|
+
export type AsyncDataHandler<ResT> = (nuxtApp: NuxtApp, options: { signal: AbortSignal }) => Promise<ResT>
|
|
234
|
+
|
|
173
235
|
export function useAsyncData<DataT, DataE> (
|
|
174
|
-
handler:
|
|
175
|
-
options?: AsyncDataOptions<DataT
|
|
236
|
+
handler: AsyncDataHandler<DataT>,
|
|
237
|
+
options?: AsyncDataOptions<DataT>,
|
|
176
238
|
): AsyncData<DataT, DataE>
|
|
177
239
|
export function useAsyncData<DataT, DataE> (
|
|
178
240
|
key: MaybeRefOrGetter<string>,
|
|
179
|
-
handler:
|
|
180
|
-
options?: AsyncDataOptions<DataT
|
|
241
|
+
handler: AsyncDataHandler<DataT>,
|
|
242
|
+
options?: AsyncDataOptions<DataT>,
|
|
181
243
|
): Promise<AsyncData<DataT, DataE>>
|
|
182
244
|
|
|
183
245
|
type AsyncDataOptions<DataT> = {
|
|
@@ -206,6 +268,7 @@ type AsyncData<DataT, ErrorT> = {
|
|
|
206
268
|
clear: () => void
|
|
207
269
|
error: Ref<ErrorT | undefined>
|
|
208
270
|
status: Ref<AsyncDataRequestStatus>
|
|
271
|
+
pending: Ref<boolean>
|
|
209
272
|
}
|
|
210
273
|
|
|
211
274
|
interface AsyncDataExecuteOptions {
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 'useCookie'
|
|
3
|
+
description: useCookie is an SSR-friendly composable to read and write cookies.
|
|
4
|
+
links:
|
|
5
|
+
- label: Source
|
|
6
|
+
icon: i-simple-icons-github
|
|
7
|
+
to: https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/cookie.ts
|
|
8
|
+
size: xs
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
Within your pages, components, and plugins, you can use `useCookie` to read and write cookies in an SSR-friendly way.
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
const cookie = useCookie(name, options)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
::note
|
|
20
|
+
`useCookie` only works in the [Nuxt context](/docs/4.x/guide/going-further/nuxt-app#the-nuxt-context).
|
|
21
|
+
::
|
|
22
|
+
|
|
23
|
+
::tip
|
|
24
|
+
The returned ref will automatically serialize and deserialize cookie values to JSON.
|
|
25
|
+
::
|
|
26
|
+
|
|
27
|
+
## Type
|
|
28
|
+
|
|
29
|
+
```ts [Signature]
|
|
30
|
+
import type { Ref } from 'vue'
|
|
31
|
+
import type { CookieParseOptions, CookieSerializeOptions } from 'cookie-es'
|
|
32
|
+
|
|
33
|
+
export interface CookieOptions<T = any> extends Omit<CookieSerializeOptions & CookieParseOptions, 'decode' | 'encode'> {
|
|
34
|
+
decode?(value: string): T
|
|
35
|
+
encode?(value: T): string
|
|
36
|
+
default?: () => T | Ref<T>
|
|
37
|
+
watch?: boolean | 'shallow'
|
|
38
|
+
readonly?: boolean
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface CookieRef<T> extends Ref<T> {}
|
|
42
|
+
|
|
43
|
+
export function useCookie<T = string | null | undefined> (
|
|
44
|
+
name: string,
|
|
45
|
+
options?: CookieOptions<T>,
|
|
46
|
+
): CookieRef<T>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Parameters
|
|
50
|
+
|
|
51
|
+
`name`: The name of the cookie.
|
|
52
|
+
|
|
53
|
+
`options`: Options to control cookie behavior. The object can have the following properties:
|
|
54
|
+
|
|
55
|
+
Most of the options will be directly passed to the [cookie](https://github.com/jshttp/cookie) package.
|
|
56
|
+
|
|
57
|
+
| Property | Type | Default | Description |
|
|
58
|
+
|---------------|------------------------|----------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
59
|
+
| `decode` | `(value: string) => T` | `decodeURIComponent` + [destr](https://github.com/unjs/destr). | Custom function to decode the cookie value. Since the value of a cookie has a limited character set (and must be a simple string), this function can be used to decode a previously encoded cookie value into a JavaScript string or other object. <br/> **Note:** If an error is thrown from this function, the original, non-decoded cookie value will be returned as the cookie's value. |
|
|
60
|
+
| `encode` | `(value: T) => string` | `JSON.stringify` + `encodeURIComponent` | Custom function to encode the cookie value. Since the value of a cookie has a limited character set (and must be a simple string), this function can be used to encode a value into a string suited for a cookie's value. |
|
|
61
|
+
| `default` | `() => T \| Ref<T>` | `undefined` | Function returning the default value if the cookie does not exist. The function can also return a `Ref`. |
|
|
62
|
+
| `watch` | `boolean \| 'shallow'` | `true` | Whether to watch for changes and update the cookie. `true` for deep watch, `'shallow'` for shallow watch, i.e. data changes for only top level properties, `false` to disable. <br/> **Note:** Refresh `useCookie` values manually when a cookie has changed with [`refreshCookie`](/docs/4.x/api/utils/refresh-cookie). |
|
|
63
|
+
| `readonly` | `boolean` | `false` | If `true`, disables writing to the cookie. |
|
|
64
|
+
| `maxAge` | `number` | `undefined` | Max age in seconds for the cookie, i.e. the value for the [`Max-Age` `Set-Cookie` attribute](https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.2). The given number will be converted to an integer by rounding down. By default, no maximum age is set. |
|
|
65
|
+
| `expires` | `Date` | `undefined` | Expiration date for the cookie. By default, no expiration is set. Most clients will consider this a "non-persistent cookie" and will delete it on a condition like exiting a web browser application. <br/> **Note:** The [cookie storage model specification](https://datatracker.ietf.org/doc/html/rfc6265#section-5.3) states that if both `expires` and `maxAge` is set, then `maxAge` takes precedence, but not all clients may obey this, so if both are set, they should point to the same date and time! <br/>If neither of `expires` and `maxAge` is set, the cookie will be session-only and removed when the user closes their browser. |
|
|
66
|
+
| `httpOnly` | `boolean` | `false` | Sets the HttpOnly attribute. <br/> **Note:** Be careful when setting this to `true`, as compliant clients will not allow client-side JavaScript to see the cookie in `document.cookie`. |
|
|
67
|
+
| `secure` | `boolean` | `false` | Sets the [`Secure` `Set-Cookie` attribute](https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.5). <br/>**Note:** Be careful when setting this to `true`, as compliant clients will not send the cookie back to the server in the future if the browser does not have an HTTPS connection. This can lead to hydration errors. |
|
|
68
|
+
| `partitioned` | `boolean` | `false` | Sets the [`Partitioned` `Set-Cookie` attribute](https://datatracker.ietf.org/doc/html/draft-cutler-httpbis-partitioned-cookies#section-2.1). <br/>**Note:** This is an attribute that has not yet been fully standardized, and may change in the future. <br/>This also means many clients may ignore this attribute until they understand it.<br/>More information can be found in the [proposal](https://github.com/privacycg/CHIPS). |
|
|
69
|
+
| `domain` | `string` | `undefined` | Sets the [`Domain` `Set-Cookie` attribute](https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.3). By default, no domain is set, and most clients will consider applying the cookie only to the current domain. |
|
|
70
|
+
| `path` | `string` | `'/'` | Sets the [`Path` `Set-Cookie` attribute](https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.4). By default, the path is considered the ["default path"](https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.4). |
|
|
71
|
+
| `sameSite` | `boolean \| string` | `undefined` | Sets the [`SameSite` `Set-Cookie` attribute](https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.2.7). <br/>- `true` will set the `SameSite` attribute to `Strict` for strict same-site enforcement.<br/>- `false` will not set the `SameSite` attribute.<br/>- `'lax'` will set the `SameSite` attribute to `Lax` for lax same-site enforcement.<br/>- `'none'` will set the `SameSite` attribute to `None` for an explicit cross-site cookie.<br/>- `'strict'` will set the `SameSite` attribute to `Strict` for strict same-site enforcement. |
|
|
72
|
+
|
|
73
|
+
## Return Values
|
|
74
|
+
|
|
75
|
+
Returns a Vue `Ref<T>` representing the cookie value. Updating the ref will update the cookie (unless `readonly` is set). The ref is SSR-friendly and will work on both client and server.
|
|
76
|
+
|
|
77
|
+
## Examples
|
|
78
|
+
|
|
79
|
+
### Basic Usage
|
|
80
|
+
|
|
81
|
+
The example below creates a cookie called `counter`. If the cookie doesn't exist, it is initially set to a random value. Whenever we update the `counter` variable, the cookie will be updated accordingly.
|
|
82
|
+
|
|
83
|
+
```vue [app/app.vue]
|
|
84
|
+
<script setup lang="ts">
|
|
85
|
+
const counter = useCookie('counter')
|
|
86
|
+
|
|
87
|
+
counter.value ||= Math.round(Math.random() * 1000)
|
|
88
|
+
</script>
|
|
89
|
+
|
|
90
|
+
<template>
|
|
91
|
+
<div>
|
|
92
|
+
<h1>Counter: {{ counter || '-' }}</h1>
|
|
93
|
+
<button @click="counter = null">
|
|
94
|
+
reset
|
|
95
|
+
</button>
|
|
96
|
+
<button @click="counter--">
|
|
97
|
+
-
|
|
98
|
+
</button>
|
|
99
|
+
<button @click="counter++">
|
|
100
|
+
+
|
|
101
|
+
</button>
|
|
102
|
+
</div>
|
|
103
|
+
</template>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Readonly Cookies
|
|
107
|
+
|
|
108
|
+
```vue
|
|
109
|
+
<script setup lang="ts">
|
|
110
|
+
const user = useCookie(
|
|
111
|
+
'userInfo',
|
|
112
|
+
{
|
|
113
|
+
default: () => ({ score: -1 }),
|
|
114
|
+
watch: false,
|
|
115
|
+
},
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
if (user.value) {
|
|
119
|
+
// the actual `userInfo` cookie will not be updated
|
|
120
|
+
user.value.score++
|
|
121
|
+
}
|
|
122
|
+
</script>
|
|
123
|
+
|
|
124
|
+
<template>
|
|
125
|
+
<div>User score: {{ user?.score }}</div>
|
|
126
|
+
</template>
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Writable Cookies
|
|
130
|
+
|
|
131
|
+
```vue
|
|
132
|
+
<script setup lang="ts">
|
|
133
|
+
const list = useCookie(
|
|
134
|
+
'list',
|
|
135
|
+
{
|
|
136
|
+
default: () => [],
|
|
137
|
+
watch: 'shallow',
|
|
138
|
+
},
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
function add () {
|
|
142
|
+
list.value?.push(Math.round(Math.random() * 1000))
|
|
143
|
+
// list cookie won't be updated with this change
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function save () {
|
|
147
|
+
// the actual `list` cookie will be updated
|
|
148
|
+
list.value &&= [...list.value]
|
|
149
|
+
}
|
|
150
|
+
</script>
|
|
151
|
+
|
|
152
|
+
<template>
|
|
153
|
+
<div>
|
|
154
|
+
<h1>List</h1>
|
|
155
|
+
<pre>{{ list }}</pre>
|
|
156
|
+
<button @click="add">
|
|
157
|
+
Add
|
|
158
|
+
</button>
|
|
159
|
+
<button @click="save">
|
|
160
|
+
Save
|
|
161
|
+
</button>
|
|
162
|
+
</div>
|
|
163
|
+
</template>
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Cookies in API Routes
|
|
167
|
+
|
|
168
|
+
You can use `getCookie` and `setCookie` from [`h3`](https://github.com/h3js/h3) package to set cookies in server API routes.
|
|
169
|
+
|
|
170
|
+
```ts [server/api/counter.ts]
|
|
171
|
+
export default defineEventHandler((event) => {
|
|
172
|
+
// Read counter cookie
|
|
173
|
+
let counter = getCookie(event, 'counter') || 0
|
|
174
|
+
|
|
175
|
+
// Increase counter cookie by 1
|
|
176
|
+
setCookie(event, 'counter', ++counter)
|
|
177
|
+
|
|
178
|
+
// Send JSON response
|
|
179
|
+
return { counter }
|
|
180
|
+
})
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
:link-example{to="/docs/4.x/examples/advanced/use-cookie"}
|
|
@@ -100,7 +100,7 @@ If you encounter the `data` variable destructured from a `useFetch` returns a st
|
|
|
100
100
|
|
|
101
101
|
### Reactive Fetch Options
|
|
102
102
|
|
|
103
|
-
Fetch options can be provided as reactive, supporting `computed`, `ref` and [computed getters](https://vuejs.org/guide/essentials/computed
|
|
103
|
+
Fetch options can be provided as reactive, supporting `computed`, `ref` and [computed getters](https://vuejs.org/guide/essentials/computed). When a reactive fetch option is updated it will trigger a refetch using the updated resolved reactive value.
|
|
104
104
|
|
|
105
105
|
```ts
|
|
106
106
|
const searchQuery = ref('initial')
|
|
@@ -128,7 +128,7 @@ searchQuery.value = 'new search'
|
|
|
128
128
|
```ts [Signature]
|
|
129
129
|
export function useFetch<DataT, ErrorT> (
|
|
130
130
|
url: string | Request | Ref<string | Request> | (() => string | Request),
|
|
131
|
-
options?: UseFetchOptions<DataT
|
|
131
|
+
options?: UseFetchOptions<DataT>,
|
|
132
132
|
): Promise<AsyncData<DataT, ErrorT>>
|
|
133
133
|
|
|
134
134
|
type UseFetchOptions<DataT> = {
|
|
@@ -183,29 +183,29 @@ type AsyncDataRequestStatus = 'idle' | 'pending' | 'success' | 'error'
|
|
|
183
183
|
|
|
184
184
|
- `options` (object): Configuration for the fetch request. Extends [unjs/ofetch](https://github.com/unjs/ofetch) options and [`AsyncDataOptions`](/docs/4.x/api/composables/use-async-data#params). All options can be a static value, a `ref`, or a computed value.
|
|
185
185
|
|
|
186
|
-
| Option
|
|
187
|
-
|
|
188
|
-
| `key`
|
|
189
|
-
| `method`
|
|
190
|
-
| `query`
|
|
191
|
-
| `params`
|
|
192
|
-
| `body`
|
|
193
|
-
| `headers`
|
|
194
|
-
| `baseURL`
|
|
195
|
-
| `timeout`
|
|
196
|
-
| `cache`
|
|
197
|
-
| `server`
|
|
198
|
-
| `lazy`
|
|
199
|
-
| `immediate`
|
|
200
|
-
| `default`
|
|
201
|
-
| `timeout`
|
|
202
|
-
| `transform`
|
|
203
|
-
| `getCachedData
|
|
204
|
-
| `pick`
|
|
205
|
-
| `watch`
|
|
206
|
-
| `deep`
|
|
207
|
-
| `dedupe`
|
|
208
|
-
| `$fetch`
|
|
186
|
+
| Option | Type | Default | Description |
|
|
187
|
+
|-----------------|-------------------------------------------------------------------------|------------|------------------------------------------------------------------------------------------------------------------|
|
|
188
|
+
| `key` | `MaybeRefOrGetter<string>` | auto-gen | Unique key for de-duplication. If not provided, generated from URL and options. |
|
|
189
|
+
| `method` | `MaybeRefOrGetter<string>` | `'GET'` | HTTP request method. |
|
|
190
|
+
| `query` | `MaybeRefOrGetter<SearchParams>` | - | Query/search params to append to the URL. Alias: `params`. |
|
|
191
|
+
| `params` | `MaybeRefOrGetter<SearchParams>` | - | Alias for `query`. |
|
|
192
|
+
| `body` | `MaybeRefOrGetter<RequestInit['body'] \| Record<string, any>>` | - | Request body. Objects are automatically stringified. |
|
|
193
|
+
| `headers` | `MaybeRefOrGetter<Record<string, string> \| [key, value][] \| Headers>` | - | Request headers. |
|
|
194
|
+
| `baseURL` | `MaybeRefOrGetter<string>` | - | Base URL for the request. |
|
|
195
|
+
| `timeout` | `MaybeRefOrGetter<number>` | - | Timeout in milliseconds to abort the request. |
|
|
196
|
+
| `cache` | `boolean \| string` | - | Cache control. Boolean disables cache, or use Fetch API values: `default`, `no-store`, etc. |
|
|
197
|
+
| `server` | `boolean` | `true` | Whether to fetch on the server. |
|
|
198
|
+
| `lazy` | `boolean` | `false` | If true, resolves after route loads (does not block navigation). |
|
|
199
|
+
| `immediate` | `boolean` | `true` | If false, prevents request from firing immediately. |
|
|
200
|
+
| `default` | `() => DataT` | - | Factory for default value of `data` before async resolves. |
|
|
201
|
+
| `timeout` | `number` | - | A number in milliseconds to wait before timing out the request (defaults to `undefined`, which means no timeout) |
|
|
202
|
+
| `transform` | `(input: DataT) => DataT \| Promise<DataT>` | - | Function to transform the result after resolving. |
|
|
203
|
+
| `getCachedData` | `(key, nuxtApp, ctx) => DataT \| undefined` | - | Function to return cached data. See below for default. |
|
|
204
|
+
| `pick` | `string[]` | - | Only pick specified keys from the result. |
|
|
205
|
+
| `watch` | `MultiWatchSources \| false` | - | Array of reactive sources to watch and auto-refresh. `false` disables watching. |
|
|
206
|
+
| `deep` | `boolean` | `false` | Return data in a deep ref object. |
|
|
207
|
+
| `dedupe` | `'cancel' \| 'defer'` | `'cancel'` | Avoid fetching same key more than once at a time. |
|
|
208
|
+
| `$fetch` | `typeof globalThis.$fetch` | - | Custom $fetch implementation. See [Custom useFetch in Nuxt](/docs/4.x/guide/recipes/custom-usefetch) |
|
|
209
209
|
|
|
210
210
|
::note
|
|
211
211
|
All fetch options can be given a `computed` or `ref` value. These will be watched and new requests made automatically with any new values if they are updated.
|
|
@@ -222,14 +222,14 @@ This only caches data when `experimental.payloadExtraction` in `nuxt.config` is
|
|
|
222
222
|
|
|
223
223
|
## Return Values
|
|
224
224
|
|
|
225
|
-
| Name
|
|
226
|
-
|
|
227
|
-
| `data`
|
|
228
|
-
| `refresh` | `(opts?: AsyncDataExecuteOptions) => Promise<void>` | Function to manually refresh the data. By default, Nuxt waits until a `refresh` is finished before it can be executed again.
|
|
229
|
-
| `execute` | `(opts?: AsyncDataExecuteOptions) => Promise<void>` | Alias for `refresh`.
|
|
230
|
-
| `error`
|
|
231
|
-
| `status`
|
|
232
|
-
| `clear`
|
|
225
|
+
| Name | Type | Description |
|
|
226
|
+
|-----------|-----------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
227
|
+
| `data` | `Ref<DataT \| undefined>` | The result of the asynchronous fetch. |
|
|
228
|
+
| `refresh` | `(opts?: AsyncDataExecuteOptions) => Promise<void>` | Function to manually refresh the data. By default, Nuxt waits until a `refresh` is finished before it can be executed again. |
|
|
229
|
+
| `execute` | `(opts?: AsyncDataExecuteOptions) => Promise<void>` | Alias for `refresh`. |
|
|
230
|
+
| `error` | `Ref<ErrorT \| undefined>` | Error object if the data fetching failed. |
|
|
231
|
+
| `status` | `Ref<'idle' \| 'pending' \| 'success' \| 'error'>` | Status of the data request. See below for possible values. |
|
|
232
|
+
| `clear` | `() => void` | Resets `data` to `undefined` (or the value of `options.default()` if provided), `error` to `undefined`, set `status` to `idle`, and cancels any pending requests. |
|
|
233
233
|
|
|
234
234
|
### Status values
|
|
235
235
|
|
|
@@ -8,28 +8,12 @@ links:
|
|
|
8
8
|
size: xs
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
The `useHeadSafe` composable is a wrapper around the [`useHead`](/docs/4.x/api/composables/use-head) composable that restricts the input to only allow safe values.
|
|
12
|
-
|
|
13
11
|
## Usage
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
```ts
|
|
18
|
-
useHeadSafe({
|
|
19
|
-
script: [
|
|
20
|
-
{ id: 'xss-script', innerHTML: 'alert("xss")' },
|
|
21
|
-
],
|
|
22
|
-
meta: [
|
|
23
|
-
{ 'http-equiv': 'refresh', 'content': '0;javascript:alert(1)' },
|
|
24
|
-
],
|
|
25
|
-
})
|
|
26
|
-
// Will safely generate
|
|
27
|
-
// <script id="xss-script"></script>
|
|
28
|
-
// <meta content="0;javascript:alert(1)">
|
|
29
|
-
```
|
|
13
|
+
The `useHeadSafe` composable is a wrapper around the [`useHead`](/docs/4.x/api/composables/use-head) composable that restricts the input to only allow safe values. This is the recommended way to manage head data when working with user input, as it prevents XSS attacks by sanitizing potentially dangerous attributes.
|
|
30
14
|
|
|
31
|
-
::
|
|
32
|
-
|
|
15
|
+
::warning
|
|
16
|
+
When using `useHeadSafe`, potentially dangerous attributes like `innerHTML` in scripts or `http-equiv` in meta tags are automatically stripped out to prevent XSS attacks. Use this composable whenever you're working with user-generated content.
|
|
33
17
|
::
|
|
34
18
|
|
|
35
19
|
## Type
|
|
@@ -38,7 +22,9 @@ Read more on the `Unhead` documentation.
|
|
|
38
22
|
export function useHeadSafe (input: MaybeComputedRef<HeadSafe>): void
|
|
39
23
|
```
|
|
40
24
|
|
|
41
|
-
|
|
25
|
+
### Allowed Attributes
|
|
26
|
+
|
|
27
|
+
The following attributes are whitelisted for each head element type:
|
|
42
28
|
|
|
43
29
|
```ts
|
|
44
30
|
const WhitelistAttributes = {
|
|
@@ -53,3 +39,34 @@ const WhitelistAttributes = {
|
|
|
53
39
|
```
|
|
54
40
|
|
|
55
41
|
See [@unhead/vue](https://github.com/unjs/unhead/blob/main/packages/vue/src/types/safeSchema.ts) for more detailed types.
|
|
42
|
+
|
|
43
|
+
## Parameters
|
|
44
|
+
|
|
45
|
+
`input`: A `MaybeComputedRef<HeadSafe>` object containing head data. You can pass all the same values as [`useHead`](/docs/4.x/api/composables/use-head), but only safe attributes will be rendered.
|
|
46
|
+
|
|
47
|
+
## Return Values
|
|
48
|
+
|
|
49
|
+
This composable does not return any value.
|
|
50
|
+
|
|
51
|
+
## Example
|
|
52
|
+
|
|
53
|
+
```vue [app/pages/user-profile.vue]
|
|
54
|
+
<script setup lang="ts">
|
|
55
|
+
// User-generated content that might contain malicious code
|
|
56
|
+
const userBio = ref('<script>alert("xss")<' + '/script>')
|
|
57
|
+
|
|
58
|
+
useHeadSafe({
|
|
59
|
+
title: `User Profile`,
|
|
60
|
+
meta: [
|
|
61
|
+
{
|
|
62
|
+
name: 'description',
|
|
63
|
+
content: userBio.value, // Safely sanitized
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
})
|
|
67
|
+
</script>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
::read-more{to="https://unhead.unjs.io/docs/typescript/head/api/composables/use-head-safe" target="_blank"}
|
|
71
|
+
Read more on the `Unhead` documentation.
|
|
72
|
+
::
|