@ecopages/lit 0.2.0-beta.26 → 0.2.0-beta.28

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ecopages/lit",
3
- "version": "0.2.0-beta.26",
3
+ "version": "0.2.0-beta.28",
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.26",
42
+ "@ecopages/core": "0.2.0-beta.28",
43
43
  "@lit-labs/ssr": "^3.3.0",
44
44
  "@lit-labs/ssr-client": "^1.1.7",
45
45
  "lit": "^3.2.1"
@@ -11,37 +11,59 @@ LitPlugin.setup()
11
11
  └─ LitStaticRenderSession.ensureWorker()
12
12
  └─ LitStaticRenderWorkerClient.start()
13
13
  └─ postMessage(init) ──► setupAppRuntimePlugins()
14
- installAppRuntimeBuildExecutor()
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
- └─ session.renderPageInWorker()
19
- └─ postMessage(render) ─────► RouteRendererFactory.execute()
20
- (no active session in worker)
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` | Build-scoped session: worker lifecycle + SSR preload |
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 to HTML |
46
- | `result` / `error` | worker → main | Render outcome |
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 |
@@ -4,18 +4,39 @@
4
4
  */
5
5
  import type { ComponentRenderInput, ComponentRenderResult, EcoComponent, EcoPagesElement, IntegrationRendererRenderOptions, RouteRenderResult, RouteRendererBody, RouteRendererOptions } from '@ecopages/core';
6
6
  import './dom-shim.js';
7
- import { IntegrationRenderer, type RenderToResponseContext } from '@ecopages/core/route-renderer/integration-renderer';
7
+ import { IntegrationRenderer, type RenderToResponseContext } from '@ecopages/core/route-renderer/orchestration/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
  *
@@ -1,6 +1,11 @@
1
1
  import "./dom-shim.js";
2
- import { IntegrationRenderer } from "@ecopages/core/route-renderer/integration-renderer";
3
- import { getActiveLitStaticRenderSession } from "./lit-static-render-coordinator.js";
2
+ import {
3
+ IntegrationRenderer
4
+ } from "@ecopages/core/route-renderer/orchestration/integration-renderer";
5
+ import {
6
+ getForeignSubtreeResolutionContextKey,
7
+ resolveOwningIntegrationRenderer
8
+ } from "@ecopages/core/route-renderer/orchestration/foreign-child/owning-renderer-resolution";
4
9
  import { LitSsrLazyPreloader } from "./lit-ssr-lazy-preloader.js";
5
10
  import { LIT_PLUGIN_NAME } from "./lit.constants.js";
6
11
  import {
@@ -11,15 +16,34 @@ import {
11
16
  } from "./utils/lit-html-rendering.js";
12
17
  class LitRenderer extends IntegrationRenderer {
13
18
  name = LIT_PLUGIN_NAME;
19
+ getRenderSession;
20
+ constructor(options) {
21
+ const { getRenderSession, ...rendererOptions } = options;
22
+ super(rendererOptions);
23
+ this.getRenderSession = getRenderSession;
24
+ }
25
+ /**
26
+ * Renders a Lit page route, preferring the plugin worker when available.
27
+ *
28
+ * @remarks
29
+ * Activates the integration runtime before reading {@link getRenderSession}
30
+ * so a renderer constructed before plugin setup still sees the session.
31
+ * When `options.locals` is present, rendering stays in-process: request locals
32
+ * are not structured-cloned across the worker boundary.
33
+ */
14
34
  async execute(options) {
15
- const session = getActiveLitStaticRenderSession();
16
- if (session) {
17
- const html = await session.renderPageInWorker({
35
+ await this.ensureIntegrationRuntimeActivated();
36
+ const renderSession = this.getRenderSession?.();
37
+ if (renderSession && options.locals === void 0) {
38
+ const params = options.params ?? {};
39
+ const result = await renderSession.renderPageInWorker({
18
40
  filePath: options.file,
19
- params: options.params ?? {}
41
+ params,
42
+ query: options.query
20
43
  });
21
44
  return {
22
- body: html
45
+ body: result.html,
46
+ cacheStrategy: result.cacheStrategy
23
47
  };
24
48
  }
25
49
  return super.execute(options);
@@ -59,12 +83,6 @@ class LitRenderer extends IntegrationRenderer {
59
83
  html: renderedChildren
60
84
  };
61
85
  }
62
- shouldRenderPageComponent() {
63
- return false;
64
- }
65
- isLitManagedComponent(component) {
66
- return component?.config?.integration === this.name || component?.config?.__eco?.integration === this.name;
67
- }
68
86
  /**
69
87
  * Renders a Lit component for component-level orchestration.
70
88
  *
@@ -94,12 +112,26 @@ class LitRenderer extends IntegrationRenderer {
94
112
  const content = await component(props);
95
113
  const renderedHtml = await renderLitValueToString(content);
96
114
  const html = renderedChildren === void 0 ? renderedHtml : injectLitRenderedChildren(renderedHtml, renderedChildren);
97
- const queuedForeignSubtreeResolution = await this.resolveQueuedForeignSubtreeHtml(
115
+ const queuedForeignSubtreeResolution = await this.foreignSubtreeExecutionService.resolveQueuedHtml({
116
+ currentIntegrationName: this.name,
98
117
  html,
99
- this.getQueuedForeignSubtreeResolutionContext(input),
100
- (children, _runtimeContext, queuedResolutionsByToken, resolveToken) => this.renderLitQueuedForeignSubtreeChildren(children, queuedResolutionsByToken, resolveToken),
101
- "Lit"
102
- );
118
+ runtimeContext: this.foreignSubtreeExecutionService.getQueuedRuntimeContext(
119
+ input,
120
+ getForeignSubtreeResolutionContextKey(this.name)
121
+ ),
122
+ queueLabel: "Lit",
123
+ getOwningRenderer: (integrationName, rendererCache) => resolveOwningIntegrationRenderer({
124
+ appConfig: this.appConfig,
125
+ runtimeOrigin: this.runtimeOrigin,
126
+ currentIntegrationName: this.name,
127
+ currentRenderer: this,
128
+ integrationName,
129
+ cache: rendererCache
130
+ }),
131
+ applyAttributesToFirstElement: (resolvedHtml, attributes) => this.htmlTransformer.applyAttributesToFirstElement(resolvedHtml, attributes),
132
+ dedupeProcessedAssets: (assets2) => this.htmlTransformer.dedupeProcessedAssets(assets2),
133
+ renderQueuedChildren: (children, _runtimeContext, queuedResolutionsByToken, resolveToken) => this.renderLitQueuedForeignSubtreeChildren(children, queuedResolutionsByToken, resolveToken)
134
+ });
103
135
  const hasDependencies = Boolean(input.component.config?.dependencies);
104
136
  const canResolveAssets = typeof this.assetProcessingService?.processDependencies === "function";
105
137
  const assets = hasDependencies && canResolveAssets ? await this.processComponentDependencies([input.component]) : void 0;
@@ -141,9 +173,9 @@ class LitRenderer extends IntegrationRenderer {
141
173
  * Preloads SSR-eligible lazy scripts to register custom elements before render.
142
174
  */
143
175
  async preloadSsrLazyScripts(components) {
144
- const session = getActiveLitStaticRenderSession();
145
- if (session) {
146
- await session.preloadSsrLazyScripts(components);
176
+ const renderSession = this.getRenderSession?.();
177
+ if (renderSession) {
178
+ await renderSession.preloadSsrLazyScripts(components);
147
179
  return;
148
180
  }
149
181
  await this.ssrLazyPreloader.preloadSsrLazyScripts(components);
@@ -194,45 +226,16 @@ class LitRenderer extends IntegrationRenderer {
194
226
  }
195
227
  async renderToResponse(view, props, ctx) {
196
228
  try {
197
- if (ctx.partial) {
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;
229
+ const layouts = view.config?.layouts;
207
230
  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
231
  await this.preloadSsrLazyScripts([view, Layout]);
212
- await this.prepareViewDependencies(view, Layout);
213
- const pageRender = await this.renderComponentWithForeignChildren({
214
- component: view,
215
- props: normalizedProps
216
- });
217
- const layoutRender = Layout ? await this.renderComponentWithForeignChildren({
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
232
+ return await this.renderViewWithDocumentShell({
233
+ view,
234
+ props,
235
+ ctx,
236
+ layout: Layout,
237
+ transformDocumentHtml: normalizeLitHtml
234
238
  });
235
- return this.createHtmlResponse(body, ctx);
236
239
  } catch (error) {
237
240
  throw this.createRenderError("Error rendering view", error);
238
241
  }
@@ -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: Record<string, string>;
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
- * Build-scoped Lit server render session.
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
- * Preloads SSR-eligible lazy scripts and renders Lit page routes through a
15
- * dedicated worker thread for both static export and runtime/dev requests.
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: Record<string, string>;
31
- }): Promise<string>;
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 = new LitStaticRenderWorkerClient({
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: Record<string, string>;
17
- }): Promise<string>;
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 { installAppRuntimeBuildExecutor } from "@ecopages/core/build/runtime-build-executor";
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
- installAppRuntimeBuildExecutor(appConfig);
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 html = await renderPage(message.filePath, message.params);
64
- postMessage({ type: "result", id: message.id, html });
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);
@@ -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,3 +0,0 @@
1
- import type { LitStaticRenderSession } from './lit-static-render-session.js';
2
- export declare function setActiveLitStaticRenderSession(session: LitStaticRenderSession | null): void;
3
- export declare function getActiveLitStaticRenderSession(): LitStaticRenderSession | null;
@@ -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
- };