mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-25 15:15:19 +00:00
feat(nuxt): allow readonly option for useCookie
(#24503)
This commit is contained in:
parent
0c47399f33
commit
e3b8b84a24
@ -133,6 +133,10 @@ be returned as the cookie's value.
|
|||||||
|
|
||||||
Specifies a function that returns the cookie's default value. The function can also return a `Ref`.
|
Specifies a function that returns the cookie's default value. The function can also return a `Ref`.
|
||||||
|
|
||||||
|
### `readonly`
|
||||||
|
|
||||||
|
Allows _accessing_ a cookie value without the ability to set it.
|
||||||
|
|
||||||
### `watch`
|
### `watch`
|
||||||
|
|
||||||
Specifies the `boolean` or `string` value for [watch](https://vuejs.org/api/reactivity-core.html#watch) cookie ref data.
|
Specifies the `boolean` or `string` value for [watch](https://vuejs.org/api/reactivity-core.html#watch) cookie ref data.
|
||||||
|
@ -16,6 +16,7 @@ export interface CookieOptions<T = any> extends _CookieOptions {
|
|||||||
encode?(value: T): string
|
encode?(value: T): string
|
||||||
default?: () => T | Ref<T>
|
default?: () => T | Ref<T>
|
||||||
watch?: boolean | 'shallow'
|
watch?: boolean | 'shallow'
|
||||||
|
readonly?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CookieRef<T> extends Ref<T> {}
|
export interface CookieRef<T> extends Ref<T> {}
|
||||||
@ -27,6 +28,8 @@ const CookieDefaults = {
|
|||||||
encode: val => encodeURIComponent(typeof val === 'string' ? val : JSON.stringify(val))
|
encode: val => encodeURIComponent(typeof val === 'string' ? val : JSON.stringify(val))
|
||||||
} satisfies CookieOptions<any>
|
} satisfies CookieOptions<any>
|
||||||
|
|
||||||
|
export function useCookie<T = string | null | undefined> (name: string, _opts?: CookieOptions<T> & { readonly?: false }): CookieRef<T>
|
||||||
|
export function useCookie<T = string | null | undefined> (name: string, _opts: CookieOptions<T> & { readonly: true }): Readonly<CookieRef<T>>
|
||||||
export function useCookie<T = string | null | undefined> (name: string, _opts?: CookieOptions<T>): CookieRef<T> {
|
export function useCookie<T = string | null | undefined> (name: string, _opts?: CookieOptions<T>): CookieRef<T> {
|
||||||
const opts = { ...CookieDefaults, ..._opts }
|
const opts = { ...CookieDefaults, ..._opts }
|
||||||
const cookies = readRawCookies(opts) || {}
|
const cookies = readRawCookies(opts) || {}
|
||||||
@ -55,6 +58,7 @@ export function useCookie<T = string | null | undefined> (name: string, _opts?:
|
|||||||
if (import.meta.client) {
|
if (import.meta.client) {
|
||||||
const channel = typeof BroadcastChannel === 'undefined' ? null : new BroadcastChannel(`nuxt:cookies:${name}`)
|
const channel = typeof BroadcastChannel === 'undefined' ? null : new BroadcastChannel(`nuxt:cookies:${name}`)
|
||||||
const callback = () => {
|
const callback = () => {
|
||||||
|
if (opts.readonly || isEqual(cookie.value, cookies[name])) { return }
|
||||||
writeClientCookie(name, cookie.value, opts as CookieSerializeOptions)
|
writeClientCookie(name, cookie.value, opts as CookieSerializeOptions)
|
||||||
channel?.postMessage(opts.encode(cookie.value as T))
|
channel?.postMessage(opts.encode(cookie.value as T))
|
||||||
}
|
}
|
||||||
@ -72,7 +76,7 @@ export function useCookie<T = string | null | undefined> (name: string, _opts?:
|
|||||||
if (channel) {
|
if (channel) {
|
||||||
channel.onmessage = (event) => {
|
channel.onmessage = (event) => {
|
||||||
watchPaused = true
|
watchPaused = true
|
||||||
cookie.value = opts.decode(event.data)
|
cookies[name] = cookie.value = opts.decode(event.data)
|
||||||
nextTick(() => { watchPaused = false })
|
nextTick(() => { watchPaused = false })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -89,10 +93,9 @@ export function useCookie<T = string | null | undefined> (name: string, _opts?:
|
|||||||
} else if (import.meta.server) {
|
} else if (import.meta.server) {
|
||||||
const nuxtApp = useNuxtApp()
|
const nuxtApp = useNuxtApp()
|
||||||
const writeFinalCookieValue = () => {
|
const writeFinalCookieValue = () => {
|
||||||
if (!isEqual(cookie.value, cookies[name])) {
|
if (opts.readonly || isEqual(cookie.value, cookies[name])) { return }
|
||||||
writeServerCookie(useRequestEvent(nuxtApp), name, cookie.value, opts as CookieOptions<any>)
|
writeServerCookie(useRequestEvent(nuxtApp), name, cookie.value, opts as CookieOptions<any>)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
const unhook = nuxtApp.hooks.hookOnce('app:rendered', writeFinalCookieValue)
|
const unhook = nuxtApp.hooks.hookOnce('app:rendered', writeFinalCookieValue)
|
||||||
nuxtApp.hooks.hookOnce('app:error', () => {
|
nuxtApp.hooks.hookOnce('app:error', () => {
|
||||||
unhook() // don't write cookie subsequently when app:rendered is called
|
unhook() // don't write cookie subsequently when app:rendered is called
|
||||||
|
5
test/fixtures/basic-types/types.ts
vendored
5
test/fixtures/basic-types/types.ts
vendored
@ -346,6 +346,11 @@ describe('composables', () => {
|
|||||||
expectTypeOf(useFetch('/test', { default: () => 500 }).data).toEqualTypeOf<Ref<unknown>>()
|
expectTypeOf(useFetch('/test', { default: () => 500 }).data).toEqualTypeOf<Ref<unknown>>()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('enforces readonly cookies', () => {
|
||||||
|
// @ts-expect-error readonly cookie
|
||||||
|
useCookie('test', { readonly: true }).value = 'thing'
|
||||||
|
})
|
||||||
|
|
||||||
it('correct types when using ResT type-assertion with default function', () => {
|
it('correct types when using ResT type-assertion with default function', () => {
|
||||||
// @ts-expect-error default type should match generic type
|
// @ts-expect-error default type should match generic type
|
||||||
useFetch<string>('/test', { default: () => 0 })
|
useFetch<string>('/test', { default: () => 0 })
|
||||||
|
Loading…
Reference in New Issue
Block a user