lit-ui-router-ssr 0.7.0 → 0.8.0
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 +84 -30
- package/dist/development/index.js.map +1 -1
- package/dist/development/prerender.js +41 -12
- package/dist/development/prerender.js.map +1 -1
- package/dist/development/signature.js +1 -1
- package/dist/development/vite-preload.js +7 -0
- package/dist/development/vite-preload.js.map +1 -0
- package/dist/development/vite.js +27 -0
- package/dist/development/vite.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/prerender.d.ts +66 -16
- package/dist/prerender.d.ts.map +1 -1
- package/dist/prerender.js +40 -11
- package/dist/prerender.js.map +1 -1
- package/dist/signature.js +1 -1
- package/dist/vite-preload.d.ts +11 -0
- package/dist/vite-preload.d.ts.map +1 -0
- package/dist/vite-preload.js +7 -0
- package/dist/vite-preload.js.map +1 -0
- package/dist/vite.d.ts +86 -0
- package/dist/vite.d.ts.map +1 -0
- package/dist/vite.js +27 -0
- package/dist/vite.js.map +1 -0
- package/package.json +23 -2
- package/src/index.ts +2 -0
- package/src/prerender.ts +128 -23
- package/src/vite-preload.ts +18 -0
- package/src/vite.ts +158 -0
package/README.md
CHANGED
|
@@ -24,14 +24,14 @@ imports the pre-1.0 renderer or re-derives the incantation.
|
|
|
24
24
|
on the page carries `defer-hydration` and renders nothing until the client's walk reaches it.
|
|
25
25
|
- **The hydration signature.** A page rendered from a template opens on a JSON data block,
|
|
26
26
|
`<script type="application/json" data-lit-ui-router-ssr>`, naming this package's version, the
|
|
27
|
-
state the router stood on, that state's url parameter values, and the resolved values
|
|
28
|
-
`payload` hook
|
|
27
|
+
state the router stood on, that state's url parameter values, and the resolved values
|
|
28
|
+
`dehydrate` or the `payload` hook draws. A page `renderShell` returns as a string is written as-is, without one.
|
|
29
29
|
- **The lit render inside the emit loop.** The loop itself — verdict to file name, redirect to
|
|
30
30
|
rules line, the `_redirects` file, delegating states skipped, tally, warnings for paths that
|
|
31
31
|
matched nothing — is
|
|
32
32
|
`prerender` from `ui-router-server/prerender`, which takes any render. This package's `prerender`
|
|
33
33
|
supplies the lit one and takes the same options, plus `router`, `renderShell`, `document`,
|
|
34
|
-
`root`, `elementRenderers`, `payload`, `responses` and `origin`. No SPA catch-all is ever written: one
|
|
34
|
+
`root`, `elementRenderers`, `dehydrate`, `payload`, `responses` and `origin`. No SPA catch-all is ever written: one
|
|
35
35
|
turns every 404 into a 200.
|
|
36
36
|
- **Response states after settle.** `responder` runs the handler bound to a response state's name
|
|
37
37
|
with the resolves its transition landed with.
|
|
@@ -51,7 +51,8 @@ npm install lit-ui-router-ssr
|
|
|
51
51
|
`lit-ui-router`, `ui-router-server`, `@lit-labs/ssr`, `@lit-labs/ssr-client`, `lit`, and
|
|
52
52
|
`@uirouter/core` are peer dependencies. `@lit-labs/ssr` is the server half and `@lit-labs/ssr-client`
|
|
53
53
|
the client half, so a bundle takes one or the other, never both. `@lit-labs/ssr-client` is optional:
|
|
54
|
-
install it when you import `lit-ui-router-ssr/client`.
|
|
54
|
+
install it when you import `lit-ui-router-ssr/client`. `lit-ui-router-ssr/vite` wraps
|
|
55
|
+
`ui-router-server/vite`, so it takes `vite` through that package's optional peer.
|
|
55
56
|
|
|
56
57
|
The `lit-ui-router` peer is `^1.19.0`: the server renders a view through the helper `<ui-view>`
|
|
57
58
|
renders through, and the client hands a served class element to the view it wakes.
|
|
@@ -88,6 +89,14 @@ on. `dryRun: true` plans all of it and writes nothing.
|
|
|
88
89
|
Files land through `node:fs`, imported lazily on first write; pass `write` to emit into memory or a
|
|
89
90
|
virtual fs instead.
|
|
90
91
|
|
|
92
|
+
## After `vite build`
|
|
93
|
+
|
|
94
|
+
`lit-ui-router-ssr/vite` prerenders the built app after `vite build`. Its `serverRouterPlugin` is
|
|
95
|
+
`ui-router-server/vite`'s, with the DOM shim and `lit-ui-router-ssr/register` loaded before the
|
|
96
|
+
prerender script, and its `definePrerender` calls this package's `prerender` with the options the
|
|
97
|
+
script returns; [Prerender with Vite](https://lit-ui-router.dev/guides/prerender-with-vite) shows
|
|
98
|
+
both files in full.
|
|
99
|
+
|
|
91
100
|
## Static hosts add a trailing slash
|
|
92
101
|
|
|
93
102
|
A shell page lands at `<subpath>/index.html`. Cloudflare Pages, Netlify, and S3-style hosts serve
|
|
@@ -144,22 +153,17 @@ as `responses`, writing a 2xx body at the path its url spells or a 3xx as a rule
|
|
|
144
153
|
|
|
145
154
|
## Adopting the resolves on boot
|
|
146
155
|
|
|
147
|
-
The `
|
|
148
|
-
|
|
156
|
+
The `dehydrate` option draws each rendered page's resolve payload: `prerender` calls `dehydrate`
|
|
157
|
+
from `ui-router-server/ssr` on the page's landed transition with the options given, so
|
|
158
|
+
`shouldDehydrate` and `transport` act exactly as they do there. Pass `{}` to draw every resolve:
|
|
149
159
|
|
|
150
160
|
```typescript
|
|
151
161
|
import { prerender } from 'lit-ui-router-ssr';
|
|
152
|
-
import { dehydrate } from 'ui-router-server/ssr';
|
|
153
162
|
|
|
154
163
|
await prerender({
|
|
155
164
|
// mounts, router, paths, renderShell, …
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
for (const { state, token } of unserializable)
|
|
160
|
-
console.warn(`${path}: ${state}.${token} re-runs on the client`);
|
|
161
|
-
|
|
162
|
-
return payload;
|
|
165
|
+
dehydrate: {
|
|
166
|
+
shouldDehydrate: ({ token }) => token !== 'manifest',
|
|
163
167
|
},
|
|
164
168
|
});
|
|
165
169
|
```
|
|
@@ -169,15 +173,47 @@ The payload's `resolves` go into the page's hydration signature, beside `version
|
|
|
169
173
|
the router starts: each resolve the page was drawn with adopts its value in place of running its
|
|
170
174
|
function. Every other resolve runs as it would without one: a value `dehydrate` left out, a
|
|
171
175
|
`NOWAIT` resolve, every resolve of a boot that lands on another state or other parameters, and
|
|
172
|
-
every resolve of a page whose block carries no `resolves`. Without
|
|
173
|
-
resolves. What `dehydrate` draws, and which values it leaves out, is in
|
|
176
|
+
every resolve of a page whose block carries no `resolves`. Without `dehydrate` or a `payload` hook
|
|
177
|
+
no page carries resolves. What `dehydrate` draws, and which values it leaves out, is in
|
|
174
178
|
[its documentation](https://lit-ui-router.dev/packages/server#handing-resolves-to-the-client).
|
|
175
179
|
|
|
176
180
|
A value plain JSON can't carry, such as a `Date`, travels through a transporter. Pass the same
|
|
177
|
-
`transport`
|
|
178
|
-
|
|
181
|
+
`transport` in `dehydrate` and to `bootstrap()`: the signature keeps the payload's `transported`
|
|
182
|
+
marks, and `bootstrap()` hands `transport` to `seed`. See
|
|
179
183
|
[values beyond plain JSON](https://lit-ui-router.dev/packages/server#values-beyond-plain-json).
|
|
180
184
|
|
|
185
|
+
The `payload` option takes the drawing over by hand: a hook handed each page's landed transition
|
|
186
|
+
returns the payload to write, or `undefined` to write none. Pass one or the other; passing both
|
|
187
|
+
throws.
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
import { dehydrate } from 'ui-router-server/ssr';
|
|
191
|
+
|
|
192
|
+
await prerender({
|
|
193
|
+
// mounts, router, paths, renderShell, …
|
|
194
|
+
payload: (transition, { path }) =>
|
|
195
|
+
path.startsWith('/drafts/')
|
|
196
|
+
? undefined
|
|
197
|
+
: dehydrate(transition, { transport }).payload,
|
|
198
|
+
});
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Each rendered page's entry in `result.pages` reports its payload as `payload`: `bytes`, what the
|
|
202
|
+
payload adds to the page's signature as written, and, when `dehydrate` drew it, `unserializable`,
|
|
203
|
+
the resolves left out to re-run on the client. A hook returns the payload alone, so behind one the
|
|
204
|
+
report carries `bytes` only. A page with no payload has no `payload` field.
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
const { pages } = await prerender({ /* … */ dehydrate: {} });
|
|
208
|
+
|
|
209
|
+
for (const { path, payload } of pages) {
|
|
210
|
+
if (!payload) continue;
|
|
211
|
+
console.log(`${path}: ${payload.bytes} bytes of resolves`);
|
|
212
|
+
for (const { state, token } of payload.unserializable ?? [])
|
|
213
|
+
console.warn(`${path}: ${state}.${token} re-runs on the client`);
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
181
217
|
## The routed view, drawn on the server
|
|
182
218
|
|
|
183
219
|
`elementRenderers` defaults to `[UiViewRenderer, LightElementRenderer]` — not `@lit-labs/ssr`'s
|
|
@@ -362,23 +398,41 @@ await bootstrap(router, root, page(router));
|
|
|
362
398
|
|
|
363
399
|
A `<ui-view>` another class already defined throws, naming both ways out.
|
|
364
400
|
|
|
365
|
-
The build-time entry that calls `prerender()`
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
401
|
+
The build-time entry that calls `prerender()` needs the DOM shim installed before anything defines
|
|
402
|
+
an element. The shim module awaits at its top level, so a static import beside it evaluates first:
|
|
403
|
+
lit's Node build installs a registry of its own, the elements are defined there, and the shim then
|
|
404
|
+
replaces `globalThis.customElements` with an empty one. Load the shim and `lit-ui-router-ssr/register`
|
|
405
|
+
before the entry starts. `serverRouterPlugin` from `lit-ui-router-ssr/vite` names both as preloads
|
|
406
|
+
of its prerender worker, and its `definePrerender` calls `prerender()` with the options the entry
|
|
407
|
+
returns:
|
|
370
408
|
|
|
371
409
|
```typescript
|
|
372
|
-
|
|
410
|
+
// vite.config.ts
|
|
411
|
+
import { createServerRouter } from 'ui-router-server';
|
|
412
|
+
import { serverRouterPlugin } from 'lit-ui-router-ssr/vite';
|
|
413
|
+
|
|
414
|
+
plugins: [
|
|
415
|
+
serverRouterPlugin(createServerRouter({ mounts }), {
|
|
416
|
+
prerender: './src/prerender.ts',
|
|
417
|
+
}),
|
|
418
|
+
];
|
|
373
419
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
420
|
+
// src/prerender.ts
|
|
421
|
+
import { definePrerender } from 'lit-ui-router-ssr/vite';
|
|
422
|
+
|
|
423
|
+
export default definePrerender((site) => ({
|
|
424
|
+
mounts,
|
|
425
|
+
router,
|
|
426
|
+
paths,
|
|
427
|
+
renderShell,
|
|
428
|
+
document,
|
|
429
|
+
}));
|
|
378
430
|
```
|
|
379
431
|
|
|
380
|
-
|
|
381
|
-
|
|
432
|
+
The entry then uses plain static imports; see
|
|
433
|
+
[Prerender with Vite](https://lit-ui-router.dev/guides/prerender-with-vite). An entry node runs
|
|
434
|
+
directly gets the same order from `node --import @lit-labs/ssr/lib/install-global-dom-shim.js`.
|
|
435
|
+
`UiViewRenderer` draws the served
|
|
382
436
|
class, and a `<ui-view>` nothing defined on the server renders as an inert element with an empty
|
|
383
437
|
part pair — no error, and every page's body missing. In development `prerender()` warns when the
|
|
384
438
|
registry holds no `<ui-view>`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","mappings":"AAMA,
|
|
1
|
+
{"version":3,"file":"index.js","mappings":"AAMA,SAIE,iBAOK;AAEP,SAEE,cAEK;AAEP,SAAS,4BAA4B;AAErC,SAA8C,iBAAiB;AAQ/D,SAAS,sBAAsB","names":[],"ignoreList":[],"sources":["../../src/index.ts"]}
|
|
@@ -3,6 +3,7 @@ import { collectResultSync } from "@lit-labs/ssr/lib/render-result.js";
|
|
|
3
3
|
import { provideRouter, withRouterSync } from "lit-ui-router/context";
|
|
4
4
|
import { isString } from "@uirouter/core";
|
|
5
5
|
import { prerender as prerenderSite } from "ui-router-server/prerender";
|
|
6
|
+
import { dehydrate as dehydrateLanded } from "ui-router-server/ssr";
|
|
6
7
|
import { devGate } from "#dev-gate";
|
|
7
8
|
import { LightElementRenderer } from "./light-element-renderer.js";
|
|
8
9
|
import { responder } from "./respond.js";
|
|
@@ -45,6 +46,8 @@ export const signatureBlock = (signature) => {
|
|
|
45
46
|
const json = JSON.stringify(signature).replaceAll("<", "\\u003c").replaceAll(">", "\\u003e");
|
|
46
47
|
return `<script type="application/json" ${signatureAttribute}>${json}<\/script>`;
|
|
47
48
|
};
|
|
49
|
+
const utf8Length = (text) => new TextEncoder().encode(text).length;
|
|
50
|
+
const payloadBytes = (router, drawn) => utf8Length(signatureBlock(signatureOf(router, drawn))) - utf8Length(signatureBlock(signatureOf(router)));
|
|
48
51
|
export const renderPage = (body, router, root, elementRenderers, drawn) => signatureBlock(signatureOf(router, drawn)) + withRouterSync(router, () => collectResultSync(render(body, {
|
|
49
52
|
eventTargetStack: rootedStack(root),
|
|
50
53
|
elementRenderers,
|
|
@@ -53,15 +56,32 @@ export const renderPage = (body, router, root, elementRenderers, drawn) => signa
|
|
|
53
56
|
const warnUnregistered = () => {
|
|
54
57
|
if (!devGate()) return;
|
|
55
58
|
if (globalThis.customElements?.get("ui-view")) return;
|
|
56
|
-
console.warn("lit-ui-router-ssr: <ui-view> is not defined on the current customElements registry, so every <ui-view> on these pages renders empty. The DOM shim replaces the registry when it finishes installing: load lit-ui-router-ssr/register by dynamic import after the shim, or preload the shim with node --import.");
|
|
59
|
+
console.warn("lit-ui-router-ssr: <ui-view> is not defined on the current customElements registry, so every <ui-view> on these pages renders empty. The DOM shim replaces the registry when it finishes installing: prerender through serverRouterPlugin from lit-ui-router-ssr/vite, which preloads both, load lit-ui-router-ssr/register by dynamic import after the shim, or preload the shim with node --import.");
|
|
57
60
|
};
|
|
58
61
|
export async function prerender(options) {
|
|
59
|
-
const { router, renderShell, document, elementRenderers = [UiViewRenderer, LightElementRenderer], root = new EventTarget(), write = nodeWrite, payload, responses, origin = "http://lit-ui-router-ssr", ...site } = options;
|
|
62
|
+
const { router, renderShell, document, elementRenderers = [UiViewRenderer, LightElementRenderer], root = new EventTarget(), write = nodeWrite, dehydrate: dehydrateOptions, payload, responses, origin = "http://lit-ui-router-ssr", ...site } = options;
|
|
63
|
+
if (dehydrateOptions && payload) throw new Error("prerender: pass `dehydrate` or `payload`, not both; a `payload` hook calls `dehydrate()` itself");
|
|
60
64
|
warnUnregistered();
|
|
61
|
-
const
|
|
62
|
-
if (
|
|
65
|
+
const draw = (transition, context) => {
|
|
66
|
+
if (dehydrateOptions) return dehydrateLanded(transition, dehydrateOptions);
|
|
67
|
+
return { payload: payload?.(transition, context) };
|
|
68
|
+
};
|
|
69
|
+
const drawLanded = (context) => {
|
|
70
|
+
if (!dehydrateOptions && !payload) return {};
|
|
63
71
|
const landed = router.globals.successfulTransitions.peekTail();
|
|
64
|
-
return landed
|
|
72
|
+
return landed ? draw(landed, context) : {};
|
|
73
|
+
};
|
|
74
|
+
const reports = new Map();
|
|
75
|
+
const renderTemplate = (body, context) => {
|
|
76
|
+
const { payload: drawn, unserializable } = drawLanded(context);
|
|
77
|
+
if (drawn) {
|
|
78
|
+
const bytes = payloadBytes(router, drawn);
|
|
79
|
+
reports.set(context.file, unserializable ? {
|
|
80
|
+
bytes,
|
|
81
|
+
unserializable
|
|
82
|
+
} : { bytes });
|
|
83
|
+
}
|
|
84
|
+
return renderPage(body, router, root, elementRenderers, drawn);
|
|
65
85
|
};
|
|
66
86
|
const renderLit = async (verdict, siteContext) => {
|
|
67
87
|
const context = {
|
|
@@ -69,7 +89,7 @@ export async function prerender(options) {
|
|
|
69
89
|
root
|
|
70
90
|
};
|
|
71
91
|
const body = await renderShell(verdict, context);
|
|
72
|
-
const markup = isString(body) ? body :
|
|
92
|
+
const markup = isString(body) ? body : renderTemplate(body, context);
|
|
73
93
|
return document ? document(markup, context) : markup;
|
|
74
94
|
};
|
|
75
95
|
const uninstall = provideRouter(root, router);
|
|
@@ -78,13 +98,22 @@ export async function prerender(options) {
|
|
|
78
98
|
if (responses === void 0) throw new Error(`prerender: '${path}' matched response state '${verdict.state}'; pass \`responses\` to answer it`);
|
|
79
99
|
return responder(router, responses)(verdict, new Request(new URL(path, origin)));
|
|
80
100
|
};
|
|
101
|
+
const result = await prerenderSite({
|
|
102
|
+
...site,
|
|
103
|
+
render: renderLit,
|
|
104
|
+
respond,
|
|
105
|
+
write
|
|
106
|
+
});
|
|
107
|
+
const pages = result.pages.map((page) => {
|
|
108
|
+
const report = reports.get(page.file);
|
|
109
|
+
return report ? {
|
|
110
|
+
...page,
|
|
111
|
+
payload: report
|
|
112
|
+
} : page;
|
|
113
|
+
});
|
|
81
114
|
return {
|
|
82
|
-
...
|
|
83
|
-
|
|
84
|
-
render: renderLit,
|
|
85
|
-
respond,
|
|
86
|
-
write
|
|
87
|
-
}),
|
|
115
|
+
...result,
|
|
116
|
+
pages,
|
|
88
117
|
root
|
|
89
118
|
};
|
|
90
119
|
} finally {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prerender.js","mappings":"AACA,SAAS,cAAc;AAEvB,SAAS,yBAAyB;AAIlC,SAAS,eAAe,sBAAsB;AAC9C,SAAS,gBAAgB;AAEzB,SAAS,aAAa,qBAAqB;AAQ3C,SAAS,eAAe;AAExB,SAAS,4BAA4B;AACrC,SAAS,iBAAiB;AAE1B,SAAS,gBAAgB,SAAS,0BAA0B;AAC5D,SAAS,sBAAsB;AAc/B,MAAM,UAAU;AAWhB,MAAM,SAAS,SAAyB;CACtC,MAAM,MAAM,KAAK,YAAY,GAAG;CAEhC,OAAO,QAAQ,KAAK,KAAK,KAAK,MAAM,GAAG,GAAG;AAC5C;AAEA,MAAM,YAAwB,OAAO,MAAM,SAAS;CAElD,MAAM,EAAE,OAAO,cAAe,MAAM,OAAO;CAC3C,MAAM,MAAM,MAAM,IAAI;CAEtB,IAAI,KAAK,MAAM,MAAM,KAAK,EAAE,WAAW,KAAK,CAAC;CAC7C,MAAM,UAAU,MAAM,MAAM,MAAM;AACpC;
|
|
1
|
+
{"version":3,"file":"prerender.js","mappings":"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","names":[],"ignoreList":[],"sources":["../../src/prerender.ts"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DefType } from "@uirouter/core";
|
|
2
2
|
export const signatureAttribute = "data-lit-ui-router-ssr";
|
|
3
3
|
export const signatureSelector = `script[type="application/json"][${signatureAttribute}]`;
|
|
4
|
-
export const packageVersion = "0.
|
|
4
|
+
export const packageVersion = "0.8.0";
|
|
5
5
|
export const urlParamsOf = (state, params) => Object.fromEntries(state.parameters().flatMap((param) => param.location === DefType.CONFIG ? [] : [[param.id, param.type.encode(params[param.id])]]));
|
|
6
6
|
export const routeOf = ({ $current, params }) => [$current.name, urlParamsOf($current, params)];
|
|
7
7
|
//# sourceMappingURL=signature.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vite-preload.js","mappings":"AACA,OAAO,MAAM,WAA8B,CACzC,8CACF;AASA,OAAO,MAAM,cACX,MACA,YACa,CACb,GAAG,IAAI,IAAI;CAAC,GAAG;CAAM;CAA8B,GAAG;AAAO,CAAC,CAChE","names":[],"ignoreList":[],"sources":["../../src/vite-preload.ts"]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { serverRouterPlugin as siteRouterPlugin } from "ui-router-server/vite";
|
|
2
|
+
import { DOM_SHIM, litPreload } from "./vite-preload.js";
|
|
3
|
+
const loadPrerender = async () => (await import("./prerender.js")).prerender;
|
|
4
|
+
export function definePrerender(script) {
|
|
5
|
+
return async (build) => {
|
|
6
|
+
const [options, prerender] = await Promise.all([script(build), loadPrerender()]);
|
|
7
|
+
const { root: _root, ...result } = await prerender({
|
|
8
|
+
...build,
|
|
9
|
+
...options
|
|
10
|
+
});
|
|
11
|
+
return result;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export function serverRouterPlugin(router, options = {}) {
|
|
15
|
+
const { shim = DOM_SHIM, ...siteOptions } = options;
|
|
16
|
+
const { prerender } = siteOptions;
|
|
17
|
+
if (prerender === void 0) return siteRouterPlugin(router, siteOptions);
|
|
18
|
+
const { entry, preload = [] } = typeof prerender === "string" ? { entry: prerender } : prerender;
|
|
19
|
+
return siteRouterPlugin(router, {
|
|
20
|
+
...siteOptions,
|
|
21
|
+
prerender: {
|
|
22
|
+
entry,
|
|
23
|
+
preload: litPreload(shim, preload)
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=vite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vite.js","mappings":"AAcA,SAAS,sBAAsB,wBAAwB;AAUvD,SAAS,UAAU,kBAAkB;AA6CrC,MAAM,gBAAgB,aAAa,MAAM,OAAO,kBAAiB,CAAE;AAyBnE,OAAO,SAAS,gBAAgB,QAAyC;CACvE,OAAO,OAAO,UAAU;EACtB,MAAM,CAAC,SAAS,aAAa,MAAM,QAAQ,IAAI,CAC7C,OAAO,KAAK,GACZ,cAAc,CAChB,CAAC;EAGD,MAAM,EAAE,MAAM,OAAO,GAAG,WAAW,MAAM,UAAU;GACjD,GAAG;GACH,GAAG;EACL,CAAC;EAED,OAAO;CACT;AACF;AA+BA,OAAO,SAAS,mBACd,QACA,UAAqC,CAAC,GAClB;CACpB,MAAM,EAAE,OAAO,UAAU,GAAG,gBAAgB;CAC5C,MAAM,EAAE,cAAc;CAEtB,IAAI,cAAc,QAAW,OAAO,iBAAiB,QAAQ,WAAW;CAExE,MAAM,EAAE,OAAO,UAAU,CAAC,MAExB,OAAO,cAAc,WAAW,EAAE,OAAO,UAAU,IAAI;CAEzD,OAAO,iBAAiB,QAAQ;EAC9B,GAAG;EACH,WAAW;GAAE;GAAO,SAAS,WAAW,MAAM,OAAO;EAAE;CACzD,CAAC;AACH","names":[],"ignoreList":[],"sources":["../../src/vite.ts"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* @module
|
|
6
6
|
*/
|
|
7
|
-
export { type EmittedPage, type FileWriter, prerender, type PrerenderOptions, type PrerenderResult, type PrerenderTally, type RedirectLine, type RenderContext } from "./prerender.js";
|
|
7
|
+
export { type EmittedPage, type FileWriter, type PagePayload, prerender, type PrerenderedPage, type PrerenderOptions, type PrerenderResult, type PrerenderTally, type RedirectLine, type RenderContext } from "./prerender.js";
|
|
8
8
|
export { type ResolvePayload, settle, type SettleOptions } from "ui-router-server/ssr";
|
|
9
9
|
export { LightElementRenderer } from "./light-element-renderer.js";
|
|
10
10
|
export { type BoundResponses, type Responder, responder } from "./respond.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","mappings":";;;;;;AAMA,cACO,kBACA,
|
|
1
|
+
{"version":3,"file":"index.d.ts","mappings":";;;;;;AAMA,cACO,kBACA,iBACA,aACL,gBACK,sBACA,uBACA,sBACA,qBACA,mBACA,qBACA;AAEP,cACO,gBACL,aACK,qBACA;AAEP,SAAS,4BAA4B;AAErC,cAAc,qBAAqB,WAAW,iBAAiB;AAE/D,cACE,iBACA,iBACA,wBACK;AAEP,SAAS,sBAAsB","names":[],"ignoreList":[],"sources":["../src/index.ts"]}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","mappings":"AAMA,
|
|
1
|
+
{"version":3,"file":"index.js","mappings":"AAMA,SAIE,iBAOK;AAEP,SAEE,cAEK;AAEP,SAAS,4BAA4B;AAErC,SAA8C,iBAAiB;AAQ/D,SAAS,sBAAsB","names":[],"ignoreList":[],"sources":["../src/index.ts"]}
|
package/dist/prerender.d.ts
CHANGED
|
@@ -3,8 +3,8 @@ import type { TemplateResult } from "lit";
|
|
|
3
3
|
import type { Transition } from "@uirouter/core";
|
|
4
4
|
import type { UIRouterLit } from "lit-ui-router";
|
|
5
5
|
import type { Verdict } from "ui-router-server";
|
|
6
|
-
import type { FileWriter, PrerenderOptions as SitePrerenderOptions, PrerenderResult as SitePrerenderResult, RenderContext as SiteRenderContext } from "ui-router-server/prerender";
|
|
7
|
-
import type { ResolvePayload } from "ui-router-server/ssr";
|
|
6
|
+
import type { EmittedPage, FileWriter, PrerenderOptions as SitePrerenderOptions, PrerenderResult as SitePrerenderResult, RenderContext as SiteRenderContext } from "ui-router-server/prerender";
|
|
7
|
+
import type { DehydrateOptions, DehydrateResult, ResolvePayload } from "ui-router-server/ssr";
|
|
8
8
|
import type { BoundResponses } from "./respond.js";
|
|
9
9
|
export type { EmittedPage, FileWriter, PrerenderTally, RedirectLine } from "ui-router-server/prerender";
|
|
10
10
|
type ShellVerdict = Extract<Verdict, {
|
|
@@ -79,32 +79,78 @@ export interface PrerenderOptions extends Omit<SitePrerenderOptions, "render" |
|
|
|
79
79
|
/** Writes a file. Defaults to `node:fs`, imported lazily on first write. */
|
|
80
80
|
write?: FileWriter;
|
|
81
81
|
/**
|
|
82
|
-
* Draws
|
|
82
|
+
* Draws each rendered page's resolve payload with `dehydrate` from
|
|
83
|
+
* `ui-router-server/ssr`, called with these options on the transition the
|
|
83
84
|
* router last landed, once `renderShell` has returned a template. The
|
|
84
85
|
* payload's `resolves` go into the page's hydration signature, beside the
|
|
85
86
|
* state and parameters the router stands on, and the client adopts them on
|
|
86
|
-
* boot in place of running those resolve functions.
|
|
87
|
-
*
|
|
87
|
+
* boot in place of running those resolve functions. Pass `{}` to draw every
|
|
88
|
+
* resolve `dehydrate` draws by default. Without this option or
|
|
89
|
+
* {@link PrerenderOptions.payload | `payload`}, no page carries resolves.
|
|
88
90
|
*
|
|
89
|
-
* `dehydrate`
|
|
90
|
-
*
|
|
91
|
+
* `dehydrate`'s documentation says which values it leaves out and how
|
|
92
|
+
* `shouldDehydrate` and `transport` act. The payload's
|
|
91
93
|
* `transported` marks go into the signature too, so a value a transporter
|
|
92
94
|
* carried is rebuilt when `bootstrap()` gets the same `transport`.
|
|
93
95
|
*
|
|
94
96
|
* @example
|
|
95
97
|
* ```ts
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
* console.warn(`${path}: ${state}.${token} re-runs on the client`);
|
|
100
|
-
* return payload;
|
|
98
|
+
* dehydrate: {
|
|
99
|
+
* shouldDehydrate: ({ token }) => token !== 'manifest',
|
|
100
|
+
* transport,
|
|
101
101
|
* },
|
|
102
102
|
* ```
|
|
103
103
|
*/
|
|
104
|
+
dehydrate?: DehydrateOptions;
|
|
105
|
+
/**
|
|
106
|
+
* Draws the resolve payload for a rendered page by hand, in place of
|
|
107
|
+
* {@link PrerenderOptions.dehydrate | `dehydrate`}: handed the transition the
|
|
108
|
+
* router last landed, once `renderShell` has returned a template, it returns
|
|
109
|
+
* the payload the page's signature carries, or `undefined` to write none.
|
|
110
|
+
* Passing both this and `dehydrate` throws.
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* Shape the payload `dehydrate` draws before it is written:
|
|
114
|
+
* ```ts
|
|
115
|
+
* import { dehydrate } from 'ui-router-server/ssr';
|
|
116
|
+
*
|
|
117
|
+
* payload: (transition, { path }) =>
|
|
118
|
+
* path.startsWith('/drafts/')
|
|
119
|
+
* ? undefined
|
|
120
|
+
* : dehydrate(transition, { transport }).payload,
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
104
123
|
payload?: (transition: Transition, context: RenderContext) => ResolvePayload | undefined;
|
|
105
124
|
}
|
|
125
|
+
/** What a page's hydration signature carries of its resolve payload. */
|
|
126
|
+
export interface PagePayload {
|
|
127
|
+
/**
|
|
128
|
+
* The bytes the payload adds to the page's signature as written: its
|
|
129
|
+
* `resolves` and `transported` members, escaped as the block spells them.
|
|
130
|
+
*/
|
|
131
|
+
bytes: number;
|
|
132
|
+
/**
|
|
133
|
+
* The resolves {@link PrerenderOptions.dehydrate | `dehydrate`} left out of
|
|
134
|
+
* the payload because their value is not plain JSON data and no transporter
|
|
135
|
+
* carries it, each to re-run on the client. Present only when `dehydrate`
|
|
136
|
+
* drew the payload: a {@link PrerenderOptions.payload | `payload`} hook
|
|
137
|
+
* returns the payload alone.
|
|
138
|
+
*/
|
|
139
|
+
unserializable?: DehydrateResult["unserializable"];
|
|
140
|
+
}
|
|
141
|
+
/** A page {@link prerender} emitted. */
|
|
142
|
+
export interface PrerenderedPage extends EmittedPage {
|
|
143
|
+
/**
|
|
144
|
+
* What the page's signature carries of its resolve payload. Absent on a page
|
|
145
|
+
* that carries none: one drawn with no payload, one `renderShell` returned
|
|
146
|
+
* as a string, and a response state's body.
|
|
147
|
+
*/
|
|
148
|
+
payload?: PagePayload;
|
|
149
|
+
}
|
|
106
150
|
/** What {@link prerender} did. */
|
|
107
|
-
export interface PrerenderResult extends SitePrerenderResult {
|
|
151
|
+
export interface PrerenderResult extends Omit<SitePrerenderResult, "pages"> {
|
|
152
|
+
/** Every page emitted or planned, in enumeration order. */
|
|
153
|
+
pages: PrerenderedPage[];
|
|
108
154
|
/** The root event target, created or passed through. */
|
|
109
155
|
root: EventTarget;
|
|
110
156
|
}
|
|
@@ -150,9 +196,12 @@ export declare const renderPage: (body: TemplateResult, router: UIRouterLit, roo
|
|
|
150
196
|
* A rendered page opens on its hydration signature: a JSON data block,
|
|
151
197
|
* `<script type="application/json" data-lit-ui-router-ssr>`, naming this
|
|
152
198
|
* package's version and the state and parameter values the router stood on,
|
|
153
|
-
* which `hydrateRoot()` reads before it touches the document.
|
|
154
|
-
* {@link PrerenderOptions.
|
|
155
|
-
*
|
|
199
|
+
* which `hydrateRoot()` reads before it touches the document.
|
|
200
|
+
* {@link PrerenderOptions.dehydrate | `dehydrate`}, or a
|
|
201
|
+
* {@link PrerenderOptions.payload | `payload`} hook, adds the resolved values
|
|
202
|
+
* the page was drawn with, which `bootstrap()` adopts; the page's entry in
|
|
203
|
+
* the result's `pages` reports the bytes they add and, from `dehydrate`, the
|
|
204
|
+
* resolves left to re-run on the client. A `renderShell`
|
|
156
205
|
* that returns a string is written as-is, with no signature, so the client
|
|
157
206
|
* renders it cold.
|
|
158
207
|
*
|
|
@@ -166,6 +215,7 @@ export declare const renderPage: (body: TemplateResult, router: UIRouterLit, roo
|
|
|
166
215
|
* @returns what was emitted, planned or written
|
|
167
216
|
* @throws an `Error` when neither `mounts` nor `resolver` is supplied
|
|
168
217
|
* @throws an `Error` when the 404 document needs a default probe and only a `resolver` is supplied
|
|
218
|
+
* @throws an `Error` when both `dehydrate` and `payload` are supplied
|
|
169
219
|
*
|
|
170
220
|
* @example
|
|
171
221
|
* ```ts
|
package/dist/prerender.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prerender.d.ts","mappings":"AAEA,cAAc,kBAAkB;AAEhC,cAAc,sBAAsB;AACpC,cAAc,kBAAkB;AAChC,cAAc,mBAAmB;AAGjC,cAAc,eAAe;AAE7B,cACE,YACA,oBAAoB,sBACpB,mBAAmB,qBACnB,iBAAiB,yBACZ;
|
|
1
|
+
{"version":3,"file":"prerender.d.ts","mappings":"AAEA,cAAc,kBAAkB;AAEhC,cAAc,sBAAsB;AACpC,cAAc,kBAAkB;AAChC,cAAc,mBAAmB;AAGjC,cAAc,eAAe;AAE7B,cACE,aACA,YACA,oBAAoB,sBACpB,mBAAmB,qBACnB,iBAAiB,yBACZ;AAEP,cACE,kBACA,iBACA,sBACK;AAKP,cAAc,sBAAsB;AAIpC,cACE,aACA,YACA,gBACA,oBACK;KAEF,eAAe,QAAQ,SAAS;CAAE,MAAM;AAAQ;;AAgCrD,iBAAiB,sBAAsB,kBAAkB;;CAEvD,MAAM;AACR;;;;;AAMA,iBAAiB,yBAAyB,KACxC,sBACA,WAAW,YAAY,SACvB;;;;;;CAMA,QAAQ;;;;;;;CAOR,cACE,SAAS,cACT,SAAS,kBACN,0BAA0B,QAAQ;;;;;;CAMvC,YAAY,cAAc,SAAS,2BAA2B;;;;;;;;CAQ9D,OAAO;;;;;;;;;;;CAWP,mBAAmB,WAAW;;;;;;;;;;CAU9B,YAAY;;;;;;;;CAQZ;;CAEA,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;CAwBR,YAAY;;;;;;;;;;;;;;;;;;;CAmBZ,WACE,YAAY,YACZ,SAAS,kBACN;AACP;;AAGA,iBAAiB,YAAY;;;;;CAK3B;;;;;;;;CAQA,iBAAiB,gBAAgB;AACnC;;AAGA,iBAAiB,wBAAwB,YAAY;;;;;;CAMnD,UAAU;AACZ;;AAGA,iBAAiB,wBAAwB,KAAK,qBAAqB,SAAS;;CAE1E,OAAO;;CAEP,MAAM;AACR;;UAcU,iBAAiB;UAChB;UACA;UACA,QAAQ,SAAS;UACjB,WAAW,eAAe;UAC1B,cAAc,eAAe;AACxC;;KAGK,gBAAgB,KAAK,gBAAgB,aAAa;;AAGvD,OAAO,cAAM,cACX,QAAQ,aACR,QAAQ,kBACP;;;;;;AAkBH,OAAO,cAAM,iBAAkB,WAAW;;;;;;;AAsB1C,OAAO,cAAM,aACX,MAAM,gBACN,QAAQ,aACR,MAAM,aACN,kBAAkB,WAAW,qBAC7B,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+EV,OAAO,iBAAe,UACpB,SAAS,mBACR,QAAQ","names":[],"ignoreList":[],"sources":["../src/prerender.ts"]}
|
package/dist/prerender.js
CHANGED
|
@@ -3,6 +3,7 @@ import { collectResultSync } from "@lit-labs/ssr/lib/render-result.js";
|
|
|
3
3
|
import { provideRouter, withRouterSync } from "lit-ui-router/context";
|
|
4
4
|
import { isString } from "@uirouter/core";
|
|
5
5
|
import { prerender as prerenderSite } from "ui-router-server/prerender";
|
|
6
|
+
import { dehydrate as dehydrateLanded } from "ui-router-server/ssr";
|
|
6
7
|
import "#dev-gate";
|
|
7
8
|
import { LightElementRenderer } from "./light-element-renderer.js";
|
|
8
9
|
import { responder } from "./respond.js";
|
|
@@ -45,17 +46,36 @@ export const signatureBlock = (signature) => {
|
|
|
45
46
|
const json = JSON.stringify(signature).replaceAll("<", "\\u003c").replaceAll(">", "\\u003e");
|
|
46
47
|
return `<script type="application/json" ${signatureAttribute}>${json}<\/script>`;
|
|
47
48
|
};
|
|
49
|
+
const utf8Length = (text) => new TextEncoder().encode(text).length;
|
|
50
|
+
const payloadBytes = (router, drawn) => utf8Length(signatureBlock(signatureOf(router, drawn))) - utf8Length(signatureBlock(signatureOf(router)));
|
|
48
51
|
export const renderPage = (body, router, root, elementRenderers, drawn) => signatureBlock(signatureOf(router, drawn)) + withRouterSync(router, () => collectResultSync(render(body, {
|
|
49
52
|
eventTargetStack: rootedStack(root),
|
|
50
53
|
elementRenderers,
|
|
51
54
|
deferHydration: true
|
|
52
55
|
})));
|
|
53
56
|
export async function prerender(options) {
|
|
54
|
-
const { router, renderShell, document, elementRenderers = [UiViewRenderer, LightElementRenderer], root = new EventTarget(), write = nodeWrite, payload, responses, origin = "http://lit-ui-router-ssr", ...site } = options;
|
|
55
|
-
|
|
56
|
-
|
|
57
|
+
const { router, renderShell, document, elementRenderers = [UiViewRenderer, LightElementRenderer], root = new EventTarget(), write = nodeWrite, dehydrate: dehydrateOptions, payload, responses, origin = "http://lit-ui-router-ssr", ...site } = options;
|
|
58
|
+
if (dehydrateOptions && payload) throw new Error("prerender: pass `dehydrate` or `payload`, not both; a `payload` hook calls `dehydrate()` itself");
|
|
59
|
+
const draw = (transition, context) => {
|
|
60
|
+
if (dehydrateOptions) return dehydrateLanded(transition, dehydrateOptions);
|
|
61
|
+
return { payload: payload?.(transition, context) };
|
|
62
|
+
};
|
|
63
|
+
const drawLanded = (context) => {
|
|
64
|
+
if (!dehydrateOptions && !payload) return {};
|
|
57
65
|
const landed = router.globals.successfulTransitions.peekTail();
|
|
58
|
-
return landed
|
|
66
|
+
return landed ? draw(landed, context) : {};
|
|
67
|
+
};
|
|
68
|
+
const reports = new Map();
|
|
69
|
+
const renderTemplate = (body, context) => {
|
|
70
|
+
const { payload: drawn, unserializable } = drawLanded(context);
|
|
71
|
+
if (drawn) {
|
|
72
|
+
const bytes = payloadBytes(router, drawn);
|
|
73
|
+
reports.set(context.file, unserializable ? {
|
|
74
|
+
bytes,
|
|
75
|
+
unserializable
|
|
76
|
+
} : { bytes });
|
|
77
|
+
}
|
|
78
|
+
return renderPage(body, router, root, elementRenderers, drawn);
|
|
59
79
|
};
|
|
60
80
|
const renderLit = async (verdict, siteContext) => {
|
|
61
81
|
const context = {
|
|
@@ -63,7 +83,7 @@ export async function prerender(options) {
|
|
|
63
83
|
root
|
|
64
84
|
};
|
|
65
85
|
const body = await renderShell(verdict, context);
|
|
66
|
-
const markup = isString(body) ? body :
|
|
86
|
+
const markup = isString(body) ? body : renderTemplate(body, context);
|
|
67
87
|
return document ? document(markup, context) : markup;
|
|
68
88
|
};
|
|
69
89
|
const uninstall = provideRouter(root, router);
|
|
@@ -72,13 +92,22 @@ export async function prerender(options) {
|
|
|
72
92
|
if (responses === void 0) throw new Error(`prerender: '${path}' matched response state '${verdict.state}'; pass \`responses\` to answer it`);
|
|
73
93
|
return responder(router, responses)(verdict, new Request(new URL(path, origin)));
|
|
74
94
|
};
|
|
95
|
+
const result = await prerenderSite({
|
|
96
|
+
...site,
|
|
97
|
+
render: renderLit,
|
|
98
|
+
respond,
|
|
99
|
+
write
|
|
100
|
+
});
|
|
101
|
+
const pages = result.pages.map((page) => {
|
|
102
|
+
const report = reports.get(page.file);
|
|
103
|
+
return report ? {
|
|
104
|
+
...page,
|
|
105
|
+
payload: report
|
|
106
|
+
} : page;
|
|
107
|
+
});
|
|
75
108
|
return {
|
|
76
|
-
...
|
|
77
|
-
|
|
78
|
-
render: renderLit,
|
|
79
|
-
respond,
|
|
80
|
-
write
|
|
81
|
-
}),
|
|
109
|
+
...result,
|
|
110
|
+
pages,
|
|
82
111
|
root
|
|
83
112
|
};
|
|
84
113
|
} finally {
|
package/dist/prerender.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prerender.js","mappings":"AACA,SAAS,cAAc;AAEvB,SAAS,yBAAyB;AAIlC,SAAS,eAAe,sBAAsB;AAC9C,SAAS,gBAAgB;AAEzB,SAAS,aAAa,qBAAqB;AAQ3C,OAAwB;AAExB,SAAS,4BAA4B;AACrC,SAAS,iBAAiB;AAE1B,SAAS,gBAAgB,SAAS,0BAA0B;AAC5D,SAAS,sBAAsB;AAc/B,MAAM,UAAU;AAWhB,MAAM,SAAS,SAAyB;CACtC,MAAM,MAAM,KAAK,YAAY,GAAG;CAEhC,OAAO,QAAQ,KAAK,KAAK,KAAK,MAAM,GAAG,GAAG;AAC5C;AAEA,MAAM,YAAwB,OAAO,MAAM,SAAS;CAElD,MAAM,EAAE,OAAO,cAAe,MAAM,OAAO;CAC3C,MAAM,MAAM,MAAM,IAAI;CAEtB,IAAI,KAAK,MAAM,MAAM,KAAK,EAAE,WAAW,KAAK,CAAC;CAC7C,MAAM,UAAU,MAAM,MAAM,MAAM;AACpC;
|
|
1
|
+
{"version":3,"file":"prerender.js","mappings":"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","names":[],"ignoreList":[],"sources":["../src/prerender.ts"]}
|
package/dist/signature.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DefType } from "@uirouter/core";
|
|
2
2
|
export const signatureAttribute = "data-lit-ui-router-ssr";
|
|
3
3
|
export const signatureSelector = `script[type="application/json"][${signatureAttribute}]`;
|
|
4
|
-
export const packageVersion = "0.
|
|
4
|
+
export const packageVersion = "0.8.0";
|
|
5
5
|
export const urlParamsOf = (state, params) => Object.fromEntries(state.parameters().flatMap((param) => param.location === DefType.CONFIG ? [] : [[param.id, param.type.encode(params[param.id])]]));
|
|
6
6
|
export const routeOf = ({ $current, params }) => [$current.name, urlParamsOf($current, params)];
|
|
7
7
|
//# sourceMappingURL=signature.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** `@lit-labs/ssr`'s DOM shim: the default for `serverRouterPlugin`'s `shim`. @internal */
|
|
2
|
+
export declare const DOM_SHIM: readonly string[];
|
|
3
|
+
/**
|
|
4
|
+
* The worker's preloads for a Lit app: the shim modules, then
|
|
5
|
+
* `lit-ui-router-ssr/register` in the registry they installed, then the app's
|
|
6
|
+
* own, each once, at its first position.
|
|
7
|
+
*
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
export declare const litPreload: (shim: readonly string[], preload: readonly string[]) => string[];
|
|
11
|
+
//# sourceMappingURL=vite-preload.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vite-preload.d.ts","mappings":";AACA,OAAO,cAAM;;;;;;;;AAWb,OAAO,cAAM,aACX,yBACA","names":[],"ignoreList":[],"sources":["../src/vite-preload.ts"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vite-preload.js","mappings":"AACA,OAAO,MAAM,WAA8B,CACzC,8CACF;AASA,OAAO,MAAM,cACX,MACA,YACa,CACb,GAAG,IAAI,IAAI;CAAC,GAAG;CAAM;CAA8B,GAAG;AAAO,CAAC,CAChE","names":[],"ignoreList":[],"sources":["../src/vite-preload.ts"]}
|
package/dist/vite.d.ts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { PrerenderBuild, PrerenderEntry, ServerRouterPlugin, ServerRouterPluginOptions as SiteRouterPluginOptions } from "ui-router-server/vite";
|
|
2
|
+
import type { ServerRouter } from "ui-router-server";
|
|
3
|
+
import type { PrerenderOptions } from "./prerender.js";
|
|
4
|
+
export type { PrerenderBuild, PrerenderEntry, ServerRouterPlugin } from "ui-router-server/vite";
|
|
5
|
+
/**
|
|
6
|
+
* `ui-router-server/vite`'s plugin options, plus the DOM the prerender
|
|
7
|
+
* worker installs for Lit.
|
|
8
|
+
*/
|
|
9
|
+
export interface ServerRouterPluginOptions extends SiteRouterPluginOptions {
|
|
10
|
+
/**
|
|
11
|
+
* Modules that install a DOM in the prerender worker, loaded in order
|
|
12
|
+
* before `lit-ui-router-ssr/register` and any `preload`. Defaults to
|
|
13
|
+
* `@lit-labs/ssr`'s DOM shim. List another DOM's setup to use it
|
|
14
|
+
* instead, or pass `[]` to install none: Lit's Node build still renders,
|
|
15
|
+
* but app code that reads `document` or `window` fails.
|
|
16
|
+
*/
|
|
17
|
+
shim?: readonly string[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* What a prerender script's callback returns: this package's
|
|
21
|
+
* {@link PrerenderOptions}, less what the build supplies. `outDir` and
|
|
22
|
+
* `write` come from the build, so a script may still pass either to
|
|
23
|
+
* override it.
|
|
24
|
+
*/
|
|
25
|
+
export type PrerenderScriptOptions = Omit<PrerenderOptions, "outDir" | "write"> & Partial<Pick<PrerenderOptions, "outDir" | "write">>;
|
|
26
|
+
/**
|
|
27
|
+
* The callback {@link definePrerender} takes: handed the build's values,
|
|
28
|
+
* such as `shellHtml` for a `document` hook, it returns the prerender
|
|
29
|
+
* options.
|
|
30
|
+
*/
|
|
31
|
+
export type PrerenderScript = (build: PrerenderBuild) => PrerenderScriptOptions | Promise<PrerenderScriptOptions>;
|
|
32
|
+
/**
|
|
33
|
+
* Turns a callback that returns this package's prerender options into a
|
|
34
|
+
* prerender script's default export. The export spreads the build's values
|
|
35
|
+
* (`outDir`, `shellHtml`, `write`) under the options and calls this
|
|
36
|
+
* package's `prerender()`, so the script never calls it itself.
|
|
37
|
+
*
|
|
38
|
+
* @param script - returns the prerender options; handed the build's values
|
|
39
|
+
* @returns the default export for the prerender script
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* export default definePrerender((site) => ({
|
|
44
|
+
* mounts,
|
|
45
|
+
* router,
|
|
46
|
+
* paths: ['/', '/about'],
|
|
47
|
+
* renderShell: async (_verdict, { path }) => {
|
|
48
|
+
* await settle(router, path);
|
|
49
|
+
* return page(router);
|
|
50
|
+
* },
|
|
51
|
+
* document: (body) => site.shellHtml.replace('<!--app-->', body),
|
|
52
|
+
* }));
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export declare function definePrerender(script: PrerenderScript): PrerenderEntry;
|
|
56
|
+
/**
|
|
57
|
+
* `ui-router-server/vite`'s `serverRouterPlugin`, set up for a Lit app: with
|
|
58
|
+
* {@link ServerRouterPluginOptions.prerender | prerender}, the worker loads
|
|
59
|
+
* the {@link ServerRouterPluginOptions.shim | shim}, then
|
|
60
|
+
* `lit-ui-router-ssr/register`, then any `preload` passed here, each once,
|
|
61
|
+
* before the prerender script, so the script imports everything statically. Its default export
|
|
62
|
+
* comes from this module's {@link definePrerender}.
|
|
63
|
+
*
|
|
64
|
+
* `vite dev` and `vite preview` behave as under `ui-router-server/vite`.
|
|
65
|
+
*
|
|
66
|
+
* @param router - the server router the middleware and the build step read
|
|
67
|
+
* @param options - the Connect adapter's options, plus the build step
|
|
68
|
+
* @returns a plugin to spread into `plugins: [...]`
|
|
69
|
+
* @throws from the build step when the script has no default export
|
|
70
|
+
* function, the built `index.html` is missing, or a listed path matches no
|
|
71
|
+
* route
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```ts
|
|
75
|
+
* import { createServerRouter } from 'ui-router-server';
|
|
76
|
+
* import { serverRouterPlugin } from 'lit-ui-router-ssr/vite';
|
|
77
|
+
*
|
|
78
|
+
* plugins: [
|
|
79
|
+
* serverRouterPlugin(createServerRouter({ mounts }), {
|
|
80
|
+
* prerender: './src/prerender.ts',
|
|
81
|
+
* }),
|
|
82
|
+
* ],
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
export declare function serverRouterPlugin(router: ServerRouter, options?: ServerRouterPluginOptions): ServerRouterPlugin;
|
|
86
|
+
//# sourceMappingURL=vite.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vite.d.ts","mappings":"AAeA,cACE,gBACA,gBACA,oBACA,6BAA6B,+BACxB;AACP,cAAc,oBAAoB;AAElC,cAAc,wBAAwB;AAGtC,cACE,gBACA,gBACA,0BACK;;;;;AAMP,iBAAiB,kCAAkC,wBAAwB;;;;;;;;CAQzE;AACF;;;;;;;AAQA,YAAY,yBAAyB,KACnC,kBACA,WAAW,WAEX,QAAQ,KAAK,kBAAkB,WAAW;;;;;;AAO5C,YAAY,mBACV,OAAO,mBACJ,yBAAyB,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;AA4BtC,OAAO,iBAAS,gBAAgB,QAAQ,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8C1D,OAAO,iBAAS,mBACd,QAAQ,cACR,UAAS,4BACR","names":[],"ignoreList":[],"sources":["../src/vite.ts"]}
|
package/dist/vite.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { serverRouterPlugin as siteRouterPlugin } from "ui-router-server/vite";
|
|
2
|
+
import { DOM_SHIM, litPreload } from "./vite-preload.js";
|
|
3
|
+
const loadPrerender = async () => (await import("./prerender.js")).prerender;
|
|
4
|
+
export function definePrerender(script) {
|
|
5
|
+
return async (build) => {
|
|
6
|
+
const [options, prerender] = await Promise.all([script(build), loadPrerender()]);
|
|
7
|
+
const { root: _root, ...result } = await prerender({
|
|
8
|
+
...build,
|
|
9
|
+
...options
|
|
10
|
+
});
|
|
11
|
+
return result;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export function serverRouterPlugin(router, options = {}) {
|
|
15
|
+
const { shim = DOM_SHIM, ...siteOptions } = options;
|
|
16
|
+
const { prerender } = siteOptions;
|
|
17
|
+
if (prerender === void 0) return siteRouterPlugin(router, siteOptions);
|
|
18
|
+
const { entry, preload = [] } = typeof prerender === "string" ? { entry: prerender } : prerender;
|
|
19
|
+
return siteRouterPlugin(router, {
|
|
20
|
+
...siteOptions,
|
|
21
|
+
prerender: {
|
|
22
|
+
entry,
|
|
23
|
+
preload: litPreload(shim, preload)
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=vite.js.map
|
package/dist/vite.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vite.js","mappings":"AAcA,SAAS,sBAAsB,wBAAwB;AAUvD,SAAS,UAAU,kBAAkB;AA6CrC,MAAM,gBAAgB,aAAa,MAAM,OAAO,kBAAiB,CAAE;AAyBnE,OAAO,SAAS,gBAAgB,QAAyC;CACvE,OAAO,OAAO,UAAU;EACtB,MAAM,CAAC,SAAS,aAAa,MAAM,QAAQ,IAAI,CAC7C,OAAO,KAAK,GACZ,cAAc,CAChB,CAAC;EAGD,MAAM,EAAE,MAAM,OAAO,GAAG,WAAW,MAAM,UAAU;GACjD,GAAG;GACH,GAAG;EACL,CAAC;EAED,OAAO;CACT;AACF;AA+BA,OAAO,SAAS,mBACd,QACA,UAAqC,CAAC,GAClB;CACpB,MAAM,EAAE,OAAO,UAAU,GAAG,gBAAgB;CAC5C,MAAM,EAAE,cAAc;CAEtB,IAAI,cAAc,QAAW,OAAO,iBAAiB,QAAQ,WAAW;CAExE,MAAM,EAAE,OAAO,UAAU,CAAC,MAExB,OAAO,cAAc,WAAW,EAAE,OAAO,UAAU,IAAI;CAEzD,OAAO,iBAAiB,QAAQ;EAC9B,GAAG;EACH,WAAW;GAAE;GAAO,SAAS,WAAW,MAAM,OAAO;EAAE;CACzD,CAAC;AACH","names":[],"ignoreList":[],"sources":["../src/vite.ts"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lit-ui-router-ssr",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Static prerendering for lit-ui-router: mount verdicts in, an emitted site out",
|
|
5
5
|
"homepage": "https://lit-ui-router.dev/packages/ssr",
|
|
6
6
|
"bugs": {
|
|
@@ -69,6 +69,14 @@
|
|
|
69
69
|
"deno": "./dist/testing.js",
|
|
70
70
|
"node": "./dist/development/testing.js",
|
|
71
71
|
"default": "./dist/testing.js"
|
|
72
|
+
},
|
|
73
|
+
"./vite": {
|
|
74
|
+
"types": "./dist/vite.d.ts",
|
|
75
|
+
"development": "./dist/development/vite.js",
|
|
76
|
+
"production": "./dist/vite.js",
|
|
77
|
+
"deno": "./dist/vite.js",
|
|
78
|
+
"node": "./dist/development/vite.js",
|
|
79
|
+
"default": "./dist/vite.js"
|
|
72
80
|
}
|
|
73
81
|
},
|
|
74
82
|
"dependencies": {
|
|
@@ -80,7 +88,7 @@
|
|
|
80
88
|
"@uirouter/core": "^6.0.8",
|
|
81
89
|
"lit": "^3.1.2",
|
|
82
90
|
"lit-ui-router": "^1.19.0",
|
|
83
|
-
"ui-router-server": "^0.
|
|
91
|
+
"ui-router-server": "^0.8.0"
|
|
84
92
|
},
|
|
85
93
|
"peerDependenciesMeta": {
|
|
86
94
|
"@lit-labs/ssr-client": {
|
|
@@ -130,6 +138,19 @@
|
|
|
130
138
|
"node:fs",
|
|
131
139
|
"node:path"
|
|
132
140
|
]
|
|
141
|
+
},
|
|
142
|
+
"./vite": {
|
|
143
|
+
"free": [
|
|
144
|
+
"@lit-labs/ssr",
|
|
145
|
+
"@lit-labs/ssr-client",
|
|
146
|
+
"@uirouter/core",
|
|
147
|
+
"lit",
|
|
148
|
+
"lit-ui-router",
|
|
149
|
+
"hono",
|
|
150
|
+
"vite",
|
|
151
|
+
"node:fs",
|
|
152
|
+
"node:path"
|
|
153
|
+
]
|
|
133
154
|
}
|
|
134
155
|
}
|
|
135
156
|
}
|
package/src/index.ts
CHANGED
package/src/prerender.ts
CHANGED
|
@@ -10,12 +10,18 @@ import { isString } from '@uirouter/core';
|
|
|
10
10
|
import type { Verdict } from 'ui-router-server';
|
|
11
11
|
import { prerender as prerenderSite } from 'ui-router-server/prerender';
|
|
12
12
|
import type {
|
|
13
|
+
EmittedPage,
|
|
13
14
|
FileWriter,
|
|
14
15
|
PrerenderOptions as SitePrerenderOptions,
|
|
15
16
|
PrerenderResult as SitePrerenderResult,
|
|
16
17
|
RenderContext as SiteRenderContext,
|
|
17
18
|
} from 'ui-router-server/prerender';
|
|
18
|
-
import
|
|
19
|
+
import { dehydrate as dehydrateLanded } from 'ui-router-server/ssr';
|
|
20
|
+
import type {
|
|
21
|
+
DehydrateOptions,
|
|
22
|
+
DehydrateResult,
|
|
23
|
+
ResolvePayload,
|
|
24
|
+
} from 'ui-router-server/ssr';
|
|
19
25
|
import { devGate } from '#dev-gate';
|
|
20
26
|
|
|
21
27
|
import { LightElementRenderer } from './light-element-renderer.js';
|
|
@@ -138,36 +144,84 @@ export interface PrerenderOptions extends Omit<
|
|
|
138
144
|
/** Writes a file. Defaults to `node:fs`, imported lazily on first write. */
|
|
139
145
|
write?: FileWriter;
|
|
140
146
|
/**
|
|
141
|
-
* Draws
|
|
147
|
+
* Draws each rendered page's resolve payload with `dehydrate` from
|
|
148
|
+
* `ui-router-server/ssr`, called with these options on the transition the
|
|
142
149
|
* router last landed, once `renderShell` has returned a template. The
|
|
143
150
|
* payload's `resolves` go into the page's hydration signature, beside the
|
|
144
151
|
* state and parameters the router stands on, and the client adopts them on
|
|
145
|
-
* boot in place of running those resolve functions.
|
|
146
|
-
*
|
|
152
|
+
* boot in place of running those resolve functions. Pass `{}` to draw every
|
|
153
|
+
* resolve `dehydrate` draws by default. Without this option or
|
|
154
|
+
* {@link PrerenderOptions.payload | `payload`}, no page carries resolves.
|
|
147
155
|
*
|
|
148
|
-
* `dehydrate`
|
|
149
|
-
*
|
|
156
|
+
* `dehydrate`'s documentation says which values it leaves out and how
|
|
157
|
+
* `shouldDehydrate` and `transport` act. The payload's
|
|
150
158
|
* `transported` marks go into the signature too, so a value a transporter
|
|
151
159
|
* carried is rebuilt when `bootstrap()` gets the same `transport`.
|
|
152
160
|
*
|
|
153
161
|
* @example
|
|
154
162
|
* ```ts
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
* console.warn(`${path}: ${state}.${token} re-runs on the client`);
|
|
159
|
-
* return payload;
|
|
163
|
+
* dehydrate: {
|
|
164
|
+
* shouldDehydrate: ({ token }) => token !== 'manifest',
|
|
165
|
+
* transport,
|
|
160
166
|
* },
|
|
161
167
|
* ```
|
|
162
168
|
*/
|
|
169
|
+
dehydrate?: DehydrateOptions;
|
|
170
|
+
/**
|
|
171
|
+
* Draws the resolve payload for a rendered page by hand, in place of
|
|
172
|
+
* {@link PrerenderOptions.dehydrate | `dehydrate`}: handed the transition the
|
|
173
|
+
* router last landed, once `renderShell` has returned a template, it returns
|
|
174
|
+
* the payload the page's signature carries, or `undefined` to write none.
|
|
175
|
+
* Passing both this and `dehydrate` throws.
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* Shape the payload `dehydrate` draws before it is written:
|
|
179
|
+
* ```ts
|
|
180
|
+
* import { dehydrate } from 'ui-router-server/ssr';
|
|
181
|
+
*
|
|
182
|
+
* payload: (transition, { path }) =>
|
|
183
|
+
* path.startsWith('/drafts/')
|
|
184
|
+
* ? undefined
|
|
185
|
+
* : dehydrate(transition, { transport }).payload,
|
|
186
|
+
* ```
|
|
187
|
+
*/
|
|
163
188
|
payload?: (
|
|
164
189
|
transition: Transition,
|
|
165
190
|
context: RenderContext,
|
|
166
191
|
) => ResolvePayload | undefined;
|
|
167
192
|
}
|
|
168
193
|
|
|
194
|
+
/** What a page's hydration signature carries of its resolve payload. */
|
|
195
|
+
export interface PagePayload {
|
|
196
|
+
/**
|
|
197
|
+
* The bytes the payload adds to the page's signature as written: its
|
|
198
|
+
* `resolves` and `transported` members, escaped as the block spells them.
|
|
199
|
+
*/
|
|
200
|
+
bytes: number;
|
|
201
|
+
/**
|
|
202
|
+
* The resolves {@link PrerenderOptions.dehydrate | `dehydrate`} left out of
|
|
203
|
+
* the payload because their value is not plain JSON data and no transporter
|
|
204
|
+
* carries it, each to re-run on the client. Present only when `dehydrate`
|
|
205
|
+
* drew the payload: a {@link PrerenderOptions.payload | `payload`} hook
|
|
206
|
+
* returns the payload alone.
|
|
207
|
+
*/
|
|
208
|
+
unserializable?: DehydrateResult['unserializable'];
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** A page {@link prerender} emitted. */
|
|
212
|
+
export interface PrerenderedPage extends EmittedPage {
|
|
213
|
+
/**
|
|
214
|
+
* What the page's signature carries of its resolve payload. Absent on a page
|
|
215
|
+
* that carries none: one drawn with no payload, one `renderShell` returned
|
|
216
|
+
* as a string, and a response state's body.
|
|
217
|
+
*/
|
|
218
|
+
payload?: PagePayload;
|
|
219
|
+
}
|
|
220
|
+
|
|
169
221
|
/** What {@link prerender} did. */
|
|
170
|
-
export interface PrerenderResult extends SitePrerenderResult {
|
|
222
|
+
export interface PrerenderResult extends Omit<SitePrerenderResult, 'pages'> {
|
|
223
|
+
/** Every page emitted or planned, in enumeration order. */
|
|
224
|
+
pages: PrerenderedPage[];
|
|
171
225
|
/** The root event target, created or passed through. */
|
|
172
226
|
root: EventTarget;
|
|
173
227
|
}
|
|
@@ -225,6 +279,14 @@ export const signatureBlock = (signature: WrittenSignature): string => {
|
|
|
225
279
|
return `<script type="application/json" ${signatureAttribute}>${json}</script>`;
|
|
226
280
|
};
|
|
227
281
|
|
|
282
|
+
const utf8Length = (text: string): number =>
|
|
283
|
+
new TextEncoder().encode(text).length;
|
|
284
|
+
|
|
285
|
+
/** The bytes `drawn` adds to the signature of the page `router` stands on. */
|
|
286
|
+
const payloadBytes = (router: UIRouterLit, drawn: DrawnResolves): number =>
|
|
287
|
+
utf8Length(signatureBlock(signatureOf(router, drawn))) -
|
|
288
|
+
utf8Length(signatureBlock(signatureOf(router)));
|
|
289
|
+
|
|
228
290
|
/**
|
|
229
291
|
* Renders one page: the signature first, then the render, so the client reads
|
|
230
292
|
* the one before it hydrates the other.
|
|
@@ -258,7 +320,7 @@ const warnUnregistered = (): void => {
|
|
|
258
320
|
if (globalThis.customElements?.get('ui-view')) return;
|
|
259
321
|
console.warn(
|
|
260
322
|
'lit-ui-router-ssr: <ui-view> is not defined on the current customElements registry, so every <ui-view> on these pages renders empty. ' +
|
|
261
|
-
'The DOM shim replaces the registry when it finishes installing: load lit-ui-router-ssr/register by dynamic import after the shim, or preload the shim with node --import.',
|
|
323
|
+
'The DOM shim replaces the registry when it finishes installing: prerender through serverRouterPlugin from lit-ui-router-ssr/vite, which preloads both, load lit-ui-router-ssr/register by dynamic import after the shim, or preload the shim with node --import.',
|
|
262
324
|
);
|
|
263
325
|
};
|
|
264
326
|
|
|
@@ -279,9 +341,12 @@ const warnUnregistered = (): void => {
|
|
|
279
341
|
* A rendered page opens on its hydration signature: a JSON data block,
|
|
280
342
|
* `<script type="application/json" data-lit-ui-router-ssr>`, naming this
|
|
281
343
|
* package's version and the state and parameter values the router stood on,
|
|
282
|
-
* which `hydrateRoot()` reads before it touches the document.
|
|
283
|
-
* {@link PrerenderOptions.
|
|
284
|
-
*
|
|
344
|
+
* which `hydrateRoot()` reads before it touches the document.
|
|
345
|
+
* {@link PrerenderOptions.dehydrate | `dehydrate`}, or a
|
|
346
|
+
* {@link PrerenderOptions.payload | `payload`} hook, adds the resolved values
|
|
347
|
+
* the page was drawn with, which `bootstrap()` adopts; the page's entry in
|
|
348
|
+
* the result's `pages` reports the bytes they add and, from `dehydrate`, the
|
|
349
|
+
* resolves left to re-run on the client. A `renderShell`
|
|
285
350
|
* that returns a string is written as-is, with no signature, so the client
|
|
286
351
|
* renders it cold.
|
|
287
352
|
*
|
|
@@ -295,6 +360,7 @@ const warnUnregistered = (): void => {
|
|
|
295
360
|
* @returns what was emitted, planned or written
|
|
296
361
|
* @throws an `Error` when neither `mounts` nor `resolver` is supplied
|
|
297
362
|
* @throws an `Error` when the 404 document needs a default probe and only a `resolver` is supplied
|
|
363
|
+
* @throws an `Error` when both `dehydrate` and `payload` are supplied
|
|
298
364
|
*
|
|
299
365
|
* @example
|
|
300
366
|
* ```ts
|
|
@@ -321,23 +387,58 @@ export async function prerender(
|
|
|
321
387
|
elementRenderers = [UiViewRenderer, LightElementRenderer],
|
|
322
388
|
root = new EventTarget(),
|
|
323
389
|
write = nodeWrite,
|
|
390
|
+
dehydrate: dehydrateOptions,
|
|
324
391
|
payload,
|
|
325
392
|
responses,
|
|
326
393
|
origin = 'http://lit-ui-router-ssr',
|
|
327
394
|
...site
|
|
328
395
|
} = options;
|
|
329
396
|
|
|
397
|
+
if (dehydrateOptions && payload)
|
|
398
|
+
throw new Error(
|
|
399
|
+
'prerender: pass `dehydrate` or `payload`, not both; a `payload` hook calls `dehydrate()` itself',
|
|
400
|
+
);
|
|
401
|
+
|
|
330
402
|
warnUnregistered();
|
|
331
403
|
|
|
332
|
-
const
|
|
333
|
-
|
|
404
|
+
const draw = (
|
|
405
|
+
transition: Transition,
|
|
406
|
+
context: RenderContext,
|
|
407
|
+
): Partial<DehydrateResult> => {
|
|
408
|
+
if (dehydrateOptions) return dehydrateLanded(transition, dehydrateOptions);
|
|
409
|
+
|
|
410
|
+
return { payload: payload?.(transition, context) };
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
const drawLanded = (context: RenderContext): Partial<DehydrateResult> => {
|
|
414
|
+
if (!dehydrateOptions && !payload) return {};
|
|
334
415
|
|
|
335
416
|
// SAFETY: `peekTail()` is typed `Transition` and returns `undefined` on an empty queue.
|
|
336
417
|
const landed = router.globals.successfulTransitions.peekTail() as
|
|
337
418
|
| Transition
|
|
338
419
|
| undefined;
|
|
339
420
|
|
|
340
|
-
return landed
|
|
421
|
+
return landed ? draw(landed, context) : {};
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
const reports = new Map<string, PagePayload>();
|
|
425
|
+
|
|
426
|
+
const renderTemplate = (
|
|
427
|
+
body: TemplateResult,
|
|
428
|
+
context: RenderContext,
|
|
429
|
+
): string => {
|
|
430
|
+
const { payload: drawn, unserializable } = drawLanded(context);
|
|
431
|
+
|
|
432
|
+
if (drawn) {
|
|
433
|
+
const bytes = payloadBytes(router, drawn);
|
|
434
|
+
|
|
435
|
+
reports.set(
|
|
436
|
+
context.file,
|
|
437
|
+
unserializable ? { bytes, unserializable } : { bytes },
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
return renderPage(body, router, root, elementRenderers, drawn);
|
|
341
442
|
};
|
|
342
443
|
|
|
343
444
|
const renderLit = async (
|
|
@@ -347,9 +448,7 @@ export async function prerender(
|
|
|
347
448
|
const context: RenderContext = { ...siteContext, root };
|
|
348
449
|
const body = await renderShell(verdict, context);
|
|
349
450
|
|
|
350
|
-
const markup = isString(body)
|
|
351
|
-
? body
|
|
352
|
-
: renderPage(body, router, root, elementRenderers, payloadOf(context));
|
|
451
|
+
const markup = isString(body) ? body : renderTemplate(body, context);
|
|
353
452
|
|
|
354
453
|
return document ? document(markup, context) : markup;
|
|
355
454
|
};
|
|
@@ -379,7 +478,13 @@ export async function prerender(
|
|
|
379
478
|
write,
|
|
380
479
|
});
|
|
381
480
|
|
|
382
|
-
|
|
481
|
+
const pages = result.pages.map((page): PrerenderedPage => {
|
|
482
|
+
const report = reports.get(page.file);
|
|
483
|
+
|
|
484
|
+
return report ? { ...page, payload: report } : page;
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
return { ...result, pages, root };
|
|
383
488
|
} finally {
|
|
384
489
|
uninstall();
|
|
385
490
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** `@lit-labs/ssr`'s DOM shim: the default for `serverRouterPlugin`'s `shim`. @internal */
|
|
2
|
+
export const DOM_SHIM: readonly string[] = [
|
|
3
|
+
'@lit-labs/ssr/lib/install-global-dom-shim.js',
|
|
4
|
+
];
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The worker's preloads for a Lit app: the shim modules, then
|
|
8
|
+
* `lit-ui-router-ssr/register` in the registry they installed, then the app's
|
|
9
|
+
* own, each once, at its first position.
|
|
10
|
+
*
|
|
11
|
+
* @internal
|
|
12
|
+
*/
|
|
13
|
+
export const litPreload = (
|
|
14
|
+
shim: readonly string[],
|
|
15
|
+
preload: readonly string[],
|
|
16
|
+
): string[] => [
|
|
17
|
+
...new Set([...shim, 'lit-ui-router-ssr/register', ...preload]),
|
|
18
|
+
];
|
package/src/vite.ts
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Vite plugin for a Lit app: `ui-router-server/vite`'s
|
|
3
|
+
* `serverRouterPlugin`, with the prerender worker set up for Lit. It names
|
|
4
|
+
* a DOM shim (`@lit-labs/ssr`'s by default) and `lit-ui-router-ssr/register` as preloads, so
|
|
5
|
+
* the prerender script imports the app, the router and this package
|
|
6
|
+
* statically, and `definePrerender` calls this package's `prerender()` with
|
|
7
|
+
* the options the script returns.
|
|
8
|
+
*
|
|
9
|
+
* Nothing here imports Lit, `@lit-labs/ssr` or Vite, so `vite.config.ts`
|
|
10
|
+
* loads it without defining an element or installing a global in Vite's
|
|
11
|
+
* process.
|
|
12
|
+
*
|
|
13
|
+
* @module
|
|
14
|
+
*/
|
|
15
|
+
import { serverRouterPlugin as siteRouterPlugin } from 'ui-router-server/vite';
|
|
16
|
+
import type {
|
|
17
|
+
PrerenderBuild,
|
|
18
|
+
PrerenderEntry,
|
|
19
|
+
ServerRouterPlugin,
|
|
20
|
+
ServerRouterPluginOptions as SiteRouterPluginOptions,
|
|
21
|
+
} from 'ui-router-server/vite';
|
|
22
|
+
import type { ServerRouter } from 'ui-router-server';
|
|
23
|
+
|
|
24
|
+
import type { PrerenderOptions } from './prerender.js';
|
|
25
|
+
import { DOM_SHIM, litPreload } from './vite-preload.js';
|
|
26
|
+
|
|
27
|
+
export type {
|
|
28
|
+
PrerenderBuild,
|
|
29
|
+
PrerenderEntry,
|
|
30
|
+
ServerRouterPlugin,
|
|
31
|
+
} from 'ui-router-server/vite';
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* `ui-router-server/vite`'s plugin options, plus the DOM the prerender
|
|
35
|
+
* worker installs for Lit.
|
|
36
|
+
*/
|
|
37
|
+
export interface ServerRouterPluginOptions extends SiteRouterPluginOptions {
|
|
38
|
+
/**
|
|
39
|
+
* Modules that install a DOM in the prerender worker, loaded in order
|
|
40
|
+
* before `lit-ui-router-ssr/register` and any `preload`. Defaults to
|
|
41
|
+
* `@lit-labs/ssr`'s DOM shim. List another DOM's setup to use it
|
|
42
|
+
* instead, or pass `[]` to install none: Lit's Node build still renders,
|
|
43
|
+
* but app code that reads `document` or `window` fails.
|
|
44
|
+
*/
|
|
45
|
+
shim?: readonly string[];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* What a prerender script's callback returns: this package's
|
|
50
|
+
* {@link PrerenderOptions}, less what the build supplies. `outDir` and
|
|
51
|
+
* `write` come from the build, so a script may still pass either to
|
|
52
|
+
* override it.
|
|
53
|
+
*/
|
|
54
|
+
export type PrerenderScriptOptions = Omit<
|
|
55
|
+
PrerenderOptions,
|
|
56
|
+
'outDir' | 'write'
|
|
57
|
+
> &
|
|
58
|
+
Partial<Pick<PrerenderOptions, 'outDir' | 'write'>>;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* The callback {@link definePrerender} takes: handed the build's values,
|
|
62
|
+
* such as `shellHtml` for a `document` hook, it returns the prerender
|
|
63
|
+
* options.
|
|
64
|
+
*/
|
|
65
|
+
export type PrerenderScript = (
|
|
66
|
+
build: PrerenderBuild,
|
|
67
|
+
) => PrerenderScriptOptions | Promise<PrerenderScriptOptions>;
|
|
68
|
+
|
|
69
|
+
// Loaded on call, inside the worker: the plugin's process never evaluates lit.
|
|
70
|
+
const loadPrerender = async () => (await import('./prerender.js')).prerender;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Turns a callback that returns this package's prerender options into a
|
|
74
|
+
* prerender script's default export. The export spreads the build's values
|
|
75
|
+
* (`outDir`, `shellHtml`, `write`) under the options and calls this
|
|
76
|
+
* package's `prerender()`, so the script never calls it itself.
|
|
77
|
+
*
|
|
78
|
+
* @param script - returns the prerender options; handed the build's values
|
|
79
|
+
* @returns the default export for the prerender script
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```ts
|
|
83
|
+
* export default definePrerender((site) => ({
|
|
84
|
+
* mounts,
|
|
85
|
+
* router,
|
|
86
|
+
* paths: ['/', '/about'],
|
|
87
|
+
* renderShell: async (_verdict, { path }) => {
|
|
88
|
+
* await settle(router, path);
|
|
89
|
+
* return page(router);
|
|
90
|
+
* },
|
|
91
|
+
* document: (body) => site.shellHtml.replace('<!--app-->', body),
|
|
92
|
+
* }));
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
export function definePrerender(script: PrerenderScript): PrerenderEntry {
|
|
96
|
+
return async (build) => {
|
|
97
|
+
const [options, prerender] = await Promise.all([
|
|
98
|
+
script(build),
|
|
99
|
+
loadPrerender(),
|
|
100
|
+
]);
|
|
101
|
+
|
|
102
|
+
// `root` is an event target, which the worker can't post back.
|
|
103
|
+
const { root: _root, ...result } = await prerender({
|
|
104
|
+
...build,
|
|
105
|
+
...options,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
return result;
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* `ui-router-server/vite`'s `serverRouterPlugin`, set up for a Lit app: with
|
|
114
|
+
* {@link ServerRouterPluginOptions.prerender | prerender}, the worker loads
|
|
115
|
+
* the {@link ServerRouterPluginOptions.shim | shim}, then
|
|
116
|
+
* `lit-ui-router-ssr/register`, then any `preload` passed here, each once,
|
|
117
|
+
* before the prerender script, so the script imports everything statically. Its default export
|
|
118
|
+
* comes from this module's {@link definePrerender}.
|
|
119
|
+
*
|
|
120
|
+
* `vite dev` and `vite preview` behave as under `ui-router-server/vite`.
|
|
121
|
+
*
|
|
122
|
+
* @param router - the server router the middleware and the build step read
|
|
123
|
+
* @param options - the Connect adapter's options, plus the build step
|
|
124
|
+
* @returns a plugin to spread into `plugins: [...]`
|
|
125
|
+
* @throws from the build step when the script has no default export
|
|
126
|
+
* function, the built `index.html` is missing, or a listed path matches no
|
|
127
|
+
* route
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* ```ts
|
|
131
|
+
* import { createServerRouter } from 'ui-router-server';
|
|
132
|
+
* import { serverRouterPlugin } from 'lit-ui-router-ssr/vite';
|
|
133
|
+
*
|
|
134
|
+
* plugins: [
|
|
135
|
+
* serverRouterPlugin(createServerRouter({ mounts }), {
|
|
136
|
+
* prerender: './src/prerender.ts',
|
|
137
|
+
* }),
|
|
138
|
+
* ],
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
export function serverRouterPlugin(
|
|
142
|
+
router: ServerRouter,
|
|
143
|
+
options: ServerRouterPluginOptions = {},
|
|
144
|
+
): ServerRouterPlugin {
|
|
145
|
+
const { shim = DOM_SHIM, ...siteOptions } = options;
|
|
146
|
+
const { prerender } = siteOptions;
|
|
147
|
+
|
|
148
|
+
if (prerender === undefined) return siteRouterPlugin(router, siteOptions);
|
|
149
|
+
|
|
150
|
+
const { entry, preload = [] } =
|
|
151
|
+
// oxlint-disable-next-line anti-slop/no-runtime-typeof -- the option's own union: a string is shorthand for `{ entry }`
|
|
152
|
+
typeof prerender === 'string' ? { entry: prerender } : prerender;
|
|
153
|
+
|
|
154
|
+
return siteRouterPlugin(router, {
|
|
155
|
+
...siteOptions,
|
|
156
|
+
prerender: { entry, preload: litPreload(shim, preload) },
|
|
157
|
+
});
|
|
158
|
+
}
|