@ecopages/core 0.2.0-beta.31 → 0.2.0-beta.32
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 -0
- package/package.json +82 -3
- package/src/adapters/abstract/application-adapter.d.ts +0 -8
- package/src/adapters/abstract/application-adapter.js +252 -261
- package/src/adapters/abstract/router-adapter.js +12 -4
- package/src/adapters/abstract/segment-path-matcher.js +132 -134
- package/src/adapters/abstract/server-adapter.js +22 -14
- package/src/adapters/abstract/ws-pattern-matcher.js +24 -26
- package/src/adapters/bun/bun-user-websocket-lifecycle.js +83 -86
- package/src/adapters/bun/client-bridge.js +51 -50
- package/src/adapters/bun/create-app.js +171 -161
- package/src/adapters/bun/hmr-manager.js +62 -57
- package/src/adapters/bun/index.js +2 -31
- package/src/adapters/bun/runtime-host.js +61 -54
- package/src/adapters/bun/server-adapter.d.ts +0 -1
- package/src/adapters/bun/server-adapter.js +561 -561
- package/src/adapters/bun/static-preview-host.js +43 -46
- package/src/adapters/create-app.js +11 -14
- package/src/adapters/index.js +2 -30
- package/src/adapters/node/create-app.js +123 -129
- package/src/adapters/node/http-request-bridge.js +147 -106
- package/src/adapters/node/node-client-bridge.js +62 -64
- package/src/adapters/node/node-hmr-manager.js +58 -48
- package/src/adapters/node/runtime-host.js +96 -89
- package/src/adapters/node/server-adapter-dependencies.js +18 -21
- package/src/adapters/node/server-adapter.d.ts +0 -1
- package/src/adapters/node/server-adapter.js +347 -326
- package/src/adapters/node/static-content-server.js +172 -191
- package/src/adapters/node/static-preview-host.js +87 -78
- package/src/adapters/shared/hmr/dev-transform-entrypoint-registry.d.ts +16 -0
- package/src/adapters/shared/hmr/dev-transform-entrypoint-registry.js +32 -0
- package/src/adapters/shared/hmr/hmr-html-response.js +46 -32
- package/src/adapters/shared/hmr/shared-hmr-manager.d.ts +29 -38
- package/src/adapters/shared/hmr/shared-hmr-manager.js +439 -425
- package/src/adapters/shared/http/api-request-pipeline.js +122 -119
- package/src/adapters/shared/http/api-response.js +77 -77
- package/src/adapters/shared/http/create-body-response.js +22 -19
- package/src/adapters/shared/http/define-api-handler.js +41 -55
- package/src/adapters/shared/http/explicit-static-render-preparation.js +26 -23
- package/src/adapters/shared/http/explicit-static-route-matcher.js +55 -62
- package/src/adapters/shared/http/file-route-middleware-pipeline.js +81 -75
- package/src/adapters/shared/http/fs-server-response-factory.js +101 -96
- package/src/adapters/shared/http/fs-server-response-matcher.js +239 -257
- package/src/adapters/shared/http/run-middleware-chain.js +15 -15
- package/src/adapters/shared/runtime/application-adapter.js +72 -87
- package/src/adapters/shared/runtime/copy-runtime-public-dir.js +25 -22
- package/src/adapters/shared/runtime/port-manager.js +207 -177
- package/src/adapters/shared/runtime/render-context.js +94 -79
- package/src/adapters/shared/runtime/runtime-app-bootstrap.js +33 -38
- package/src/adapters/shared/runtime/runtime-host.js +1 -0
- package/src/adapters/shared/runtime/runtime-server-lifecycle.d.ts +2 -3
- package/src/adapters/shared/runtime/runtime-server-lifecycle.js +65 -51
- package/src/adapters/shared/runtime/server-adapter.d.ts +1 -0
- package/src/adapters/shared/runtime/server-adapter.js +233 -217
- package/src/adapters/shared/runtime/server-route-handler.js +74 -70
- package/src/adapters/shared/runtime/server-static-builder.js +165 -184
- package/src/adapters/shared/runtime/static-preview-host.js +1 -0
- package/src/adapters/shared/ws/node-http-websocket-upgrades.js +97 -88
- package/src/adapters/shared/ws/websocket-lifecycle.js +57 -50
- package/src/build/README.md +52 -1
- package/src/build/app-build-manifest-runtime.js +129 -108
- package/src/build/browser/browser-runtime-manifest.js +47 -50
- package/src/build/browser/browser-runtime-plugin-helpers.js +32 -12
- package/src/build/browser/browser-runtime-plugin.js +206 -160
- package/src/build/browser/jsx-ownership-plugins.js +51 -37
- package/src/build/browser/lit-static-render-worker-context.js +3 -5
- package/src/build/build-adapter.js +276 -139
- package/src/build/cache/build-input-fingerprint.js +28 -26
- package/src/build/cache/cache-constants.js +4 -6
- package/src/build/cache/cache-keys.js +64 -56
- package/src/build/cache/pages-unified-graph-build.js +179 -178
- package/src/build/cache/production-build-cache.js +47 -54
- package/src/build/cache/server-entry-build-cache.js +134 -146
- package/src/build/contracts/build-contracts.d.ts +4 -4
- package/src/build/contracts/build-contracts.js +1 -0
- package/src/build/contracts/build-manifest.js +58 -43
- package/src/build/contracts/build-types.js +1 -0
- package/src/build/rolldown/rolldown-adapter-helpers.d.ts +9 -0
- package/src/build/rolldown/rolldown-adapter-helpers.js +405 -298
- package/src/build/rolldown/rolldown-build-adapter.js +53 -61
- package/src/build/rolldown/rolldown-build-invocation-metrics.js +31 -35
- package/src/build/rolldown/rolldown-plugin-bridge.js +264 -194
- package/src/build/rolldown/rolldown-source-transform-pass.js +59 -50
- package/src/build/rolldown/runtime-build-output-normalizer.js +227 -175
- package/src/build/rolldown/server-side-css-shim-plugin.js +54 -31
- package/src/build/runtime/build-profile-options.js +36 -36
- package/src/build/runtime/build-request-identity.js +70 -45
- package/src/build/runtime/build-request-policy.js +80 -42
- package/src/build/runtime/build-runtime.js +64 -54
- package/src/build/runtime/deduping-build-executor.js +38 -32
- package/src/build/runtime/parallel-build-executor.js +58 -50
- package/src/build/runtime/serialized-build-executor.js +78 -62
- package/src/cache/index.js +6 -6
- package/src/cache/module-parse-cache.js +99 -68
- package/src/client/navigation-scripts/classification.js +45 -37
- package/src/client/navigation-scripts/index.js +3 -23
- package/src/client/navigation-scripts/navigation-scripts.test.browser.js +58 -62
- package/src/client/navigation-scripts/registry.js +15 -11
- package/src/client/navigation-scripts/rerun-queue.js +81 -64
- package/src/client/scroll.js +32 -24
- package/src/client/scroll.test.browser.js +27 -33
- package/src/client/view-transitions.js +68 -55
- package/src/config/config-builder.d.ts +8 -0
- package/src/config/config-builder.js +637 -642
- package/src/config/constants.js +44 -24
- package/src/declarations.d.ts +1 -0
- package/src/dev/README.md +24 -0
- package/src/dev/client-bridge-registry.js +7 -12
- package/src/dev/dev-client-ownership.js +7 -5
- package/src/dev/hmr-manager-registry.js +7 -12
- package/src/dev/host-runtime.js +25 -30
- package/src/dev/runtime-server-started-message.js +2 -5
- package/src/dev/sc-server.js +106 -103
- package/src/dev/transform-server/dev-transform-bundler.d.ts +24 -0
- package/src/dev/transform-server/dev-transform-bundler.js +79 -0
- package/src/dev/transform-server/dev-transform-externalize-plugin.d.ts +12 -0
- package/src/dev/transform-server/dev-transform-externalize-plugin.js +29 -0
- package/src/dev/transform-server/dev-transform-import-rewriter.d.ts +16 -0
- package/src/dev/transform-server/dev-transform-import-rewriter.js +110 -0
- package/src/dev/transform-server/dev-transform-module-kind.d.ts +13 -0
- package/src/dev/transform-server/dev-transform-module-kind.js +17 -0
- package/src/dev/transform-server/dev-transform-runtime-specifiers.d.ts +5 -0
- package/src/dev/transform-server/dev-transform-runtime-specifiers.js +16 -0
- package/src/dev/transform-server/dev-transform-server.d.ts +41 -0
- package/src/dev/transform-server/dev-transform-server.js +191 -0
- package/src/dev/transform-server/dev-transform-url.d.ts +13 -0
- package/src/dev/transform-server/dev-transform-url.js +58 -0
- package/src/dev/transform-server/dev-transform-vendor-registry.d.ts +27 -0
- package/src/dev/transform-server/dev-transform-vendor-registry.js +145 -0
- package/src/dev/transform-server/index.d.ts +6 -0
- package/src/dev/transform-server/index.js +4 -0
- package/src/dev/transform-server/types.d.ts +15 -0
- package/src/dev/transform-server/types.js +1 -0
- package/src/dev-toolbar/README.md +51 -0
- package/src/dev-toolbar/define-dev-tool.d.ts +21 -0
- package/src/dev-toolbar/define-dev-tool.js +9 -0
- package/src/dev-toolbar/dev-toolbar-config.d.ts +25 -0
- package/src/dev-toolbar/dev-toolbar-config.js +19 -0
- package/src/dev-toolbar/dev-toolbar-host.d.ts +49 -0
- package/src/dev-toolbar/dev-toolbar-host.js +117 -0
- package/src/dev-toolbar/dev-toolbar-html-response.d.ts +11 -0
- package/src/dev-toolbar/dev-toolbar-html-response.js +14 -0
- package/src/dev-toolbar/dev-toolbar-manifest.d.ts +15 -0
- package/src/dev-toolbar/dev-toolbar-manifest.js +52 -0
- package/src/dev-toolbar/dev-toolbar-package.d.ts +31 -0
- package/src/dev-toolbar/dev-toolbar-package.js +72 -0
- package/src/dev-toolbar/dev-toolbar-runtime-paths.d.ts +10 -0
- package/src/dev-toolbar/dev-toolbar-runtime-paths.js +13 -0
- package/src/diagnostics/request-build-dedupe.js +34 -28
- package/src/diagnostics/startup-trace.d.ts +10 -1
- package/src/diagnostics/startup-trace.js +269 -241
- package/src/eco/README.md +6 -0
- package/src/eco/eco-declared-component.js +19 -14
- package/src/eco/eco.browser.js +56 -69
- package/src/eco/eco.js +156 -96
- package/src/eco/eco.types.js +5 -0
- package/src/eco/eco.utils.js +1 -10
- package/src/eco/global-injector-map.js +55 -41
- package/src/eco/lazy-injector-map.js +90 -60
- package/src/eco/module-dependencies.js +52 -44
- package/src/eco/page-layout-normalization.js +59 -49
- package/src/errors/http-error.js +50 -49
- package/src/errors/index.js +3 -12
- package/src/errors/locals-access-error.js +5 -8
- package/src/errors/undeclared-component-dependency-error.js +15 -15
- package/src/global/app-logger.js +3 -6
- package/src/hmr/README.md +10 -0
- package/src/hmr/client/hmr-runtime.js +117 -113
- package/src/hmr/client/module-update.d.ts +13 -0
- package/src/hmr/client/module-update.js +39 -0
- package/src/hmr/hmr-asset-paths.d.ts +14 -0
- package/src/hmr/hmr-asset-paths.js +22 -0
- package/src/hmr/hmr-entrypoint-output.d.ts +11 -39
- package/src/hmr/hmr-entrypoint-output.js +28 -54
- package/src/hmr/hmr-file-change-prep.js +13 -16
- package/src/hmr/hmr-registered-entrypoints-context.d.ts +7 -0
- package/src/hmr/hmr-registered-entrypoints-context.js +1 -0
- package/src/hmr/hmr-runtime-paths.d.ts +10 -0
- package/src/hmr/hmr-runtime-paths.js +13 -0
- package/src/hmr/hmr-strategy.d.ts +5 -11
- package/src/hmr/hmr-strategy.js +113 -61
- package/src/hmr/strategies/default-hmr-strategy.js +55 -33
- package/src/hmr/strategies/js-hmr-strategy.d.ts +6 -95
- package/src/hmr/strategies/js-hmr-strategy.js +104 -217
- package/src/hmr/strategies/server-rendered-template-hmr-strategy.js +33 -27
- package/src/index.browser.js +1 -4
- package/src/index.d.ts +1 -0
- package/src/index.js +6 -47
- package/src/integrations/ghtml/ghtml-renderer.js +12 -7
- package/src/integrations/ghtml/ghtml.constants.js +1 -4
- package/src/integrations/ghtml/ghtml.plugin.js +9 -12
- package/src/islands/README.md +25 -0
- package/src/islands/island-host.d.ts +37 -0
- package/src/islands/island-host.js +55 -0
- package/src/plugins/alias-resolver-cache.js +114 -97
- package/src/plugins/alias-resolver-plugin.js +33 -47
- package/src/plugins/define-integration.js +18 -17
- package/src/plugins/eco-component-meta-plugin.js +387 -145
- package/src/plugins/foreign-jsx-override-plugin.js +49 -35
- package/src/plugins/integration-plugin.js +212 -203
- package/src/plugins/jsx-import-source.utils.js +16 -21
- package/src/plugins/processor.js +159 -149
- package/src/plugins/runtime-capability.js +1 -0
- package/src/plugins/source-transform.js +109 -79
- package/src/plugins/tsconfig-import-resolver.d.ts +17 -0
- package/src/plugins/tsconfig-import-resolver.js +218 -142
- package/src/route-renderer/README.md +12 -1
- package/src/route-renderer/orchestration/document-shell/document-shell-render.service.js +143 -136
- package/src/route-renderer/orchestration/document-shell/layout-shell-props.service.js +33 -27
- package/src/route-renderer/orchestration/foreign-child/component-render-context.js +173 -126
- package/src/route-renderer/orchestration/foreign-child/foreign-child-output.utils.js +165 -154
- package/src/route-renderer/orchestration/foreign-child/foreign-subtree-execution.service.js +329 -341
- package/src/route-renderer/orchestration/foreign-child/owning-renderer-resolution.js +33 -32
- package/src/route-renderer/orchestration/integration-renderer.d.ts +1 -0
- package/src/route-renderer/orchestration/integration-renderer.js +731 -750
- package/src/route-renderer/orchestration/integration-renderer.test-fixtures.js +168 -172
- package/src/route-renderer/orchestration/ownership-graph/component-graph-collectors.js +119 -131
- package/src/route-renderer/orchestration/ownership-graph/component-graph.js +82 -91
- package/src/route-renderer/orchestration/ownership-graph/ownership-validation.service.js +82 -76
- package/src/route-renderer/orchestration/page-browser-graph/global-injector-assets.service.js +29 -31
- package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph-contribution.loader.js +10 -6
- package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph-merge.utils.js +31 -28
- package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph-session.d.ts +3 -0
- package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph-session.js +430 -413
- package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph.service.js +191 -212
- package/src/route-renderer/orchestration/page-browser-graph/processed-asset-dedupe.js +20 -24
- package/src/route-renderer/orchestration/route-pipeline/integration-route-render-adapter.d.ts +4 -0
- package/src/route-renderer/orchestration/route-pipeline/integration-route-render-adapter.js +24 -24
- package/src/route-renderer/orchestration/route-pipeline/marker-artifact.utils.js +22 -24
- package/src/route-renderer/orchestration/route-pipeline/robots-meta.contribution.js +41 -34
- package/src/route-renderer/orchestration/route-pipeline/route-html-finalization.service.d.ts +5 -0
- package/src/route-renderer/orchestration/route-pipeline/route-html-finalization.service.js +42 -22
- package/src/route-renderer/orchestration/route-pipeline/route-prepared-options.builder.js +50 -48
- package/src/route-renderer/orchestration/route-pipeline/route-prepared-options.utils.js +29 -32
- package/src/route-renderer/orchestration/route-pipeline/route-render-orchestrator.js +150 -156
- package/src/route-renderer/orchestration/string-markup-renderer.js +48 -51
- package/src/route-renderer/page-loading/component-dependency-collection.js +120 -124
- package/src/route-renderer/page-loading/declared-asset-collection.js +66 -94
- package/src/route-renderer/page-loading/dependency-resolver.js +101 -104
- package/src/route-renderer/page-loading/ecopages-virtual-imports.js +68 -54
- package/src/route-renderer/page-loading/lazy-entry-collection.js +75 -98
- package/src/route-renderer/page-loading/lazy-trigger-planning.js +46 -36
- package/src/route-renderer/page-loading/module-declaration-aggregation.js +38 -31
- package/src/route-renderer/page-loading/module-declaration-scripts.js +10 -15
- package/src/route-renderer/page-loading/page-dependency-bundling.js +156 -113
- package/src/route-renderer/page-loading/page-module-loader.js +130 -124
- package/src/route-renderer/route-renderer.js +74 -76
- package/src/router/client/link-intent.js +55 -39
- package/src/router/client/link-intent.test.browser.js +49 -49
- package/src/router/client/link-navigation-policy.js +114 -93
- package/src/router/client/link-navigation-policy.test.browser.js +70 -80
- package/src/router/client/navigation-coordinator.js +235 -211
- package/src/router/server/route-registry.js +237 -242
- package/src/services/assets/asset-processing-service/asset-dependency-keys.js +64 -53
- package/src/services/assets/asset-processing-service/asset-processing.service.js +287 -303
- package/src/services/assets/asset-processing-service/asset.factory.js +78 -81
- package/src/services/assets/asset-processing-service/assets.types.js +1 -0
- package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.js +57 -46
- package/src/services/assets/asset-processing-service/browser-runtime-entry-resolution.js +106 -69
- package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.js +53 -53
- package/src/services/assets/asset-processing-service/finalize-processed-asset.js +4 -6
- package/src/services/assets/asset-processing-service/grouped-content-bundles.js +79 -80
- package/src/services/assets/asset-processing-service/index.js +8 -8
- package/src/services/assets/asset-processing-service/inline-content-script-body.js +22 -16
- package/src/services/assets/asset-processing-service/materialize-content-script-asset.js +21 -17
- package/src/services/assets/asset-processing-service/page-package.js +70 -72
- package/src/services/assets/asset-processing-service/processor.interface.js +7 -5
- package/src/services/assets/asset-processing-service/processor.registry.js +11 -14
- package/src/services/assets/asset-processing-service/processors/base/base-processor.js +59 -62
- package/src/services/assets/asset-processing-service/processors/base/base-script-processor.js +102 -117
- package/src/services/assets/asset-processing-service/processors/index.js +5 -5
- package/src/services/assets/asset-processing-service/processors/script/content-script.processor.js +110 -115
- package/src/services/assets/asset-processing-service/processors/script/file-script.processor.js +95 -97
- package/src/services/assets/asset-processing-service/processors/script/node-module-script.processor.js +136 -135
- package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.js +27 -29
- package/src/services/assets/asset-processing-service/processors/stylesheet/file-stylesheet.processor.js +34 -40
- package/src/services/assets/asset-processing-service/processors/stylesheet/stylesheet-processor-pipeline.js +36 -35
- package/src/services/assets/asset-processing-service/resolve-integration-plugin.js +14 -16
- package/src/services/assets/asset-processing-service/ungrouped-dependency-processing.js +27 -39
- package/src/services/assets/browser-bundle.service.js +52 -47
- package/src/services/cache/cache.types.js +5 -0
- package/src/services/cache/index.js +6 -7
- package/src/services/cache/memory-cache-store.js +101 -89
- package/src/services/cache/page-cache-service.js +156 -145
- package/src/services/cache/page-request-cache-coordinator.service.js +102 -102
- package/src/services/html/html-rewriter-provider.service.js +61 -61
- package/src/services/html/html-transformer.service.js +249 -266
- package/src/services/invalidation/development-invalidation.service.js +252 -241
- package/src/services/module-loading/app-module-loader.service.js +1 -0
- package/src/services/module-loading/app-server-module-transpiler.service.js +107 -101
- package/src/services/module-loading/host-module-loader-registry.js +6 -11
- package/src/services/module-loading/module-loading-types.js +1 -0
- package/src/services/module-loading/page-module-import.service.js +235 -243
- package/src/services/module-loading/route-module-build-cache-registry.js +47 -33
- package/src/services/module-loading/route-module-build-cache.js +3 -38
- package/src/services/module-loading/route-module-build-cache.store.js +195 -200
- package/src/services/module-loading/route-module-build-manifest.js +61 -74
- package/src/services/module-loading/route-module-dependency-hasher.js +136 -110
- package/src/services/module-loading/server-module-transpiler.service.js +68 -62
- package/src/services/module-loading/source-module-support.js +15 -7
- package/src/services/runtime-state/dev-graph.service.js +165 -157
- package/src/services/runtime-state/entrypoint-dependency-graph.service.js +85 -76
- package/src/services/runtime-state/server-invalidation-state.service.js +38 -30
- package/src/services/validation/schema-validation-service.js +157 -95
- package/src/services/validation/standard-schema.types.js +1 -0
- package/src/services/validation/validate-standard-schema.js +13 -13
- package/src/static-site-generator/production-page-browser-graph-prebuild.js +35 -19
- package/src/static-site-generator/sitemap-routes.js +33 -28
- package/src/static-site-generator/sitemap.js +38 -29
- package/src/static-site-generator/static-build-invalidation.js +34 -56
- package/src/static-site-generator/static-export-context.js +1 -0
- package/src/static-site-generator/static-site-generator.js +517 -553
- package/src/types/internal-types.d.ts +19 -3
- package/src/types/internal-types.js +1 -0
- package/src/types/public-types.d.ts +16 -46
- package/src/types/public-types.js +1 -0
- package/src/utils/deep-merge.js +39 -26
- package/src/utils/ecopages-route-info.js +27 -23
- package/src/utils/hash.js +3 -6
- package/src/utils/html-escaping.js +21 -8
- package/src/utils/html.js +1 -4
- package/src/utils/invariant.js +11 -10
- package/src/utils/locals-utils.js +32 -22
- package/src/utils/parse-cli-args.js +73 -65
- package/src/utils/path-pattern.js +38 -23
- package/src/utils/path-utils.module.js +8 -11
- package/src/utils/resolve-entry-file.js +70 -38
- package/src/utils/resolve-work-dir.js +23 -27
- package/src/utils/runtime.js +24 -33
- package/src/utils/server-utils.module.js +60 -52
- package/src/utils/static-file-extensions.js +52 -46
- package/src/watchers/project-watcher-ignore.js +16 -15
- package/src/watchers/project-watcher.js +385 -366
- package/src/watchers/project-watcher.test-helpers.js +45 -50
- package/src/adapters/shared/hmr/hmr-entrypoint-registrar.d.ts +0 -56
- package/src/adapters/shared/hmr/hmr-entrypoint-registrar.js +0 -106
- package/src/build/cache/dev-browser-script-cache.d.ts +0 -34
- package/src/build/cache/dev-browser-script-cache.js +0 -90
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { cachedParseSync } from '../../cache/module-parse-cache.js';
|
|
3
|
+
import { isBarePackageImportSpecifier, resolveProjectModulePath } from '../../plugins/tsconfig-import-resolver.js';
|
|
4
|
+
import { resolveDevTransformModuleUrl } from './dev-transform-url.js';
|
|
5
|
+
function isRecord(value) {
|
|
6
|
+
return Boolean(value) && typeof value === 'object';
|
|
7
|
+
}
|
|
8
|
+
function readStringLiteral(node) {
|
|
9
|
+
if (!isRecord(node)) {
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
12
|
+
if (node.type !== 'StringLiteral' && node.type !== 'Literal') {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
if (typeof node.value !== 'string' || typeof node.start !== 'number' || typeof node.end !== 'number') {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
return { start: node.start, end: node.end, value: node.value };
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Rewrites static and dynamic import specifiers to dev-transform or vendor URLs.
|
|
22
|
+
*/
|
|
23
|
+
export async function rewriteModuleImports(options) {
|
|
24
|
+
const normalizedSource = path.resolve(options.sourcePath);
|
|
25
|
+
const dependencies = new Set();
|
|
26
|
+
const specifierNodes = [];
|
|
27
|
+
const parseResult = cachedParseSync(normalizedSource, options.code, {
|
|
28
|
+
sourceType: 'module',
|
|
29
|
+
lang: path.extname(normalizedSource).endsWith('x') ? 'tsx' : 'ts',
|
|
30
|
+
});
|
|
31
|
+
const walk = (node) => {
|
|
32
|
+
if (!isRecord(node)) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (node.type === 'ImportDeclaration' ||
|
|
36
|
+
node.type === 'ExportNamedDeclaration' ||
|
|
37
|
+
node.type === 'ExportAllDeclaration') {
|
|
38
|
+
const literal = readStringLiteral(node.source);
|
|
39
|
+
if (literal) {
|
|
40
|
+
specifierNodes.push(literal);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (node.type === 'ImportExpression') {
|
|
44
|
+
const literal = readStringLiteral(node.source);
|
|
45
|
+
if (literal) {
|
|
46
|
+
specifierNodes.push(literal);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
for (const value of Object.values(node)) {
|
|
50
|
+
if (Array.isArray(value)) {
|
|
51
|
+
for (const child of value) {
|
|
52
|
+
walk(child);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
walk(value);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
walk(parseResult.program);
|
|
61
|
+
const edits = [];
|
|
62
|
+
for (const specifierNode of specifierNodes) {
|
|
63
|
+
const rewritten = await resolveImportSpecifier({
|
|
64
|
+
specifier: specifierNode.value,
|
|
65
|
+
sourcePath: normalizedSource,
|
|
66
|
+
srcDir: options.srcDir,
|
|
67
|
+
projectRoot: options.projectRoot,
|
|
68
|
+
runtimeSpecifierMap: options.runtimeSpecifierMap,
|
|
69
|
+
resolveVendorUrl: options.resolveVendorUrl,
|
|
70
|
+
dependencies,
|
|
71
|
+
});
|
|
72
|
+
if (!rewritten || rewritten === specifierNode.value) {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
const quote = options.code[specifierNode.start] === "'" ? "'" : '"';
|
|
76
|
+
edits.push({
|
|
77
|
+
start: specifierNode.start,
|
|
78
|
+
end: specifierNode.end,
|
|
79
|
+
replacement: `${quote}${rewritten}${quote}`,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
edits.sort((left, right) => right.start - left.start);
|
|
83
|
+
let code = options.code;
|
|
84
|
+
for (const edit of edits) {
|
|
85
|
+
code = `${code.slice(0, edit.start)}${edit.replacement}${code.slice(edit.end)}`;
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
code,
|
|
89
|
+
dependencies: [...dependencies],
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
async function resolveImportSpecifier(options) {
|
|
93
|
+
const runtimeUrl = options.runtimeSpecifierMap.get(options.specifier);
|
|
94
|
+
if (runtimeUrl) {
|
|
95
|
+
return runtimeUrl;
|
|
96
|
+
}
|
|
97
|
+
if (options.specifier.startsWith('node:')) {
|
|
98
|
+
throw new Error(`[dev-transform] Node builtin "${options.specifier}" imported from client module ${options.sourcePath}. ` +
|
|
99
|
+
`Check package "browser" exports / client-graph boundary for the importer.`);
|
|
100
|
+
}
|
|
101
|
+
if (options.specifier.startsWith('.') || !isBarePackageImportSpecifier(options.specifier, options.projectRoot)) {
|
|
102
|
+
const resolvedPath = resolveProjectModulePath(options.projectRoot, options.sourcePath, options.specifier);
|
|
103
|
+
if (!resolvedPath) {
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
options.dependencies.add(resolvedPath);
|
|
107
|
+
return resolveDevTransformModuleUrl(options.srcDir, resolvedPath);
|
|
108
|
+
}
|
|
109
|
+
return options.resolveVendorUrl(options.specifier);
|
|
110
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type DevTransformModuleKind = 'script' | 'stylesheet';
|
|
2
|
+
/**
|
|
3
|
+
* Classifies a dev-transform source path for materialization.
|
|
4
|
+
*/
|
|
5
|
+
export declare function resolveDevTransformModuleKind(sourcePath: string): DevTransformModuleKind;
|
|
6
|
+
/**
|
|
7
|
+
* Emits browser ESM for a stylesheet import (`import styles from './x.css'`).
|
|
8
|
+
*
|
|
9
|
+
* @remarks
|
|
10
|
+
* Parallels the server-side CSS shim: CSS stays in the module graph as a string
|
|
11
|
+
* export while real stylesheet delivery uses `dependencies.stylesheets`.
|
|
12
|
+
*/
|
|
13
|
+
export declare function materializeDevTransformStylesheet(cssContent: string): string;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
/**
|
|
3
|
+
* Classifies a dev-transform source path for materialization.
|
|
4
|
+
*/
|
|
5
|
+
export function resolveDevTransformModuleKind(sourcePath) {
|
|
6
|
+
return path.extname(sourcePath) === '.css' ? 'stylesheet' : 'script';
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Emits browser ESM for a stylesheet import (`import styles from './x.css'`).
|
|
10
|
+
*
|
|
11
|
+
* @remarks
|
|
12
|
+
* Parallels the server-side CSS shim: CSS stays in the module graph as a string
|
|
13
|
+
* export while real stylesheet delivery uses `dependencies.stylesheets`.
|
|
14
|
+
*/
|
|
15
|
+
export function materializeDevTransformStylesheet(cssContent) {
|
|
16
|
+
return `export default ${JSON.stringify(cssContent)};\n`;
|
|
17
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { DevTransformBundleContributor } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Merges runtime manifest specifiers from all dev-transform contributors.
|
|
4
|
+
*/
|
|
5
|
+
export declare function mergeContributorRuntimeSpecifierMaps(contributors: readonly DevTransformBundleContributor[]): Map<string, string>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merges runtime manifest specifiers from all dev-transform contributors.
|
|
3
|
+
*/
|
|
4
|
+
export function mergeContributorRuntimeSpecifierMaps(contributors) {
|
|
5
|
+
const merged = new Map();
|
|
6
|
+
for (const contributor of contributors) {
|
|
7
|
+
const runtimeSpecifierMap = contributor.getRuntimeSpecifierMap?.();
|
|
8
|
+
if (!runtimeSpecifierMap) {
|
|
9
|
+
continue;
|
|
10
|
+
}
|
|
11
|
+
for (const [specifier, url] of runtimeSpecifierMap) {
|
|
12
|
+
merged.set(specifier, url);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return merged;
|
|
16
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { EcoPagesAppConfig } from '../../types/internal-types.js';
|
|
2
|
+
import type { DevTransformBundleContributor } from './types.js';
|
|
3
|
+
export type DevTransformServerOptions = {
|
|
4
|
+
appConfig: EcoPagesAppConfig;
|
|
5
|
+
contributors?: readonly DevTransformBundleContributor[];
|
|
6
|
+
onModuleDependencies?: (modulePath: string, dependencies: string[]) => void;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Serves per-module browser ESM on demand during native CLI dev.
|
|
10
|
+
*
|
|
11
|
+
* @remarks
|
|
12
|
+
* Registration returns a stable URL immediately; the first request (or a cache miss)
|
|
13
|
+
* transpiles one source file and rewrites imports to dev-transform or vendor URLs.
|
|
14
|
+
*/
|
|
15
|
+
export declare class DevTransformServer {
|
|
16
|
+
private readonly appConfig;
|
|
17
|
+
private readonly bundler;
|
|
18
|
+
private readonly vendorRegistry;
|
|
19
|
+
private readonly contributors;
|
|
20
|
+
private readonly runtimeSpecifierMap;
|
|
21
|
+
private readonly onModuleDependencies?;
|
|
22
|
+
private readonly urlToSource;
|
|
23
|
+
private readonly sourceToUrl;
|
|
24
|
+
private readonly cache;
|
|
25
|
+
private readonly inFlight;
|
|
26
|
+
private cacheGeneration;
|
|
27
|
+
constructor(options: DevTransformServerOptions);
|
|
28
|
+
registerModule(sourcePath: string): string;
|
|
29
|
+
getRegisteredSourcePath(moduleUrl: string): string | undefined;
|
|
30
|
+
addContributor(contributor: DevTransformBundleContributor): void;
|
|
31
|
+
private rebuildRuntimeSpecifierMap;
|
|
32
|
+
private resolveVendorBundlePlugins;
|
|
33
|
+
getWatchedModules(): ReadonlyMap<string, string>;
|
|
34
|
+
invalidateSource(sourcePath: string): void;
|
|
35
|
+
invalidateAll(): void;
|
|
36
|
+
reset(): void;
|
|
37
|
+
tryHandleRequest(request: Request): Promise<Response | null>;
|
|
38
|
+
private resolveSourcePathFromModuleUrl;
|
|
39
|
+
private createJavaScriptResponse;
|
|
40
|
+
private materialize;
|
|
41
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { fileSystem } from '@ecopages/file-system';
|
|
3
|
+
import { appLogger } from '../../global/app-logger.js';
|
|
4
|
+
import { startupTrace } from '../../diagnostics/startup-trace.js';
|
|
5
|
+
import { DevTransformBundler } from './dev-transform-bundler.js';
|
|
6
|
+
import { DevTransformVendorRegistry } from './dev-transform-vendor-registry.js';
|
|
7
|
+
import { materializeDevTransformStylesheet, resolveDevTransformModuleKind } from './dev-transform-module-kind.js';
|
|
8
|
+
import { mergeContributorRuntimeSpecifierMaps } from './dev-transform-runtime-specifiers.js';
|
|
9
|
+
import { resolveDevTransformModuleSourcePath, resolveDevTransformModuleUrl } from './dev-transform-url.js';
|
|
10
|
+
/**
|
|
11
|
+
* Serves per-module browser ESM on demand during native CLI dev.
|
|
12
|
+
*
|
|
13
|
+
* @remarks
|
|
14
|
+
* Registration returns a stable URL immediately; the first request (or a cache miss)
|
|
15
|
+
* transpiles one source file and rewrites imports to dev-transform or vendor URLs.
|
|
16
|
+
*/
|
|
17
|
+
export class DevTransformServer {
|
|
18
|
+
appConfig;
|
|
19
|
+
bundler;
|
|
20
|
+
vendorRegistry;
|
|
21
|
+
contributors = [];
|
|
22
|
+
runtimeSpecifierMap = new Map();
|
|
23
|
+
onModuleDependencies;
|
|
24
|
+
urlToSource = new Map();
|
|
25
|
+
sourceToUrl = new Map();
|
|
26
|
+
cache = new Map();
|
|
27
|
+
inFlight = new Map();
|
|
28
|
+
cacheGeneration = 0;
|
|
29
|
+
constructor(options) {
|
|
30
|
+
this.appConfig = options.appConfig;
|
|
31
|
+
this.onModuleDependencies = options.onModuleDependencies;
|
|
32
|
+
this.contributors.push(...(options.contributors ?? []));
|
|
33
|
+
this.rebuildRuntimeSpecifierMap();
|
|
34
|
+
this.vendorRegistry = new DevTransformVendorRegistry({
|
|
35
|
+
appConfig: options.appConfig,
|
|
36
|
+
getRuntimeSpecifierMap: () => this.runtimeSpecifierMap,
|
|
37
|
+
resolveVendorBundlePlugins: () => this.resolveVendorBundlePlugins(),
|
|
38
|
+
});
|
|
39
|
+
this.bundler = new DevTransformBundler({
|
|
40
|
+
appConfig: options.appConfig,
|
|
41
|
+
contributors: this.contributors,
|
|
42
|
+
getRuntimeSpecifierMap: () => this.runtimeSpecifierMap,
|
|
43
|
+
vendorRegistry: this.vendorRegistry,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
registerModule(sourcePath) {
|
|
47
|
+
const normalized = path.resolve(sourcePath);
|
|
48
|
+
const existing = this.sourceToUrl.get(normalized);
|
|
49
|
+
if (existing) {
|
|
50
|
+
return existing;
|
|
51
|
+
}
|
|
52
|
+
const url = resolveDevTransformModuleUrl(this.appConfig.absolutePaths.srcDir, normalized);
|
|
53
|
+
this.sourceToUrl.set(normalized, url);
|
|
54
|
+
this.urlToSource.set(url, normalized);
|
|
55
|
+
return url;
|
|
56
|
+
}
|
|
57
|
+
getRegisteredSourcePath(moduleUrl) {
|
|
58
|
+
return this.urlToSource.get(moduleUrl);
|
|
59
|
+
}
|
|
60
|
+
addContributor(contributor) {
|
|
61
|
+
this.contributors.push(contributor);
|
|
62
|
+
this.rebuildRuntimeSpecifierMap();
|
|
63
|
+
this.bundler.addContributor(contributor);
|
|
64
|
+
}
|
|
65
|
+
rebuildRuntimeSpecifierMap() {
|
|
66
|
+
this.runtimeSpecifierMap.clear();
|
|
67
|
+
for (const [specifier, url] of mergeContributorRuntimeSpecifierMaps(this.contributors)) {
|
|
68
|
+
this.runtimeSpecifierMap.set(specifier, url);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async resolveVendorBundlePlugins() {
|
|
72
|
+
const plugins = [];
|
|
73
|
+
for (const contributor of this.contributors) {
|
|
74
|
+
if (!contributor.getVendorBundlePlugins) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
plugins.push(...(await contributor.getVendorBundlePlugins()));
|
|
78
|
+
}
|
|
79
|
+
return plugins;
|
|
80
|
+
}
|
|
81
|
+
getWatchedModules() {
|
|
82
|
+
return this.urlToSource;
|
|
83
|
+
}
|
|
84
|
+
invalidateSource(sourcePath) {
|
|
85
|
+
const normalized = path.resolve(sourcePath);
|
|
86
|
+
this.cache.delete(normalized);
|
|
87
|
+
}
|
|
88
|
+
invalidateAll() {
|
|
89
|
+
this.cacheGeneration += 1;
|
|
90
|
+
this.cache.clear();
|
|
91
|
+
this.inFlight.clear();
|
|
92
|
+
this.vendorRegistry.invalidateAll();
|
|
93
|
+
}
|
|
94
|
+
reset() {
|
|
95
|
+
this.urlToSource.clear();
|
|
96
|
+
this.sourceToUrl.clear();
|
|
97
|
+
this.invalidateAll();
|
|
98
|
+
}
|
|
99
|
+
async tryHandleRequest(request) {
|
|
100
|
+
const url = new URL(request.url);
|
|
101
|
+
const vendorResponse = this.vendorRegistry.tryHandleVendorRequest(url.pathname);
|
|
102
|
+
if (vendorResponse) {
|
|
103
|
+
return vendorResponse;
|
|
104
|
+
}
|
|
105
|
+
const sourcePath = this.urlToSource.get(url.pathname) ?? this.resolveSourcePathFromModuleUrl(url.pathname);
|
|
106
|
+
if (!sourcePath) {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
startupTrace.beginDevClientTransform();
|
|
110
|
+
const startedAt = performance.now();
|
|
111
|
+
try {
|
|
112
|
+
const entry = await this.materialize(sourcePath);
|
|
113
|
+
if (process.env.ECOPAGES_STARTUP_TRACE === 'true') {
|
|
114
|
+
appLogger.debug(`[dev-transform] materialize path=${url.pathname} bytes=${entry.code.length} durationMs=${Math.round(performance.now() - startedAt)}`);
|
|
115
|
+
}
|
|
116
|
+
return this.createJavaScriptResponse(entry.code);
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
120
|
+
return new Response(message, {
|
|
121
|
+
status: 500,
|
|
122
|
+
headers: {
|
|
123
|
+
'Content-Type': 'text/plain',
|
|
124
|
+
'Cache-Control': 'no-store, must-revalidate',
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
finally {
|
|
129
|
+
startupTrace.endDevClientTransform();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
resolveSourcePathFromModuleUrl(moduleUrl) {
|
|
133
|
+
const discoveredSourcePath = resolveDevTransformModuleSourcePath(this.appConfig.absolutePaths.srcDir, moduleUrl);
|
|
134
|
+
if (!discoveredSourcePath) {
|
|
135
|
+
return undefined;
|
|
136
|
+
}
|
|
137
|
+
this.registerModule(discoveredSourcePath);
|
|
138
|
+
return path.resolve(discoveredSourcePath);
|
|
139
|
+
}
|
|
140
|
+
createJavaScriptResponse(code) {
|
|
141
|
+
return new Response(code, {
|
|
142
|
+
headers: {
|
|
143
|
+
'Content-Type': 'application/javascript',
|
|
144
|
+
'Cache-Control': 'no-store, must-revalidate',
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
async materialize(sourcePath) {
|
|
149
|
+
const normalized = path.resolve(sourcePath);
|
|
150
|
+
if (!fileSystem.exists(normalized)) {
|
|
151
|
+
throw new Error(`[dev-transform] Missing source module: ${normalized}`);
|
|
152
|
+
}
|
|
153
|
+
const sourceHash = fileSystem.hash(normalized);
|
|
154
|
+
const cached = this.cache.get(normalized);
|
|
155
|
+
if (cached && cached.sourceHash === sourceHash) {
|
|
156
|
+
return cached;
|
|
157
|
+
}
|
|
158
|
+
const pending = this.inFlight.get(normalized);
|
|
159
|
+
if (pending) {
|
|
160
|
+
return pending;
|
|
161
|
+
}
|
|
162
|
+
const moduleKind = resolveDevTransformModuleKind(normalized);
|
|
163
|
+
if (moduleKind === 'stylesheet') {
|
|
164
|
+
const entry = {
|
|
165
|
+
code: materializeDevTransformStylesheet(fileSystem.readFileSync(normalized)),
|
|
166
|
+
sourceHash,
|
|
167
|
+
};
|
|
168
|
+
this.cache.set(normalized, entry);
|
|
169
|
+
return entry;
|
|
170
|
+
}
|
|
171
|
+
const generation = this.cacheGeneration;
|
|
172
|
+
const promise = this.bundler
|
|
173
|
+
.transpileModule(normalized)
|
|
174
|
+
.then((result) => {
|
|
175
|
+
if (generation !== this.cacheGeneration) {
|
|
176
|
+
throw new Error(`[dev-transform] Stale transpile result for ${normalized}`);
|
|
177
|
+
}
|
|
178
|
+
if (result.dependencies) {
|
|
179
|
+
this.onModuleDependencies?.(normalized, result.dependencies);
|
|
180
|
+
}
|
|
181
|
+
const entry = { code: result.code, sourceHash: fileSystem.hash(normalized) };
|
|
182
|
+
this.cache.set(normalized, entry);
|
|
183
|
+
return entry;
|
|
184
|
+
})
|
|
185
|
+
.finally(() => {
|
|
186
|
+
this.inFlight.delete(normalized);
|
|
187
|
+
});
|
|
188
|
+
this.inFlight.set(normalized, promise);
|
|
189
|
+
return promise;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { DEV_TRANSFORM_URL_PREFIX } from '../../hmr/hmr-asset-paths.js';
|
|
2
|
+
/**
|
|
3
|
+
* Maps a source entrypoint to the browser URL served by the dev transform server.
|
|
4
|
+
*/
|
|
5
|
+
export declare function resolveDevTransformModuleUrl(srcDir: string, entrypointPath: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* Resolves a dev-transform browser URL back to an on-disk page entrypoint.
|
|
8
|
+
*
|
|
9
|
+
* @remarks
|
|
10
|
+
* Client-side navigation can request page modules that were not registered during
|
|
11
|
+
* the current SSR response. Lazy resolution keeps those URLs materializable on demand.
|
|
12
|
+
*/
|
|
13
|
+
export declare function resolveDevTransformModuleSourcePath(srcDir: string, moduleUrl: string): string | undefined;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { fileSystem } from '@ecopages/file-system';
|
|
3
|
+
import { DEV_TRANSFORM_URL_PREFIX, stripModuleUrlQuery } from '../../hmr/hmr-asset-paths.js';
|
|
4
|
+
import { decodeHmrDynamicSegments, encodeHmrDynamicSegments } from '../../hmr/hmr-entrypoint-output.js';
|
|
5
|
+
import { resolveDevTransformModuleKind } from './dev-transform-module-kind.js';
|
|
6
|
+
export { DEV_TRANSFORM_URL_PREFIX } from '../../hmr/hmr-asset-paths.js';
|
|
7
|
+
const PAGE_SOURCE_EXTENSIONS = ['.tsx', '.ts', '.jsx', '.js', '.mdx', '.md'];
|
|
8
|
+
/**
|
|
9
|
+
* Maps a source entrypoint to the browser URL served by the dev transform server.
|
|
10
|
+
*/
|
|
11
|
+
export function resolveDevTransformModuleUrl(srcDir, entrypointPath) {
|
|
12
|
+
const resolvedSrcDir = path.resolve(srcDir);
|
|
13
|
+
const normalizedEntrypoint = path.resolve(entrypointPath);
|
|
14
|
+
const relativePath = path.relative(resolvedSrcDir, normalizedEntrypoint);
|
|
15
|
+
if (relativePath.startsWith('..') || path.isAbsolute(relativePath)) {
|
|
16
|
+
throw new Error(`[dev-transform] Entrypoint must be under srcDir: ${entrypointPath}`);
|
|
17
|
+
}
|
|
18
|
+
const relativePathJs = relativePath.replace(/\.(tsx?|jsx?|mdx?)$/, '.js');
|
|
19
|
+
const encodedPathJs = encodeHmrDynamicSegments(relativePathJs);
|
|
20
|
+
const urlPath = encodedPathJs.split(path.sep).join('/');
|
|
21
|
+
return `${DEV_TRANSFORM_URL_PREFIX}/${urlPath}`;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Resolves a dev-transform browser URL back to an on-disk page entrypoint.
|
|
25
|
+
*
|
|
26
|
+
* @remarks
|
|
27
|
+
* Client-side navigation can request page modules that were not registered during
|
|
28
|
+
* the current SSR response. Lazy resolution keeps those URLs materializable on demand.
|
|
29
|
+
*/
|
|
30
|
+
export function resolveDevTransformModuleSourcePath(srcDir, moduleUrl) {
|
|
31
|
+
const pathname = stripModuleUrlQuery(moduleUrl);
|
|
32
|
+
const prefix = `${DEV_TRANSFORM_URL_PREFIX}/`;
|
|
33
|
+
if (!pathname.startsWith(prefix)) {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
const resolvedSrcDir = path.resolve(srcDir);
|
|
37
|
+
const relativeUrlPath = pathname.slice(prefix.length);
|
|
38
|
+
const relativePathJs = relativeUrlPath.split('/').join(path.sep);
|
|
39
|
+
const decodedRelativePathJs = decodeHmrDynamicSegments(relativePathJs);
|
|
40
|
+
if (resolveDevTransformModuleKind(decodedRelativePathJs) === 'stylesheet') {
|
|
41
|
+
const cssPath = path.resolve(resolvedSrcDir, decodedRelativePathJs);
|
|
42
|
+
if (cssPath.startsWith(`${resolvedSrcDir}${path.sep}`) && fileSystem.exists(cssPath)) {
|
|
43
|
+
return cssPath;
|
|
44
|
+
}
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
const basePath = decodedRelativePathJs.replace(/\.js$/u, '');
|
|
48
|
+
for (const extension of PAGE_SOURCE_EXTENSIONS) {
|
|
49
|
+
const candidate = path.resolve(resolvedSrcDir, `${basePath}${extension}`);
|
|
50
|
+
if (!candidate.startsWith(`${resolvedSrcDir}${path.sep}`)) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (fileSystem.exists(candidate)) {
|
|
54
|
+
return candidate;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { EcoBuildPlugin } from '../../build/contracts/build-types.js';
|
|
2
|
+
import type { EcoPagesAppConfig } from '../../types/internal-types.js';
|
|
3
|
+
export type DevTransformVendorRegistryOptions = {
|
|
4
|
+
appConfig: EcoPagesAppConfig;
|
|
5
|
+
getRuntimeSpecifierMap: () => ReadonlyMap<string, string>;
|
|
6
|
+
resolveVendorBundlePlugins?: () => Promise<readonly EcoBuildPlugin[]>;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Lazily prebundles bare npm imports into cacheable `/assets/vendors/*` chunks.
|
|
10
|
+
*/
|
|
11
|
+
export declare class DevTransformVendorRegistry {
|
|
12
|
+
private readonly appConfig;
|
|
13
|
+
private readonly browserBundleService;
|
|
14
|
+
private readonly getRuntimeSpecifierMap;
|
|
15
|
+
private readonly resolveVendorBundlePlugins?;
|
|
16
|
+
private readonly vendorsDir;
|
|
17
|
+
private readonly cache;
|
|
18
|
+
private readonly inFlight;
|
|
19
|
+
constructor(options: DevTransformVendorRegistryOptions);
|
|
20
|
+
resolveKnownVendorUrl(specifier: string): string | undefined;
|
|
21
|
+
resolveVendorUrl(specifier: string): Promise<string>;
|
|
22
|
+
tryHandleVendorRequest(pathname: string): Response | null;
|
|
23
|
+
invalidateAll(): void;
|
|
24
|
+
private createVendorResponse;
|
|
25
|
+
private prebundleSpecifier;
|
|
26
|
+
private resolvePackageEntry;
|
|
27
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileSystem } from '@ecopages/file-system';
|
|
4
|
+
import { RESOLVED_ASSETS_VENDORS_DIR } from '../../config/constants.js';
|
|
5
|
+
import { getAppBrowserBuildPlugins } from '../../build/build-adapter.js';
|
|
6
|
+
import { resolveBarePackageBrowserEntry } from '../../plugins/tsconfig-import-resolver.js';
|
|
7
|
+
import { BrowserBundleService } from '../../services/assets/browser-bundle.service.js';
|
|
8
|
+
const BROWSER_VENDOR_CONDITIONS = ['browser', 'module', 'import', 'default'];
|
|
9
|
+
const BROWSER_NODE_BUILTIN_GUARD_MARKER = '[browser-build] Node builtin';
|
|
10
|
+
/**
|
|
11
|
+
* Lazily prebundles bare npm imports into cacheable `/assets/vendors/*` chunks.
|
|
12
|
+
*/
|
|
13
|
+
export class DevTransformVendorRegistry {
|
|
14
|
+
appConfig;
|
|
15
|
+
browserBundleService;
|
|
16
|
+
getRuntimeSpecifierMap;
|
|
17
|
+
resolveVendorBundlePlugins;
|
|
18
|
+
vendorsDir;
|
|
19
|
+
cache = new Map();
|
|
20
|
+
inFlight = new Map();
|
|
21
|
+
constructor(options) {
|
|
22
|
+
this.appConfig = options.appConfig;
|
|
23
|
+
this.browserBundleService = new BrowserBundleService(options.appConfig);
|
|
24
|
+
this.getRuntimeSpecifierMap = options.getRuntimeSpecifierMap;
|
|
25
|
+
this.resolveVendorBundlePlugins = options.resolveVendorBundlePlugins;
|
|
26
|
+
const distDir = options.appConfig.absolutePaths?.distDir ?? path.join(options.appConfig.rootDir, '.eco');
|
|
27
|
+
this.vendorsDir = path.join(distDir, RESOLVED_ASSETS_VENDORS_DIR);
|
|
28
|
+
}
|
|
29
|
+
resolveKnownVendorUrl(specifier) {
|
|
30
|
+
return this.getRuntimeSpecifierMap().get(specifier);
|
|
31
|
+
}
|
|
32
|
+
async resolveVendorUrl(specifier) {
|
|
33
|
+
const known = this.resolveKnownVendorUrl(specifier);
|
|
34
|
+
if (known) {
|
|
35
|
+
return known;
|
|
36
|
+
}
|
|
37
|
+
const cached = this.cache.get(specifier);
|
|
38
|
+
if (cached) {
|
|
39
|
+
return cached.url;
|
|
40
|
+
}
|
|
41
|
+
const pending = this.inFlight.get(specifier);
|
|
42
|
+
if (pending) {
|
|
43
|
+
return (await pending).url;
|
|
44
|
+
}
|
|
45
|
+
const promise = this.prebundleSpecifier(specifier).finally(() => {
|
|
46
|
+
this.inFlight.delete(specifier);
|
|
47
|
+
});
|
|
48
|
+
this.inFlight.set(specifier, promise);
|
|
49
|
+
return (await promise).url;
|
|
50
|
+
}
|
|
51
|
+
tryHandleVendorRequest(pathname) {
|
|
52
|
+
const prefix = `/${RESOLVED_ASSETS_VENDORS_DIR}/`;
|
|
53
|
+
if (!pathname.startsWith(prefix)) {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
const fileName = pathname.slice(prefix.length);
|
|
57
|
+
if (!fileName || fileName.includes('..')) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
const filePath = path.join(this.vendorsDir, fileName);
|
|
61
|
+
if (!fileSystem.exists(filePath)) {
|
|
62
|
+
for (const entry of this.cache.values()) {
|
|
63
|
+
if (entry.url === pathname) {
|
|
64
|
+
return this.createVendorResponse(entry.filePath);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
return this.createVendorResponse(filePath);
|
|
70
|
+
}
|
|
71
|
+
invalidateAll() {
|
|
72
|
+
this.cache.clear();
|
|
73
|
+
this.inFlight.clear();
|
|
74
|
+
}
|
|
75
|
+
createVendorResponse(filePath) {
|
|
76
|
+
return new Response(fileSystem.readFileSync(filePath), {
|
|
77
|
+
headers: {
|
|
78
|
+
'Content-Type': 'application/javascript',
|
|
79
|
+
'Cache-Control': 'public, max-age=31536000, immutable',
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
async prebundleSpecifier(specifier) {
|
|
84
|
+
const resolvedEntry = this.resolvePackageEntry(specifier);
|
|
85
|
+
fileSystem.ensureDir(this.vendorsDir);
|
|
86
|
+
const fileName = `${sanitizeSpecifierForFileName(specifier)}.${hashVendorEntry(specifier, resolvedEntry)}.js`;
|
|
87
|
+
const outPath = path.join(this.vendorsDir, fileName);
|
|
88
|
+
const url = `/${RESOLVED_ASSETS_VENDORS_DIR}/${fileName}`;
|
|
89
|
+
if (fileSystem.exists(outPath)) {
|
|
90
|
+
const entry = { url, filePath: outPath };
|
|
91
|
+
this.cache.set(specifier, entry);
|
|
92
|
+
return entry;
|
|
93
|
+
}
|
|
94
|
+
const vendorPlugins = this.resolveVendorBundlePlugins ? await this.resolveVendorBundlePlugins() : [];
|
|
95
|
+
const result = await this.browserBundleService.bundle({
|
|
96
|
+
profile: 'browser-script',
|
|
97
|
+
entrypoints: [resolvedEntry],
|
|
98
|
+
outdir: this.vendorsDir,
|
|
99
|
+
naming: fileName,
|
|
100
|
+
minify: false,
|
|
101
|
+
externalPackages: false,
|
|
102
|
+
treeshaking: true,
|
|
103
|
+
splitting: false,
|
|
104
|
+
conditions: [...BROWSER_VENDOR_CONDITIONS],
|
|
105
|
+
excludeAppBuildPlugins: getAppBrowserBuildPlugins(this.appConfig).map((plugin) => plugin.name),
|
|
106
|
+
plugins: [...vendorPlugins],
|
|
107
|
+
});
|
|
108
|
+
if (!result.success) {
|
|
109
|
+
const details = result.logs.map((log) => log.message).join('\n');
|
|
110
|
+
throw new Error(formatVendorPrebundleError(specifier, details));
|
|
111
|
+
}
|
|
112
|
+
const outputPath = result.outputs[0]?.path ?? outPath;
|
|
113
|
+
const entry = { url, filePath: outputPath };
|
|
114
|
+
this.cache.set(specifier, entry);
|
|
115
|
+
return entry;
|
|
116
|
+
}
|
|
117
|
+
resolvePackageEntry(specifier) {
|
|
118
|
+
const resolved = resolveBarePackageBrowserEntry(this.appConfig.rootDir, specifier);
|
|
119
|
+
if (!resolved) {
|
|
120
|
+
throw new Error(`[dev-transform] Unable to resolve bare import "${specifier}" for vendor prebundle`);
|
|
121
|
+
}
|
|
122
|
+
return resolved;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function formatVendorPrebundleError(specifier, details) {
|
|
126
|
+
if (details.includes(BROWSER_NODE_BUILTIN_GUARD_MARKER)) {
|
|
127
|
+
return (`[dev-transform] Bare import "${specifier}" resolved to a server-only entry. ` +
|
|
128
|
+
`Import a browser subpath or register the package in the browser runtime manifest.` +
|
|
129
|
+
(details ? `\n${details}` : ''));
|
|
130
|
+
}
|
|
131
|
+
return details
|
|
132
|
+
? `[dev-transform] Vendor prebundle failed for ${specifier}:\n${details}`
|
|
133
|
+
: `[dev-transform] Vendor prebundle failed for ${specifier}`;
|
|
134
|
+
}
|
|
135
|
+
function sanitizeSpecifierForFileName(specifier) {
|
|
136
|
+
return specifier.replaceAll(/^@/gu, '').replaceAll(/[/:@]/gu, '-');
|
|
137
|
+
}
|
|
138
|
+
function hashVendorEntry(specifier, entryPath) {
|
|
139
|
+
return createHash('sha256')
|
|
140
|
+
.update(specifier)
|
|
141
|
+
.update('\0')
|
|
142
|
+
.update(fileSystem.readFileSync(entryPath))
|
|
143
|
+
.digest('hex')
|
|
144
|
+
.slice(0, 8);
|
|
145
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { DevTransformServer } from './dev-transform-server.js';
|
|
2
|
+
export type { DevTransformServerOptions } from './dev-transform-server.js';
|
|
3
|
+
export { DevTransformBundler } from './dev-transform-bundler.js';
|
|
4
|
+
export type { DevTransformBundleContributor, DevTransformBundleResult } from './types.js';
|
|
5
|
+
export { DevTransformVendorRegistry } from './dev-transform-vendor-registry.js';
|
|
6
|
+
export { resolveDevTransformModuleUrl, DEV_TRANSFORM_URL_PREFIX } from './dev-transform-url.js';
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { DevTransformServer } from './dev-transform-server.js';
|
|
2
|
+
export { DevTransformBundler } from './dev-transform-bundler.js';
|
|
3
|
+
export { DevTransformVendorRegistry } from './dev-transform-vendor-registry.js';
|
|
4
|
+
export { resolveDevTransformModuleUrl, DEV_TRANSFORM_URL_PREFIX } from './dev-transform-url.js';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { EcoBuildPlugin } from '../../build/contracts/build-types.js';
|
|
2
|
+
export type DevTransformBundleResult = {
|
|
3
|
+
code: string;
|
|
4
|
+
dependencies?: string[];
|
|
5
|
+
};
|
|
6
|
+
export type DevTransformBundleContributor = {
|
|
7
|
+
/** Returns whether this contributor owns the source module path. */
|
|
8
|
+
ownsModule(sourcePath: string): boolean;
|
|
9
|
+
/** Integration-owned plugins for one dev-transform module (boundary, MDX, etc.). */
|
|
10
|
+
getModulePlugins(sourcePath: string): Promise<readonly EcoBuildPlugin[]>;
|
|
11
|
+
/** Runtime manifest specifiers already served from `/assets/vendors/*`. */
|
|
12
|
+
getRuntimeSpecifierMap?(): ReadonlyMap<string, string>;
|
|
13
|
+
/** Plugins applied to lazy vendor prebundles (client-graph boundary, runtime rewrites). */
|
|
14
|
+
getVendorBundlePlugins?(): Promise<readonly EcoBuildPlugin[]>;
|
|
15
|
+
};
|