@ecopages/lit 0.2.1 → 0.3.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 +35 -17
- package/package.json +15 -4
- package/src/STATIC_RENDER.md +75 -0
- package/src/console.d.ts +0 -1
- package/src/console.js +12 -6
- package/src/dom-shim.d.ts +11 -0
- package/src/dom-shim.js +60 -0
- package/src/lit-element-hydrate.d.ts +10 -0
- package/src/lit-element-hydrate.js +11 -4
- package/src/lit-renderer.d.ts +18 -60
- package/src/lit-renderer.js +110 -278
- package/src/lit-static-render-protocol.d.ts +40 -0
- package/src/lit-static-render-protocol.js +1 -0
- package/src/lit-static-render-result.d.ts +10 -0
- package/src/lit-static-render-result.js +21 -0
- package/src/lit-static-render-session.d.ts +65 -0
- package/src/lit-static-render-session.js +145 -0
- package/src/lit-static-render-worker-client.d.ts +26 -0
- package/src/lit-static-render-worker-client.js +181 -0
- package/src/lit-static-render-worker.d.ts +1 -0
- package/src/lit-static-render-worker.js +111 -0
- package/src/lit.constants.d.ts +1 -0
- package/src/lit.constants.js +1 -0
- package/src/lit.plugin.d.ts +36 -3
- package/src/lit.plugin.js +138 -47
- package/src/styled-mixin.js +20 -12
- package/src/utils/lit-html-rendering.d.ts +5 -0
- package/src/utils/lit-html-rendering.js +45 -0
- package/CHANGELOG.md +0 -19
- package/src/lit-ssr-lazy-preloader.d.ts +0 -43
- package/src/lit-ssr-lazy-preloader.js +0 -160
package/src/lit-renderer.js
CHANGED
|
@@ -1,284 +1,116 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
1
|
+
/**
|
|
2
|
+
* This module contains the Lit renderer hooks.
|
|
3
|
+
* @module
|
|
4
|
+
*/
|
|
5
|
+
import { createIntegrationRenderer } from '@ecopages/core/integration';
|
|
6
|
+
import { resolveQueuedTokens } from '@ecopages/core/integration';
|
|
7
|
+
import { CUSTOM_ELEMENT_SSR_PRELOAD_CACHE_SCOPES, CustomElementScriptPreloader, } from '@ecopages/core/integration';
|
|
8
|
+
import { requireAppRuntime } from '@ecopages/core/integration';
|
|
9
|
+
import { createCustomElementServerModuleImporter } from '@ecopages/core/integration';
|
|
10
|
+
import { ensureLitDomShim } from './dom-shim.js';
|
|
11
|
+
import { LIT_PLUGIN_NAME } from './lit.constants.js';
|
|
12
|
+
import { injectLitRenderedChildren, LIT_COMPONENT_CHILDREN_SLOT_MARKER, normalizeLitHtml, renderLitValueToString, } from './utils/lit-html-rendering.js';
|
|
13
|
+
/**
|
|
14
|
+
* Creates the Lit renderer class with a lazy worker-session lookup.
|
|
15
|
+
*
|
|
16
|
+
* @remarks
|
|
17
|
+
* The plugin may create its renderer before `setup()` assigns the static render session, so hooks read the
|
|
18
|
+
* session when they run instead of capturing its construction-time value.
|
|
19
|
+
*/
|
|
20
|
+
export function createLitRenderer(getRenderSession = () => undefined) {
|
|
21
|
+
return createIntegrationRenderer(LIT_PLUGIN_NAME, ({ appConfig, resolveComponentDependencies, resolveDependencyPath }) => {
|
|
22
|
+
const ssrScriptPreloader = new CustomElementScriptPreloader({
|
|
23
|
+
cacheScope: CUSTOM_ELEMENT_SSR_PRELOAD_CACHE_SCOPES.lit,
|
|
24
|
+
preloadScopes: requireAppRuntime(appConfig).customElementSsrPreloadScopes,
|
|
25
|
+
logLabel: 'lit',
|
|
26
|
+
requireLazyScriptEntry: true,
|
|
27
|
+
resolveDependencyPath,
|
|
28
|
+
importServerModule: createCustomElementServerModuleImporter(appConfig, '.lit-ssr'),
|
|
29
|
+
});
|
|
30
|
+
const preloadSsrScripts = async (components) => {
|
|
31
|
+
ensureLitDomShim();
|
|
32
|
+
const renderSession = getRenderSession();
|
|
33
|
+
if (renderSession) {
|
|
34
|
+
await renderSession.preloadSsrScripts(components);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
await ssrScriptPreloader.preloadSsrScripts(components);
|
|
38
|
+
};
|
|
37
39
|
return {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
+
beforeRender: async (renderOptions) => preloadSsrScripts([
|
|
41
|
+
renderOptions.Page,
|
|
42
|
+
renderOptions.Layout,
|
|
43
|
+
...(renderOptions.pageDependencyComponents ?? []),
|
|
44
|
+
]),
|
|
45
|
+
transformDocumentHtml: normalizeLitHtml,
|
|
46
|
+
renderRemote: (routeOptions) => renderLitPageInWorker(routeOptions, getRenderSession),
|
|
47
|
+
renderComponent: async (input) => {
|
|
48
|
+
await preloadSsrScripts([input.component]);
|
|
49
|
+
if (!isFunctionComponent(input.component)) {
|
|
50
|
+
throw new TypeError('Lit renderer expected a callable component.');
|
|
51
|
+
}
|
|
52
|
+
const component = input.component;
|
|
53
|
+
let renderedChildren;
|
|
54
|
+
if (input.children !== undefined) {
|
|
55
|
+
renderedChildren =
|
|
56
|
+
typeof input.children === 'string'
|
|
57
|
+
? input.children
|
|
58
|
+
: await renderLitValueToString(input.children);
|
|
59
|
+
}
|
|
60
|
+
const props = renderedChildren === undefined
|
|
61
|
+
? input.props
|
|
62
|
+
: {
|
|
63
|
+
...input.props,
|
|
64
|
+
children: LIT_COMPONENT_CHILDREN_SLOT_MARKER,
|
|
65
|
+
};
|
|
66
|
+
const content = await component(props);
|
|
67
|
+
const renderedHtml = await renderLitValueToString(content);
|
|
68
|
+
const html = renderedChildren === undefined
|
|
69
|
+
? renderedHtml
|
|
70
|
+
: injectLitRenderedChildren(renderedHtml, renderedChildren);
|
|
71
|
+
const assets = input.component.config?.dependencies
|
|
72
|
+
? await resolveComponentDependencies([input.component])
|
|
73
|
+
: undefined;
|
|
74
|
+
return {
|
|
75
|
+
html,
|
|
76
|
+
canAttachAttributes: true,
|
|
77
|
+
integrationName: LIT_PLUGIN_NAME,
|
|
78
|
+
assets,
|
|
79
|
+
};
|
|
80
|
+
},
|
|
81
|
+
renderQueuedChildren: async (children, _runtimeContext, queuedResolutionsByToken, resolveToken) => {
|
|
82
|
+
if (children === undefined) {
|
|
83
|
+
return {};
|
|
84
|
+
}
|
|
85
|
+
if (typeof children !== 'string') {
|
|
86
|
+
return { children };
|
|
87
|
+
}
|
|
88
|
+
return { html: await resolveQueuedTokens(children, queuedResolutionsByToken, resolveToken) };
|
|
89
|
+
},
|
|
40
90
|
};
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
return {
|
|
44
|
-
html: queuedBoundaryResolution.html,
|
|
45
|
-
assets: queuedBoundaryResolution.assets.length > 0 ? queuedBoundaryResolution.assets : void 0
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
normalizeDeclarativeShadowRootMarkup(markup) {
|
|
49
|
-
return markup.replace(DUPLICATE_DECLARATIVE_SHADOW_ROOT_ATTRIBUTE, "");
|
|
50
|
-
}
|
|
51
|
-
createRenderableMarkup(markup) {
|
|
52
|
-
return staticHtml`${unsafeStatic(markup)}`;
|
|
53
|
-
}
|
|
54
|
-
shouldRenderPageComponent() {
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
57
|
-
async renderMarkupToString(markup) {
|
|
58
|
-
let renderedHtml = "";
|
|
59
|
-
for (const chunk of render(this.createRenderableMarkup(markup))) {
|
|
60
|
-
renderedHtml += chunk;
|
|
61
|
-
}
|
|
62
|
-
return this.normalizeDeclarativeShadowRootMarkup(renderedHtml);
|
|
63
|
-
}
|
|
64
|
-
async renderValueToString(value) {
|
|
65
|
-
if (typeof value === "string") {
|
|
66
|
-
return await this.renderMarkupToString(value);
|
|
67
|
-
}
|
|
68
|
-
let renderedHtml = "";
|
|
69
|
-
for (const chunk of render(value)) {
|
|
70
|
-
renderedHtml += chunk;
|
|
71
|
-
}
|
|
72
|
-
return this.normalizeDeclarativeShadowRootMarkup(renderedHtml);
|
|
73
|
-
}
|
|
74
|
-
isLitManagedComponent(component) {
|
|
75
|
-
return component?.config?.integration === this.name || component?.config?.__eco?.integration === this.name;
|
|
76
|
-
}
|
|
77
|
-
injectRenderedChildren(template, renderedChildren) {
|
|
78
|
-
for (const marker of [
|
|
79
|
-
COMPONENT_CHILDREN_SLOT_MARKER,
|
|
80
|
-
ESCAPED_COMPONENT_CHILDREN_SLOT_MARKER,
|
|
81
|
-
DOUBLE_ESCAPED_COMPONENT_CHILDREN_SLOT_MARKER
|
|
82
|
-
]) {
|
|
83
|
-
if (template.includes(marker)) {
|
|
84
|
-
return template.split(marker).join(renderedChildren);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
if (template.includes(HTML_TEMPLATE_SLOT_MARKER)) {
|
|
88
|
-
return template.split(HTML_TEMPLATE_SLOT_MARKER).join(renderedChildren);
|
|
89
|
-
}
|
|
90
|
-
if (template.includes("</body>")) {
|
|
91
|
-
return template.replace("</body>", `${renderedChildren}</body>`);
|
|
92
|
-
}
|
|
93
|
-
if (template.includes("</html>")) {
|
|
94
|
-
return template.replace("</html>", `${renderedChildren}</html>`);
|
|
95
|
-
}
|
|
96
|
-
return `${template}${renderedChildren}`;
|
|
97
|
-
}
|
|
98
|
-
async renderHtmlTemplate(options) {
|
|
99
|
-
if (!options.isLitManagedHtmlTemplate) {
|
|
100
|
-
return String(
|
|
101
|
-
await options.HtmlTemplate({
|
|
102
|
-
metadata: options.metadata,
|
|
103
|
-
children: options.renderedChildren,
|
|
104
|
-
pageProps: options.pageProps
|
|
105
|
-
})
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
const template = await options.HtmlTemplate({
|
|
109
|
-
metadata: options.metadata,
|
|
110
|
-
children: HTML_TEMPLATE_SLOT_MARKER,
|
|
111
|
-
pageProps: options.pageProps
|
|
112
91
|
});
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
if (input.children !== void 0) {
|
|
129
|
-
renderedChildren = typeof input.children === "string" ? input.children : await this.renderValueToString(input.children);
|
|
130
|
-
}
|
|
131
|
-
let props = input.props;
|
|
132
|
-
if (renderedChildren !== void 0) {
|
|
133
|
-
props = {
|
|
134
|
-
...input.props,
|
|
135
|
-
children: COMPONENT_CHILDREN_SLOT_MARKER
|
|
136
|
-
};
|
|
92
|
+
}
|
|
93
|
+
export const LitRenderer = createLitRenderer();
|
|
94
|
+
function isFunctionComponent(component) {
|
|
95
|
+
return typeof component === 'function';
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Renders a Lit page route in its build-scoped worker when request data can cross the worker boundary.
|
|
99
|
+
*
|
|
100
|
+
* @remarks
|
|
101
|
+
* Locals and explicit props stay in-process: locals are request objects, and the worker re-imports the route module.
|
|
102
|
+
*/
|
|
103
|
+
async function renderLitPageInWorker(options, getRenderSession) {
|
|
104
|
+
const renderSession = getRenderSession();
|
|
105
|
+
if (!renderSession || options.locals !== undefined || options.props !== undefined) {
|
|
106
|
+
return undefined;
|
|
137
107
|
}
|
|
138
|
-
const
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
this.getQueuedBoundaryRuntime(input)
|
|
144
|
-
);
|
|
145
|
-
const hasDependencies = Boolean(input.component.config?.dependencies);
|
|
146
|
-
const canResolveAssets = typeof this.assetProcessingService?.processDependencies === "function";
|
|
147
|
-
const assets = hasDependencies && canResolveAssets ? await this.processComponentDependencies([input.component]) : void 0;
|
|
148
|
-
return {
|
|
149
|
-
html: queuedBoundaryResolution.html,
|
|
150
|
-
canAttachAttributes: true,
|
|
151
|
-
rootTag: this.getRootTagName(queuedBoundaryResolution.html),
|
|
152
|
-
integrationName: this.name,
|
|
153
|
-
assets: this.htmlTransformer.dedupeProcessedAssets([
|
|
154
|
-
...assets ?? [],
|
|
155
|
-
...queuedBoundaryResolution.assets ?? []
|
|
156
|
-
])
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
createComponentBoundaryRuntime(options) {
|
|
160
|
-
return this.createQueuedBoundaryRuntime({
|
|
161
|
-
boundaryInput: options.boundaryInput,
|
|
162
|
-
rendererCache: options.rendererCache
|
|
108
|
+
const params = options.params ?? {};
|
|
109
|
+
const result = await renderSession.renderPageInWorker({
|
|
110
|
+
filePath: options.file,
|
|
111
|
+
params,
|
|
112
|
+
query: options.query,
|
|
163
113
|
});
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
resolveDependencyPath: this.resolveDependencyPath.bind(this),
|
|
167
|
-
processDependencies: this.assetProcessingService?.processDependencies?.bind(this.assetProcessingService)
|
|
168
|
-
});
|
|
169
|
-
/**
|
|
170
|
-
* Detects preload failures that are expected for browser-only modules.
|
|
171
|
-
*
|
|
172
|
-
* These errors are treated as non-fatal during SSR preload because some
|
|
173
|
-
* lazy client scripts intentionally depend on browser globals.
|
|
174
|
-
*/
|
|
175
|
-
isExpectedSsrPreloadError(error) {
|
|
176
|
-
return this.ssrLazyPreloader.isExpectedSsrPreloadError(error);
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* Collects lazy script file paths eligible for SSR preloading.
|
|
180
|
-
*
|
|
181
|
-
* Only per-entry lazy script dependencies with `ssr: true` are collected.
|
|
182
|
-
* File-backed entries are required (`src` must be present);
|
|
183
|
-
* inline content lazy entries are intentionally skipped.
|
|
184
|
-
*/
|
|
185
|
-
collectSsrPreloadScripts(components) {
|
|
186
|
-
return this.ssrLazyPreloader.collectSsrPreloadScripts(components);
|
|
187
|
-
}
|
|
188
|
-
/**
|
|
189
|
-
* Preloads SSR-eligible lazy scripts to register custom elements before render.
|
|
190
|
-
*/
|
|
191
|
-
async preloadSsrLazyScripts(components) {
|
|
192
|
-
await this.ssrLazyPreloader.preloadSsrLazyScripts(components);
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* Resolves the concrete JS entrypoint used for SSR preloading.
|
|
196
|
-
*
|
|
197
|
-
* Scripts are passed through the asset pipeline so preload imports can use
|
|
198
|
-
* the same processed output shape as runtime dependencies.
|
|
199
|
-
*/
|
|
200
|
-
async resolveSsrPreloadEntrypoint(scriptPath) {
|
|
201
|
-
return this.ssrLazyPreloader.resolveSsrPreloadEntrypoint(scriptPath);
|
|
202
|
-
}
|
|
203
|
-
async render({
|
|
204
|
-
params,
|
|
205
|
-
query,
|
|
206
|
-
props,
|
|
207
|
-
locals,
|
|
208
|
-
metadata,
|
|
209
|
-
Page,
|
|
210
|
-
Layout,
|
|
211
|
-
HtmlTemplate
|
|
212
|
-
}) {
|
|
213
|
-
try {
|
|
214
|
-
await this.preloadSsrLazyScripts([Page, Layout]);
|
|
215
|
-
return await this.renderPageWithDocumentShell({
|
|
216
|
-
page: {
|
|
217
|
-
component: Page,
|
|
218
|
-
props: {
|
|
219
|
-
params,
|
|
220
|
-
query,
|
|
221
|
-
...props,
|
|
222
|
-
locals
|
|
223
|
-
}
|
|
224
|
-
},
|
|
225
|
-
layout: Layout ? {
|
|
226
|
-
component: Layout,
|
|
227
|
-
props: locals ? { locals } : {}
|
|
228
|
-
} : void 0,
|
|
229
|
-
htmlTemplate: HtmlTemplate,
|
|
230
|
-
metadata,
|
|
231
|
-
pageProps: props || {},
|
|
232
|
-
transformDocumentHtml: (html) => this.normalizeDeclarativeShadowRootMarkup(html)
|
|
233
|
-
});
|
|
234
|
-
} catch (error) {
|
|
235
|
-
throw this.createRenderError("Error rendering page", error);
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
async renderToResponse(view, props, ctx) {
|
|
239
|
-
try {
|
|
240
|
-
if (ctx.partial) {
|
|
241
|
-
return this.renderPartialViewResponse({
|
|
242
|
-
view,
|
|
243
|
-
props,
|
|
244
|
-
ctx,
|
|
245
|
-
transformHtml: (html) => this.normalizeDeclarativeShadowRootMarkup(html)
|
|
246
|
-
});
|
|
247
|
-
}
|
|
248
|
-
const viewConfig = view.config;
|
|
249
|
-
const Layout = viewConfig?.layout;
|
|
250
|
-
const HtmlTemplate = await this.getHtmlTemplate();
|
|
251
|
-
const metadata = await this.resolveViewMetadata(view, props);
|
|
252
|
-
await this.preloadSsrLazyScripts([view, Layout]);
|
|
253
|
-
await this.prepareViewDependencies(view, Layout);
|
|
254
|
-
const pageRender = await this.renderComponentBoundary({
|
|
255
|
-
component: view,
|
|
256
|
-
props: props ?? {}
|
|
257
|
-
});
|
|
258
|
-
const layoutRender = Layout ? await this.renderComponentBoundary({
|
|
259
|
-
component: Layout,
|
|
260
|
-
props: {},
|
|
261
|
-
children: pageRender.html
|
|
262
|
-
}) : void 0;
|
|
263
|
-
const documentRender = await this.renderComponentBoundary({
|
|
264
|
-
component: HtmlTemplate,
|
|
265
|
-
props: {
|
|
266
|
-
metadata,
|
|
267
|
-
pageProps: props ?? {}
|
|
268
|
-
},
|
|
269
|
-
children: layoutRender?.html ?? pageRender.html
|
|
270
|
-
});
|
|
271
|
-
this.appendProcessedDependencies(pageRender.assets, layoutRender?.assets, documentRender.assets);
|
|
272
|
-
const body = await this.finalizeResolvedHtml({
|
|
273
|
-
html: `${this.DOC_TYPE}${this.normalizeDeclarativeShadowRootMarkup(documentRender.html)}`,
|
|
274
|
-
partial: false
|
|
275
|
-
});
|
|
276
|
-
return this.createHtmlResponse(body, ctx);
|
|
277
|
-
} catch (error) {
|
|
278
|
-
throw this.createRenderError("Error rendering view", error);
|
|
279
|
-
}
|
|
280
|
-
}
|
|
114
|
+
const { html, ...metadata } = result;
|
|
115
|
+
return { body: html, ...metadata };
|
|
281
116
|
}
|
|
282
|
-
export {
|
|
283
|
-
LitRenderer
|
|
284
|
-
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { PageParams, PageQuery } from '@ecopages/core';
|
|
2
|
+
import type { RouteRenderResult } from '@ecopages/core/integration';
|
|
3
|
+
/** A rendered page, its resolved metadata, and what the main thread needs to cache it. */
|
|
4
|
+
export type LitStaticRenderResult = Pick<RouteRenderResult, 'cacheStrategy' | 'sourceDependencyPaths' | 'metadata'> & {
|
|
5
|
+
html: string;
|
|
6
|
+
};
|
|
7
|
+
export type LitStaticRenderWorkerInitMessage = {
|
|
8
|
+
type: 'init';
|
|
9
|
+
configModulePath: string;
|
|
10
|
+
runtimeOrigin: string;
|
|
11
|
+
};
|
|
12
|
+
export type LitStaticRenderWorkerRenderMessage = {
|
|
13
|
+
type: 'render';
|
|
14
|
+
id: string;
|
|
15
|
+
filePath: string;
|
|
16
|
+
/** Route params; multi-value keys stay as `string[]`. */
|
|
17
|
+
params: PageParams;
|
|
18
|
+
/** Serializable route query; preserves multi-value keys as `string[]`. */
|
|
19
|
+
query?: PageQuery;
|
|
20
|
+
};
|
|
21
|
+
export type LitStaticRenderWorkerShutdownMessage = {
|
|
22
|
+
type: 'shutdown';
|
|
23
|
+
};
|
|
24
|
+
export type LitStaticRenderWorkerRequestMessage = LitStaticRenderWorkerInitMessage | LitStaticRenderWorkerRenderMessage | LitStaticRenderWorkerShutdownMessage;
|
|
25
|
+
export type LitStaticRenderWorkerReadyMessage = {
|
|
26
|
+
type: 'ready';
|
|
27
|
+
};
|
|
28
|
+
export type LitStaticRenderWorkerResultMessage = {
|
|
29
|
+
type: 'result';
|
|
30
|
+
id: string;
|
|
31
|
+
} & LitStaticRenderResult;
|
|
32
|
+
export type LitStaticRenderWorkerErrorMessage = {
|
|
33
|
+
type: 'error';
|
|
34
|
+
id?: string;
|
|
35
|
+
message: string;
|
|
36
|
+
};
|
|
37
|
+
export type LitStaticRenderWorkerShutdownCompleteMessage = {
|
|
38
|
+
type: 'shutdown-complete';
|
|
39
|
+
};
|
|
40
|
+
export type LitStaticRenderWorkerResponseMessage = LitStaticRenderWorkerReadyMessage | LitStaticRenderWorkerResultMessage | LitStaticRenderWorkerErrorMessage | LitStaticRenderWorkerShutdownCompleteMessage;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { RouteRenderResult } from '@ecopages/core/integration';
|
|
2
|
+
import type { LitStaticRenderResult } from './lit-static-render-protocol.js';
|
|
3
|
+
/**
|
|
4
|
+
* Turns a route render into the message the worker posts back to the main thread.
|
|
5
|
+
*
|
|
6
|
+
* @remarks
|
|
7
|
+
* The resolved `metadata` travels with the HTML so the main thread can decide sitemap eligibility
|
|
8
|
+
* from the render instead of loading the page again.
|
|
9
|
+
*/
|
|
10
|
+
export declare function toLitStaticRenderResult(result: RouteRenderResult): Promise<LitStaticRenderResult>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turns a route render into the message the worker posts back to the main thread.
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* The resolved `metadata` travels with the HTML so the main thread can decide sitemap eligibility
|
|
6
|
+
* from the render instead of loading the page again.
|
|
7
|
+
*/
|
|
8
|
+
export async function toLitStaticRenderResult(result) {
|
|
9
|
+
const { body, cacheStrategy, sourceDependencyPaths, metadata } = result;
|
|
10
|
+
const rendered = { cacheStrategy, sourceDependencyPaths, metadata };
|
|
11
|
+
if (typeof body === 'string') {
|
|
12
|
+
return { html: body, ...rendered };
|
|
13
|
+
}
|
|
14
|
+
if (Buffer.isBuffer(body)) {
|
|
15
|
+
return { html: body.toString('utf8'), ...rendered };
|
|
16
|
+
}
|
|
17
|
+
if (body instanceof ReadableStream) {
|
|
18
|
+
return { html: await new Response(body).text(), ...rendered };
|
|
19
|
+
}
|
|
20
|
+
throw new TypeError(`Unsupported Lit static render body type: ${typeof body}`);
|
|
21
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { PageParams, PageQuery } from '@ecopages/core';
|
|
2
|
+
import type { StaticExportContext } from '@ecopages/core/integration';
|
|
3
|
+
import { type CustomElementSsrPreloadComponent } from '@ecopages/core/integration';
|
|
4
|
+
import type { CustomElementScriptPreloadScopeState } from '@ecopages/core/integration';
|
|
5
|
+
import { LitStaticRenderWorkerClient } from './lit-static-render-worker-client.js';
|
|
6
|
+
import type { LitStaticRenderResult } from './lit-static-render-protocol.js';
|
|
7
|
+
import type { AssetDefinition, AssetProcessingIntegration, ProcessedAsset } from '@ecopages/core/integration';
|
|
8
|
+
type LitStaticRenderWorkerClientContract = Pick<LitStaticRenderWorkerClient, 'start' | 'renderPage' | 'dispose'>;
|
|
9
|
+
type LitStaticRenderSessionOptions = {
|
|
10
|
+
preloadScopes: Map<string, CustomElementScriptPreloadScopeState>;
|
|
11
|
+
integration?: AssetProcessingIntegration;
|
|
12
|
+
resolveDependencyPath: (componentDir: string, sourcePath: string) => string;
|
|
13
|
+
processDependencies: (dependencies: AssetDefinition[], integration?: AssetProcessingIntegration) => Promise<ProcessedAsset[]>;
|
|
14
|
+
getInvalidationVersion?: () => number;
|
|
15
|
+
createWorkerClient?: (input: {
|
|
16
|
+
configModulePath: string;
|
|
17
|
+
runtimeOrigin: string;
|
|
18
|
+
}) => LitStaticRenderWorkerClientContract;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Plugin-runtime-scoped Lit server render session.
|
|
22
|
+
*
|
|
23
|
+
* @remarks
|
|
24
|
+
* Owns worker lifecycle and SSR preload for Lit page routes during static export
|
|
25
|
+
* and runtime/dev requests. Injected into `LitRenderer` via a lazy accessor from
|
|
26
|
+
* `LitPlugin`; there is no process-global coordinator.
|
|
27
|
+
*
|
|
28
|
+
* Worker init identity is sticky for the first `{ configModulePath, runtimeOrigin }`.
|
|
29
|
+
* Later `ensureWorker` calls with the same identity are no-ops; a different identity
|
|
30
|
+
* recreates the worker so stale config/origin is never silently reused.
|
|
31
|
+
*/
|
|
32
|
+
export declare class LitStaticRenderSession {
|
|
33
|
+
private readonly preloader;
|
|
34
|
+
private readonly createWorkerClient;
|
|
35
|
+
private workerClient;
|
|
36
|
+
private workerIdentity;
|
|
37
|
+
private readonly getInvalidationVersion;
|
|
38
|
+
private workerInvalidationVersion;
|
|
39
|
+
private renderChain;
|
|
40
|
+
constructor(options: LitStaticRenderSessionOptions);
|
|
41
|
+
/**
|
|
42
|
+
* Ensures the static render worker is running for the given identity.
|
|
43
|
+
*
|
|
44
|
+
* @remarks
|
|
45
|
+
* First successful start sticks that identity. Matching re-entry is a no-op.
|
|
46
|
+
* A different `configModulePath` or `runtimeOrigin` disposes and recreates.
|
|
47
|
+
*/
|
|
48
|
+
ensureWorker(input: {
|
|
49
|
+
configModulePath: string;
|
|
50
|
+
runtimeOrigin: string;
|
|
51
|
+
}): Promise<void>;
|
|
52
|
+
preloadStaticRoutes(context: StaticExportContext): Promise<void>;
|
|
53
|
+
preloadSsrScripts(components: Array<CustomElementSsrPreloadComponent | undefined>): Promise<void>;
|
|
54
|
+
collectSsrPreloadScripts(components: Array<CustomElementSsrPreloadComponent | undefined>): string[];
|
|
55
|
+
renderPageInWorker(input: {
|
|
56
|
+
filePath: string;
|
|
57
|
+
params: PageParams;
|
|
58
|
+
query?: PageQuery;
|
|
59
|
+
}): Promise<LitStaticRenderResult>;
|
|
60
|
+
isExpectedSsrPreloadError(error: unknown): boolean;
|
|
61
|
+
dispose(): Promise<void>;
|
|
62
|
+
private preloadLitRoutes;
|
|
63
|
+
private isLitRoute;
|
|
64
|
+
}
|
|
65
|
+
export {};
|