@ecopages/core 0.2.0-beta.2 → 0.2.0-beta.21
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 +1 -1
- package/package.json +163 -3
- package/src/adapters/abstract/application-adapter.d.ts +104 -5
- package/src/adapters/abstract/application-adapter.js +125 -1
- package/src/adapters/abstract/server-adapter.d.ts +6 -2
- package/src/adapters/abstract/ws-pattern-matcher.d.ts +60 -0
- package/src/adapters/abstract/ws-pattern-matcher.js +61 -0
- package/src/adapters/bun/client-bridge.d.ts +1 -0
- package/src/adapters/bun/client-bridge.js +3 -0
- package/src/adapters/bun/create-app.d.ts +6 -4
- package/src/adapters/bun/create-app.js +65 -43
- package/src/adapters/bun/server-adapter.d.ts +90 -22
- package/src/adapters/bun/server-adapter.js +266 -84
- package/src/adapters/bun/static-preview-host.js +25 -20
- package/src/adapters/create-app.d.ts +13 -11
- package/src/adapters/create-app.js +2 -51
- package/src/adapters/index.d.ts +1 -1
- package/src/adapters/index.js +1 -2
- package/src/adapters/node/create-app.d.ts +5 -1
- package/src/adapters/node/create-app.js +51 -12
- package/src/adapters/node/node-client-bridge.d.ts +1 -0
- package/src/adapters/node/node-client-bridge.js +3 -0
- package/src/adapters/node/server-adapter-dependencies.js +4 -0
- package/src/adapters/node/server-adapter.d.ts +62 -20
- package/src/adapters/node/server-adapter.js +160 -131
- package/src/adapters/node/static-content-server.d.ts +1 -0
- package/src/adapters/node/static-content-server.js +10 -2
- package/src/adapters/node/static-preview-host.js +27 -12
- package/src/adapters/shared/bun-user-websocket-lifecycle.d.ts +22 -0
- package/src/adapters/shared/bun-user-websocket-lifecycle.js +96 -0
- package/src/adapters/shared/copy-runtime-public-dir.d.ts +6 -0
- package/src/adapters/shared/copy-runtime-public-dir.js +24 -0
- package/src/adapters/shared/fs-server-response-matcher.d.ts +2 -0
- package/src/adapters/shared/fs-server-response-matcher.js +40 -18
- package/src/adapters/shared/hmr-entrypoint-registrar.d.ts +21 -30
- package/src/adapters/shared/hmr-entrypoint-registrar.js +49 -54
- package/src/adapters/shared/hmr-html-response.d.ts +1 -1
- package/src/adapters/shared/hmr-html-response.js +4 -1
- package/src/adapters/shared/node-http-websocket-upgrades.d.ts +21 -0
- package/src/adapters/shared/node-http-websocket-upgrades.js +100 -0
- package/src/adapters/shared/port-manager.d.ts +116 -0
- package/src/adapters/shared/port-manager.js +196 -0
- package/src/adapters/shared/runtime-app-bootstrap.d.ts +2 -1
- package/src/adapters/shared/runtime-app-bootstrap.js +3 -6
- package/src/adapters/shared/runtime-server-lifecycle.d.ts +46 -0
- package/src/adapters/shared/runtime-server-lifecycle.js +50 -0
- package/src/adapters/shared/server-adapter.d.ts +2 -1
- package/src/adapters/shared/server-adapter.js +13 -6
- package/src/adapters/shared/server-route-handler.d.ts +4 -1
- package/src/adapters/shared/server-route-handler.js +5 -2
- package/src/adapters/shared/server-static-builder.d.ts +23 -32
- package/src/adapters/shared/server-static-builder.js +100 -73
- package/src/adapters/shared/shared-hmr-manager.d.ts +45 -11
- package/src/adapters/shared/shared-hmr-manager.js +204 -58
- package/src/adapters/shared/static-preview-host.d.ts +5 -0
- package/src/adapters/shared/websocket-lifecycle.d.ts +24 -0
- package/src/adapters/shared/websocket-lifecycle.js +55 -0
- package/src/build/README.md +77 -14
- package/src/build/app-build-manifest-runtime.d.ts +9 -0
- package/src/build/app-build-manifest-runtime.js +87 -0
- package/src/build/build-adapter.d.ts +17 -319
- package/src/build/build-adapter.js +28 -94
- package/src/build/build-contracts.d.ts +97 -0
- package/src/build/build-contracts.js +0 -0
- package/src/build/build-input-fingerprint.d.ts +28 -0
- package/src/build/build-input-fingerprint.js +31 -0
- package/src/build/build-profile-options.d.ts +7 -0
- package/src/build/build-profile-options.js +37 -0
- package/src/build/build-runtime.d.ts +24 -0
- package/src/build/build-runtime.js +65 -0
- package/src/build/deduping-build-executor.d.ts +28 -0
- package/src/build/deduping-build-executor.js +56 -0
- package/src/build/jsx-ownership-plugins.d.ts +24 -0
- package/src/build/jsx-ownership-plugins.js +41 -0
- package/src/build/pages-unified-graph-build.d.ts +31 -0
- package/src/build/pages-unified-graph-build.js +206 -0
- package/src/build/parallel-build-executor.d.ts +21 -0
- package/src/build/parallel-build-executor.js +52 -0
- package/src/build/production-build-cache.d.ts +20 -0
- package/src/build/production-build-cache.js +63 -0
- package/src/build/rolldown-adapter-helpers.d.ts +3 -6
- package/src/build/rolldown-adapter-helpers.js +71 -6
- package/src/build/rolldown-build-adapter.d.ts +2 -6
- package/src/build/rolldown-build-adapter.js +3 -3
- package/src/build/rolldown-build-invocation-metrics.d.ts +12 -0
- package/src/build/rolldown-build-invocation-metrics.js +43 -0
- package/src/build/rolldown-plugin-bridge.d.ts +15 -1
- package/src/build/rolldown-plugin-bridge.js +20 -5
- package/src/build/rolldown-source-transform-pass.d.ts +15 -0
- package/src/build/rolldown-source-transform-pass.js +58 -0
- package/src/build/runtime-build-executor.d.ts +8 -15
- package/src/build/runtime-build-executor.js +12 -15
- package/src/build/runtime-build-output-normalizer.d.ts +7 -0
- package/src/build/runtime-build-output-normalizer.js +94 -2
- package/src/build/server-entry-build-cache.d.ts +44 -0
- package/src/build/server-entry-build-cache.js +161 -0
- package/src/client/navigation-scripts/classification.d.ts +16 -0
- package/src/client/navigation-scripts/classification.js +41 -0
- package/src/client/navigation-scripts/index.d.ts +3 -0
- package/src/client/navigation-scripts/index.js +23 -0
- package/src/client/navigation-scripts/navigation-scripts.test.browser.js +65 -0
- package/src/client/navigation-scripts/registry.d.ts +11 -0
- package/src/client/navigation-scripts/registry.js +12 -0
- package/src/client/navigation-scripts/rerun-queue.d.ts +37 -0
- package/src/client/navigation-scripts/rerun-queue.js +73 -0
- package/src/client/scroll.d.ts +17 -0
- package/src/client/scroll.js +25 -0
- package/src/client/scroll.test.browser.js +37 -0
- package/src/client/view-transitions.d.ts +16 -0
- package/src/client/view-transitions.js +63 -0
- package/src/config/config-builder.d.ts +12 -7
- package/src/config/config-builder.js +12 -9
- package/src/dev/client-bridge-registry.d.ts +5 -0
- package/src/dev/client-bridge-registry.js +15 -0
- package/src/dev/dev-client-ownership.d.ts +7 -0
- package/src/dev/dev-client-ownership.js +6 -0
- package/src/dev/hmr-manager-registry.d.ts +8 -0
- package/src/dev/hmr-manager-registry.js +15 -0
- package/src/dev/host-runtime.d.ts +3 -0
- package/src/dev/host-runtime.js +7 -0
- package/src/dev/runtime-server-started-message.d.ts +2 -0
- package/src/dev/runtime-server-started-message.js +6 -0
- package/src/eco/README.md +11 -0
- package/src/eco/eco-declared-component.d.ts +14 -0
- package/src/eco/eco-declared-component.js +16 -0
- package/src/eco/eco.browser.js +5 -6
- package/src/eco/eco.js +5 -6
- package/src/eco/eco.types.d.ts +2 -2
- package/src/eco/page-layout-normalization.d.ts +21 -0
- package/src/eco/page-layout-normalization.js +59 -0
- package/src/errors/index.d.ts +1 -0
- package/src/errors/index.js +7 -1
- package/src/errors/undeclared-component-dependency-error.d.ts +11 -0
- package/src/errors/undeclared-component-dependency-error.js +17 -0
- package/src/hmr/client/hmr-runtime.js +5 -2
- package/src/hmr/hmr-entrypoint-output.d.ts +43 -0
- package/src/hmr/hmr-entrypoint-output.js +53 -0
- package/src/hmr/hmr-strategy.d.ts +15 -0
- package/src/hmr/hmr-strategy.js +19 -0
- package/src/hmr/strategies/js-hmr-strategy.d.ts +3 -5
- package/src/hmr/strategies/js-hmr-strategy.js +67 -19
- package/src/hmr/strategies/server-rendered-template-hmr-strategy.d.ts +17 -0
- package/src/hmr/strategies/server-rendered-template-hmr-strategy.js +29 -0
- package/src/integrations/ghtml/ghtml-renderer.d.ts +2 -6
- package/src/integrations/ghtml/ghtml-renderer.js +2 -51
- package/src/integrations/ghtml/ghtml.plugin.d.ts +3 -16
- package/src/integrations/ghtml/ghtml.plugin.js +7 -14
- package/src/plugins/define-integration.d.ts +26 -0
- package/src/plugins/define-integration.js +19 -0
- package/src/plugins/eco-component-meta-plugin.js +5 -8
- package/src/plugins/foreign-jsx-override-plugin.js +4 -6
- package/src/plugins/integration-plugin.d.ts +19 -9
- package/src/plugins/integration-plugin.js +7 -4
- package/src/plugins/jsx-import-source.utils.d.ts +8 -0
- package/src/plugins/jsx-import-source.utils.js +26 -0
- package/src/plugins/processor.d.ts +19 -4
- package/src/plugins/processor.js +22 -4
- package/src/plugins/source-transform.d.ts +31 -0
- package/src/plugins/source-transform.js +23 -1
- package/src/route-renderer/GRAPH.md +8 -8
- package/src/route-renderer/README.md +30 -28
- package/src/route-renderer/orchestration/component-graph-collectors.d.ts +10 -0
- package/src/route-renderer/orchestration/component-graph-collectors.js +143 -0
- package/src/route-renderer/orchestration/component-graph.d.ts +36 -0
- package/src/route-renderer/orchestration/component-graph.js +98 -0
- package/src/route-renderer/orchestration/component-render-context.d.ts +3 -10
- package/src/route-renderer/orchestration/component-render-context.js +3 -1
- package/src/route-renderer/orchestration/declared-ownership-graph.d.ts +1 -18
- package/src/route-renderer/orchestration/declared-ownership-graph.js +5 -31
- package/src/route-renderer/orchestration/document-shell-render.service.d.ts +90 -0
- package/src/route-renderer/orchestration/document-shell-render.service.js +120 -0
- package/src/route-renderer/orchestration/foreign-subtree-execution.service.d.ts +59 -29
- package/src/route-renderer/orchestration/foreign-subtree-execution.service.js +164 -35
- package/src/route-renderer/orchestration/global-injector-assets.service.d.ts +7 -0
- package/src/route-renderer/orchestration/global-injector-assets.service.js +32 -0
- package/src/route-renderer/orchestration/integration-renderer.d.ts +18 -54
- package/src/route-renderer/orchestration/integration-renderer.js +113 -195
- package/src/route-renderer/orchestration/integration-route-render-adapter.d.ts +38 -0
- package/src/route-renderer/orchestration/integration-route-render-adapter.js +27 -0
- package/src/route-renderer/orchestration/layout-shell-props.service.d.ts +20 -0
- package/src/route-renderer/orchestration/layout-shell-props.service.js +31 -0
- package/src/route-renderer/orchestration/ownership-validation.service.d.ts +5 -0
- package/src/route-renderer/orchestration/ownership-validation.service.js +29 -1
- package/src/route-renderer/orchestration/page-browser-graph-contribution.loader.d.ts +9 -0
- package/src/route-renderer/orchestration/page-browser-graph-contribution.loader.js +7 -0
- package/src/route-renderer/orchestration/page-browser-graph.service.d.ts +25 -0
- package/src/route-renderer/orchestration/page-browser-graph.service.js +174 -0
- package/src/route-renderer/orchestration/render-output.utils.d.ts +2 -0
- package/src/route-renderer/orchestration/render-output.utils.js +4 -0
- package/src/route-renderer/orchestration/route-html-finalization.service.d.ts +17 -0
- package/src/route-renderer/orchestration/route-html-finalization.service.js +26 -0
- package/src/route-renderer/orchestration/route-prepared-options.builder.d.ts +26 -0
- package/src/route-renderer/orchestration/route-prepared-options.builder.js +54 -0
- package/src/route-renderer/orchestration/route-prepared-options.utils.d.ts +4 -0
- package/src/route-renderer/orchestration/route-prepared-options.utils.js +33 -0
- package/src/route-renderer/orchestration/route-render-orchestrator.d.ts +8 -39
- package/src/route-renderer/orchestration/route-render-orchestrator.js +53 -461
- package/src/route-renderer/orchestration/string-markup-renderer.d.ts +14 -0
- package/src/route-renderer/orchestration/string-markup-renderer.js +55 -0
- package/src/route-renderer/page-loading/component-dependency-collection.js +5 -2
- package/src/router/client/link-intent.d.ts +11 -21
- package/src/router/client/link-intent.js +10 -0
- package/src/router/client/link-intent.test.browser.js +12 -1
- package/src/router/client/link-navigation-policy.d.ts +45 -0
- package/src/router/client/link-navigation-policy.js +101 -0
- package/src/router/client/link-navigation-policy.test.browser.d.ts +1 -0
- package/src/router/client/link-navigation-policy.test.browser.js +92 -0
- package/src/router/client/navigation-coordinator.d.ts +1 -1
- package/src/router/client/navigation-coordinator.js +12 -2
- package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.d.ts +1 -0
- package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.js +1 -0
- package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.d.ts +4 -2
- package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.js +27 -7
- package/src/services/assets/asset-processing-service/processors/script/file-script.processor.d.ts +0 -1
- package/src/services/assets/asset-processing-service/processors/script/file-script.processor.js +18 -15
- package/src/services/assets/asset-processing-service/processors/script/node-module-script.processor.js +17 -3
- package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.d.ts +0 -3
- package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.js +2 -31
- package/src/services/assets/asset-processing-service/processors/stylesheet/file-stylesheet.processor.d.ts +0 -3
- package/src/services/assets/asset-processing-service/processors/stylesheet/file-stylesheet.processor.js +2 -30
- package/src/services/assets/asset-processing-service/processors/stylesheet/stylesheet-processor-pipeline.d.ts +2 -0
- package/src/services/assets/asset-processing-service/processors/stylesheet/stylesheet-processor-pipeline.js +43 -0
- package/src/services/assets/browser-bundle.service.d.ts +3 -1
- package/src/services/assets/browser-bundle.service.js +17 -5
- package/src/services/html/html-transformer.service.d.ts +1 -1
- package/src/services/html/html-transformer.service.js +4 -4
- package/src/services/invalidation/development-invalidation.service.d.ts +20 -2
- package/src/services/invalidation/development-invalidation.service.js +56 -2
- package/src/services/module-loading/README.md +49 -0
- package/src/services/module-loading/app-server-module-transpiler.service.js +5 -17
- package/src/services/module-loading/page-module-import.service.d.ts +5 -1
- package/src/services/module-loading/page-module-import.service.js +96 -45
- package/src/services/module-loading/route-module-build-cache-registry.d.ts +24 -0
- package/src/services/module-loading/route-module-build-cache-registry.js +37 -0
- package/src/services/module-loading/route-module-build-cache.d.ts +4 -0
- package/src/services/module-loading/route-module-build-cache.js +38 -0
- package/src/services/module-loading/route-module-build-cache.store.d.ts +57 -0
- package/src/services/module-loading/route-module-build-cache.store.js +207 -0
- package/src/services/module-loading/route-module-build-manifest.d.ts +61 -0
- package/src/services/module-loading/route-module-build-manifest.js +116 -0
- package/src/services/module-loading/route-module-dependency-hasher.d.ts +81 -0
- package/src/services/module-loading/route-module-dependency-hasher.js +122 -0
- package/src/services/module-loading/server-module-transpiler.service.js +1 -1
- package/src/static-site-generator/README.md +33 -0
- package/src/static-site-generator/static-build-invalidation.d.ts +10 -0
- package/src/static-site-generator/static-build-invalidation.js +59 -0
- package/src/static-site-generator/static-export-context.d.ts +22 -0
- package/src/static-site-generator/static-export-context.js +0 -0
- package/src/static-site-generator/static-site-generator.d.ts +17 -20
- package/src/static-site-generator/static-site-generator.js +188 -85
- package/src/types/internal-types.d.ts +16 -9
- package/src/types/public-types.d.ts +144 -40
- package/src/utils/parse-cli-args.d.ts +2 -0
- package/src/utils/parse-cli-args.js +6 -0
- package/src/utils/server-utils.module.d.ts +3 -2
- package/src/utils/server-utils.module.js +5 -6
- package/src/utils/static-file-extensions.d.ts +12 -0
- package/src/utils/static-file-extensions.js +48 -0
- package/src/watchers/project-watcher-ignore.d.ts +11 -0
- package/src/watchers/project-watcher-ignore.js +16 -0
- package/src/watchers/project-watcher.d.ts +26 -3
- package/src/watchers/project-watcher.js +132 -30
- package/src/watchers/project-watcher.test-helpers.js +5 -5
- package/src/build/rolldown-dev-build-adapter.d.ts +0 -82
- package/src/build/rolldown-dev-build-adapter.js +0 -166
- package/src/hmr/hmr.postcss.test.e2e.js +0 -31
- package/src/hmr/hmr.test.e2e.js +0 -43
- package/src/route-renderer/orchestration/ownership-planning.service.d.ts +0 -24
- package/src/route-renderer/orchestration/ownership-planning.service.js +0 -63
- package/src/route-renderer/orchestration/queued-foreign-subtree-resolution.service.d.ts +0 -91
- package/src/route-renderer/orchestration/queued-foreign-subtree-resolution.service.js +0 -170
- /package/src/{hmr/hmr.postcss.test.e2e.d.ts → client/navigation-scripts/navigation-scripts.test.browser.d.ts} +0 -0
- /package/src/{hmr/hmr.test.e2e.d.ts → client/scroll.test.browser.d.ts} +0 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { isNonExecutableHeadScript } from "./classification.js";
|
|
3
|
+
import {
|
|
4
|
+
collectRerunScripts,
|
|
5
|
+
createRerunScriptUrl,
|
|
6
|
+
flushPendingRerunScripts,
|
|
7
|
+
resetRerunNonceForTests
|
|
8
|
+
} from "./rerun-queue.js";
|
|
9
|
+
import { RERUN_SRC_ATTR } from "./registry.js";
|
|
10
|
+
describe("isNonExecutableHeadScript", () => {
|
|
11
|
+
it("treats JSON-LD scripts as non-executable", () => {
|
|
12
|
+
const script = document.createElement("script");
|
|
13
|
+
script.type = "application/ld+json";
|
|
14
|
+
expect(isNonExecutableHeadScript(script)).toBe(true);
|
|
15
|
+
});
|
|
16
|
+
it("treats untyped scripts as executable", () => {
|
|
17
|
+
const script = document.createElement("script");
|
|
18
|
+
expect(isNonExecutableHeadScript(script)).toBe(false);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
describe("collectRerunScripts and flushPendingRerunScripts", () => {
|
|
22
|
+
afterEach(() => {
|
|
23
|
+
document.head.replaceChildren();
|
|
24
|
+
document.body.replaceChildren();
|
|
25
|
+
resetRerunNonceForTests();
|
|
26
|
+
});
|
|
27
|
+
it("replays registered rerun callbacks without duplicating script tags", () => {
|
|
28
|
+
const callback = vi.fn();
|
|
29
|
+
window.__ECO_PAGES__ = {
|
|
30
|
+
rerunScripts: { "eco-test": callback }
|
|
31
|
+
};
|
|
32
|
+
try {
|
|
33
|
+
flushPendingRerunScripts([
|
|
34
|
+
{
|
|
35
|
+
parent: "head",
|
|
36
|
+
attributes: [
|
|
37
|
+
["data-eco-rerun", ""],
|
|
38
|
+
["data-eco-script-id", "eco-test"]
|
|
39
|
+
],
|
|
40
|
+
textContent: "",
|
|
41
|
+
src: null,
|
|
42
|
+
scriptId: "eco-test"
|
|
43
|
+
}
|
|
44
|
+
]);
|
|
45
|
+
expect(callback).toHaveBeenCalledOnce();
|
|
46
|
+
expect(document.head.querySelector('script[data-eco-script-id="eco-test"]')).toBeNull();
|
|
47
|
+
} finally {
|
|
48
|
+
delete window.__ECO_PAGES__;
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
it("cache-busts external module rerun scripts", () => {
|
|
52
|
+
const html = '<html><head><script data-eco-rerun src="/app.js" type="module"><\/script></head></html>';
|
|
53
|
+
const parsed = new DOMParser().parseFromString(html, "text/html");
|
|
54
|
+
const scripts = collectRerunScripts(parsed);
|
|
55
|
+
flushPendingRerunScripts(scripts);
|
|
56
|
+
const inserted = document.head.querySelector(`script[${RERUN_SRC_ATTR}]`);
|
|
57
|
+
expect(inserted?.getAttribute("src")).toMatch(/__eco_rerun=1/);
|
|
58
|
+
expect(inserted?.getAttribute(RERUN_SRC_ATTR)).toBe("/app.js");
|
|
59
|
+
});
|
|
60
|
+
it("appends a unique nonce on each module rerun url", () => {
|
|
61
|
+
const first = createRerunScriptUrl("/app.js");
|
|
62
|
+
const second = createRerunScriptUrl("/app.js");
|
|
63
|
+
expect(first).not.toBe(second);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `__ECO_PAGES__.rerunScripts` registry access for navigation reruns.
|
|
3
|
+
* @module
|
|
4
|
+
*/
|
|
5
|
+
export type RerunScriptCallback = () => void;
|
|
6
|
+
/** Attribute storing the original module `src` after cache-busting. */
|
|
7
|
+
export declare const RERUN_SRC_ATTR = "data-eco-rerun-src";
|
|
8
|
+
/**
|
|
9
|
+
* Returns a registered in-memory rerun callback for the given script id.
|
|
10
|
+
*/
|
|
11
|
+
export declare function getRegisteredRerunScript(scriptId: string | null): RerunScriptCallback | null;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const RERUN_SRC_ATTR = "data-eco-rerun-src";
|
|
2
|
+
function getRegisteredRerunScript(scriptId) {
|
|
3
|
+
if (!scriptId) {
|
|
4
|
+
return null;
|
|
5
|
+
}
|
|
6
|
+
const runtimeWindow = window;
|
|
7
|
+
return runtimeWindow.__ECO_PAGES__?.rerunScripts?.[scriptId] ?? null;
|
|
8
|
+
}
|
|
9
|
+
export {
|
|
10
|
+
RERUN_SRC_ATTR,
|
|
11
|
+
getRegisteredRerunScript
|
|
12
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Queueing and replay of `data-eco-rerun` scripts after navigation.
|
|
3
|
+
* @module
|
|
4
|
+
*/
|
|
5
|
+
export type PendingRerunScript = {
|
|
6
|
+
parent: 'head' | 'body';
|
|
7
|
+
attributes: Array<[string, string]>;
|
|
8
|
+
textContent: string;
|
|
9
|
+
src: string | null;
|
|
10
|
+
scriptId: string | null;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Collects rerun scripts from an incoming document.
|
|
14
|
+
*/
|
|
15
|
+
export declare function collectRerunScripts(document: Document, filter?: (script: HTMLScriptElement) => boolean): PendingRerunScript[];
|
|
16
|
+
/**
|
|
17
|
+
* Returns whether a rerun script is an external ES module that needs cache busting.
|
|
18
|
+
*/
|
|
19
|
+
export declare function isExternalModuleRerunScript(script: PendingRerunScript): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Finds an existing rerun script in `root` by id or by src and inline content.
|
|
22
|
+
*/
|
|
23
|
+
export declare function findExistingRerunScript(root: ParentNode, script: PendingRerunScript): HTMLScriptElement | null;
|
|
24
|
+
/**
|
|
25
|
+
* Appends a nonce query parameter so module scripts re-execute after navigation.
|
|
26
|
+
*/
|
|
27
|
+
export declare function createRerunScriptUrl(src: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* Replays queued rerun scripts after the incoming page body is in place.
|
|
30
|
+
*
|
|
31
|
+
* @remarks
|
|
32
|
+
* Flushed elements keep `data-eco-rerun` so head cleanup does not treat them
|
|
33
|
+
* as persistable inline scripts on the next navigation.
|
|
34
|
+
*/
|
|
35
|
+
export declare function flushPendingRerunScripts(scripts: readonly PendingRerunScript[]): void;
|
|
36
|
+
/** @remarks Test-only reset for nonce sequencing. */
|
|
37
|
+
export declare function resetRerunNonceForTests(): void;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { RERUN_SRC_ATTR, getRegisteredRerunScript } from "./registry.js";
|
|
2
|
+
let rerunNonce = 0;
|
|
3
|
+
function collectRerunScripts(document2, filter) {
|
|
4
|
+
return Array.from(document2.querySelectorAll("script[data-eco-rerun]")).filter((script) => filter ? filter(script) : true).map((script) => ({
|
|
5
|
+
parent: script.closest("body") ? "body" : "head",
|
|
6
|
+
attributes: Array.from(script.attributes).map((attribute) => [attribute.name, attribute.value]),
|
|
7
|
+
textContent: script.textContent ?? "",
|
|
8
|
+
src: script.getAttribute("src"),
|
|
9
|
+
scriptId: script.getAttribute("data-eco-script-id")
|
|
10
|
+
}));
|
|
11
|
+
}
|
|
12
|
+
function isExternalModuleRerunScript(script) {
|
|
13
|
+
if (!script.src) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
return script.attributes.some(([name, value]) => name === "type" && value === "module");
|
|
17
|
+
}
|
|
18
|
+
function findExistingRerunScript(root, script) {
|
|
19
|
+
const scripts = Array.from(root.querySelectorAll("script"));
|
|
20
|
+
if (script.scriptId) {
|
|
21
|
+
return scripts.find((candidate) => candidate.getAttribute("data-eco-script-id") === script.scriptId) ?? null;
|
|
22
|
+
}
|
|
23
|
+
return scripts.find(
|
|
24
|
+
(candidate) => (candidate.getAttribute(RERUN_SRC_ATTR) ?? candidate.getAttribute("src")) === script.src && (candidate.textContent ?? "") === script.textContent
|
|
25
|
+
) ?? null;
|
|
26
|
+
}
|
|
27
|
+
function createRerunScriptUrl(src) {
|
|
28
|
+
const url = new URL(src, document.baseURI);
|
|
29
|
+
url.searchParams.set("__eco_rerun", String(++rerunNonce));
|
|
30
|
+
return url.toString();
|
|
31
|
+
}
|
|
32
|
+
function flushPendingRerunScripts(scripts) {
|
|
33
|
+
for (const script of scripts) {
|
|
34
|
+
const targetParent = script.parent === "body" ? document.body : document.head;
|
|
35
|
+
const registeredRerun = getRegisteredRerunScript(script.scriptId);
|
|
36
|
+
const replacement = document.createElement("script");
|
|
37
|
+
const shouldBustModuleSrc = isExternalModuleRerunScript(script) && !registeredRerun;
|
|
38
|
+
for (const [name, value] of script.attributes) {
|
|
39
|
+
if (name === "src" && shouldBustModuleSrc) {
|
|
40
|
+
replacement.setAttribute(RERUN_SRC_ATTR, value);
|
|
41
|
+
replacement.setAttribute("src", createRerunScriptUrl(value));
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
replacement.setAttribute(name, value);
|
|
45
|
+
}
|
|
46
|
+
replacement.textContent = script.textContent;
|
|
47
|
+
const existingScript = findExistingRerunScript(targetParent, script);
|
|
48
|
+
if (registeredRerun) {
|
|
49
|
+
const needsScriptElement = isExternalModuleRerunScript(script);
|
|
50
|
+
if (!existingScript && needsScriptElement) {
|
|
51
|
+
targetParent.appendChild(replacement);
|
|
52
|
+
}
|
|
53
|
+
registeredRerun();
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (existingScript) {
|
|
57
|
+
existingScript.replaceWith(replacement);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
targetParent.appendChild(replacement);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function resetRerunNonceForTests() {
|
|
64
|
+
rerunNonce = 0;
|
|
65
|
+
}
|
|
66
|
+
export {
|
|
67
|
+
collectRerunScripts,
|
|
68
|
+
createRerunScriptUrl,
|
|
69
|
+
findExistingRerunScript,
|
|
70
|
+
flushPendingRerunScripts,
|
|
71
|
+
isExternalModuleRerunScript,
|
|
72
|
+
resetRerunNonceForTests
|
|
73
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Window scroll behavior during client-side navigations.
|
|
3
|
+
* @module
|
|
4
|
+
*/
|
|
5
|
+
export type WindowScrollBehavior = 'top' | 'preserve' | 'auto';
|
|
6
|
+
export type ManageWindowScrollOptions = {
|
|
7
|
+
scrollBehavior: WindowScrollBehavior;
|
|
8
|
+
smoothScroll: boolean;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Updates window scroll position after a navigation commit.
|
|
12
|
+
*
|
|
13
|
+
* @remarks
|
|
14
|
+
* Hash navigations always scroll to the target element and ignore `scrollBehavior`.
|
|
15
|
+
* Fragment targets are resolved by element id (`#section` → `getElementById('section')`).
|
|
16
|
+
*/
|
|
17
|
+
export declare function manageWindowScroll(newUrl: URL, previousUrl: URL, options: ManageWindowScrollOptions): void;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
function manageWindowScroll(newUrl, previousUrl, options) {
|
|
2
|
+
const { scrollBehavior, smoothScroll } = options;
|
|
3
|
+
if (newUrl.hash) {
|
|
4
|
+
const target = document.getElementById(newUrl.hash.slice(1));
|
|
5
|
+
target?.scrollIntoView({ behavior: smoothScroll ? "smooth" : "instant" });
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
const behavior = smoothScroll ? "smooth" : "instant";
|
|
9
|
+
switch (scrollBehavior) {
|
|
10
|
+
case "preserve":
|
|
11
|
+
break;
|
|
12
|
+
case "auto":
|
|
13
|
+
if (newUrl.pathname !== previousUrl.pathname) {
|
|
14
|
+
window.scrollTo({ top: 0, left: 0, behavior });
|
|
15
|
+
}
|
|
16
|
+
break;
|
|
17
|
+
case "top":
|
|
18
|
+
default:
|
|
19
|
+
window.scrollTo({ top: 0, left: 0, behavior });
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export {
|
|
24
|
+
manageWindowScroll
|
|
25
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { manageWindowScroll } from "./scroll.js";
|
|
3
|
+
const options = { scrollBehavior: "top", smoothScroll: false };
|
|
4
|
+
describe("manageWindowScroll", () => {
|
|
5
|
+
afterEach(() => {
|
|
6
|
+
history.replaceState({}, "", "/");
|
|
7
|
+
document.body.replaceChildren();
|
|
8
|
+
vi.restoreAllMocks();
|
|
9
|
+
});
|
|
10
|
+
it("scrolls to top by default", () => {
|
|
11
|
+
const scrollTo = vi.spyOn(window, "scrollTo").mockImplementation(() => {
|
|
12
|
+
});
|
|
13
|
+
manageWindowScroll(new URL("/next", window.location.origin), new URL("/prev", window.location.origin), options);
|
|
14
|
+
expect(scrollTo).toHaveBeenCalledWith({ top: 0, left: 0, behavior: "instant" });
|
|
15
|
+
});
|
|
16
|
+
it("preserves scroll when scrollBehavior is preserve", () => {
|
|
17
|
+
const scrollTo = vi.spyOn(window, "scrollTo").mockImplementation(() => {
|
|
18
|
+
});
|
|
19
|
+
manageWindowScroll(new URL("/next", window.location.origin), new URL("/prev", window.location.origin), {
|
|
20
|
+
...options,
|
|
21
|
+
scrollBehavior: "preserve"
|
|
22
|
+
});
|
|
23
|
+
expect(scrollTo).not.toHaveBeenCalled();
|
|
24
|
+
});
|
|
25
|
+
it("scrolls to hash target by element id", () => {
|
|
26
|
+
const section = document.createElement("section");
|
|
27
|
+
section.id = "section";
|
|
28
|
+
section.scrollIntoView = vi.fn();
|
|
29
|
+
document.body.append(section);
|
|
30
|
+
manageWindowScroll(
|
|
31
|
+
new URL("/page#section", window.location.origin),
|
|
32
|
+
new URL("/page", window.location.origin),
|
|
33
|
+
options
|
|
34
|
+
);
|
|
35
|
+
expect(section.scrollIntoView).toHaveBeenCalledWith({ behavior: "instant" });
|
|
36
|
+
});
|
|
37
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* View Transition API helpers for `data-view-transition` markup.
|
|
3
|
+
* @module
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Assigns `view-transition-name` from `data-view-transition` and injects morph styles.
|
|
7
|
+
*
|
|
8
|
+
* @remarks
|
|
9
|
+
* Elements without `data-view-transition-animate="fade"` get a geometric morph:
|
|
10
|
+
* the old snapshot is hidden so cross-fade ghosting does not appear.
|
|
11
|
+
*/
|
|
12
|
+
export declare function applyViewTransitionNames(): void;
|
|
13
|
+
/**
|
|
14
|
+
* Clears inline transition names and dynamic morph styles after a transition ends.
|
|
15
|
+
*/
|
|
16
|
+
export declare function clearViewTransitionNames(): void;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
const VIEW_TRANSITION_ATTR = "data-view-transition";
|
|
2
|
+
const VIEW_TRANSITION_ANIMATE_ATTR = "data-view-transition-animate";
|
|
3
|
+
const VIEW_TRANSITION_DURATION_ATTR = "data-view-transition-duration";
|
|
4
|
+
const DYNAMIC_STYLES_ID = "eco-vt-dynamic-styles";
|
|
5
|
+
function applyViewTransitionNames() {
|
|
6
|
+
const elements = document.querySelectorAll(`[${VIEW_TRANSITION_ATTR}]`);
|
|
7
|
+
const morphNames = [];
|
|
8
|
+
const customDurations = [];
|
|
9
|
+
elements.forEach((el) => {
|
|
10
|
+
const name = el.getAttribute(VIEW_TRANSITION_ATTR);
|
|
11
|
+
if (!name) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
el.style.viewTransitionName = name;
|
|
15
|
+
const animate = el.getAttribute(VIEW_TRANSITION_ANIMATE_ATTR);
|
|
16
|
+
if (animate !== "fade") {
|
|
17
|
+
morphNames.push(name);
|
|
18
|
+
}
|
|
19
|
+
const duration = el.getAttribute(VIEW_TRANSITION_DURATION_ATTR);
|
|
20
|
+
if (duration) {
|
|
21
|
+
customDurations.push({ name, duration });
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
if (morphNames.length > 0 || customDurations.length > 0) {
|
|
25
|
+
injectDynamicStyles(morphNames, customDurations);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function clearViewTransitionNames() {
|
|
29
|
+
const elements = document.querySelectorAll(`[${VIEW_TRANSITION_ATTR}]`);
|
|
30
|
+
elements.forEach((el) => {
|
|
31
|
+
el.style.viewTransitionName = "";
|
|
32
|
+
});
|
|
33
|
+
const styleEl = document.getElementById(DYNAMIC_STYLES_ID);
|
|
34
|
+
if (styleEl) {
|
|
35
|
+
styleEl.textContent = "";
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function injectDynamicStyles(morphNames, customDurations) {
|
|
39
|
+
let styleEl = document.getElementById(DYNAMIC_STYLES_ID);
|
|
40
|
+
if (!styleEl) {
|
|
41
|
+
styleEl = document.createElement("style");
|
|
42
|
+
styleEl.id = DYNAMIC_STYLES_ID;
|
|
43
|
+
styleEl.setAttribute("data-eco-persist", "");
|
|
44
|
+
document.head.append(styleEl);
|
|
45
|
+
}
|
|
46
|
+
const morphCss = morphNames.map(
|
|
47
|
+
(name) => `
|
|
48
|
+
::view-transition-old(${name}) { display: none !important; }
|
|
49
|
+
::view-transition-new(${name}) { animation: none !important; opacity: 1 !important; }
|
|
50
|
+
`
|
|
51
|
+
).join("\n");
|
|
52
|
+
const durationCss = customDurations.map(
|
|
53
|
+
({ name, duration }) => `
|
|
54
|
+
::view-transition-group(${name}) { animation-duration: ${duration} !important; }
|
|
55
|
+
`
|
|
56
|
+
).join("\n");
|
|
57
|
+
styleEl.textContent = `${morphCss}
|
|
58
|
+
${durationCss}`;
|
|
59
|
+
}
|
|
60
|
+
export {
|
|
61
|
+
applyViewTransitionNames,
|
|
62
|
+
clearViewTransitionNames
|
|
63
|
+
};
|
|
@@ -70,12 +70,7 @@ export declare class ConfigBuilder {
|
|
|
70
70
|
*
|
|
71
71
|
* - `'rolldown'` (default): Ecopages runs builds through
|
|
72
72
|
* {@link RolldownBuildAdapter}, creating a new `rolldown()` instance
|
|
73
|
-
* per build.
|
|
74
|
-
* - `'rolldown-dev'`: Ecopages runs builds through
|
|
75
|
-
* {@link RolldownDevBuildAdapter}, which wraps Rolldown's experimental
|
|
76
|
-
* `DevEngine` and reuses the cached module graph, resolver, and
|
|
77
|
-
* transform cache across rebuilds. Best for HMR and watch mode where
|
|
78
|
-
* the same entrypoints are rebuilt repeatedly.
|
|
73
|
+
* per build.
|
|
79
74
|
* - `'vite-host'`: a host runtime owns the build. Ecopages exposes a
|
|
80
75
|
* {@link ViteHostBuildAdapter} boundary marker that throws on direct
|
|
81
76
|
* use. Select this only for host-driven compatibility flows where
|
|
@@ -250,7 +245,17 @@ export declare class ConfigBuilder {
|
|
|
250
245
|
private compareVersions;
|
|
251
246
|
/**
|
|
252
247
|
* Initializes default loaders that are required for EcoPages to function.
|
|
253
|
-
*
|
|
248
|
+
*
|
|
249
|
+
* @remarks
|
|
250
|
+
* `eco-component-meta` is registered twice on purpose:
|
|
251
|
+
*
|
|
252
|
+
* - `sourceTransforms` is the canonical browser/HMR path. The Rolldown bridge
|
|
253
|
+
* runs these after first-wins `onLoad` plugins rewrite module source.
|
|
254
|
+
* - `loaders` keeps the same transform available to server-oriented builds
|
|
255
|
+
* that still use competing `onLoad` handlers directly.
|
|
256
|
+
*
|
|
257
|
+
* Browser builds exclude the loader copy in {@link getAppBrowserBuildPlugins}
|
|
258
|
+
* when the transform name is already present in `sourceTransforms`.
|
|
254
259
|
*/
|
|
255
260
|
private initializeDefaultLoaders;
|
|
256
261
|
private reviewBaseUrl;
|
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
collectConfiguredAppBuildManifestContributions,
|
|
10
10
|
createBuildAdapter,
|
|
11
11
|
setAppBuildAdapter,
|
|
12
|
-
setAppBuildExecutor,
|
|
13
12
|
updateAppBuildManifest
|
|
14
13
|
} from "../build/build-adapter.js";
|
|
15
14
|
import { GHTML_PLUGIN_NAME } from "../integrations/ghtml/ghtml.constants.js";
|
|
@@ -112,12 +111,7 @@ class ConfigBuilder {
|
|
|
112
111
|
*
|
|
113
112
|
* - `'rolldown'` (default): Ecopages runs builds through
|
|
114
113
|
* {@link RolldownBuildAdapter}, creating a new `rolldown()` instance
|
|
115
|
-
* per build.
|
|
116
|
-
* - `'rolldown-dev'`: Ecopages runs builds through
|
|
117
|
-
* {@link RolldownDevBuildAdapter}, which wraps Rolldown's experimental
|
|
118
|
-
* `DevEngine` and reuses the cached module graph, resolver, and
|
|
119
|
-
* transform cache across rebuilds. Best for HMR and watch mode where
|
|
120
|
-
* the same entrypoints are rebuilt repeatedly.
|
|
114
|
+
* per build.
|
|
121
115
|
* - `'vite-host'`: a host runtime owns the build. Ecopages exposes a
|
|
122
116
|
* {@link ViteHostBuildAdapter} boundary marker that throws on direct
|
|
123
117
|
* use. Select this only for host-driven compatibility flows where
|
|
@@ -547,7 +541,17 @@ class ConfigBuilder {
|
|
|
547
541
|
}
|
|
548
542
|
/**
|
|
549
543
|
* Initializes default loaders that are required for EcoPages to function.
|
|
550
|
-
*
|
|
544
|
+
*
|
|
545
|
+
* @remarks
|
|
546
|
+
* `eco-component-meta` is registered twice on purpose:
|
|
547
|
+
*
|
|
548
|
+
* - `sourceTransforms` is the canonical browser/HMR path. The Rolldown bridge
|
|
549
|
+
* runs these after first-wins `onLoad` plugins rewrite module source.
|
|
550
|
+
* - `loaders` keeps the same transform available to server-oriented builds
|
|
551
|
+
* that still use competing `onLoad` handlers directly.
|
|
552
|
+
*
|
|
553
|
+
* Browser builds exclude the loader copy in {@link getAppBrowserBuildPlugins}
|
|
554
|
+
* when the transform name is already present in `sourceTransforms`.
|
|
551
555
|
*/
|
|
552
556
|
async initializeDefaultLoaders() {
|
|
553
557
|
const componentMetaTransform = createEcoComponentMetaTransform({ config: this.config });
|
|
@@ -593,7 +597,6 @@ class ConfigBuilder {
|
|
|
593
597
|
updateAppBuildManifest(this.config, await collectConfiguredAppBuildManifestContributions(this.config));
|
|
594
598
|
setAppServerInvalidationState(this.config, new CounterServerInvalidationState());
|
|
595
599
|
setAppEntrypointDependencyGraph(this.config, new NoopEntrypointDependencyGraph());
|
|
596
|
-
setAppBuildExecutor(this.config, buildAdapter);
|
|
597
600
|
return this.config;
|
|
598
601
|
}
|
|
599
602
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { EcoPagesAppConfig } from '../types/public-types.js';
|
|
2
|
+
import type { IClientBridge } from '../types/public-types.js';
|
|
3
|
+
export declare function setAppDevClientBridge(appConfig: EcoPagesAppConfig, bridge: IClientBridge): void;
|
|
4
|
+
export declare function getAppDevClientBridge(appConfig: EcoPagesAppConfig): IClientBridge | undefined;
|
|
5
|
+
export declare function clearAppDevClientBridge(appConfig: EcoPagesAppConfig): void;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const appDevClientBridges = /* @__PURE__ */ new WeakMap();
|
|
2
|
+
function setAppDevClientBridge(appConfig, bridge) {
|
|
3
|
+
appDevClientBridges.set(appConfig, bridge);
|
|
4
|
+
}
|
|
5
|
+
function getAppDevClientBridge(appConfig) {
|
|
6
|
+
return appDevClientBridges.get(appConfig);
|
|
7
|
+
}
|
|
8
|
+
function clearAppDevClientBridge(appConfig) {
|
|
9
|
+
appDevClientBridges.delete(appConfig);
|
|
10
|
+
}
|
|
11
|
+
export {
|
|
12
|
+
clearAppDevClientBridge,
|
|
13
|
+
getAppDevClientBridge,
|
|
14
|
+
setAppDevClientBridge
|
|
15
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ApplicationRuntimeOptions } from '../adapters/abstract/application-adapter.js';
|
|
2
|
+
/**
|
|
3
|
+
* Returns whether the host dev server owns all browser dev-client bootstrap.
|
|
4
|
+
*
|
|
5
|
+
* When true, core must not inject the HMR runtime or signal full-page reloads.
|
|
6
|
+
*/
|
|
7
|
+
export declare function hostOwnsDevClient(runtime?: ApplicationRuntimeOptions): boolean;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-app registry for the shared HMR manager used by host-owned dev clients.
|
|
3
|
+
*/
|
|
4
|
+
import type { EcoPagesAppConfig } from '../types/public-types.js';
|
|
5
|
+
import type { IHmrManager } from '../types/public-types.js';
|
|
6
|
+
export declare function setAppHmrManager(appConfig: EcoPagesAppConfig, hmrManager: IHmrManager): void;
|
|
7
|
+
export declare function getAppHmrManager(appConfig: EcoPagesAppConfig): IHmrManager | undefined;
|
|
8
|
+
export declare function clearAppHmrManager(appConfig: EcoPagesAppConfig): void;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const appHmrManagers = /* @__PURE__ */ new WeakMap();
|
|
2
|
+
function setAppHmrManager(appConfig, hmrManager) {
|
|
3
|
+
appHmrManagers.set(appConfig, hmrManager);
|
|
4
|
+
}
|
|
5
|
+
function getAppHmrManager(appConfig) {
|
|
6
|
+
return appHmrManagers.get(appConfig);
|
|
7
|
+
}
|
|
8
|
+
function clearAppHmrManager(appConfig) {
|
|
9
|
+
appHmrManagers.delete(appConfig);
|
|
10
|
+
}
|
|
11
|
+
export {
|
|
12
|
+
clearAppHmrManager,
|
|
13
|
+
getAppHmrManager,
|
|
14
|
+
setAppHmrManager
|
|
15
|
+
};
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import type { EcoPagesAppConfig } from '../types/public-types.js';
|
|
2
2
|
import { type DevelopmentInvalidationPlan } from '../services/invalidation/development-invalidation.service.js';
|
|
3
|
+
import type { ClientBridgeEvent } from '../types/public-types.js';
|
|
3
4
|
export type HostRuntimeModuleLoader = (id: string) => Promise<unknown>;
|
|
4
5
|
export interface DevelopmentHostRuntime {
|
|
5
6
|
registerHostModuleLoader(loader: HostRuntimeModuleLoader): void;
|
|
6
7
|
planFileChange(filePath: string): DevelopmentInvalidationPlan;
|
|
7
8
|
invalidateServerModules(changedFiles?: string[]): void;
|
|
8
9
|
resetRuntimeState(changedFiles?: string[]): void;
|
|
10
|
+
broadcastClientEvent(event: ClientBridgeEvent): void;
|
|
11
|
+
isServerRenderedTemplatePlan(plan: DevelopmentInvalidationPlan): boolean;
|
|
9
12
|
}
|
|
10
13
|
export declare function createDevelopmentHostRuntime(appConfig: EcoPagesAppConfig): DevelopmentHostRuntime;
|
package/src/dev/host-runtime.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DevelopmentInvalidationService
|
|
3
3
|
} from "../services/invalidation/development-invalidation.service.js";
|
|
4
|
+
import { getAppDevClientBridge } from "./client-bridge-registry.js";
|
|
4
5
|
import { setHostModuleLoader } from "../services/module-loading/host-module-loader-registry.js";
|
|
5
6
|
function createDevelopmentHostRuntime(appConfig) {
|
|
6
7
|
const invalidationService = new DevelopmentInvalidationService(appConfig);
|
|
@@ -16,6 +17,12 @@ function createDevelopmentHostRuntime(appConfig) {
|
|
|
16
17
|
},
|
|
17
18
|
resetRuntimeState(changedFiles) {
|
|
18
19
|
invalidationService.resetRuntimeState(changedFiles);
|
|
20
|
+
},
|
|
21
|
+
broadcastClientEvent(event) {
|
|
22
|
+
getAppDevClientBridge(appConfig)?.broadcast(event);
|
|
23
|
+
},
|
|
24
|
+
isServerRenderedTemplatePlan(plan) {
|
|
25
|
+
return plan.category === "include-source" || plan.category === "explicit-server-view";
|
|
19
26
|
}
|
|
20
27
|
};
|
|
21
28
|
}
|
package/src/eco/README.md
CHANGED
|
@@ -279,6 +279,17 @@ export default eco.page({
|
|
|
279
279
|
});
|
|
280
280
|
```
|
|
281
281
|
|
|
282
|
+
**Nested layouts (outer → inner):**
|
|
283
|
+
|
|
284
|
+
```tsx
|
|
285
|
+
export default eco.page({
|
|
286
|
+
layout: [MarketingShell, DocsShell],
|
|
287
|
+
render: () => <h1>Hello</h1>,
|
|
288
|
+
});
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
A single layout remains equivalent to a one-element array. Normalization stores the stack on `config.layouts` and `config.layoutEntries` at factory time.
|
|
292
|
+
|
|
282
293
|
### `eco.component()`
|
|
283
294
|
|
|
284
295
|
Define a reusable component with dependencies.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { EcoDeclaredComponent } from '../types/public-types.js';
|
|
2
|
+
export { getUndeclaredComponentDependencyMessage } from '../errors/undeclared-component-dependency-error.js';
|
|
3
|
+
/**
|
|
4
|
+
* @remarks
|
|
5
|
+
* Declared components are produced by `eco.component()`, `eco.layout()`, and
|
|
6
|
+
* `eco.html()` after the component-meta plugin injects `config.__eco`.
|
|
7
|
+
*/
|
|
8
|
+
export declare function isEcoDeclaredComponent(component: unknown): component is EcoDeclaredComponent;
|
|
9
|
+
/**
|
|
10
|
+
* @throws {UndeclaredComponentDependencyError} When the value lacks `config.__eco`.
|
|
11
|
+
*/
|
|
12
|
+
export declare function assertEcoDeclaredComponent(component: unknown, context?: {
|
|
13
|
+
parentComponentFile?: string;
|
|
14
|
+
}): asserts component is EcoDeclaredComponent;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { UndeclaredComponentDependencyError } from "../errors/undeclared-component-dependency-error.js";
|
|
2
|
+
import { getUndeclaredComponentDependencyMessage } from "../errors/undeclared-component-dependency-error.js";
|
|
3
|
+
function isEcoDeclaredComponent(component) {
|
|
4
|
+
return typeof component === "function" && typeof component.config?.__eco?.file === "string" && typeof component.config?.__eco?.integration === "string";
|
|
5
|
+
}
|
|
6
|
+
function assertEcoDeclaredComponent(component, context = {}) {
|
|
7
|
+
if (isEcoDeclaredComponent(component)) {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
throw new UndeclaredComponentDependencyError(context.parentComponentFile);
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
assertEcoDeclaredComponent,
|
|
14
|
+
getUndeclaredComponentDependencyMessage,
|
|
15
|
+
isEcoDeclaredComponent
|
|
16
|
+
};
|
package/src/eco/eco.browser.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { applyPageLayoutConfig, mergeLayoutDependencies, normalizePageLayouts } from "./page-layout-normalization.js";
|
|
1
2
|
function createComponentFactory(options) {
|
|
2
3
|
const component2 = ((props) => options.render(props));
|
|
3
4
|
component2.config = {
|
|
@@ -32,17 +33,15 @@ function page(options) {
|
|
|
32
33
|
requires,
|
|
33
34
|
middleware
|
|
34
35
|
} = options;
|
|
36
|
+
const layoutEntries = normalizePageLayouts(pageLayout);
|
|
35
37
|
const pageComponent = createComponentFactory({
|
|
36
38
|
__eco: options.__eco,
|
|
37
39
|
integration: options.integration,
|
|
38
|
-
dependencies:
|
|
39
|
-
...dependencies,
|
|
40
|
-
components: [...dependencies?.components ?? [], pageLayout]
|
|
41
|
-
} : dependencies,
|
|
40
|
+
dependencies: mergeLayoutDependencies(dependencies, layoutEntries),
|
|
42
41
|
render
|
|
43
42
|
});
|
|
44
|
-
if (
|
|
45
|
-
pageComponent.config
|
|
43
|
+
if (pageComponent.config) {
|
|
44
|
+
applyPageLayoutConfig(pageComponent.config, layoutEntries);
|
|
46
45
|
}
|
|
47
46
|
if (staticPaths2) {
|
|
48
47
|
pageComponent.staticPaths = staticPaths2;
|