-
-
Notifications
You must be signed in to change notification settings - Fork 242
Expand file tree
/
Copy pathssr.node.tsx
More file actions
100 lines (91 loc) · 2.98 KB
/
ssr.node.tsx
File metadata and controls
100 lines (91 loc) · 2.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import * as ReactDOM from 'react-dom'
import assetsManifest from 'virtual:vite-rsc/assets-manifest'
import * as clientReferences from 'virtual:vite-rsc/client-references'
import { setRequireModule } from './core/ssr'
import type { ResolvedAssetDeps } from './plugin'
import { toCssVirtual, toReferenceValidationVirtual } from './plugins/shared'
export { createServerConsumerManifest } from './core/ssr'
export * from './react/ssr.node'
/**
* Callback type for client reference dependency notifications.
* Called during SSR when a client component's dependencies are loaded.
* @experimental
*/
export type OnClientReference = (reference: {
id: string
deps: ResolvedAssetDeps
}) => void
// Registered callback for client reference deps
let onClientReference: OnClientReference | undefined
/**
* Register a callback to be notified when client reference dependencies are loaded.
* Called during SSR when a client component is accessed.
* @experimental
*/
export function setOnClientReference(
callback: OnClientReference | undefined,
): void {
onClientReference = callback
}
initialize()
function initialize(): void {
setRequireModule({
load: async (id) => {
if (!import.meta.env.__vite_rsc_build__) {
await import(
/* @vite-ignore */ '/@id/__x00__' +
toReferenceValidationVirtual({ id, type: 'client' })
)
const mod = await import(/* @vite-ignore */ id)
const modCss = await import(
/* @vite-ignore */ '/@id/__x00__' + toCssVirtual({ id, type: 'ssr' })
)
return wrapResourceProxy(mod, id, { js: [], css: modCss.default })
} else {
const import_ = clientReferences.default[id]
if (!import_) {
throw new Error(`client reference not found '${id}'`)
}
const deps = assetsManifest.clientReferenceDeps[id] ?? {
js: [],
css: [],
}
// kick off preload/notify before initial async import, which is not sync-cached
preloadDeps(deps)
onClientReference?.({ id, deps })
const mod: any = await import_()
return wrapResourceProxy(mod, id, deps)
}
},
})
}
// preload/preinit during getter access since `load` is cached on production.
// also notify `onClientReference` callback here since module export access is not memoized by React.
function wrapResourceProxy(mod: any, id: string, deps: ResolvedAssetDeps) {
return new Proxy(mod, {
get(target, p, receiver) {
if (p in mod) {
preloadDeps(deps)
onClientReference?.({ id, deps })
}
return Reflect.get(target, p, receiver)
},
})
}
function preloadDeps(deps: ResolvedAssetDeps) {
for (const href of deps.js) {
ReactDOM.preloadModule(href, {
as: 'script',
crossOrigin: '',
})
}
for (const href of deps.css) {
ReactDOM.preinit(href, {
as: 'style',
precedence:
assetsManifest.cssLinkPrecedence !== false
? 'vite-rsc/client-reference'
: undefined,
})
}
}