mirror of
https://github.com/nuxt/nuxt.git
synced 2025-01-18 09:25:54 +00:00
feat(nuxt3, bridge): useCookie
universal composable (#2085)
This commit is contained in:
parent
cc342eb6c4
commit
9920181df3
156
docs/content/3.docs/1.usage/6-cookies.md
Normal file
156
docs/content/3.docs/1.usage/6-cookies.md
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
# Cookies
|
||||||
|
|
||||||
|
> Nuxt provides SSR-friendly composable to read and write cookies.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Within your pages, components, and plugins you can use `useCookie` to create a reactive reference bound to a specific cookie.
|
||||||
|
|
||||||
|
```js
|
||||||
|
const cookie = useCookie(name, options)
|
||||||
|
```
|
||||||
|
|
||||||
|
::alert{icon=👉}
|
||||||
|
**`useCookie` only works during `setup` or `Lifecycle Hooks`**
|
||||||
|
::
|
||||||
|
|
||||||
|
::alert{icon=😌}
|
||||||
|
`useCookie` ref will be automatically serialize and deserialized cookie value to JSON.
|
||||||
|
::
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
The example below creates a cookie called counter and if it doesn't exist set a random value. Whenever we update `counter`, the cookie will be updated.
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<h1> Counter: {{ counter || '-' }}</h1>
|
||||||
|
<button @click="counter = null">
|
||||||
|
reset
|
||||||
|
</button>
|
||||||
|
<button @click="counter--">
|
||||||
|
-
|
||||||
|
</button>
|
||||||
|
<button @click="counter++">
|
||||||
|
+
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const counter = useCookie('counter')
|
||||||
|
counter.value = counter.value || Math.round(Math.random() * 1000)
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
:button-link[Open on StackBlitz]{href="https://stackblitz.com/github/nuxt/framework/tree/main/examples/use-cookie?terminal=dev" blank}
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
Cookie composable accepts these properties in the options. Use them to modify the behavior of cookies.
|
||||||
|
|
||||||
|
Most of the options will be directly passed to [cookie](https://github.com/jshttp/cookie) package.
|
||||||
|
|
||||||
|
### `maxAge` / `expires`
|
||||||
|
|
||||||
|
**`maxAge`** Specifies the `number` (in seconds) to be the value for the [`Max-Age` `Set-Cookie` attribute](https://tools.ietf.org/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.
|
||||||
|
|
||||||
|
**`expires`**: Specifies the `Date` object to be the value for the [`Expires` `Set-Cookie` attribute](https://tools.ietf.org/html/rfc6265#section-5.2.1).
|
||||||
|
By default, no expiration is set, and most clients will consider this a "non-persistent cookie" and
|
||||||
|
will delete it on a condition like exiting a web browser application.
|
||||||
|
|
||||||
|
::alert{icon=💡}
|
||||||
|
**Note:** The [cookie storage model specification](https://tools.ietf.org/html/rfc6265#section-5.3) states that if both `expires` and
|
||||||
|
`maxAge` are set, then `maxAge` takes precedence, but it is possible not all clients obey this,
|
||||||
|
so if both are set, they should point to the same date and time.eaks!
|
||||||
|
::
|
||||||
|
|
||||||
|
::alert
|
||||||
|
If neither of `expires` and `maxAge` are set, cookie will be session-only and removed if the user closes their browser.
|
||||||
|
::
|
||||||
|
|
||||||
|
#### `httpOnly`
|
||||||
|
|
||||||
|
Specifies the `boolean` value for the [`HttpOnly` `Set-Cookie` attribute](https://tools.ietf.org/html/rfc6265#section-5.2.6). When truthy,
|
||||||
|
the `HttpOnly` attribute is set, otherwise, it is not. By default, the `HttpOnly` attribute is not set.
|
||||||
|
|
||||||
|
::alert{icon=💡}
|
||||||
|
**Note** be careful when setting this to `true`, as compliant clients will not allow client-side
|
||||||
|
JavaScript to see the cookie in `document.cookie`.
|
||||||
|
::
|
||||||
|
|
||||||
|
#### `secure`
|
||||||
|
|
||||||
|
Specifies the `boolean` value for the [`Secure` `Set-Cookie` attribute](https://tools.ietf.org/html/rfc6265#section-5.2.5). When truthy,
|
||||||
|
the `Secure` attribute is set, otherwise,it is not. By default, the `Secure` attribute is not set.
|
||||||
|
|
||||||
|
::alert{icon=💡}
|
||||||
|
**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.
|
||||||
|
::
|
||||||
|
|
||||||
|
#### `domain`
|
||||||
|
|
||||||
|
Specifies the value for the [`Domain` `Set-Cookie` attribute](https://tools.ietf.org/html/rfc6265#section-5.2.3). By default, no
|
||||||
|
domain is set, and most clients will consider the cookie to apply to only the current domain.
|
||||||
|
|
||||||
|
#### `path`
|
||||||
|
|
||||||
|
Specifies the value for the [`Path` `Set-Cookie` attribute](https://tools.ietf.org/html/rfc6265#section-5.2.4). By default, the path
|
||||||
|
is considered the ["default path"](https://tools.ietf.org/html/rfc6265#section-5.1.4).
|
||||||
|
|
||||||
|
#### `sameSite`
|
||||||
|
|
||||||
|
Specifies the `boolean` or `string` to be the value for the [`SameSite` `Set-Cookie` attribute](https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.2.7).
|
||||||
|
|
||||||
|
- `true` will set the `SameSite` attribute to `Strict` for strict same site enforcement.
|
||||||
|
- `false` will not set the `SameSite` attribute.
|
||||||
|
- `'lax'` will set the `SameSite` attribute to `Lax` for lax same site enforcement.
|
||||||
|
- `'none'` will set the `SameSite` attribute to `None` for an explicit cross-site cookie.
|
||||||
|
- `'strict'` will set the `SameSite` attribute to `Strict` for strict same site enforcement.
|
||||||
|
|
||||||
|
More information about the different enforcement levels can be found in [the specification](https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.2.7).
|
||||||
|
|
||||||
|
#### `encode`
|
||||||
|
|
||||||
|
Specifies a function that will be used to encode a cookie's value. Since 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.
|
||||||
|
|
||||||
|
The default encoder is the `JSON.stringify` + `encodeURIComponent`.
|
||||||
|
|
||||||
|
#### `decode`
|
||||||
|
|
||||||
|
Specifies a function that will be used to decode a cookie's 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.
|
||||||
|
|
||||||
|
The default decoder is `decodeURIComponent` + [destr](https://github.com/unjs/destr).
|
||||||
|
|
||||||
|
::alert{icon=💡}
|
||||||
|
**Note** if an error is thrown from this function, the original, non-decoded cookie value will
|
||||||
|
be returned as the cookie's value.
|
||||||
|
::
|
||||||
|
|
||||||
|
## Handling cookies in API routes
|
||||||
|
|
||||||
|
You can use `useCookie` and `setCookie` from [`h3`](https://github.com/unjs/h3) package to set cookies in server API routes.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { useCookie, setCookie } from 'h3'
|
||||||
|
|
||||||
|
export default (req, res) => {
|
||||||
|
// Reat counter cookie
|
||||||
|
let counter = useCookie(req, 'counter') || 0
|
||||||
|
|
||||||
|
// Increase counter cookie by 1
|
||||||
|
setCookie(res, 'counter', ++counter)
|
||||||
|
|
||||||
|
// Send JSON response
|
||||||
|
return { counter }
|
||||||
|
}
|
||||||
|
```
|
23
examples/use-cookie/app.vue
Normal file
23
examples/use-cookie/app.vue
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<h1> Counter: {{ counter || '-' }}</h1>
|
||||||
|
<button @click="counter = null">
|
||||||
|
reset
|
||||||
|
</button>
|
||||||
|
<button @click="counter--">
|
||||||
|
-
|
||||||
|
</button>
|
||||||
|
<button @click="counter++">
|
||||||
|
+
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const counter = useCookie('counter')
|
||||||
|
counter.value = counter.value || Math.round(Math.random() * 1000)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
button { margin: 10px 5px; }
|
||||||
|
</style>
|
4
examples/use-cookie/nuxt.config.ts
Normal file
4
examples/use-cookie/nuxt.config.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import { defineNuxtConfig } from 'nuxt3'
|
||||||
|
|
||||||
|
export default defineNuxtConfig({
|
||||||
|
})
|
12
examples/use-cookie/package.json
Normal file
12
examples/use-cookie/package.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"name": "example-use-cookie",
|
||||||
|
"private": true,
|
||||||
|
"devDependencies": {
|
||||||
|
"nuxt3": "latest"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"dev": "nuxi dev",
|
||||||
|
"build": "nuxi build",
|
||||||
|
"start": "node .output/server/index.mjs"
|
||||||
|
}
|
||||||
|
}
|
3
examples/use-cookie/tsconfig.json
Normal file
3
examples/use-cookie/tsconfig.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"extends": "./.nuxt/tsconfig.json"
|
||||||
|
}
|
@ -23,17 +23,21 @@
|
|||||||
"@nuxt/nitro": "3.0.0",
|
"@nuxt/nitro": "3.0.0",
|
||||||
"@nuxt/postcss8": "^1.1.3",
|
"@nuxt/postcss8": "^1.1.3",
|
||||||
"@nuxt/schema": "3.0.0",
|
"@nuxt/schema": "3.0.0",
|
||||||
|
"@types/cookie": "^0.4.1",
|
||||||
"@vitejs/plugin-legacy": "^1.6.3",
|
"@vitejs/plugin-legacy": "^1.6.3",
|
||||||
"@vue/composition-api": "^1.4.0",
|
"@vue/composition-api": "^1.4.0",
|
||||||
"@vueuse/head": "^0.7.2",
|
"@vueuse/head": "^0.7.2",
|
||||||
"acorn": "^8.6.0",
|
"acorn": "^8.6.0",
|
||||||
"consola": "^2.15.3",
|
"consola": "^2.15.3",
|
||||||
|
"cookie": "^0.4.1",
|
||||||
"defu": "^5.0.0",
|
"defu": "^5.0.0",
|
||||||
|
"destr": "^1.1.0",
|
||||||
"enhanced-resolve": "^5.8.3",
|
"enhanced-resolve": "^5.8.3",
|
||||||
"estree-walker": "^2.0.2",
|
"estree-walker": "^2.0.2",
|
||||||
"externality": "^0.1.5",
|
"externality": "^0.1.5",
|
||||||
"fs-extra": "^10.0.0",
|
"fs-extra": "^10.0.0",
|
||||||
"globby": "^11.0.4",
|
"globby": "^11.0.4",
|
||||||
|
"h3": "^0.3.3",
|
||||||
"hash-sum": "^2.0.0",
|
"hash-sum": "^2.0.0",
|
||||||
"magic-string": "^0.25.7",
|
"magic-string": "^0.25.7",
|
||||||
"mlly": "^0.3.13",
|
"mlly": "^0.3.13",
|
||||||
|
@ -8,6 +8,7 @@ import { useNuxtApp } from './app'
|
|||||||
|
|
||||||
export { useLazyAsyncData } from './asyncData'
|
export { useLazyAsyncData } from './asyncData'
|
||||||
export { useLazyFetch } from './fetch'
|
export { useLazyFetch } from './fetch'
|
||||||
|
export { useCookie } from './cookie'
|
||||||
|
|
||||||
export * from '@vue/composition-api'
|
export * from '@vue/composition-api'
|
||||||
|
|
||||||
|
1
packages/bridge/src/runtime/cookie.ts
Symbolic link
1
packages/bridge/src/runtime/cookie.ts
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../../nuxt3/src/app/composables/cookie.ts
|
@ -25,13 +25,17 @@
|
|||||||
"@nuxt/schema": "3.0.0",
|
"@nuxt/schema": "3.0.0",
|
||||||
"@nuxt/vite-builder": "3.0.0",
|
"@nuxt/vite-builder": "3.0.0",
|
||||||
"@nuxt/webpack-builder": "3.0.0",
|
"@nuxt/webpack-builder": "3.0.0",
|
||||||
|
"@types/cookie": "^0.4.1",
|
||||||
"@vue/reactivity": "^3.2.22",
|
"@vue/reactivity": "^3.2.22",
|
||||||
"@vue/shared": "^3.2.22",
|
"@vue/shared": "^3.2.22",
|
||||||
"@vueuse/head": "^0.7.2",
|
"@vueuse/head": "^0.7.2",
|
||||||
"chokidar": "^3.5.2",
|
"chokidar": "^3.5.2",
|
||||||
"consola": "^2.15.3",
|
"consola": "^2.15.3",
|
||||||
|
"cookie": "^0.4.1",
|
||||||
"defu": "^5.0.0",
|
"defu": "^5.0.0",
|
||||||
|
"destr": "^1.1.0",
|
||||||
"globby": "^11.0.4",
|
"globby": "^11.0.4",
|
||||||
|
"h3": "^0.3.3",
|
||||||
"hash-sum": "^2.0.0",
|
"hash-sum": "^2.0.0",
|
||||||
"hookable": "^5.0.0",
|
"hookable": "^5.0.0",
|
||||||
"ignore": "^5.1.9",
|
"ignore": "^5.1.9",
|
||||||
|
77
packages/nuxt3/src/app/composables/cookie.ts
Normal file
77
packages/nuxt3/src/app/composables/cookie.ts
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import type { ServerResponse } from 'http'
|
||||||
|
import { Ref, ref, watch } from 'vue'
|
||||||
|
import type { CookieParseOptions, CookieSerializeOptions } from 'cookie'
|
||||||
|
import { parse, serialize } from 'cookie'
|
||||||
|
import { appendHeader } from 'h3'
|
||||||
|
import type { NuxtApp } from '@nuxt/schema'
|
||||||
|
import destr from 'destr'
|
||||||
|
import { useNuxtApp } from '#app'
|
||||||
|
|
||||||
|
type _CookieOptions = Omit<CookieSerializeOptions & CookieParseOptions, 'decode' | 'encode'>
|
||||||
|
export interface CookieOptions<T=any> extends _CookieOptions {
|
||||||
|
decode?(value: string): T
|
||||||
|
encode?(value: T): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CookieRef<T> extends Ref<T> {}
|
||||||
|
|
||||||
|
const CookieDefaults: CookieOptions<any> = {
|
||||||
|
decode: val => destr(decodeURIComponent(val)),
|
||||||
|
encode: val => encodeURIComponent(typeof val === 'string' ? val : JSON.stringify(val))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useCookie <T=string> (name: string, _opts: CookieOptions<T>): CookieRef<T> {
|
||||||
|
const opts = { ...CookieDefaults, ..._opts }
|
||||||
|
const cookies = readRawCookies(opts)
|
||||||
|
|
||||||
|
const cookie = ref(opts.decode(cookies[name]))
|
||||||
|
|
||||||
|
if (process.client) {
|
||||||
|
watch(cookie, () => { writeClientCookie(name, cookie.value, opts) })
|
||||||
|
} else if (process.server) {
|
||||||
|
const initialValue = cookie.value
|
||||||
|
const nuxtApp = useNuxtApp()
|
||||||
|
nuxtApp.hooks.hookOnce('app:rendered', () => {
|
||||||
|
if (cookie.value !== initialValue) {
|
||||||
|
// @ts-ignore
|
||||||
|
writeServerCookie(useSSRRes(nuxtApp), name, cookie.value, opts)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return cookie
|
||||||
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
function useSSRReq (nuxtApp?: NuxtApp = useNuxtApp()) { return nuxtApp.ssrContext?.req }
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
function useSSRRes (nuxtApp?: NuxtApp = useNuxtApp()) { return nuxtApp.ssrContext?.res }
|
||||||
|
|
||||||
|
function readRawCookies (opts: CookieOptions = {}): Record<string, string> {
|
||||||
|
if (process.server) {
|
||||||
|
return parse(useSSRReq().headers.cookie || '', opts)
|
||||||
|
} else if (process.client) {
|
||||||
|
return parse(document.cookie, opts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function serializeCookie (name: string, value: any, opts: CookieSerializeOptions = {}) {
|
||||||
|
if (value === null || value === undefined) {
|
||||||
|
opts.maxAge = -1
|
||||||
|
}
|
||||||
|
return serialize(name, value, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeClientCookie (name: string, value: any, opts: CookieSerializeOptions = {}) {
|
||||||
|
if (process.client) {
|
||||||
|
document.cookie = serializeCookie(name, value, opts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeServerCookie (res: ServerResponse, name: string, value: any, opts: CookieSerializeOptions = {}) {
|
||||||
|
if (res) {
|
||||||
|
// TODO: Try to smart join with exisiting Set-Cookie headers
|
||||||
|
appendHeader(res, 'Set-Cookie', serializeCookie(name, value, opts))
|
||||||
|
}
|
||||||
|
}
|
@ -3,3 +3,4 @@ export { useAsyncData, useLazyAsyncData } from './asyncData'
|
|||||||
export { useHydration } from './hydrate'
|
export { useHydration } from './hydrate'
|
||||||
export { useState } from './state'
|
export { useState } from './state'
|
||||||
export { useFetch, useLazyFetch } from './fetch'
|
export { useFetch, useLazyFetch } from './fetch'
|
||||||
|
export { useCookie } from './cookie'
|
||||||
|
@ -13,7 +13,8 @@ export const Nuxt3AutoImports: AutoImportSource[] = [
|
|||||||
'useRuntimeConfig',
|
'useRuntimeConfig',
|
||||||
'useState',
|
'useState',
|
||||||
'useFetch',
|
'useFetch',
|
||||||
'useLazyFetch'
|
'useLazyFetch',
|
||||||
|
'useCookie'
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
// #meta
|
// #meta
|
||||||
|
23
yarn.lock
23
yarn.lock
@ -2427,6 +2427,7 @@ __metadata:
|
|||||||
"@nuxt/postcss8": ^1.1.3
|
"@nuxt/postcss8": ^1.1.3
|
||||||
"@nuxt/schema": 3.0.0
|
"@nuxt/schema": 3.0.0
|
||||||
"@nuxt/types": ^2.15.8
|
"@nuxt/types": ^2.15.8
|
||||||
|
"@types/cookie": ^0.4.1
|
||||||
"@types/fs-extra": ^9.0.13
|
"@types/fs-extra": ^9.0.13
|
||||||
"@types/hash-sum": ^1.0.0
|
"@types/hash-sum": ^1.0.0
|
||||||
"@types/node-fetch": ^3.0.2
|
"@types/node-fetch": ^3.0.2
|
||||||
@ -2435,12 +2436,15 @@ __metadata:
|
|||||||
"@vueuse/head": ^0.7.2
|
"@vueuse/head": ^0.7.2
|
||||||
acorn: ^8.6.0
|
acorn: ^8.6.0
|
||||||
consola: ^2.15.3
|
consola: ^2.15.3
|
||||||
|
cookie: ^0.4.1
|
||||||
defu: ^5.0.0
|
defu: ^5.0.0
|
||||||
|
destr: ^1.1.0
|
||||||
enhanced-resolve: ^5.8.3
|
enhanced-resolve: ^5.8.3
|
||||||
estree-walker: ^2.0.2
|
estree-walker: ^2.0.2
|
||||||
externality: ^0.1.5
|
externality: ^0.1.5
|
||||||
fs-extra: ^10.0.0
|
fs-extra: ^10.0.0
|
||||||
globby: ^11.0.4
|
globby: ^11.0.4
|
||||||
|
h3: ^0.3.3
|
||||||
hash-sum: ^2.0.0
|
hash-sum: ^2.0.0
|
||||||
magic-string: ^0.25.7
|
magic-string: ^0.25.7
|
||||||
mlly: ^0.3.13
|
mlly: ^0.3.13
|
||||||
@ -3800,6 +3804,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@types/cookie@npm:^0.4.1":
|
||||||
|
version: 0.4.1
|
||||||
|
resolution: "@types/cookie@npm:0.4.1"
|
||||||
|
checksum: 3275534ed69a76c68eb1a77d547d75f99fedc80befb75a3d1d03662fb08d697e6f8b1274e12af1a74c6896071b11510631ba891f64d30c78528d0ec45a9c1a18
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@types/eslint-scope@npm:^3.7.0":
|
"@types/eslint-scope@npm:^3.7.0":
|
||||||
version: 3.7.1
|
version: 3.7.1
|
||||||
resolution: "@types/eslint-scope@npm:3.7.1"
|
resolution: "@types/eslint-scope@npm:3.7.1"
|
||||||
@ -10491,6 +10502,14 @@ __metadata:
|
|||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
|
"example-use-cookie@workspace:examples/use-cookie":
|
||||||
|
version: 0.0.0-use.local
|
||||||
|
resolution: "example-use-cookie@workspace:examples/use-cookie"
|
||||||
|
dependencies:
|
||||||
|
nuxt3: latest
|
||||||
|
languageName: unknown
|
||||||
|
linkType: soft
|
||||||
|
|
||||||
"example-use-fetch@workspace:examples/use-fetch":
|
"example-use-fetch@workspace:examples/use-fetch":
|
||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "example-use-fetch@workspace:examples/use-fetch"
|
resolution: "example-use-fetch@workspace:examples/use-fetch"
|
||||||
@ -15269,14 +15288,18 @@ __metadata:
|
|||||||
"@nuxt/schema": 3.0.0
|
"@nuxt/schema": 3.0.0
|
||||||
"@nuxt/vite-builder": 3.0.0
|
"@nuxt/vite-builder": 3.0.0
|
||||||
"@nuxt/webpack-builder": 3.0.0
|
"@nuxt/webpack-builder": 3.0.0
|
||||||
|
"@types/cookie": ^0.4.1
|
||||||
"@types/hash-sum": ^1.0.0
|
"@types/hash-sum": ^1.0.0
|
||||||
"@vue/reactivity": ^3.2.22
|
"@vue/reactivity": ^3.2.22
|
||||||
"@vue/shared": ^3.2.22
|
"@vue/shared": ^3.2.22
|
||||||
"@vueuse/head": ^0.7.2
|
"@vueuse/head": ^0.7.2
|
||||||
chokidar: ^3.5.2
|
chokidar: ^3.5.2
|
||||||
consola: ^2.15.3
|
consola: ^2.15.3
|
||||||
|
cookie: ^0.4.1
|
||||||
defu: ^5.0.0
|
defu: ^5.0.0
|
||||||
|
destr: ^1.1.0
|
||||||
globby: ^11.0.4
|
globby: ^11.0.4
|
||||||
|
h3: ^0.3.3
|
||||||
hash-sum: ^2.0.0
|
hash-sum: ^2.0.0
|
||||||
hookable: ^5.0.0
|
hookable: ^5.0.0
|
||||||
ignore: ^5.1.9
|
ignore: ^5.1.9
|
||||||
|
Loading…
Reference in New Issue
Block a user