@llui/vike 0.0.15 → 0.0.16
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/README.md +162 -7
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/on-render-client.d.ts +97 -51
- package/dist/on-render-client.d.ts.map +1 -1
- package/dist/on-render-client.js +235 -52
- package/dist/on-render-client.js.map +1 -1
- package/dist/on-render-html.d.ts +45 -15
- package/dist/on-render-html.d.ts.map +1 -1
- package/dist/on-render-html.js +119 -20
- package/dist/on-render-html.js.map +1 -1
- package/dist/page-slot.d.ts +63 -0
- package/dist/page-slot.d.ts.map +1 -0
- package/dist/page-slot.js +77 -0
- package/dist/page-slot.js.map +1 -0
- package/package.json +2 -2
package/dist/on-render-client.js
CHANGED
|
@@ -1,25 +1,44 @@
|
|
|
1
1
|
import { hydrateApp, mountApp } from '@llui/dom';
|
|
2
|
+
import { _consumePendingSlot, _resetPendingSlot } from './page-slot.js';
|
|
3
|
+
// Re-exported so `@llui/vike/client` is a one-stop-shop for everything
|
|
4
|
+
// a pages/+onRenderClient.ts / +Layout.ts file needs.
|
|
5
|
+
export { pageSlot } from './page-slot.js';
|
|
6
|
+
/**
|
|
7
|
+
* Resolves the layout chain for a given pageContext. A single layout
|
|
8
|
+
* becomes a one-element chain; a function resolver gives callers full
|
|
9
|
+
* control to return different chains for different routes (e.g. nested
|
|
10
|
+
* layouts keyed on Vike's `pageContext.urlPathname`).
|
|
11
|
+
*/
|
|
12
|
+
function resolveLayoutChain(layoutOption, pageContext) {
|
|
13
|
+
if (!layoutOption)
|
|
14
|
+
return [];
|
|
15
|
+
if (typeof layoutOption === 'function') {
|
|
16
|
+
return layoutOption(pageContext) ?? [];
|
|
17
|
+
}
|
|
18
|
+
if (Array.isArray(layoutOption))
|
|
19
|
+
return layoutOption;
|
|
20
|
+
return [layoutOption];
|
|
21
|
+
}
|
|
2
22
|
/**
|
|
3
23
|
* Adapt a `TransitionOptions` object (e.g. the output of
|
|
4
|
-
* `routeTransition()` from `@llui/transitions`, or
|
|
5
|
-
*
|
|
6
|
-
*
|
|
24
|
+
* `routeTransition()` from `@llui/transitions`, or a preset like `fade`
|
|
25
|
+
* / `slide`) into the `onLeave` / `onEnter` pair expected by
|
|
26
|
+
* `createOnRenderClient`.
|
|
7
27
|
*
|
|
8
|
-
* ```
|
|
28
|
+
* ```ts
|
|
9
29
|
* import { createOnRenderClient, fromTransition } from '@llui/vike/client'
|
|
10
30
|
* import { routeTransition } from '@llui/transitions'
|
|
11
31
|
*
|
|
12
32
|
* export const onRenderClient = createOnRenderClient({
|
|
33
|
+
* Layout: AppLayout,
|
|
13
34
|
* ...fromTransition(routeTransition({ duration: 200 })),
|
|
14
35
|
* })
|
|
15
36
|
* ```
|
|
16
37
|
*
|
|
17
|
-
* The transition operates on the
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* when the new page mounts; use `enter` to reset them explicitly or
|
|
22
|
-
* pick presets that self-clean.
|
|
38
|
+
* The transition operates on the slot element — in a no-layout setup,
|
|
39
|
+
* the root container; in a layout setup, the innermost surviving
|
|
40
|
+
* layer's `pageSlot()` element. Opacity / transform fades apply to the
|
|
41
|
+
* outgoing page content, then the new page fades in.
|
|
23
42
|
*/
|
|
24
43
|
export function fromTransition(t) {
|
|
25
44
|
return {
|
|
@@ -38,40 +57,53 @@ export function fromTransition(t) {
|
|
|
38
57
|
: undefined,
|
|
39
58
|
};
|
|
40
59
|
}
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
let
|
|
60
|
+
// Live chain of mounted layers. Module-level state: there's exactly
|
|
61
|
+
// one chain per Vike-managed app per page load.
|
|
62
|
+
let chainHandles = [];
|
|
44
63
|
/**
|
|
45
|
-
* @internal — test helper. Disposes
|
|
46
|
-
* the module
|
|
47
|
-
* Not part of the public API; subject to change without notice.
|
|
64
|
+
* @internal — test helper. Disposes every layer in the current chain
|
|
65
|
+
* and clears the module state so subsequent calls behave as a first
|
|
66
|
+
* mount. Not part of the public API; subject to change without notice.
|
|
48
67
|
*/
|
|
49
|
-
export function
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
68
|
+
export function _resetChainForTest() {
|
|
69
|
+
// Dispose innermost-first to match the normal teardown path.
|
|
70
|
+
for (let i = chainHandles.length - 1; i >= 0; i--) {
|
|
71
|
+
chainHandles[i].handle.dispose();
|
|
53
72
|
}
|
|
73
|
+
chainHandles = [];
|
|
74
|
+
_resetPendingSlot();
|
|
54
75
|
}
|
|
55
76
|
/**
|
|
56
|
-
*
|
|
57
|
-
*
|
|
77
|
+
* Back-compat alias for the pre-layout test helper name.
|
|
78
|
+
* @internal
|
|
79
|
+
* @deprecated — use `_resetChainForTest` instead.
|
|
80
|
+
*/
|
|
81
|
+
export function _resetCurrentHandleForTest() {
|
|
82
|
+
_resetChainForTest();
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Default onRenderClient hook — no layout, no animation hooks. Hydrates
|
|
86
|
+
* on first load, mounts fresh on subsequent navs. Use `createOnRenderClient`
|
|
58
87
|
* for the customizable factory form.
|
|
59
88
|
*/
|
|
60
89
|
export async function onRenderClient(pageContext) {
|
|
61
90
|
await renderClient(pageContext, {});
|
|
62
91
|
}
|
|
63
92
|
/**
|
|
64
|
-
* Factory to create a customized onRenderClient hook.
|
|
93
|
+
* Factory to create a customized onRenderClient hook. See `RenderClientOptions`
|
|
94
|
+
* for the full option surface — this is the entry point for persistent
|
|
95
|
+
* layouts, route transitions, and lifecycle hooks.
|
|
65
96
|
*
|
|
66
|
-
* ```
|
|
97
|
+
* ```ts
|
|
67
98
|
* // pages/+onRenderClient.ts
|
|
68
|
-
* import { createOnRenderClient } from '@llui/vike/client'
|
|
99
|
+
* import { createOnRenderClient, fromTransition } from '@llui/vike/client'
|
|
100
|
+
* import { routeTransition } from '@llui/transitions'
|
|
101
|
+
* import { AppLayout } from './+Layout'
|
|
69
102
|
*
|
|
70
103
|
* export const onRenderClient = createOnRenderClient({
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
* onMount: () => console.log('Page ready'),
|
|
104
|
+
* Layout: AppLayout,
|
|
105
|
+
* ...fromTransition(routeTransition({ duration: 200 })),
|
|
106
|
+
* onMount: () => console.log('page rendered'),
|
|
75
107
|
* })
|
|
76
108
|
* ```
|
|
77
109
|
*/
|
|
@@ -79,37 +111,188 @@ export function createOnRenderClient(options) {
|
|
|
79
111
|
return (pageContext) => renderClient(pageContext, options);
|
|
80
112
|
}
|
|
81
113
|
async function renderClient(pageContext, options) {
|
|
82
|
-
const { Page } = pageContext;
|
|
83
114
|
const selector = options.container ?? '#app';
|
|
84
115
|
const container = document.querySelector(selector);
|
|
85
116
|
if (!container) {
|
|
86
117
|
throw new Error(`@llui/vike: container "${selector}" not found in DOM`);
|
|
87
118
|
}
|
|
88
|
-
const
|
|
89
|
-
//
|
|
90
|
-
//
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
await options.onLeave(el);
|
|
96
|
-
}
|
|
97
|
-
currentHandle.dispose();
|
|
98
|
-
currentHandle = null;
|
|
99
|
-
}
|
|
119
|
+
const rootEl = container;
|
|
120
|
+
// Resolve the chain for this render. The page component is always
|
|
121
|
+
// the innermost entry, regardless of layout configuration.
|
|
122
|
+
const layoutChain = resolveLayoutChain(options.Layout, pageContext);
|
|
123
|
+
const layoutData = pageContext.lluiLayoutData ?? [];
|
|
124
|
+
const newChain = [...layoutChain, pageContext.Page];
|
|
125
|
+
const newChainData = [...layoutData, pageContext.data];
|
|
100
126
|
if (pageContext.isHydration) {
|
|
101
|
-
|
|
102
|
-
|
|
127
|
+
// First load — the chain starts empty and we hydrate every layer
|
|
128
|
+
// against server-rendered HTML. No onLeave/onEnter on hydration.
|
|
129
|
+
await mountOrHydrateChain(newChain, newChainData, rootEl, {
|
|
130
|
+
mode: 'hydrate',
|
|
131
|
+
serverStateEnvelope: window.__LLUI_STATE__,
|
|
132
|
+
});
|
|
133
|
+
options.onMount?.();
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
// Subsequent nav — diff the chain to find the divergent suffix.
|
|
137
|
+
let firstMismatch = 0;
|
|
138
|
+
const minLen = Math.min(chainHandles.length, newChain.length);
|
|
139
|
+
while (firstMismatch < minLen && chainHandles[firstMismatch].def === newChain[firstMismatch]) {
|
|
140
|
+
firstMismatch++;
|
|
103
141
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
142
|
+
// Find the slot element whose contents will change. Shared prefix =
|
|
143
|
+
// everything before firstMismatch. The slot we're about to replace
|
|
144
|
+
// content in sits in the layer at firstMismatch - 1 (if any);
|
|
145
|
+
// otherwise we're swapping the whole app at the root container.
|
|
146
|
+
const leaveTarget = firstMismatch === 0 ? rootEl : (chainHandles[firstMismatch - 1].slotMarker ?? rootEl);
|
|
147
|
+
// If everything matches (same chain end-to-end with same defs), this
|
|
148
|
+
// is effectively a no-op nav — the page def hasn't changed. We still
|
|
149
|
+
// fire onMount so callers can run per-render side effects, but there's
|
|
150
|
+
// nothing to dispose or mount.
|
|
151
|
+
const isNoOp = firstMismatch === chainHandles.length && firstMismatch === newChain.length;
|
|
152
|
+
if (isNoOp) {
|
|
153
|
+
options.onMount?.();
|
|
154
|
+
return;
|
|
112
155
|
}
|
|
156
|
+
// onLeave runs BEFORE any teardown. Outgoing DOM still mounted here.
|
|
157
|
+
// Skip on the very first mount — there's no outgoing page to leave.
|
|
158
|
+
const isFirstMount = chainHandles.length === 0;
|
|
159
|
+
if (options.onLeave && !isFirstMount) {
|
|
160
|
+
await options.onLeave(leaveTarget);
|
|
161
|
+
}
|
|
162
|
+
// Dispose the divergent suffix, innermost first. Each handle.dispose()
|
|
163
|
+
// calls disposeScope on that layer's rootScope, which cascades through
|
|
164
|
+
// every child scope the layer owned (bindings, portals, onMount
|
|
165
|
+
// cleanups, dialog focus traps, etc.). The surviving layers are
|
|
166
|
+
// untouched because their scopes live above the disposal roots.
|
|
167
|
+
for (let i = chainHandles.length - 1; i >= firstMismatch; i--) {
|
|
168
|
+
chainHandles[i].handle.dispose();
|
|
169
|
+
}
|
|
170
|
+
chainHandles = chainHandles.slice(0, firstMismatch);
|
|
171
|
+
// Clear the slot element before mounting the new suffix. handle.dispose()
|
|
172
|
+
// above already did this for the innermost layer's container, but the
|
|
173
|
+
// slot at firstMismatch - 1 keeps its marker element (it's owned by the
|
|
174
|
+
// surviving layer) and we mount fresh children into it.
|
|
175
|
+
leaveTarget.textContent = '';
|
|
176
|
+
// Mount the new suffix starting at firstMismatch.
|
|
177
|
+
const parentScope = firstMismatch === 0 ? undefined : (chainHandles[firstMismatch - 1].slotScope ?? undefined);
|
|
178
|
+
mountChainSuffix(newChain, newChainData, firstMismatch, leaveTarget, parentScope, {
|
|
179
|
+
mode: 'mount',
|
|
180
|
+
});
|
|
181
|
+
// onEnter fires after the new suffix is in place. Fire-and-forget.
|
|
182
|
+
options.onEnter?.(leaveTarget);
|
|
113
183
|
options.onMount?.();
|
|
114
184
|
}
|
|
185
|
+
/**
|
|
186
|
+
* Walk the full chain for the first mount or hydration. Starts from
|
|
187
|
+
* depth 0 at the root container, threads each layer's slot into the
|
|
188
|
+
* next layer's mount target + parentScope.
|
|
189
|
+
*/
|
|
190
|
+
async function mountOrHydrateChain(chain, chainData, rootEl, opts) {
|
|
191
|
+
mountChainSuffix(chain, chainData, 0, rootEl, undefined, opts);
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Mount (or hydrate) `chain[startAt..end]` into `initialTarget`, with
|
|
195
|
+
* the initial layer's rootScope parented at `initialParentScope`.
|
|
196
|
+
* Threads slot → next-target → next-parentScope through the chain.
|
|
197
|
+
*
|
|
198
|
+
* Fails loudly if a non-innermost layer forgot to call `pageSlot()`,
|
|
199
|
+
* or if the innermost layer called `pageSlot()` unnecessarily.
|
|
200
|
+
*/
|
|
201
|
+
function mountChainSuffix(chain, chainData, startAt, initialTarget, initialParentScope, opts) {
|
|
202
|
+
let mountTarget = initialTarget;
|
|
203
|
+
let parentScope = initialParentScope;
|
|
204
|
+
for (let i = startAt; i < chain.length; i++) {
|
|
205
|
+
const def = chain[i];
|
|
206
|
+
const layerData = chainData[i];
|
|
207
|
+
const isInnermost = i === chain.length - 1;
|
|
208
|
+
// Defensive: clear any stale slot from a prior failed mount.
|
|
209
|
+
_resetPendingSlot();
|
|
210
|
+
let handle;
|
|
211
|
+
if (opts.mode === 'hydrate') {
|
|
212
|
+
// Hydration envelope: each layer pulls its own state slice. The
|
|
213
|
+
// envelope shape is `{ layouts: [...], page: {...} }` with each
|
|
214
|
+
// entry carrying `{ name, state }`. We match by name so a server/
|
|
215
|
+
// client mismatch throws with a clear error instead of silently
|
|
216
|
+
// hydrating the wrong state into the wrong instance.
|
|
217
|
+
const layerState = extractHydrationState(opts.serverStateEnvelope, i, chain.length, def);
|
|
218
|
+
handle = hydrateApp(mountTarget, def, layerState, { parentScope });
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
handle = mountApp(mountTarget, def, layerData, { parentScope });
|
|
222
|
+
}
|
|
223
|
+
const slot = _consumePendingSlot();
|
|
224
|
+
if (isInnermost && slot !== null) {
|
|
225
|
+
// Innermost layer declared a slot with nothing to fill it —
|
|
226
|
+
// probably a misuse of pageSlot() in the page component itself.
|
|
227
|
+
handle.dispose();
|
|
228
|
+
throw new Error(`[llui/vike] <${def.name}> is the innermost component in the chain ` +
|
|
229
|
+
`but called pageSlot(). pageSlot() only belongs in layout components ` +
|
|
230
|
+
`that wrap a nested page or layout — not in the page itself.`);
|
|
231
|
+
}
|
|
232
|
+
if (!isInnermost && slot === null) {
|
|
233
|
+
// Non-innermost layer didn't declare a slot — there's nowhere to
|
|
234
|
+
// mount the remaining chain.
|
|
235
|
+
handle.dispose();
|
|
236
|
+
throw new Error(`[llui/vike] <${def.name}> is a layout layer at depth ${i} but did not ` +
|
|
237
|
+
`call pageSlot() in its view(). There are ${chain.length - i - 1} more ` +
|
|
238
|
+
`layer(s) to mount and no slot to mount them into. Add pageSlot() from ` +
|
|
239
|
+
`@llui/vike/client to the view at the position where nested content renders.`);
|
|
240
|
+
}
|
|
241
|
+
chainHandles.push({
|
|
242
|
+
def,
|
|
243
|
+
handle,
|
|
244
|
+
slotMarker: slot?.marker ?? null,
|
|
245
|
+
slotScope: slot?.slotScope ?? null,
|
|
246
|
+
});
|
|
247
|
+
if (slot !== null) {
|
|
248
|
+
mountTarget = slot.marker;
|
|
249
|
+
parentScope = slot.slotScope;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Pull the per-layer state from the hydration envelope. Supports both
|
|
255
|
+
* the new chain-aware shape (`{ layouts: [...], page: {...} }`) and the
|
|
256
|
+
* legacy flat shape (`window.__LLUI_STATE__` is the state object itself)
|
|
257
|
+
* for backward compatibility with pages written against 0.0.15 or earlier.
|
|
258
|
+
*
|
|
259
|
+
* Throws on envelope shape mismatch — missing entries, wrong component
|
|
260
|
+
* name at a given index — so server/client drift fails loud instead of
|
|
261
|
+
* silently binding the wrong state to the wrong instance.
|
|
262
|
+
*/
|
|
263
|
+
function extractHydrationState(envelope, layerIndex, chainLength, def) {
|
|
264
|
+
// Legacy flat envelope — no layout chain at render time. Only valid
|
|
265
|
+
// when the chain has a single layer (the page).
|
|
266
|
+
const isLegacyFlat = envelope !== null &&
|
|
267
|
+
typeof envelope === 'object' &&
|
|
268
|
+
!('layouts' in envelope) &&
|
|
269
|
+
!('page' in envelope);
|
|
270
|
+
if (isLegacyFlat) {
|
|
271
|
+
if (chainLength !== 1) {
|
|
272
|
+
throw new Error(`[llui/vike] Hydration envelope is in the legacy flat shape but the ` +
|
|
273
|
+
`current render has ${chainLength} chain layers. The server must emit ` +
|
|
274
|
+
`the chain-aware shape ({ layouts, page }) when rendering with a layout.`);
|
|
275
|
+
}
|
|
276
|
+
return envelope;
|
|
277
|
+
}
|
|
278
|
+
const chainEnvelope = envelope;
|
|
279
|
+
if (!chainEnvelope) {
|
|
280
|
+
throw new Error(`[llui/vike] Hydration envelope is missing. Server-side onRenderHtml must ` +
|
|
281
|
+
`populate window.__LLUI_STATE__ with the full chain before client hydration.`);
|
|
282
|
+
}
|
|
283
|
+
const isPageLayer = layerIndex === chainLength - 1;
|
|
284
|
+
const layoutEntries = chainEnvelope.layouts ?? [];
|
|
285
|
+
const expected = isPageLayer ? chainEnvelope.page : layoutEntries[layerIndex];
|
|
286
|
+
if (!expected) {
|
|
287
|
+
throw new Error(`[llui/vike] Hydration envelope has no entry for chain layer ${layerIndex} ` +
|
|
288
|
+
`(<${def.name}>). Server rendered ${layoutEntries.length} layouts + ${chainEnvelope.page ? 'a page' : 'no page'}, client expected ${chainLength} total entries.`);
|
|
289
|
+
}
|
|
290
|
+
if (expected.name !== def.name) {
|
|
291
|
+
throw new Error(`[llui/vike] Hydration mismatch at chain layer ${layerIndex}: server ` +
|
|
292
|
+
`rendered <${expected.name}> but client is trying to hydrate <${def.name}>. ` +
|
|
293
|
+
`This usually means the layout chain resolver returns different layouts ` +
|
|
294
|
+
`on the server and the client for the same route.`);
|
|
295
|
+
}
|
|
296
|
+
return expected.state;
|
|
297
|
+
}
|
|
115
298
|
//# sourceMappingURL=on-render-client.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"on-render-client.js","sourceRoot":"","sources":["../src/on-render-client.ts"],"names":[],"mappings":"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","sourcesContent":["import { hydrateApp, mountApp } from '@llui/dom'\nimport type { ComponentDef, AppHandle, TransitionOptions } from '@llui/dom'\n\ndeclare global {\n interface Window {\n __LLUI_STATE__?: unknown\n }\n}\n\nexport interface ClientPageContext {\n Page: ComponentDef<unknown, unknown, unknown, unknown>\n data?: unknown\n isHydration?: boolean\n}\n\n/**\n * Page-lifecycle hooks that fire around the dispose → clear → mount\n * sequence on client navigation. Use these to animate page transitions,\n * save scroll state, emit analytics events, or defer the swap behind\n * any async work that must complete before the next page appears.\n *\n * The sequence is:\n *\n * ```\n * client nav triggered\n * │\n * ▼\n * onLeave(el) ← awaited if it returns a promise\n * │ (the outgoing page's DOM is still mounted here)\n * ▼\n * currentHandle.dispose()\n * │ (all scopes torn down — portals, focus traps,\n * │ onMount cleanups all fire synchronously here)\n * ▼\n * el.textContent = ''\n * │ (old DOM removed)\n * ▼\n * mountApp(el, Page, data)\n * │ (new page mounted)\n * ▼\n * onEnter(el) ← not awaited; animate in-place\n * │\n * ▼\n * onMount() ← legacy shim, still fires last\n * ```\n *\n * On the initial render (hydration), `onLeave` and `onEnter` are NOT\n * called — there's no outgoing page to leave and no animation to enter.\n * If you need to run code after hydration, use `onMount`.\n */\nexport interface RenderClientOptions {\n /** CSS selector for the mount container. Default: '#app' */\n container?: string\n\n /**\n * Called on the outgoing page's container BEFORE dispose + clear + mount.\n * Return a promise to defer the swap until the leave animation finishes.\n * The container element is passed as the argument — its children are\n * still the previous page's DOM at this point.\n *\n * Not called on the initial hydration render.\n */\n onLeave?: (el: HTMLElement) => void | Promise<void>\n\n /**\n * Called after the new page is mounted into the container. Use this to\n * kick off an enter animation on the freshly-rendered content. Not\n * awaited — if you return a promise, the resolution is ignored.\n *\n * Not called on the initial hydration render.\n */\n onEnter?: (el: HTMLElement) => void\n\n /**\n * Called after mount or hydration completes. Fires on every render\n * including the initial hydration. Use this for per-render side\n * effects that don't fit the animation hooks (analytics, focus\n * management, etc.).\n */\n onMount?: () => void\n}\n\n/**\n * Adapt a `TransitionOptions` object (e.g. the output of\n * `routeTransition()` from `@llui/transitions`, or any preset like\n * `fade()` / `slide()`) into the `onLeave` / `onEnter` shape expected\n * by `createOnRenderClient`.\n *\n * ```typescript\n * import { createOnRenderClient, fromTransition } from '@llui/vike/client'\n * import { routeTransition } from '@llui/transitions'\n *\n * export const onRenderClient = createOnRenderClient({\n * ...fromTransition(routeTransition({ duration: 200 })),\n * })\n * ```\n *\n * The transition operates on the container element itself — its\n * opacity / transform fades out the outgoing page, then the new page\n * fades in when it mounts. If the preset doesn't restore its starting\n * style on `leave`, the container may still carry leftover properties\n * when the new page mounts; use `enter` to reset them explicitly or\n * pick presets that self-clean.\n */\nexport function fromTransition(\n t: TransitionOptions,\n): Pick<RenderClientOptions, 'onLeave' | 'onEnter'> {\n return {\n onLeave: t.leave\n ? (el): void | Promise<void> => {\n const result = t.leave!([el])\n return result && typeof (result as Promise<void>).then === 'function'\n ? (result as Promise<void>)\n : undefined\n }\n : undefined,\n onEnter: t.enter\n ? (el): void => {\n t.enter!([el])\n }\n : undefined,\n }\n}\n\n// Track the current app handle so we can dispose it on client navigation.\n// Module-level state: there's exactly one Vike-managed app per page load.\nlet currentHandle: AppHandle | null = null\n\n/**\n * @internal — test helper. Disposes the current handle (if any) and clears\n * the module-level state so subsequent calls behave as a first mount.\n * Not part of the public API; subject to change without notice.\n */\nexport function _resetCurrentHandleForTest(): void {\n if (currentHandle) {\n currentHandle.dispose()\n currentHandle = null\n }\n}\n\n/**\n * Default onRenderClient hook — no animation hooks. Hydrates if\n * `isHydration` is true, otherwise mounts fresh. Use `createOnRenderClient`\n * for the customizable factory form.\n */\nexport async function onRenderClient(pageContext: ClientPageContext): Promise<void> {\n await renderClient(pageContext, {})\n}\n\n/**\n * Factory to create a customized onRenderClient hook.\n *\n * ```typescript\n * // pages/+onRenderClient.ts\n * import { createOnRenderClient } from '@llui/vike/client'\n *\n * export const onRenderClient = createOnRenderClient({\n * container: '#root',\n * onLeave: (el) => el.animate({ opacity: [1, 0] }, 200).finished,\n * onEnter: (el) => el.animate({ opacity: [0, 1] }, 200),\n * onMount: () => console.log('Page ready'),\n * })\n * ```\n */\nexport function createOnRenderClient(\n options: RenderClientOptions,\n): (pageContext: ClientPageContext) => Promise<void> {\n return (pageContext) => renderClient(pageContext, options)\n}\n\nasync function renderClient(\n pageContext: ClientPageContext,\n options: RenderClientOptions,\n): Promise<void> {\n const { Page } = pageContext\n const selector = options.container ?? '#app'\n const container = document.querySelector(selector)\n\n if (!container) {\n throw new Error(`@llui/vike: container \"${selector}\" not found in DOM`)\n }\n\n const el = container as HTMLElement\n\n // Dispose the previous page's component on client navigation. If the\n // caller supplied an onLeave hook and this isn't the initial hydration,\n // await it BEFORE tearing down — that's the only moment where the\n // outgoing page's DOM still exists for an animation to read/write.\n if (currentHandle) {\n if (!pageContext.isHydration && options.onLeave) {\n await options.onLeave(el)\n }\n currentHandle.dispose()\n currentHandle = null\n }\n\n if (pageContext.isHydration) {\n const serverState = window.__LLUI_STATE__\n currentHandle = hydrateApp(el, Page, serverState)\n } else {\n // Clear old DOM before mounting the new page\n el.textContent = ''\n currentHandle = mountApp(el, Page, pageContext.data)\n // onEnter fires AFTER mount so the hook can animate the freshly\n // rendered children. It's intentionally sync — a promise return is\n // ignored, matching typical enter-animation ergonomics (fire-and-forget).\n options.onEnter?.(el)\n }\n\n options.onMount?.()\n}\n"]}
|
|
1
|
+
{"version":3,"file":"on-render-client.js","sourceRoot":"","sources":["../src/on-render-client.ts"],"names":[],"mappings":"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","sourcesContent":["import { hydrateApp, mountApp } from '@llui/dom'\nimport type { ComponentDef, AppHandle, TransitionOptions, Scope } from '@llui/dom'\nimport { _consumePendingSlot, _resetPendingSlot } from './page-slot.js'\n\n// Re-exported so `@llui/vike/client` is a one-stop-shop for everything\n// a pages/+onRenderClient.ts / +Layout.ts file needs.\nexport { pageSlot } from './page-slot.js'\n\ndeclare global {\n interface Window {\n __LLUI_STATE__?: unknown\n }\n}\n\n/**\n * Page context shape as seen by `@llui/vike`'s client-side hooks. The\n * `Page` and `data` fields come from whichever `+Page.ts` and `+data.ts`\n * Vike resolved for the current route.\n *\n * `lluiLayoutData` is optional and carries per-layer data for the layout\n * chain configured via `createOnRenderClient({ Layout })`. It's indexed\n * outermost-to-innermost, one entry per layout layer. Absent entries\n * mean the corresponding layout's `init()` receives `undefined`. Users\n * wire this from their Vike `+data.ts` files by merging layout-owned\n * data under the `lluiLayoutData` key.\n */\nexport interface ClientPageContext {\n Page: ComponentDef<unknown, unknown, unknown, unknown>\n data?: unknown\n lluiLayoutData?: readonly unknown[]\n isHydration?: boolean\n}\n\ntype AnyComponentDef = ComponentDef<unknown, unknown, unknown, unknown>\ntype LayoutChain = ReadonlyArray<AnyComponentDef>\n\n/**\n * Resolves the layout chain for a given pageContext. A single layout\n * becomes a one-element chain; a function resolver gives callers full\n * control to return different chains for different routes (e.g. nested\n * layouts keyed on Vike's `pageContext.urlPathname`).\n */\nfunction resolveLayoutChain(\n layoutOption: RenderClientOptions['Layout'],\n pageContext: ClientPageContext,\n): LayoutChain {\n if (!layoutOption) return []\n if (typeof layoutOption === 'function') {\n return layoutOption(pageContext) ?? []\n }\n if (Array.isArray(layoutOption)) return layoutOption\n return [layoutOption as AnyComponentDef]\n}\n\n/**\n * Page-lifecycle hooks that fire around the dispose → mount cycle on\n * client navigation. With persistent layouts in play the cycle only\n * tears down the *divergent* suffix of the layout chain — any layers\n * shared between the old and new routes stay mounted.\n *\n * Navigation sequence for an already-mounted app:\n *\n * ```\n * client nav triggered\n * │\n * ▼\n * compare old chain to new chain → find first mismatch index K\n * │\n * ▼\n * onLeave(leaveTarget) ← awaited; leaveTarget is the slot element\n * │ at depth K-1 (or the root container if K=0)\n * │ whose contents are about to be replaced\n * ▼\n * dispose chainHandles[K..end] innermost first\n * │\n * ▼\n * leaveTarget.textContent = ''\n * │\n * ▼\n * mount newChain[K..end] into leaveTarget, outermost first\n * │\n * ▼\n * onEnter(leaveTarget) ← fire-and-forget; fresh DOM in place\n * │\n * ▼\n * onMount()\n * ```\n *\n * On the initial hydration render, `onLeave` and `onEnter` are NOT\n * called — there's no outgoing page to leave and no animation to enter.\n * Use `onMount` for code that should run on every render including the\n * initial one.\n */\nexport interface RenderClientOptions {\n /** CSS selector for the mount container. Default: `'#app'`. */\n container?: string\n\n /**\n * Persistent layout chain. One of:\n *\n * - A single `ComponentDef` — becomes a one-layout chain.\n * - An array of `ComponentDef`s — outermost layout first, innermost\n * layout last. Every layer except the innermost must call\n * `pageSlot()` in its view to declare where nested content renders.\n * - A function that returns a chain from the current `pageContext` —\n * lets different routes use different chains, e.g. by reading\n * Vike's `pageContext.urlPathname` or `pageContext.config.Layout`.\n *\n * Layers that are shared between the previous and next navigation\n * stay mounted. Only the divergent suffix is disposed and re-mounted.\n * Dialogs, focus traps, and effect subscriptions rooted in a surviving\n * layer are unaffected by the nav.\n */\n Layout?: AnyComponentDef | LayoutChain | ((pageContext: ClientPageContext) => LayoutChain)\n\n /**\n * Called on the slot element whose contents are about to be replaced,\n * BEFORE the divergent suffix is disposed and re-mounted. The slot's\n * current DOM is still attached when this runs — the only moment a\n * leave animation can read/write it. Return a promise to defer the\n * swap until the animation completes.\n *\n * For a plain no-layout setup, the slot element is the root container.\n * Not called on the initial hydration render.\n */\n onLeave?: (el: HTMLElement) => void | Promise<void>\n\n /**\n * Called after the new divergent suffix is mounted, on the same slot\n * element that was passed to `onLeave`. Use this to kick off an enter\n * animation. Fire-and-forget — promise returns are ignored.\n *\n * Not called on the initial hydration render.\n */\n onEnter?: (el: HTMLElement) => void\n\n /**\n * Called after mount or hydration completes. Fires on every render\n * including the initial hydration. Use for per-render side effects\n * that don't fit the animation hooks.\n */\n onMount?: () => void\n}\n\n/**\n * Adapt a `TransitionOptions` object (e.g. the output of\n * `routeTransition()` from `@llui/transitions`, or a preset like `fade`\n * / `slide`) into the `onLeave` / `onEnter` pair expected by\n * `createOnRenderClient`.\n *\n * ```ts\n * import { createOnRenderClient, fromTransition } from '@llui/vike/client'\n * import { routeTransition } from '@llui/transitions'\n *\n * export const onRenderClient = createOnRenderClient({\n * Layout: AppLayout,\n * ...fromTransition(routeTransition({ duration: 200 })),\n * })\n * ```\n *\n * The transition operates on the slot element — in a no-layout setup,\n * the root container; in a layout setup, the innermost surviving\n * layer's `pageSlot()` element. Opacity / transform fades apply to the\n * outgoing page content, then the new page fades in.\n */\nexport function fromTransition(\n t: TransitionOptions,\n): Pick<RenderClientOptions, 'onLeave' | 'onEnter'> {\n return {\n onLeave: t.leave\n ? (el): void | Promise<void> => {\n const result = t.leave!([el])\n return result && typeof (result as Promise<void>).then === 'function'\n ? (result as Promise<void>)\n : undefined\n }\n : undefined,\n onEnter: t.enter\n ? (el): void => {\n t.enter!([el])\n }\n : undefined,\n }\n}\n\n/**\n * One element of the live chain the adapter keeps between navs.\n * `handle` is the AppHandle returned by mountApp/hydrateApp for this\n * layer. `slotMarker` / `slotScope` are set when the layer called\n * `pageSlot()` during its view pass; they're null for the innermost\n * layer (typically the page component, which doesn't have a slot).\n */\ninterface ChainEntry {\n def: AnyComponentDef\n handle: AppHandle\n slotMarker: HTMLElement | null\n slotScope: Scope | null\n}\n\n// Live chain of mounted layers. Module-level state: there's exactly\n// one chain per Vike-managed app per page load.\nlet chainHandles: ChainEntry[] = []\n\n/**\n * @internal — test helper. Disposes every layer in the current chain\n * and clears the module state so subsequent calls behave as a first\n * mount. Not part of the public API; subject to change without notice.\n */\nexport function _resetChainForTest(): void {\n // Dispose innermost-first to match the normal teardown path.\n for (let i = chainHandles.length - 1; i >= 0; i--) {\n chainHandles[i]!.handle.dispose()\n }\n chainHandles = []\n _resetPendingSlot()\n}\n\n/**\n * Back-compat alias for the pre-layout test helper name.\n * @internal\n * @deprecated — use `_resetChainForTest` instead.\n */\nexport function _resetCurrentHandleForTest(): void {\n _resetChainForTest()\n}\n\n/**\n * Default onRenderClient hook — no layout, no animation hooks. Hydrates\n * on first load, mounts fresh on subsequent navs. Use `createOnRenderClient`\n * for the customizable factory form.\n */\nexport async function onRenderClient(pageContext: ClientPageContext): Promise<void> {\n await renderClient(pageContext, {})\n}\n\n/**\n * Factory to create a customized onRenderClient hook. See `RenderClientOptions`\n * for the full option surface — this is the entry point for persistent\n * layouts, route transitions, and lifecycle hooks.\n *\n * ```ts\n * // pages/+onRenderClient.ts\n * import { createOnRenderClient, fromTransition } from '@llui/vike/client'\n * import { routeTransition } from '@llui/transitions'\n * import { AppLayout } from './+Layout'\n *\n * export const onRenderClient = createOnRenderClient({\n * Layout: AppLayout,\n * ...fromTransition(routeTransition({ duration: 200 })),\n * onMount: () => console.log('page rendered'),\n * })\n * ```\n */\nexport function createOnRenderClient(\n options: RenderClientOptions,\n): (pageContext: ClientPageContext) => Promise<void> {\n return (pageContext) => renderClient(pageContext, options)\n}\n\nasync function renderClient(\n pageContext: ClientPageContext,\n options: RenderClientOptions,\n): Promise<void> {\n const selector = options.container ?? '#app'\n const container = document.querySelector(selector)\n if (!container) {\n throw new Error(`@llui/vike: container \"${selector}\" not found in DOM`)\n }\n const rootEl = container as HTMLElement\n\n // Resolve the chain for this render. The page component is always\n // the innermost entry, regardless of layout configuration.\n const layoutChain = resolveLayoutChain(options.Layout, pageContext)\n const layoutData = pageContext.lluiLayoutData ?? []\n const newChain: LayoutChain = [...layoutChain, pageContext.Page]\n const newChainData: readonly unknown[] = [...layoutData, pageContext.data]\n\n if (pageContext.isHydration) {\n // First load — the chain starts empty and we hydrate every layer\n // against server-rendered HTML. No onLeave/onEnter on hydration.\n await mountOrHydrateChain(newChain, newChainData, rootEl, {\n mode: 'hydrate',\n serverStateEnvelope: window.__LLUI_STATE__,\n })\n options.onMount?.()\n return\n }\n\n // Subsequent nav — diff the chain to find the divergent suffix.\n let firstMismatch = 0\n const minLen = Math.min(chainHandles.length, newChain.length)\n while (firstMismatch < minLen && chainHandles[firstMismatch]!.def === newChain[firstMismatch]) {\n firstMismatch++\n }\n\n // Find the slot element whose contents will change. Shared prefix =\n // everything before firstMismatch. The slot we're about to replace\n // content in sits in the layer at firstMismatch - 1 (if any);\n // otherwise we're swapping the whole app at the root container.\n const leaveTarget =\n firstMismatch === 0 ? rootEl : (chainHandles[firstMismatch - 1]!.slotMarker ?? rootEl)\n\n // If everything matches (same chain end-to-end with same defs), this\n // is effectively a no-op nav — the page def hasn't changed. We still\n // fire onMount so callers can run per-render side effects, but there's\n // nothing to dispose or mount.\n const isNoOp = firstMismatch === chainHandles.length && firstMismatch === newChain.length\n if (isNoOp) {\n options.onMount?.()\n return\n }\n\n // onLeave runs BEFORE any teardown. Outgoing DOM still mounted here.\n // Skip on the very first mount — there's no outgoing page to leave.\n const isFirstMount = chainHandles.length === 0\n if (options.onLeave && !isFirstMount) {\n await options.onLeave(leaveTarget)\n }\n\n // Dispose the divergent suffix, innermost first. Each handle.dispose()\n // calls disposeScope on that layer's rootScope, which cascades through\n // every child scope the layer owned (bindings, portals, onMount\n // cleanups, dialog focus traps, etc.). The surviving layers are\n // untouched because their scopes live above the disposal roots.\n for (let i = chainHandles.length - 1; i >= firstMismatch; i--) {\n chainHandles[i]!.handle.dispose()\n }\n chainHandles = chainHandles.slice(0, firstMismatch)\n\n // Clear the slot element before mounting the new suffix. handle.dispose()\n // above already did this for the innermost layer's container, but the\n // slot at firstMismatch - 1 keeps its marker element (it's owned by the\n // surviving layer) and we mount fresh children into it.\n leaveTarget.textContent = ''\n\n // Mount the new suffix starting at firstMismatch.\n const parentScope =\n firstMismatch === 0 ? undefined : (chainHandles[firstMismatch - 1]!.slotScope ?? undefined)\n mountChainSuffix(newChain, newChainData, firstMismatch, leaveTarget, parentScope, {\n mode: 'mount',\n })\n\n // onEnter fires after the new suffix is in place. Fire-and-forget.\n options.onEnter?.(leaveTarget)\n options.onMount?.()\n}\n\n/**\n * Walk the full chain for the first mount or hydration. Starts from\n * depth 0 at the root container, threads each layer's slot into the\n * next layer's mount target + parentScope.\n */\nasync function mountOrHydrateChain(\n chain: LayoutChain,\n chainData: readonly unknown[],\n rootEl: HTMLElement,\n opts: MountOpts,\n): Promise<void> {\n mountChainSuffix(chain, chainData, 0, rootEl, undefined, opts)\n}\n\ninterface MountOpts {\n mode: 'mount' | 'hydrate'\n /** For hydration: the full `window.__LLUI_STATE__` envelope. */\n serverStateEnvelope?: unknown\n}\n\n/**\n * Mount (or hydrate) `chain[startAt..end]` into `initialTarget`, with\n * the initial layer's rootScope parented at `initialParentScope`.\n * Threads slot → next-target → next-parentScope through the chain.\n *\n * Fails loudly if a non-innermost layer forgot to call `pageSlot()`,\n * or if the innermost layer called `pageSlot()` unnecessarily.\n */\nfunction mountChainSuffix(\n chain: LayoutChain,\n chainData: readonly unknown[],\n startAt: number,\n initialTarget: HTMLElement,\n initialParentScope: Scope | undefined,\n opts: MountOpts,\n): void {\n let mountTarget: HTMLElement = initialTarget\n let parentScope: Scope | undefined = initialParentScope\n\n for (let i = startAt; i < chain.length; i++) {\n const def = chain[i]!\n const layerData = chainData[i]\n const isInnermost = i === chain.length - 1\n\n // Defensive: clear any stale slot from a prior failed mount.\n _resetPendingSlot()\n\n let handle: AppHandle\n if (opts.mode === 'hydrate') {\n // Hydration envelope: each layer pulls its own state slice. The\n // envelope shape is `{ layouts: [...], page: {...} }` with each\n // entry carrying `{ name, state }`. We match by name so a server/\n // client mismatch throws with a clear error instead of silently\n // hydrating the wrong state into the wrong instance.\n const layerState = extractHydrationState(opts.serverStateEnvelope, i, chain.length, def)\n handle = hydrateApp(mountTarget, def, layerState, { parentScope })\n } else {\n handle = mountApp(mountTarget, def, layerData, { parentScope })\n }\n\n const slot = _consumePendingSlot()\n\n if (isInnermost && slot !== null) {\n // Innermost layer declared a slot with nothing to fill it —\n // probably a misuse of pageSlot() in the page component itself.\n handle.dispose()\n throw new Error(\n `[llui/vike] <${def.name}> is the innermost component in the chain ` +\n `but called pageSlot(). pageSlot() only belongs in layout components ` +\n `that wrap a nested page or layout — not in the page itself.`,\n )\n }\n if (!isInnermost && slot === null) {\n // Non-innermost layer didn't declare a slot — there's nowhere to\n // mount the remaining chain.\n handle.dispose()\n throw new Error(\n `[llui/vike] <${def.name}> is a layout layer at depth ${i} but did not ` +\n `call pageSlot() in its view(). There are ${chain.length - i - 1} more ` +\n `layer(s) to mount and no slot to mount them into. Add pageSlot() from ` +\n `@llui/vike/client to the view at the position where nested content renders.`,\n )\n }\n\n chainHandles.push({\n def,\n handle,\n slotMarker: slot?.marker ?? null,\n slotScope: slot?.slotScope ?? null,\n })\n\n if (slot !== null) {\n mountTarget = slot.marker\n parentScope = slot.slotScope\n }\n }\n}\n\n/**\n * Pull the per-layer state from the hydration envelope. Supports both\n * the new chain-aware shape (`{ layouts: [...], page: {...} }`) and the\n * legacy flat shape (`window.__LLUI_STATE__` is the state object itself)\n * for backward compatibility with pages written against 0.0.15 or earlier.\n *\n * Throws on envelope shape mismatch — missing entries, wrong component\n * name at a given index — so server/client drift fails loud instead of\n * silently binding the wrong state to the wrong instance.\n */\nfunction extractHydrationState(\n envelope: unknown,\n layerIndex: number,\n chainLength: number,\n def: AnyComponentDef,\n): unknown {\n // Legacy flat envelope — no layout chain at render time. Only valid\n // when the chain has a single layer (the page).\n const isLegacyFlat =\n envelope !== null &&\n typeof envelope === 'object' &&\n !('layouts' in (envelope as object)) &&\n !('page' in (envelope as object))\n\n if (isLegacyFlat) {\n if (chainLength !== 1) {\n throw new Error(\n `[llui/vike] Hydration envelope is in the legacy flat shape but the ` +\n `current render has ${chainLength} chain layers. The server must emit ` +\n `the chain-aware shape ({ layouts, page }) when rendering with a layout.`,\n )\n }\n return envelope\n }\n\n const chainEnvelope = envelope as\n | { layouts?: Array<{ name: string; state: unknown }>; page?: { name: string; state: unknown } }\n | undefined\n if (!chainEnvelope) {\n throw new Error(\n `[llui/vike] Hydration envelope is missing. Server-side onRenderHtml must ` +\n `populate window.__LLUI_STATE__ with the full chain before client hydration.`,\n )\n }\n\n const isPageLayer = layerIndex === chainLength - 1\n const layoutEntries = chainEnvelope.layouts ?? []\n const expected = isPageLayer ? chainEnvelope.page : layoutEntries[layerIndex]\n\n if (!expected) {\n throw new Error(\n `[llui/vike] Hydration envelope has no entry for chain layer ${layerIndex} ` +\n `(<${def.name}>). Server rendered ${layoutEntries.length} layouts + ${\n chainEnvelope.page ? 'a page' : 'no page'\n }, client expected ${chainLength} total entries.`,\n )\n }\n\n if (expected.name !== def.name) {\n throw new Error(\n `[llui/vike] Hydration mismatch at chain layer ${layerIndex}: server ` +\n `rendered <${expected.name}> but client is trying to hydrate <${def.name}>. ` +\n `This usually means the layout chain resolver returns different layouts ` +\n `on the server and the client for the same route.`,\n )\n }\n\n return expected.state\n}\n"]}
|
package/dist/on-render-html.d.ts
CHANGED
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
import type { ComponentDef } from '@llui/dom';
|
|
2
|
+
type AnyComponentDef = ComponentDef<unknown, unknown, unknown, unknown>;
|
|
3
|
+
type LayoutChain = ReadonlyArray<AnyComponentDef>;
|
|
4
|
+
/**
|
|
5
|
+
* Page context shape as seen by `@llui/vike`'s server hook. `Page` and
|
|
6
|
+
* `data` are whichever `+Page.ts` and `+data.ts` Vike resolved for the
|
|
7
|
+
* current route; `lluiLayoutData` is an optional array of per-layer
|
|
8
|
+
* layout data matching the chain configured on `createOnRenderHtml`.
|
|
9
|
+
*/
|
|
2
10
|
export interface PageContext {
|
|
3
|
-
Page:
|
|
11
|
+
Page: AnyComponentDef;
|
|
4
12
|
data?: unknown;
|
|
13
|
+
lluiLayoutData?: readonly unknown[];
|
|
5
14
|
head?: string;
|
|
6
15
|
}
|
|
7
16
|
export interface DocumentContext {
|
|
8
|
-
/** Rendered component HTML */
|
|
17
|
+
/** Rendered component HTML (layout + page composed if a Layout is configured) */
|
|
9
18
|
html: string;
|
|
10
|
-
/** JSON-serialized
|
|
19
|
+
/** JSON-serialized hydration envelope (chain-aware when Layout is configured) */
|
|
11
20
|
state: string;
|
|
12
21
|
/** Head content from pageContext.head (e.g. from +Head.ts) */
|
|
13
22
|
head: string;
|
|
@@ -23,28 +32,49 @@ export interface RenderHtmlResult {
|
|
|
23
32
|
};
|
|
24
33
|
}
|
|
25
34
|
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
35
|
+
* Options for the customized `createOnRenderHtml` factory. Mirrors
|
|
36
|
+
* `@llui/vike/client`'s `RenderClientOptions.Layout` — the same chain
|
|
37
|
+
* shape is accepted for consistency between server and client render.
|
|
38
|
+
*/
|
|
39
|
+
export interface RenderHtmlOptions {
|
|
40
|
+
/** Custom HTML document template. Defaults to a minimal layout. */
|
|
41
|
+
document?: (ctx: DocumentContext) => string;
|
|
42
|
+
/**
|
|
43
|
+
* Persistent layout chain. One of:
|
|
44
|
+
*
|
|
45
|
+
* - A single `ComponentDef` — becomes a one-layout chain.
|
|
46
|
+
* - An array of `ComponentDef`s — outermost first, innermost last.
|
|
47
|
+
* Every layer except the innermost must call `pageSlot()` in its view.
|
|
48
|
+
* - A function that returns a chain from the current `pageContext` —
|
|
49
|
+
* enables per-route chains (e.g. reading Vike's `urlPathname`).
|
|
50
|
+
*
|
|
51
|
+
* The server renders the full chain as one composed HTML tree. Client
|
|
52
|
+
* hydration reads the matching envelope and reconstructs the chain
|
|
53
|
+
* layer-by-layer.
|
|
54
|
+
*/
|
|
55
|
+
Layout?: AnyComponentDef | LayoutChain | ((pageContext: PageContext) => LayoutChain);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Default onRenderHtml hook — no layout, minimal document template.
|
|
28
59
|
*/
|
|
29
60
|
export declare function onRenderHtml(pageContext: PageContext): Promise<RenderHtmlResult>;
|
|
30
61
|
/**
|
|
31
62
|
* Factory to create a customized onRenderHtml hook.
|
|
32
63
|
*
|
|
33
|
-
* ```
|
|
64
|
+
* ```ts
|
|
34
65
|
* // pages/+onRenderHtml.ts
|
|
35
|
-
* import { createOnRenderHtml } from '@llui/vike'
|
|
66
|
+
* import { createOnRenderHtml } from '@llui/vike/server'
|
|
67
|
+
* import { AppLayout } from './+Layout'
|
|
36
68
|
*
|
|
37
69
|
* export const onRenderHtml = createOnRenderHtml({
|
|
70
|
+
* Layout: AppLayout,
|
|
38
71
|
* document: ({ html, state, head }) => `<!DOCTYPE html>
|
|
39
|
-
* <html>
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* <script>window.__LLUI_STATE__ = ${state}</script></body>
|
|
43
|
-
* </html>`,
|
|
72
|
+
* <html><head>${head}<link rel="stylesheet" href="/styles.css" /></head>
|
|
73
|
+
* <body><div id="app">${html}</div>
|
|
74
|
+
* <script>window.__LLUI_STATE__ = ${state}</script></body></html>`,
|
|
44
75
|
* })
|
|
45
76
|
* ```
|
|
46
77
|
*/
|
|
47
|
-
export declare function createOnRenderHtml(options:
|
|
48
|
-
|
|
49
|
-
}): (pageContext: PageContext) => Promise<RenderHtmlResult>;
|
|
78
|
+
export declare function createOnRenderHtml(options: RenderHtmlOptions): (pageContext: PageContext) => Promise<RenderHtmlResult>;
|
|
79
|
+
export {};
|
|
50
80
|
//# sourceMappingURL=on-render-html.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"on-render-html.d.ts","sourceRoot":"","sources":["../src/on-render-html.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"on-render-html.d.ts","sourceRoot":"","sources":["../src/on-render-html.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAkB,MAAM,WAAW,CAAA;AAG7D,KAAK,eAAe,GAAG,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAA;AACvE,KAAK,WAAW,GAAG,aAAa,CAAC,eAAe,CAAC,CAAA;AAEjD;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,eAAe,CAAA;IACrB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,cAAc,CAAC,EAAE,SAAS,OAAO,EAAE,CAAA;IACnC,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,eAAe;IAC9B,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAA;IACZ,iFAAiF;IACjF,KAAK,EAAE,MAAM,CAAA;IACb,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAA;IACZ,yCAAyC;IACzC,WAAW,EAAE,WAAW,CAAA;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,GAAG;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAA;IAC3C,WAAW,EAAE;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAA;CACpC;AAcD;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,mEAAmE;IACnE,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,MAAM,CAAA;IAE3C;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,EAAE,eAAe,GAAG,WAAW,GAAG,CAAC,CAAC,WAAW,EAAE,WAAW,KAAK,WAAW,CAAC,CAAA;CACrF;AAcD;;GAEG;AACH,wBAAsB,YAAY,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAEtF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,iBAAiB,GACzB,CAAC,WAAW,EAAE,WAAW,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAEzD"}
|