@ecopages/lit 0.2.0-beta.26 → 0.2.0-beta.27
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/package.json +2 -2
- package/src/STATIC_RENDER.md +35 -13
- package/src/lit-renderer.d.ts +23 -2
- package/src/lit-renderer.js +34 -51
- package/src/lit-static-render-protocol.d.ts +7 -1
- package/src/lit-static-render-session.d.ts +32 -6
- package/src/lit-static-render-session.js +23 -2
- package/src/lit-static-render-worker-client.d.ts +8 -2
- package/src/lit-static-render-worker-client.js +3 -2
- package/src/lit-static-render-worker.js +10 -9
- package/src/lit.plugin.d.ts +8 -0
- package/src/lit.plugin.js +7 -4
- package/src/lit-static-render-coordinator.d.ts +0 -3
- package/src/lit-static-render-coordinator.js +0 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ecopages/lit",
|
|
3
|
-
"version": "0.2.0-beta.
|
|
3
|
+
"version": "0.2.0-beta.27",
|
|
4
4
|
"description": "Ecopages lit integration",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ecopages",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"directory": "packages/integrations/lit"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
|
-
"@ecopages/core": "0.2.0-beta.
|
|
42
|
+
"@ecopages/core": "0.2.0-beta.27",
|
|
43
43
|
"@lit-labs/ssr": "^3.3.0",
|
|
44
44
|
"@lit-labs/ssr-client": "^1.1.7",
|
|
45
45
|
"lit": "^3.2.1"
|
package/src/STATIC_RENDER.md
CHANGED
|
@@ -11,37 +11,59 @@ LitPlugin.setup()
|
|
|
11
11
|
└─ LitStaticRenderSession.ensureWorker()
|
|
12
12
|
└─ LitStaticRenderWorkerClient.start()
|
|
13
13
|
└─ postMessage(init) ──► setupAppRuntimePlugins()
|
|
14
|
-
|
|
14
|
+
installBuildRuntime()
|
|
15
15
|
RouteRendererFactory
|
|
16
16
|
|
|
17
|
+
LitPlugin.initializeRenderer()
|
|
18
|
+
└─ LitRenderer({ getRenderSession }) lazy accessor (not constructor snapshot)
|
|
19
|
+
|
|
17
20
|
LitRenderer.execute() (main)
|
|
18
|
-
└─
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
└─ ensureIntegrationRuntimeActivated()
|
|
22
|
+
└─ getRenderSession()
|
|
23
|
+
├─ locals present ──────────► super.execute() (in-process)
|
|
24
|
+
└─ session.renderPageInWorker()
|
|
25
|
+
└─ postMessage(render) ─────► RouteRendererFactory.execute()
|
|
26
|
+
(no active session in worker)
|
|
21
27
|
|
|
22
28
|
beforeStaticExport
|
|
29
|
+
└─ ensureWorker() only when `renderSession` is still null
|
|
23
30
|
└─ preloadStaticRoutes()
|
|
24
31
|
└─ preload SSR lazy scripts for Lit pages
|
|
25
32
|
```
|
|
26
33
|
|
|
27
34
|
`ECOPAGES_LIT_STATIC_RENDER_WORKER=true` in the worker environment prevents nested worker creation during `LitPlugin.setup()` and skips processor `.setup()` inside `setupAppRuntimePlugins` (main thread already prepared artifacts).
|
|
28
35
|
|
|
36
|
+
## Ownership
|
|
37
|
+
|
|
38
|
+
| Concern | Owner |
|
|
39
|
+
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
40
|
+
| Session + worker lifecycle | `LitPlugin` (`renderSession`) |
|
|
41
|
+
| Lazy session lookup | `LitRenderer` via `getRenderSession` |
|
|
42
|
+
| Worker identity | First `{ configModulePath, runtimeOrigin }` passed to `ensureWorker`; same identity is sticky; a later `ensureWorker` with a different identity disposes and recreates |
|
|
43
|
+
|
|
44
|
+
Renderers created before plugin `setup()` still use the worker after setup assigns the session, because `execute` activates the integration runtime then reads the accessor.
|
|
45
|
+
|
|
46
|
+
`beforeStaticExport` does not re-call `ensureWorker` when setup already created the session, so a different `context.baseUrl` at export time will not recreate an existing worker.
|
|
47
|
+
|
|
48
|
+
## Locals policy
|
|
49
|
+
|
|
50
|
+
When `RouteRendererOptions.locals` is present, `LitRenderer.execute` forces the in-process path (`super.execute`). Request locals are not sent through the worker protocol (structured-clone risk and request-scoped data). Static export and routes without locals continue through the worker.
|
|
51
|
+
|
|
29
52
|
## Files
|
|
30
53
|
|
|
31
54
|
| File | Role |
|
|
32
55
|
| ------------------------------------ | --------------------------------------------------------------- |
|
|
33
|
-
| `lit-static-render-session.ts` |
|
|
56
|
+
| `lit-static-render-session.ts` | Plugin-runtime-scoped session: worker lifecycle + SSR preload |
|
|
34
57
|
| `lit-static-render-worker-client.ts` | Message protocol client |
|
|
35
58
|
| `lit-static-render-worker.ts` | Worker entry (exported as `@ecopages/lit/static-render-worker`) |
|
|
36
59
|
| `lit-static-render-protocol.ts` | Request/response message types |
|
|
37
|
-
| `lit-static-render-coordinator.ts` | Active session pointer for `LitRenderer` |
|
|
38
60
|
|
|
39
61
|
## Protocol
|
|
40
62
|
|
|
41
|
-
| Message | Direction | Purpose
|
|
42
|
-
| ------------------ | ------------- |
|
|
43
|
-
| `init` | main → worker | Load `eco.config.ts`, bootstrap runtime |
|
|
44
|
-
| `ready` | worker → main | Worker initialized
|
|
45
|
-
| `render` | main → worker | Render one Lit page route
|
|
46
|
-
| `result` / `error` | worker → main |
|
|
47
|
-
| `shutdown` | main → worker | Exit worker thread
|
|
63
|
+
| Message | Direction | Purpose |
|
|
64
|
+
| ------------------ | ------------- | ----------------------------------------------------------------------------- |
|
|
65
|
+
| `init` | main → worker | Load `eco.config.ts`, bootstrap runtime (`configModulePath`, `runtimeOrigin`) |
|
|
66
|
+
| `ready` | worker → main | Worker initialized |
|
|
67
|
+
| `render` | main → worker | Render one Lit page route (`filePath`, `PageParams`, optional `PageQuery`) |
|
|
68
|
+
| `result` / `error` | worker → main | HTML body plus optional `cacheStrategy`, or an error message |
|
|
69
|
+
| `shutdown` | main → worker | Exit worker thread |
|
package/src/lit-renderer.d.ts
CHANGED
|
@@ -5,17 +5,38 @@
|
|
|
5
5
|
import type { ComponentRenderInput, ComponentRenderResult, EcoComponent, EcoPagesElement, IntegrationRendererRenderOptions, RouteRenderResult, RouteRendererBody, RouteRendererOptions } from '@ecopages/core';
|
|
6
6
|
import './dom-shim.js';
|
|
7
7
|
import { IntegrationRenderer, type RenderToResponseContext } from '@ecopages/core/route-renderer/integration-renderer';
|
|
8
|
+
import type { LitStaticRenderSession } from './lit-static-render-session.js';
|
|
9
|
+
export type LitRendererOptions = ConstructorParameters<typeof IntegrationRenderer>[0] & {
|
|
10
|
+
/**
|
|
11
|
+
* Lazy session lookup owned by {@link LitPlugin}.
|
|
12
|
+
*
|
|
13
|
+
* @remarks
|
|
14
|
+
* Must not snapshot the session at construction time. Plugin `setup()` may
|
|
15
|
+
* assign the session after the renderer is created; `execute` activates the
|
|
16
|
+
* integration runtime then reads this accessor so worker dispatch still works.
|
|
17
|
+
*/
|
|
18
|
+
getRenderSession?: () => LitStaticRenderSession | undefined;
|
|
19
|
+
};
|
|
8
20
|
/**
|
|
9
21
|
* A renderer for the Lit integration.
|
|
10
22
|
*/
|
|
11
23
|
export declare class LitRenderer extends IntegrationRenderer<EcoPagesElement> {
|
|
12
24
|
name: string;
|
|
25
|
+
private readonly getRenderSession?;
|
|
26
|
+
constructor(options: LitRendererOptions);
|
|
27
|
+
/**
|
|
28
|
+
* Renders a Lit page route, preferring the plugin worker when available.
|
|
29
|
+
*
|
|
30
|
+
* @remarks
|
|
31
|
+
* Activates the integration runtime before reading {@link getRenderSession}
|
|
32
|
+
* so a renderer constructed before plugin setup still sees the session.
|
|
33
|
+
* When `options.locals` is present, rendering stays in-process: request locals
|
|
34
|
+
* are not structured-cloned across the worker boundary.
|
|
35
|
+
*/
|
|
13
36
|
execute(options: RouteRendererOptions): Promise<RouteRenderResult>;
|
|
14
37
|
private isFunctionComponent;
|
|
15
38
|
private resolveQueuedForeignSubtreeChildren;
|
|
16
39
|
private renderLitQueuedForeignSubtreeChildren;
|
|
17
|
-
protected shouldRenderPageComponent(): boolean;
|
|
18
|
-
private isLitManagedComponent;
|
|
19
40
|
/**
|
|
20
41
|
* Renders a Lit component for component-level orchestration.
|
|
21
42
|
*
|
package/src/lit-renderer.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import "./dom-shim.js";
|
|
2
2
|
import { IntegrationRenderer } from "@ecopages/core/route-renderer/integration-renderer";
|
|
3
|
-
import { getActiveLitStaticRenderSession } from "./lit-static-render-coordinator.js";
|
|
4
3
|
import { LitSsrLazyPreloader } from "./lit-ssr-lazy-preloader.js";
|
|
5
4
|
import { LIT_PLUGIN_NAME } from "./lit.constants.js";
|
|
6
5
|
import {
|
|
@@ -11,15 +10,34 @@ import {
|
|
|
11
10
|
} from "./utils/lit-html-rendering.js";
|
|
12
11
|
class LitRenderer extends IntegrationRenderer {
|
|
13
12
|
name = LIT_PLUGIN_NAME;
|
|
13
|
+
getRenderSession;
|
|
14
|
+
constructor(options) {
|
|
15
|
+
const { getRenderSession, ...rendererOptions } = options;
|
|
16
|
+
super(rendererOptions);
|
|
17
|
+
this.getRenderSession = getRenderSession;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Renders a Lit page route, preferring the plugin worker when available.
|
|
21
|
+
*
|
|
22
|
+
* @remarks
|
|
23
|
+
* Activates the integration runtime before reading {@link getRenderSession}
|
|
24
|
+
* so a renderer constructed before plugin setup still sees the session.
|
|
25
|
+
* When `options.locals` is present, rendering stays in-process: request locals
|
|
26
|
+
* are not structured-cloned across the worker boundary.
|
|
27
|
+
*/
|
|
14
28
|
async execute(options) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
29
|
+
await this.ensureIntegrationRuntimeActivated();
|
|
30
|
+
const renderSession = this.getRenderSession?.();
|
|
31
|
+
if (renderSession && options.locals === void 0) {
|
|
32
|
+
const params = options.params ?? {};
|
|
33
|
+
const result = await renderSession.renderPageInWorker({
|
|
18
34
|
filePath: options.file,
|
|
19
|
-
params
|
|
35
|
+
params,
|
|
36
|
+
query: options.query
|
|
20
37
|
});
|
|
21
38
|
return {
|
|
22
|
-
body: html
|
|
39
|
+
body: result.html,
|
|
40
|
+
cacheStrategy: result.cacheStrategy
|
|
23
41
|
};
|
|
24
42
|
}
|
|
25
43
|
return super.execute(options);
|
|
@@ -59,12 +77,6 @@ class LitRenderer extends IntegrationRenderer {
|
|
|
59
77
|
html: renderedChildren
|
|
60
78
|
};
|
|
61
79
|
}
|
|
62
|
-
shouldRenderPageComponent() {
|
|
63
|
-
return false;
|
|
64
|
-
}
|
|
65
|
-
isLitManagedComponent(component) {
|
|
66
|
-
return component?.config?.integration === this.name || component?.config?.__eco?.integration === this.name;
|
|
67
|
-
}
|
|
68
80
|
/**
|
|
69
81
|
* Renders a Lit component for component-level orchestration.
|
|
70
82
|
*
|
|
@@ -141,9 +153,9 @@ class LitRenderer extends IntegrationRenderer {
|
|
|
141
153
|
* Preloads SSR-eligible lazy scripts to register custom elements before render.
|
|
142
154
|
*/
|
|
143
155
|
async preloadSsrLazyScripts(components) {
|
|
144
|
-
const
|
|
145
|
-
if (
|
|
146
|
-
await
|
|
156
|
+
const renderSession = this.getRenderSession?.();
|
|
157
|
+
if (renderSession) {
|
|
158
|
+
await renderSession.preloadSsrLazyScripts(components);
|
|
147
159
|
return;
|
|
148
160
|
}
|
|
149
161
|
await this.ssrLazyPreloader.preloadSsrLazyScripts(components);
|
|
@@ -194,45 +206,16 @@ class LitRenderer extends IntegrationRenderer {
|
|
|
194
206
|
}
|
|
195
207
|
async renderToResponse(view, props, ctx) {
|
|
196
208
|
try {
|
|
197
|
-
|
|
198
|
-
return this.renderPartialViewResponse({
|
|
199
|
-
view,
|
|
200
|
-
props,
|
|
201
|
-
ctx,
|
|
202
|
-
transformHtml: normalizeLitHtml
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
const viewConfig = view.config;
|
|
206
|
-
const layouts = viewConfig?.layouts;
|
|
209
|
+
const layouts = view.config?.layouts;
|
|
207
210
|
const Layout = layouts?.[layouts.length - 1];
|
|
208
|
-
const HtmlTemplate = await this.getHtmlTemplate();
|
|
209
|
-
const metadata = await this.resolveViewMetadata(view, props);
|
|
210
|
-
const normalizedProps = props ?? {};
|
|
211
211
|
await this.preloadSsrLazyScripts([view, Layout]);
|
|
212
|
-
await this.
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
component: Layout,
|
|
219
|
-
props: {},
|
|
220
|
-
children: pageRender.html
|
|
221
|
-
}) : void 0;
|
|
222
|
-
const documentRender = await this.renderComponentWithForeignChildren({
|
|
223
|
-
component: HtmlTemplate,
|
|
224
|
-
props: {
|
|
225
|
-
metadata,
|
|
226
|
-
pageProps: normalizedProps
|
|
227
|
-
},
|
|
228
|
-
children: layoutRender?.html ?? pageRender.html
|
|
229
|
-
});
|
|
230
|
-
this.appendProcessedDependencies(pageRender.assets, layoutRender?.assets, documentRender.assets);
|
|
231
|
-
const body = await this.finalizeResolvedHtml({
|
|
232
|
-
html: `${this.DOC_TYPE}${normalizeLitHtml(documentRender.html)}`,
|
|
233
|
-
partial: false
|
|
212
|
+
return await this.renderViewWithDocumentShell({
|
|
213
|
+
view,
|
|
214
|
+
props,
|
|
215
|
+
ctx,
|
|
216
|
+
layout: Layout,
|
|
217
|
+
transformDocumentHtml: normalizeLitHtml
|
|
234
218
|
});
|
|
235
|
-
return this.createHtmlResponse(body, ctx);
|
|
236
219
|
} catch (error) {
|
|
237
220
|
throw this.createRenderError("Error rendering view", error);
|
|
238
221
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { PageParams, PageQuery, RouteRenderResult } from '@ecopages/core';
|
|
2
|
+
export type LitStaticRenderCacheStrategy = RouteRenderResult['cacheStrategy'];
|
|
1
3
|
export type LitStaticRenderWorkerInitMessage = {
|
|
2
4
|
type: 'init';
|
|
3
5
|
configModulePath: string;
|
|
@@ -7,7 +9,10 @@ export type LitStaticRenderWorkerRenderMessage = {
|
|
|
7
9
|
type: 'render';
|
|
8
10
|
id: string;
|
|
9
11
|
filePath: string;
|
|
10
|
-
params
|
|
12
|
+
/** Route params; multi-value keys stay as `string[]`. */
|
|
13
|
+
params: PageParams;
|
|
14
|
+
/** Serializable route query; preserves multi-value keys as `string[]`. */
|
|
15
|
+
query?: PageQuery;
|
|
11
16
|
};
|
|
12
17
|
export type LitStaticRenderWorkerShutdownMessage = {
|
|
13
18
|
type: 'shutdown';
|
|
@@ -20,6 +25,7 @@ export type LitStaticRenderWorkerResultMessage = {
|
|
|
20
25
|
type: 'result';
|
|
21
26
|
id: string;
|
|
22
27
|
html: string;
|
|
28
|
+
cacheStrategy?: LitStaticRenderCacheStrategy;
|
|
23
29
|
};
|
|
24
30
|
export type LitStaticRenderWorkerErrorMessage = {
|
|
25
31
|
type: 'error';
|
|
@@ -1,23 +1,45 @@
|
|
|
1
|
-
import type { EcoComponent } from '@ecopages/core';
|
|
1
|
+
import type { EcoComponent, PageParams, PageQuery } from '@ecopages/core';
|
|
2
2
|
import type { StaticExportContext } from '@ecopages/core/plugins/integration-plugin';
|
|
3
3
|
import type { AssetDefinition } from '@ecopages/core/services/asset-processing-service';
|
|
4
|
+
import { LitStaticRenderWorkerClient } from './lit-static-render-worker-client.js';
|
|
5
|
+
import type { LitStaticRenderCacheStrategy } from './lit-static-render-protocol.js';
|
|
6
|
+
type LitStaticRenderWorkerClientContract = Pick<LitStaticRenderWorkerClient, 'start' | 'renderPage' | 'dispose'>;
|
|
4
7
|
type LitStaticRenderSessionOptions = {
|
|
5
8
|
resolveDependencyPath: (componentDir: string, sourcePath: string) => string;
|
|
6
9
|
processDependencies?: (dependencies: AssetDefinition[], integrationName: string) => Promise<Array<{
|
|
7
10
|
filepath?: string;
|
|
8
11
|
}>>;
|
|
9
12
|
preferSourceImports?: boolean;
|
|
13
|
+
createWorkerClient?: (input: {
|
|
14
|
+
configModulePath: string;
|
|
15
|
+
runtimeOrigin: string;
|
|
16
|
+
}) => LitStaticRenderWorkerClientContract;
|
|
10
17
|
};
|
|
11
18
|
/**
|
|
12
|
-
*
|
|
19
|
+
* Plugin-runtime-scoped Lit server render session.
|
|
20
|
+
*
|
|
21
|
+
* @remarks
|
|
22
|
+
* Owns worker lifecycle and SSR preload for Lit page routes during static export
|
|
23
|
+
* and runtime/dev requests. Injected into `LitRenderer` via a lazy accessor from
|
|
24
|
+
* `LitPlugin`; there is no process-global coordinator.
|
|
13
25
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
26
|
+
* Worker init identity is sticky for the first `{ configModulePath, runtimeOrigin }`.
|
|
27
|
+
* Later `ensureWorker` calls with the same identity are no-ops; a different identity
|
|
28
|
+
* recreates the worker so stale config/origin is never silently reused.
|
|
16
29
|
*/
|
|
17
30
|
export declare class LitStaticRenderSession {
|
|
18
31
|
private readonly preloader;
|
|
32
|
+
private readonly createWorkerClient;
|
|
19
33
|
private workerClient;
|
|
34
|
+
private workerIdentity;
|
|
20
35
|
constructor(options: LitStaticRenderSessionOptions);
|
|
36
|
+
/**
|
|
37
|
+
* Ensures the static render worker is running for the given identity.
|
|
38
|
+
*
|
|
39
|
+
* @remarks
|
|
40
|
+
* First successful start sticks that identity. Matching re-entry is a no-op.
|
|
41
|
+
* A different `configModulePath` or `runtimeOrigin` disposes and recreates.
|
|
42
|
+
*/
|
|
21
43
|
ensureWorker(input: {
|
|
22
44
|
configModulePath: string;
|
|
23
45
|
runtimeOrigin: string;
|
|
@@ -27,8 +49,12 @@ export declare class LitStaticRenderSession {
|
|
|
27
49
|
collectSsrPreloadScripts(components: Array<EcoComponent | undefined>): string[];
|
|
28
50
|
renderPageInWorker(input: {
|
|
29
51
|
filePath: string;
|
|
30
|
-
params:
|
|
31
|
-
|
|
52
|
+
params: PageParams;
|
|
53
|
+
query?: PageQuery;
|
|
54
|
+
}): Promise<{
|
|
55
|
+
html: string;
|
|
56
|
+
cacheStrategy?: LitStaticRenderCacheStrategy;
|
|
57
|
+
}>;
|
|
32
58
|
isExpectedSsrPreloadError(error: unknown): boolean;
|
|
33
59
|
dispose(): Promise<void>;
|
|
34
60
|
private preloadLitRoutes;
|
|
@@ -4,19 +4,39 @@ import { LIT_PLUGIN_NAME } from "./lit.constants.js";
|
|
|
4
4
|
import { LitStaticRenderWorkerClient } from "./lit-static-render-worker-client.js";
|
|
5
5
|
class LitStaticRenderSession {
|
|
6
6
|
preloader;
|
|
7
|
+
createWorkerClient;
|
|
7
8
|
workerClient = null;
|
|
9
|
+
workerIdentity = null;
|
|
8
10
|
constructor(options) {
|
|
9
11
|
this.preloader = new LitSsrLazyPreloader({
|
|
10
12
|
resolveDependencyPath: options.resolveDependencyPath,
|
|
11
13
|
processDependencies: options.processDependencies,
|
|
12
14
|
preferSourceImports: options.preferSourceImports
|
|
13
15
|
});
|
|
16
|
+
this.createWorkerClient = options.createWorkerClient ?? ((input) => new LitStaticRenderWorkerClient({
|
|
17
|
+
configModulePath: input.configModulePath,
|
|
18
|
+
runtimeOrigin: input.runtimeOrigin
|
|
19
|
+
}));
|
|
14
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Ensures the static render worker is running for the given identity.
|
|
23
|
+
*
|
|
24
|
+
* @remarks
|
|
25
|
+
* First successful start sticks that identity. Matching re-entry is a no-op.
|
|
26
|
+
* A different `configModulePath` or `runtimeOrigin` disposes and recreates.
|
|
27
|
+
*/
|
|
15
28
|
async ensureWorker(input) {
|
|
16
|
-
if (this.workerClient) {
|
|
29
|
+
if (this.workerClient && this.workerIdentity && this.workerIdentity.configModulePath === input.configModulePath && this.workerIdentity.runtimeOrigin === input.runtimeOrigin) {
|
|
17
30
|
return;
|
|
18
31
|
}
|
|
19
|
-
this.workerClient
|
|
32
|
+
if (this.workerClient) {
|
|
33
|
+
await this.dispose();
|
|
34
|
+
}
|
|
35
|
+
this.workerIdentity = {
|
|
36
|
+
configModulePath: input.configModulePath,
|
|
37
|
+
runtimeOrigin: input.runtimeOrigin
|
|
38
|
+
};
|
|
39
|
+
this.workerClient = this.createWorkerClient({
|
|
20
40
|
configModulePath: input.configModulePath,
|
|
21
41
|
runtimeOrigin: input.runtimeOrigin
|
|
22
42
|
});
|
|
@@ -43,6 +63,7 @@ class LitStaticRenderSession {
|
|
|
43
63
|
async dispose() {
|
|
44
64
|
await this.workerClient?.dispose();
|
|
45
65
|
this.workerClient = null;
|
|
66
|
+
this.workerIdentity = null;
|
|
46
67
|
}
|
|
47
68
|
async preloadLitRoutes(context) {
|
|
48
69
|
if (!context.routeRendererFactory) {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { PageParams, PageQuery } from '@ecopages/core';
|
|
2
|
+
import type { LitStaticRenderCacheStrategy } from './lit-static-render-protocol.js';
|
|
1
3
|
export declare class LitStaticRenderWorkerClient {
|
|
2
4
|
private readonly configModulePath;
|
|
3
5
|
private readonly runtimeOrigin;
|
|
@@ -13,8 +15,12 @@ export declare class LitStaticRenderWorkerClient {
|
|
|
13
15
|
start(): Promise<void>;
|
|
14
16
|
renderPage(input: {
|
|
15
17
|
filePath: string;
|
|
16
|
-
params:
|
|
17
|
-
|
|
18
|
+
params: PageParams;
|
|
19
|
+
query?: PageQuery;
|
|
20
|
+
}): Promise<{
|
|
21
|
+
html: string;
|
|
22
|
+
cacheStrategy?: LitStaticRenderCacheStrategy;
|
|
23
|
+
}>;
|
|
18
24
|
dispose(): Promise<void>;
|
|
19
25
|
}
|
|
20
26
|
export declare const litStaticRenderWorkerEntryPath: string;
|
|
@@ -51,7 +51,7 @@ class LitStaticRenderWorkerClient {
|
|
|
51
51
|
return;
|
|
52
52
|
}
|
|
53
53
|
this.pending.delete(message.id);
|
|
54
|
-
pending.resolve(message.html);
|
|
54
|
+
pending.resolve({ html: message.html, cacheStrategy: message.cacheStrategy });
|
|
55
55
|
}
|
|
56
56
|
});
|
|
57
57
|
worker.on("error", (error) => {
|
|
@@ -88,7 +88,8 @@ class LitStaticRenderWorkerClient {
|
|
|
88
88
|
type: "render",
|
|
89
89
|
id,
|
|
90
90
|
filePath: input.filePath,
|
|
91
|
-
params: input.params
|
|
91
|
+
params: input.params,
|
|
92
|
+
query: input.query
|
|
92
93
|
};
|
|
93
94
|
worker.postMessage(renderMessage);
|
|
94
95
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { parentPort } from "node:worker_threads";
|
|
2
2
|
import { pathToFileURL } from "node:url";
|
|
3
3
|
import { setupAppRuntimePlugins } from "@ecopages/core/build/build-adapter";
|
|
4
|
-
import {
|
|
4
|
+
import { installBuildRuntime } from "@ecopages/core/build/build-runtime";
|
|
5
5
|
import { RouteRendererFactory } from "@ecopages/core/route-renderer/route-renderer";
|
|
6
6
|
import "./dom-shim.js";
|
|
7
7
|
let appConfig = null;
|
|
@@ -16,29 +16,30 @@ async function initializeWorker(configModulePath, runtimeOrigin) {
|
|
|
16
16
|
appConfig,
|
|
17
17
|
runtimeOrigin
|
|
18
18
|
});
|
|
19
|
-
|
|
19
|
+
installBuildRuntime(appConfig);
|
|
20
20
|
routeRendererFactory = new RouteRendererFactory({
|
|
21
21
|
appConfig,
|
|
22
22
|
runtimeOrigin
|
|
23
23
|
});
|
|
24
24
|
}
|
|
25
|
-
async function renderPage(filePath, params) {
|
|
25
|
+
async function renderPage(filePath, params, query) {
|
|
26
26
|
if (!routeRendererFactory) {
|
|
27
27
|
throw new Error("Lit static render worker is not initialized");
|
|
28
28
|
}
|
|
29
29
|
const result = await routeRendererFactory.getPageRenderer(filePath).execute({
|
|
30
30
|
file: filePath,
|
|
31
|
-
params
|
|
31
|
+
params,
|
|
32
|
+
query
|
|
32
33
|
});
|
|
33
34
|
const body = result.body;
|
|
34
35
|
if (typeof body === "string") {
|
|
35
|
-
return body;
|
|
36
|
+
return { html: body, cacheStrategy: result.cacheStrategy };
|
|
36
37
|
}
|
|
37
38
|
if (Buffer.isBuffer(body)) {
|
|
38
|
-
return body.toString("utf8");
|
|
39
|
+
return { html: body.toString("utf8"), cacheStrategy: result.cacheStrategy };
|
|
39
40
|
}
|
|
40
41
|
if (body instanceof ReadableStream) {
|
|
41
|
-
return new Response(body).text();
|
|
42
|
+
return { html: await new Response(body).text(), cacheStrategy: result.cacheStrategy };
|
|
42
43
|
}
|
|
43
44
|
throw new TypeError(`Unsupported Lit static render body type: ${typeof body}`);
|
|
44
45
|
}
|
|
@@ -60,8 +61,8 @@ parentPort.on("message", async (message) => {
|
|
|
60
61
|
return;
|
|
61
62
|
}
|
|
62
63
|
if (message.type === "render") {
|
|
63
|
-
const
|
|
64
|
-
postMessage({ type: "result", id: message.id,
|
|
64
|
+
const result = await renderPage(message.filePath, message.params, message.query);
|
|
65
|
+
postMessage({ type: "result", id: message.id, ...result });
|
|
65
66
|
}
|
|
66
67
|
} catch (error) {
|
|
67
68
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
package/src/lit.plugin.d.ts
CHANGED
|
@@ -13,6 +13,11 @@ export declare const PLUGIN_NAME = "lit";
|
|
|
13
13
|
/**
|
|
14
14
|
* The Lit plugin class
|
|
15
15
|
* This plugin provides support for Lit components in Ecopages
|
|
16
|
+
*
|
|
17
|
+
* @remarks
|
|
18
|
+
* Owns the {@link LitStaticRenderSession} for worker SSR. Renderers receive a
|
|
19
|
+
* lazy `getRenderSession` accessor so construction before {@link setup} still
|
|
20
|
+
* observes the session once setup assigns it.
|
|
16
21
|
*/
|
|
17
22
|
export declare class LitPlugin extends IntegrationPlugin {
|
|
18
23
|
renderer: typeof LitRenderer;
|
|
@@ -20,6 +25,9 @@ export declare class LitPlugin extends IntegrationPlugin {
|
|
|
20
25
|
constructor(options?: Omit<IntegrationPluginConfig, 'name'>);
|
|
21
26
|
getDependencies(): AssetDefinition[];
|
|
22
27
|
private createRenderSession;
|
|
28
|
+
initializeRenderer(options?: {
|
|
29
|
+
rendererModules?: unknown;
|
|
30
|
+
}): LitRenderer;
|
|
23
31
|
setup(): Promise<void>;
|
|
24
32
|
teardown(): Promise<void>;
|
|
25
33
|
beforeStaticExport(context: StaticExportContext): Promise<void>;
|
package/src/lit.plugin.js
CHANGED
|
@@ -8,7 +8,6 @@ import { AssetFactory } from "@ecopages/core/services/asset-processing-service";
|
|
|
8
8
|
import { litElementHydrateScript } from "./lit-element-hydrate.js";
|
|
9
9
|
import { LIT_PLUGIN_NAME } from "./lit.constants.js";
|
|
10
10
|
import { LitRenderer } from "./lit-renderer.js";
|
|
11
|
-
import { setActiveLitStaticRenderSession } from "./lit-static-render-coordinator.js";
|
|
12
11
|
import { LitStaticRenderSession } from "./lit-static-render-session.js";
|
|
13
12
|
const PLUGIN_NAME = LIT_PLUGIN_NAME;
|
|
14
13
|
class LitPlugin extends IntegrationPlugin {
|
|
@@ -56,6 +55,13 @@ class LitPlugin extends IntegrationPlugin {
|
|
|
56
55
|
preferSourceImports: typeof Bun !== "undefined"
|
|
57
56
|
});
|
|
58
57
|
}
|
|
58
|
+
initializeRenderer(options) {
|
|
59
|
+
const renderer = new this.renderer({
|
|
60
|
+
...this.createRendererOptions(options),
|
|
61
|
+
getRenderSession: () => this.renderSession ?? void 0
|
|
62
|
+
});
|
|
63
|
+
return this.attachRendererRuntimeServices(renderer);
|
|
64
|
+
}
|
|
59
65
|
async setup() {
|
|
60
66
|
await super.setup();
|
|
61
67
|
if (!this.appConfig?.absolutePaths?.config) {
|
|
@@ -69,12 +75,10 @@ class LitPlugin extends IntegrationPlugin {
|
|
|
69
75
|
configModulePath: this.appConfig.absolutePaths.config,
|
|
70
76
|
runtimeOrigin: this.runtimeOrigin
|
|
71
77
|
});
|
|
72
|
-
setActiveLitStaticRenderSession(this.renderSession);
|
|
73
78
|
}
|
|
74
79
|
async teardown() {
|
|
75
80
|
await this.renderSession?.dispose();
|
|
76
81
|
this.renderSession = null;
|
|
77
|
-
setActiveLitStaticRenderSession(null);
|
|
78
82
|
await super.teardown();
|
|
79
83
|
}
|
|
80
84
|
async beforeStaticExport(context) {
|
|
@@ -84,7 +88,6 @@ class LitPlugin extends IntegrationPlugin {
|
|
|
84
88
|
configModulePath: context.appConfig.absolutePaths.config,
|
|
85
89
|
runtimeOrigin: context.baseUrl
|
|
86
90
|
});
|
|
87
|
-
setActiveLitStaticRenderSession(this.renderSession);
|
|
88
91
|
}
|
|
89
92
|
await this.renderSession.preloadStaticRoutes(context);
|
|
90
93
|
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
let activeSession = null;
|
|
2
|
-
function setActiveLitStaticRenderSession(session) {
|
|
3
|
-
activeSession = session;
|
|
4
|
-
}
|
|
5
|
-
function getActiveLitStaticRenderSession() {
|
|
6
|
-
return activeSession;
|
|
7
|
-
}
|
|
8
|
-
export {
|
|
9
|
-
getActiveLitStaticRenderSession,
|
|
10
|
-
setActiveLitStaticRenderSession
|
|
11
|
-
};
|