@ecopages/lit 0.2.1 → 0.3.1
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/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 +13 -60
- package/src/lit-renderer.js +106 -278
- package/src/lit-static-render-error.d.ts +17 -0
- package/src/lit-static-render-error.js +34 -0
- package/src/lit-static-render-protocol.d.ts +46 -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 +63 -0
- package/src/lit-static-render-session.js +139 -0
- package/src/lit-static-render-worker-client.d.ts +26 -0
- package/src/lit-static-render-worker-client.js +182 -0
- package/src/lit-static-render-worker.d.ts +1 -0
- package/src/lit-static-render-worker.js +104 -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.plugin.js
CHANGED
|
@@ -1,50 +1,141 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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
|
-
|
|
37
|
-
|
|
1
|
+
import { CUSTOM_ELEMENT_SSR_PRELOAD_CACHE_SCOPES, invalidateCustomElementScriptPreload, } from '@ecopages/core/integration';
|
|
2
|
+
/**
|
|
3
|
+
* This module contains the Lit plugin
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import './console.js';
|
|
7
|
+
import { IntegrationPlugin, } from '@ecopages/core/integration';
|
|
8
|
+
import { isLitStaticRenderWorkerThread } from '@ecopages/core/build';
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
import { AssetFactory } from '@ecopages/core/integration';
|
|
11
|
+
import { litElementHydrateScript } from './lit-element-hydrate.js';
|
|
12
|
+
import { LIT_PLUGIN_NAME } from './lit.constants.js';
|
|
13
|
+
import { createLitRenderer, LitRenderer } from './lit-renderer.js';
|
|
14
|
+
import { LitStaticRenderSession } from './lit-static-render-session.js';
|
|
15
|
+
/**
|
|
16
|
+
* The name of the Lit plugin
|
|
17
|
+
*/
|
|
18
|
+
export const PLUGIN_NAME = LIT_PLUGIN_NAME;
|
|
19
|
+
/**
|
|
20
|
+
* The Lit plugin class
|
|
21
|
+
* This plugin provides support for Lit components in Ecopages
|
|
22
|
+
*
|
|
23
|
+
* @remarks
|
|
24
|
+
* Owns the {@link LitStaticRenderSession} for worker SSR. Renderers receive a
|
|
25
|
+
* lazy `getRenderSession` accessor so construction before {@link setup} still
|
|
26
|
+
* observes the session once setup assigns it.
|
|
27
|
+
*/
|
|
28
|
+
export class LitPlugin extends IntegrationPlugin {
|
|
29
|
+
renderer = LitRenderer;
|
|
30
|
+
renderSession = null;
|
|
31
|
+
constructor(options) {
|
|
32
|
+
super({
|
|
33
|
+
name: PLUGIN_NAME,
|
|
34
|
+
extensions: ['.lit.tsx'],
|
|
35
|
+
...options,
|
|
36
|
+
});
|
|
37
|
+
this.integrationDependencies.unshift(...this.getDependencies());
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Returns the global integration dependencies required in the browser.
|
|
41
|
+
*
|
|
42
|
+
* @remarks
|
|
43
|
+
* Injects Lit's hydration support script into the document head before any
|
|
44
|
+
* custom element connects. While `@lit-labs/ssr-client/lit-element-hydrate-support.js`
|
|
45
|
+
* can be resolved directly in modern Bun and Node environments, an inline self-contained
|
|
46
|
+
* script is currently emitted to ensure synchronous availability before custom-element
|
|
47
|
+
* registration without requiring an import map for `@lit-labs/ssr-client` subpath imports.
|
|
48
|
+
*/
|
|
49
|
+
getDependencies() {
|
|
50
|
+
return [
|
|
51
|
+
AssetFactory.createInlineContentScript({
|
|
52
|
+
position: 'head',
|
|
53
|
+
content: `(() => {${litElementHydrateScript}})();`,
|
|
54
|
+
bundle: false,
|
|
55
|
+
attributes: {
|
|
56
|
+
'data-eco-script-id': 'lit-hydrate-support',
|
|
57
|
+
},
|
|
58
|
+
}),
|
|
59
|
+
];
|
|
60
|
+
}
|
|
61
|
+
createRenderSession() {
|
|
62
|
+
if (!this.appConfig || !this.runtime || !this.assetProcessingService) {
|
|
63
|
+
throw new Error('Lit plugin must be initialized before starting the render worker');
|
|
38
64
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
65
|
+
const assetProcessingService = this.assetProcessingService;
|
|
66
|
+
return new LitStaticRenderSession({
|
|
67
|
+
preloadScopes: this.runtime.customElementSsrPreloadScopes,
|
|
68
|
+
integration: this,
|
|
69
|
+
resolveDependencyPath: (componentDir, sourcePath) => path.join(componentDir, sourcePath),
|
|
70
|
+
processDependencies: (dependencies, integration) => assetProcessingService.processDependencies(dependencies, integration),
|
|
71
|
+
getInvalidationVersion: () => this.runtime?.moduleLoader.getDevelopmentGeneration() ?? 0,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
createRenderer(base) {
|
|
75
|
+
const Renderer = this.renderer === LitRenderer ? createLitRenderer(() => this.renderSession ?? undefined) : this.renderer;
|
|
76
|
+
const renderer = new Renderer(base);
|
|
77
|
+
renderer.name ||= this.name;
|
|
78
|
+
return renderer;
|
|
79
|
+
}
|
|
80
|
+
hmr(context) {
|
|
81
|
+
super.hmr(context);
|
|
82
|
+
const manager = context.runtime.hmr;
|
|
83
|
+
if (!manager)
|
|
84
|
+
return;
|
|
85
|
+
const preloadScopes = context.runtime.customElementSsrPreloadScopes;
|
|
86
|
+
manager.onScriptEntrypointChanged?.((scriptPath) => {
|
|
87
|
+
invalidateCustomElementScriptPreload(preloadScopes, scriptPath, CUSTOM_ELEMENT_SSR_PRELOAD_CACHE_SCOPES.lit);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
async setup(context) {
|
|
91
|
+
await super.setup(context);
|
|
92
|
+
if (!this.appConfig?.absolutePaths?.config) {
|
|
93
|
+
throw new Error('[ecopages][lit] Lit server rendering requires appConfig.absolutePaths.config');
|
|
94
|
+
}
|
|
95
|
+
if (isLitStaticRenderWorkerThread()) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
this.renderSession ??= this.createRenderSession();
|
|
99
|
+
await this.renderSession.ensureWorker({
|
|
100
|
+
configModulePath: this.appConfig.absolutePaths.config,
|
|
101
|
+
runtimeOrigin: context.runtime.origin,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
async teardown() {
|
|
105
|
+
await this.renderSession?.dispose();
|
|
106
|
+
this.renderSession = null;
|
|
107
|
+
await super.teardown();
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Reconciles the render worker with the export origin and preloads Lit routes.
|
|
111
|
+
*
|
|
112
|
+
* @remarks
|
|
113
|
+
* `setup()` can start the session with the runtime origin before static export resolves its own base URL. The
|
|
114
|
+
* session reuses the worker when the identities match and restarts it when the export origin differs. The returned
|
|
115
|
+
* release stops the worker once the export ends, so an in-process export leaves no worker thread running. A later
|
|
116
|
+
* render in the same process falls back to rendering in-process.
|
|
117
|
+
*/
|
|
118
|
+
async staticExport(context) {
|
|
119
|
+
this.renderSession ??= this.createRenderSession();
|
|
120
|
+
await this.renderSession.ensureWorker({
|
|
121
|
+
configModulePath: context.appConfig.absolutePaths.config,
|
|
122
|
+
runtimeOrigin: context.baseUrl,
|
|
123
|
+
});
|
|
124
|
+
const session = this.renderSession;
|
|
125
|
+
await session.preloadStaticRoutes(context);
|
|
126
|
+
return async () => {
|
|
127
|
+
await session.dispose();
|
|
128
|
+
if (this.renderSession === session) {
|
|
129
|
+
this.renderSession = null;
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
}
|
|
42
133
|
}
|
|
43
|
-
|
|
44
|
-
|
|
134
|
+
/**
|
|
135
|
+
* Factory function to create a Lit plugin instance
|
|
136
|
+
* @param options Configuration options for the Lit plugin
|
|
137
|
+
* @returns A new LitPlugin instance
|
|
138
|
+
*/
|
|
139
|
+
export function litPlugin(options) {
|
|
140
|
+
return new LitPlugin(options);
|
|
45
141
|
}
|
|
46
|
-
export {
|
|
47
|
-
LitPlugin,
|
|
48
|
-
PLUGIN_NAME,
|
|
49
|
-
litPlugin
|
|
50
|
-
};
|
package/src/styled-mixin.js
CHANGED
|
@@ -1,13 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
/**
|
|
2
|
+
* This module contains StyledMixin
|
|
3
|
+
* It is used to add styles to a LitElement
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { unsafeCSS } from 'lit';
|
|
7
|
+
/**
|
|
8
|
+
* A mixin to add styles to a LitElement
|
|
9
|
+
* @param superClass - The class to mix into
|
|
10
|
+
* @param css - The styles to add
|
|
11
|
+
* @returns The class with the styles added
|
|
12
|
+
*/
|
|
13
|
+
export const StyledMixin = (superClass, css = []) => {
|
|
14
|
+
class StyledMixinClass extends superClass {
|
|
15
|
+
static styles = [
|
|
16
|
+
superClass.styles ?? [],
|
|
17
|
+
...css.map((styles) => unsafeCSS(styles)),
|
|
18
|
+
];
|
|
19
|
+
}
|
|
20
|
+
return StyledMixinClass;
|
|
13
21
|
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const LIT_HTML_TEMPLATE_SLOT_MARKER = "<--content-->";
|
|
2
|
+
export declare const LIT_COMPONENT_CHILDREN_SLOT_MARKER = "<!--eco-lit-component-children-->";
|
|
3
|
+
export declare function normalizeLitHtml(markup: string): string;
|
|
4
|
+
export declare function injectLitRenderedChildren(template: string, renderedChildren: string): string;
|
|
5
|
+
export declare function renderLitValueToString(value: unknown): Promise<string>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { render } from '@lit-labs/ssr';
|
|
2
|
+
import { html as staticHtml, unsafeStatic } from 'lit/static-html.js';
|
|
3
|
+
export const LIT_HTML_TEMPLATE_SLOT_MARKER = '<--content-->';
|
|
4
|
+
export const LIT_COMPONENT_CHILDREN_SLOT_MARKER = '<!--eco-lit-component-children-->';
|
|
5
|
+
const ESCAPED_COMPONENT_CHILDREN_SLOT_MARKER = '<!--eco-lit-component-children-->';
|
|
6
|
+
const DOUBLE_ESCAPED_COMPONENT_CHILDREN_SLOT_MARKER = '&lt;!--eco-lit-component-children--&gt;';
|
|
7
|
+
const DUPLICATE_DECLARATIVE_SHADOW_ROOT_ATTRIBUTE = /\sshadowroot=(['"])(open|closed)\1(?=\sshadowrootmode=\1\2\1)/g;
|
|
8
|
+
export function normalizeLitHtml(markup) {
|
|
9
|
+
return markup.replace(DUPLICATE_DECLARATIVE_SHADOW_ROOT_ATTRIBUTE, '');
|
|
10
|
+
}
|
|
11
|
+
export function injectLitRenderedChildren(template, renderedChildren) {
|
|
12
|
+
for (const marker of [
|
|
13
|
+
LIT_COMPONENT_CHILDREN_SLOT_MARKER,
|
|
14
|
+
ESCAPED_COMPONENT_CHILDREN_SLOT_MARKER,
|
|
15
|
+
DOUBLE_ESCAPED_COMPONENT_CHILDREN_SLOT_MARKER,
|
|
16
|
+
]) {
|
|
17
|
+
if (template.includes(marker)) {
|
|
18
|
+
return template.split(marker).join(renderedChildren);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
if (template.includes(LIT_HTML_TEMPLATE_SLOT_MARKER)) {
|
|
22
|
+
return template.split(LIT_HTML_TEMPLATE_SLOT_MARKER).join(renderedChildren);
|
|
23
|
+
}
|
|
24
|
+
if (template.includes('</body>')) {
|
|
25
|
+
return template.replace('</body>', `${renderedChildren}</body>`);
|
|
26
|
+
}
|
|
27
|
+
if (template.includes('</html>')) {
|
|
28
|
+
return template.replace('</html>', `${renderedChildren}</html>`);
|
|
29
|
+
}
|
|
30
|
+
return `${template}${renderedChildren}`;
|
|
31
|
+
}
|
|
32
|
+
export async function renderLitValueToString(value) {
|
|
33
|
+
if (typeof value === 'string') {
|
|
34
|
+
let renderedHtml = '';
|
|
35
|
+
for (const chunk of render(staticHtml `${unsafeStatic(value)}`)) {
|
|
36
|
+
renderedHtml += chunk;
|
|
37
|
+
}
|
|
38
|
+
return normalizeLitHtml(renderedHtml);
|
|
39
|
+
}
|
|
40
|
+
let renderedHtml = '';
|
|
41
|
+
for (const chunk of render(value)) {
|
|
42
|
+
renderedHtml += chunk;
|
|
43
|
+
}
|
|
44
|
+
return normalizeLitHtml(renderedHtml);
|
|
45
|
+
}
|
package/CHANGELOG.md
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
All notable changes to `@ecopages/lit` are documented here.
|
|
4
|
-
|
|
5
|
-
> **Note:** Changelog tracking begins at version `0.2.0`. Changes prior to this release are not recorded here but are available in the git history.
|
|
6
|
-
|
|
7
|
-
## [0.2.1] — 2026-04-16
|
|
8
|
-
|
|
9
|
-
### Bug Fixes
|
|
10
|
-
|
|
11
|
-
- Fixed Lit document-shell composition, declarative shadow DOM SSR, nested child serialization, lazy preload handling, explicit render paths, and mixed-renderer boundary resolution.
|
|
12
|
-
|
|
13
|
-
### Documentation
|
|
14
|
-
|
|
15
|
-
- Updated the README to document `.lit.tsx` route ownership, standalone setup, and mixed-renderer Lit boundary handling.
|
|
16
|
-
|
|
17
|
-
### Tests
|
|
18
|
-
|
|
19
|
-
- Updated integration coverage for explicit boundary composition and Node and esbuild compatibility.
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import type { EcoComponent } from '@ecopages/core';
|
|
2
|
-
import type { AssetDefinition } from '@ecopages/core/services/asset-processing-service';
|
|
3
|
-
type ProcessDependencies = (dependencies: AssetDefinition[], integrationName: string) => Promise<Array<{
|
|
4
|
-
filepath?: string;
|
|
5
|
-
}>>;
|
|
6
|
-
export interface LitSsrLazyPreloaderOptions {
|
|
7
|
-
resolveDependencyPath: (componentDir: string, sourcePath: string) => string;
|
|
8
|
-
processDependencies?: ProcessDependencies;
|
|
9
|
-
preferSourceImports?: boolean;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Encapsulates SSR lazy script preload behavior for Lit components.
|
|
13
|
-
*
|
|
14
|
-
* Collects `dependencies.scripts` lazy entries with `ssr: true`, resolves the
|
|
15
|
-
* processed entrypoint through the asset pipeline, and imports the module so
|
|
16
|
-
* custom elements are registered before SSR rendering.
|
|
17
|
-
*/
|
|
18
|
-
export declare class LitSsrLazyPreloader {
|
|
19
|
-
private readonly resolveDependencyPath;
|
|
20
|
-
private readonly processDependencies?;
|
|
21
|
-
private readonly preferSourceImports;
|
|
22
|
-
private readonly ssrPreloadedScripts;
|
|
23
|
-
private readonly ssrPreloadFailedScripts;
|
|
24
|
-
private readonly ssrPreloadEntrypointCache;
|
|
25
|
-
constructor({ resolveDependencyPath, processDependencies, preferSourceImports }: LitSsrLazyPreloaderOptions);
|
|
26
|
-
/**
|
|
27
|
-
* Detects preload failures that are expected for browser-only modules.
|
|
28
|
-
*/
|
|
29
|
-
isExpectedSsrPreloadError(error: unknown): boolean;
|
|
30
|
-
/**
|
|
31
|
-
* Collects lazy script file paths eligible for SSR preloading.
|
|
32
|
-
*/
|
|
33
|
-
collectSsrPreloadScripts(components: Array<EcoComponent | undefined>): string[];
|
|
34
|
-
/**
|
|
35
|
-
* Preloads SSR-eligible lazy scripts to register custom elements before render.
|
|
36
|
-
*/
|
|
37
|
-
preloadSsrLazyScripts(components: Array<EcoComponent | undefined>): Promise<void>;
|
|
38
|
-
/**
|
|
39
|
-
* Resolves the concrete JS entrypoint used for SSR preloading.
|
|
40
|
-
*/
|
|
41
|
-
resolveSsrPreloadEntrypoint(scriptPath: string): Promise<string | null>;
|
|
42
|
-
}
|
|
43
|
-
export {};
|
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
import { AssetFactory } from "@ecopages/core/services/asset-processing-service";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { pathToFileURL } from "node:url";
|
|
4
|
-
class LitSsrLazyPreloader {
|
|
5
|
-
resolveDependencyPath;
|
|
6
|
-
processDependencies;
|
|
7
|
-
preferSourceImports;
|
|
8
|
-
ssrPreloadedScripts = /* @__PURE__ */ new Set();
|
|
9
|
-
ssrPreloadFailedScripts = /* @__PURE__ */ new Set();
|
|
10
|
-
ssrPreloadEntrypointCache = /* @__PURE__ */ new Map();
|
|
11
|
-
constructor({ resolveDependencyPath, processDependencies, preferSourceImports }) {
|
|
12
|
-
this.resolveDependencyPath = resolveDependencyPath;
|
|
13
|
-
this.processDependencies = processDependencies;
|
|
14
|
-
this.preferSourceImports = preferSourceImports ?? typeof Bun !== "undefined";
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Detects preload failures that are expected for browser-only modules.
|
|
18
|
-
*/
|
|
19
|
-
isExpectedSsrPreloadError(error) {
|
|
20
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
21
|
-
const errorCode = typeof error === "object" && error !== null && "code" in error ? String(error.code ?? "") : "";
|
|
22
|
-
if (errorCode === "ERR_UNKNOWN_FILE_EXTENSION") {
|
|
23
|
-
return true;
|
|
24
|
-
}
|
|
25
|
-
return errorMessage.includes(`reading 'Element'`) || errorMessage.includes("window is not defined") || errorMessage.includes("document is not defined") || errorMessage.includes("navigator is not defined");
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Collects lazy script file paths eligible for SSR preloading.
|
|
29
|
-
*/
|
|
30
|
-
collectSsrPreloadScripts(components) {
|
|
31
|
-
const scriptPaths = /* @__PURE__ */ new Set();
|
|
32
|
-
const visitedConfigs = /* @__PURE__ */ new Set();
|
|
33
|
-
const collect = (component) => {
|
|
34
|
-
const config = component?.config;
|
|
35
|
-
if (!config || visitedConfigs.has(config)) {
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
visitedConfigs.add(config);
|
|
39
|
-
const scriptEntries = config.dependencies?.scripts ?? [];
|
|
40
|
-
const componentFile = config.__eco?.file;
|
|
41
|
-
if (componentFile) {
|
|
42
|
-
const componentDir = path.dirname(componentFile);
|
|
43
|
-
for (const script of scriptEntries) {
|
|
44
|
-
if (typeof script === "string") {
|
|
45
|
-
continue;
|
|
46
|
-
}
|
|
47
|
-
if (!script.lazy || script.ssr !== true) {
|
|
48
|
-
continue;
|
|
49
|
-
}
|
|
50
|
-
if (!script.src) {
|
|
51
|
-
continue;
|
|
52
|
-
}
|
|
53
|
-
scriptPaths.add(this.resolveDependencyPath(componentDir, script.src));
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
if (config.layout) {
|
|
57
|
-
collect(config.layout);
|
|
58
|
-
}
|
|
59
|
-
for (const nestedComponent of config.dependencies?.components || []) {
|
|
60
|
-
collect(nestedComponent);
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
for (const component of components) {
|
|
64
|
-
collect(component);
|
|
65
|
-
}
|
|
66
|
-
return Array.from(scriptPaths);
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Preloads SSR-eligible lazy scripts to register custom elements before render.
|
|
70
|
-
*/
|
|
71
|
-
async preloadSsrLazyScripts(components) {
|
|
72
|
-
const scripts = this.collectSsrPreloadScripts(components);
|
|
73
|
-
if (scripts.length === 0) {
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
await Promise.all(
|
|
77
|
-
scripts.filter((scriptPath) => {
|
|
78
|
-
if (this.ssrPreloadedScripts.has(scriptPath)) {
|
|
79
|
-
return false;
|
|
80
|
-
}
|
|
81
|
-
if (this.ssrPreloadFailedScripts.has(scriptPath)) {
|
|
82
|
-
return false;
|
|
83
|
-
}
|
|
84
|
-
return true;
|
|
85
|
-
}).map(async (scriptPath) => {
|
|
86
|
-
const preloadEntrypoint = await this.resolveSsrPreloadEntrypoint(scriptPath);
|
|
87
|
-
if (!preloadEntrypoint) {
|
|
88
|
-
this.ssrPreloadFailedScripts.add(scriptPath);
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
try {
|
|
92
|
-
await import(
|
|
93
|
-
/* @vite-ignore */
|
|
94
|
-
pathToFileURL(preloadEntrypoint).href
|
|
95
|
-
);
|
|
96
|
-
this.ssrPreloadedScripts.add(scriptPath);
|
|
97
|
-
} catch (error) {
|
|
98
|
-
this.ssrPreloadFailedScripts.add(scriptPath);
|
|
99
|
-
if (this.isExpectedSsrPreloadError(error)) {
|
|
100
|
-
if (process.env.ECOPAGES_DEBUG === "true") {
|
|
101
|
-
console.warn(
|
|
102
|
-
`[ecopages][lit] Skipping SSR preload for browser-only lazy script: ${scriptPath}`
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
console.warn(`[ecopages][lit] Failed to preload lazy SSR script: ${scriptPath}`, error);
|
|
108
|
-
}
|
|
109
|
-
})
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* Resolves the concrete JS entrypoint used for SSR preloading.
|
|
114
|
-
*/
|
|
115
|
-
async resolveSsrPreloadEntrypoint(scriptPath) {
|
|
116
|
-
const cachedEntrypoint = this.ssrPreloadEntrypointCache.get(scriptPath);
|
|
117
|
-
if (cachedEntrypoint) {
|
|
118
|
-
return cachedEntrypoint;
|
|
119
|
-
}
|
|
120
|
-
if (this.preferSourceImports) {
|
|
121
|
-
this.ssrPreloadEntrypointCache.set(scriptPath, scriptPath);
|
|
122
|
-
return scriptPath;
|
|
123
|
-
}
|
|
124
|
-
if (!this.processDependencies) {
|
|
125
|
-
this.ssrPreloadEntrypointCache.set(scriptPath, scriptPath);
|
|
126
|
-
return scriptPath;
|
|
127
|
-
}
|
|
128
|
-
try {
|
|
129
|
-
const processed = await this.processDependencies(
|
|
130
|
-
[
|
|
131
|
-
AssetFactory.createInlineFileScript({
|
|
132
|
-
filepath: scriptPath,
|
|
133
|
-
position: "head",
|
|
134
|
-
bundle: true,
|
|
135
|
-
attributes: {
|
|
136
|
-
type: "module",
|
|
137
|
-
defer: ""
|
|
138
|
-
}
|
|
139
|
-
})
|
|
140
|
-
],
|
|
141
|
-
`lit-ssr-preload:${scriptPath}`
|
|
142
|
-
);
|
|
143
|
-
const entrypoint = processed[0]?.filepath;
|
|
144
|
-
if (!entrypoint) {
|
|
145
|
-
return scriptPath;
|
|
146
|
-
}
|
|
147
|
-
this.ssrPreloadEntrypointCache.set(scriptPath, entrypoint);
|
|
148
|
-
return entrypoint;
|
|
149
|
-
} catch (error) {
|
|
150
|
-
if (process.env.ECOPAGES_DEBUG === "true") {
|
|
151
|
-
console.warn(`[ecopages][lit] Failed to resolve SSR preload entrypoint for: ${scriptPath}`, error);
|
|
152
|
-
}
|
|
153
|
-
this.ssrPreloadEntrypointCache.set(scriptPath, scriptPath);
|
|
154
|
-
return scriptPath;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
export {
|
|
159
|
-
LitSsrLazyPreloader
|
|
160
|
-
};
|