Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a7e761a

Browse files
authored
fix: type render() return across all framework integrations (#672)
* fix(vue): thread RenderResult generic through VueHeadClient VueHeadClient only forwarded the Input generic to Unhead, leaving RenderResult at its default of unknown. This caused head.render() to return unknown instead of SSRHeadPayload (server) or boolean (client). * fix(react,svelte,solid): type createHead render result for all frameworks Apply the same RenderResult fix to React, Svelte, and Solid client createHead functions using ClientUnhead. Also type BaseStreamableHeadContext with ServerUnhead so streaming render() calls no longer need SSRHeadPayload casts.
1 parent 401ebf8 commit a7e761a

11 files changed

Lines changed: 44 additions & 25 deletions

File tree

packages/react/src/client.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
11
import type { ReactNode } from 'react'
2+
import type { ClientUnhead } from 'unhead/client'
23
import type { CreateClientHeadOptions, Unhead } from 'unhead/types'
34
import { createElement } from 'react'
45
import { createHead as _createHead, createDebouncedFn, createDomRenderer } from 'unhead/client'
56
import { UnheadContext } from './context'
67

78
export { renderDOMHead } from 'unhead/client'
89

9-
export function createHead(options: CreateClientHeadOptions = {}): Unhead {
10+
export function createHead(options: CreateClientHeadOptions = {}): ClientUnhead {
1011
const domRenderer = createDomRenderer()
11-
let head: Unhead
12+
let head: ClientUnhead
1213
const debouncedRenderer = createDebouncedFn(() => domRenderer(head), fn => setTimeout(fn, 0))
1314
head = _createHead({ render: debouncedRenderer, ...options })
1415
return head
1516
}
1617

17-
export function UnheadProvider({ children, head }: { children: ReactNode, head?: ReturnType<typeof createHead> }) {
18+
export function UnheadProvider({ children, head }: { children: ReactNode, head?: Unhead<any, any> }) {
1819
return createElement(UnheadContext.Provider, { value: head || createHead() }, children)
1920
}
2021

packages/solid-js/src/client.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1+
import type { ClientUnhead } from 'unhead/client'
12
import type { CreateClientHeadOptions, Unhead } from 'unhead/types'
23
import { createHead as _createHead, createDebouncedFn, createDomRenderer } from 'unhead/client'
34

45
export { UnheadContext } from './context'
56

67
export { renderDOMHead } from 'unhead/client'
78

8-
export function createHead(options: CreateClientHeadOptions = {}): Unhead {
9+
export function createHead(options: CreateClientHeadOptions = {}): ClientUnhead {
910
const domRenderer = createDomRenderer()
10-
let head: Unhead
11+
let head: ClientUnhead
1112
const debouncedRenderer = createDebouncedFn(() => domRenderer(head), fn => setTimeout(fn, 0))
1213
head = _createHead({ render: debouncedRenderer, ...options })
1314
return head

packages/solid-js/src/stream/server.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import type { CreateStreamableServerHeadOptions, SSRHeadPayload, Unhead } from 'unhead/types'
1+
import type { ServerUnhead } from 'unhead/server'
2+
import type { CreateStreamableServerHeadOptions, SSRHeadPayload } from 'unhead/types'
23
import { useContext } from 'solid-js'
34
import { ssr } from 'solid-js/web'
45
import {
@@ -22,7 +23,7 @@ export {
2223
* Solid-js streaming context returned by createStreamableHead.
2324
*/
2425
export interface SolidStreamableHeadContext {
25-
head: Unhead
26+
head: ServerUnhead
2627
/**
2728
* Callback to pass to renderToStream's onCompleteShell option.
2829
* This captures head entries from shell components before streaming starts.
@@ -68,7 +69,7 @@ export function createStreamableHead(options: CreateStreamableServerHeadOptions
6869
head,
6970
onCompleteShell: () => {
7071
// Capture head entries from shell components before streaming starts
71-
const shellState = head.render() as SSRHeadPayload
72+
const shellState = head.render()
7273
head.entries.clear()
7374
// @ts-expect-error - custom property for SolidJS streaming
7475
head._solidShellComplete = true

packages/svelte/src/client.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1+
import type { ClientUnhead } from 'unhead/client'
12
import type { CreateClientHeadOptions, Unhead } from 'unhead/types'
23
import { tick } from 'svelte'
34
import { createHead as _createHead, createDebouncedFn, createDomRenderer } from 'unhead/client'
45

56
export { UnheadContextKey } from './context'
67

7-
export function createHead(options: CreateClientHeadOptions = {}): Unhead {
8+
export function createHead(options: CreateClientHeadOptions = {}): ClientUnhead {
89
const domRenderer = createDomRenderer()
9-
let head: Unhead
10+
let head: ClientUnhead
1011
const debouncedRenderer = createDebouncedFn(() => domRenderer(head), fn => tick().then(fn))
1112
head = _createHead({ render: debouncedRenderer, ...options })
1213
return head

packages/svelte/src/stream/server.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { WebStreamableHeadContext } from 'unhead/stream/server'
2-
import type { CreateStreamableServerHeadOptions, SSRHeadPayload } from 'unhead/types'
2+
import type { CreateStreamableServerHeadOptions } from 'unhead/types'
33
import {
44
createStreamableHead as _createStreamableHead,
55
wrapStream as coreWrapStream,
@@ -60,7 +60,7 @@ export function createStreamableHead(options: CreateStreamableServerHeadOptions
6060
head,
6161
wrapStream: (stream: ReadableStream<Uint8Array>, template: string) => {
6262
// Capture shell state before clearing entries
63-
const preRenderedState = head.render() as SSRHeadPayload
63+
const preRenderedState = head.render()
6464
head.entries.clear()
6565
// Mark shell as rendered so HeadStream starts outputting streaming updates
6666
shellRendered = true

packages/unhead/src/stream/server.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { ServerUnhead } from '../server/createHead'
12
import type { CreateStreamableServerHeadOptions, ResolvableHead, SSRHeadPayload, Unhead } from '../types'
23
import { applyHeadToHtml, parseHtmlForIndexes } from '../parser'
34
import { createHead } from '../server/createHead'
@@ -11,7 +12,7 @@ export interface BaseStreamableHeadContext<T = ResolvableHead> {
1112
/**
1213
* The Unhead instance to provide to your framework
1314
*/
14-
head: Unhead<T>
15+
head: ServerUnhead<T>
1516
}
1617

1718
/**

packages/vue/src/client.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
import type { CreateClientHeadOptions } from 'unhead/types'
2-
import type { VueHeadClient } from './types'
2+
import type { UseHeadInput, VueHeadClient } from './types'
33
import { createHead as _createHead, createDebouncedFn, createDomRenderer } from 'unhead/client'
44
import { vueInstall } from './install'
55

66
export { VueHeadMixin } from './VueHeadMixin'
77
export { renderDOMHead } from 'unhead/client'
88

99
/* @__NO_SIDE_EFFECTS__ */
10-
export function createHead(options: CreateClientHeadOptions = {}): VueHeadClient {
10+
export function createHead(options: CreateClientHeadOptions = {}): VueHeadClient<UseHeadInput, boolean> {
1111
const domRenderer = createDomRenderer()
12-
let head: VueHeadClient
12+
let head: VueHeadClient<UseHeadInput, boolean>
1313
const debouncedRenderer = createDebouncedFn(() => domRenderer(head), fn => setTimeout(fn, 0))
14-
head = _createHead({ render: debouncedRenderer, ...options }) as VueHeadClient
14+
head = _createHead({ render: debouncedRenderer, ...options }) as VueHeadClient<UseHeadInput, boolean>
1515
head.install = vueInstall(head)
1616
return head
1717
}

packages/vue/src/server.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import type { CreateServerHeadOptions } from 'unhead/types'
2-
import type { VueHeadClient } from './types'
1+
import type { CreateServerHeadOptions, SSRHeadPayload } from 'unhead/types'
2+
import type { UseHeadInput, VueHeadClient } from './types'
33
import { createHead as _createServerHead } from 'unhead/server'
44
import { vueInstall } from './install'
55
import { VueResolver } from './resolver'
@@ -8,11 +8,11 @@ export { VueHeadMixin } from './VueHeadMixin'
88
export { propsToString, renderSSRHead, type SSRHeadPayload, transformHtmlTemplate } from 'unhead/server'
99

1010
/* @__NO_SIDE_EFFECTS__ */
11-
export function createHead(options: Omit<CreateServerHeadOptions, 'propsResolver'> = {}): VueHeadClient {
11+
export function createHead(options: Omit<CreateServerHeadOptions, 'propsResolver'> = {}): VueHeadClient<UseHeadInput, SSRHeadPayload> {
1212
const head = _createServerHead({
1313
...options,
1414
propResolvers: [VueResolver],
15-
}) as VueHeadClient
15+
}) as VueHeadClient<UseHeadInput, SSRHeadPayload>
1616
head.install = vueInstall(head)
1717
return head
1818
}

packages/vue/src/stream/server.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export interface VueStreamableHeadContext extends Omit<WebStreamableHeadContext<
3939
/**
4040
* The Vue head instance to use with app.use(head)
4141
*/
42-
head: VueHeadClient
42+
head: VueHeadClient<any, SSRHeadPayload>
4343
}
4444

4545
/**
@@ -72,7 +72,7 @@ export function createStreamableHead(
7272
...options,
7373
propResolvers: [VueResolver],
7474
})
75-
const vueHead = head as VueHeadClient
75+
const vueHead = head as VueHeadClient<any, SSRHeadPayload>
7676
vueHead.install = vueInstall(vueHead)
7777

7878
// Track shell render state - HeadStream skips entries until shell is rendered
@@ -83,7 +83,7 @@ export function createStreamableHead(
8383
head: vueHead,
8484
wrapStream: (stream: ReadableStream<Uint8Array>, template: string) => {
8585
// Capture shell state before clearing entries
86-
const preRenderedState = vueHead.render() as SSRHeadPayload
86+
const preRenderedState = vueHead.render()
8787
vueHead.entries.clear()
8888
// Mark shell as rendered so HeadStream starts outputting streaming updates
8989
shellRendered = true

packages/vue/src/types/schema.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,4 +148,4 @@ export type UseHeadOptions = Omit<HeadEntryOptions, 'head'> & { head?: VueHeadCl
148148

149149
export type UseHeadInput<_Deprecated = never> = ResolvableValue<ReactiveHead>
150150
export type UseSeoMetaInput = ResolvableProperties<MetaFlat> & { title?: ReactiveHead['title'], titleTemplate?: ReactiveHead['titleTemplate'] }
151-
export type VueHeadClient<I = UseHeadInput> = Unhead<I> & Plugin
151+
export type VueHeadClient<I = UseHeadInput, R = unknown> = Unhead<I, R> & Plugin

0 commit comments

Comments
 (0)