@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
|
@@ -1,591 +1,555 @@
|
|
|
1
|
-
import path from
|
|
2
|
-
import { availableParallelism } from
|
|
3
|
-
import { appLogger } from
|
|
4
|
-
import { fileSystem } from
|
|
5
|
-
import { prepareExplicitStaticRender } from
|
|
6
|
-
import { createRouteModuleStaticRenderCacheContext } from
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
} from
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
} from
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
import { renderSitemap } from "./sitemap.js";
|
|
22
|
-
import { resolveSitemapLocations } from "./sitemap-routes.js";
|
|
23
|
-
import { toEcopagesRouteInfo } from "../utils/ecopages-route-info.js";
|
|
24
|
-
import { normalizePathname } from "../utils/path-pattern.js";
|
|
25
|
-
const STATIC_SITE_GENERATOR_ERRORS = {
|
|
26
|
-
ROUTE_RENDERER_FACTORY_REQUIRED: "RouteRendererFactory is required for render strategy",
|
|
27
|
-
unsupportedBodyType: (bodyType) => `Unsupported body type for static generation: ${bodyType}`,
|
|
28
|
-
missingIntegration: (routePath) => `View at ${routePath} is missing __eco.integration. Ensure it's defined with eco.page().`,
|
|
29
|
-
noRendererForIntegration: (integrationName) => `No renderer found for integration: ${integrationName}`,
|
|
30
|
-
dynamicRouteRequiresStaticPaths: (routePath) => `Dynamic route ${routePath} requires staticPaths to be defined on the view.`
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { availableParallelism } from 'node:os';
|
|
3
|
+
import { appLogger } from '../global/app-logger.js';
|
|
4
|
+
import { fileSystem } from '@ecopages/file-system';
|
|
5
|
+
import { prepareExplicitStaticRender } from '../adapters/shared/http/explicit-static-render-preparation.js';
|
|
6
|
+
import { createRouteModuleStaticRenderCacheContext } from './static-build-invalidation.js';
|
|
7
|
+
import { getServerModuleBuildCacheOutdir, getSharedRouteModuleBuildCache, } from '../services/module-loading/route-module-build-cache-registry.js';
|
|
8
|
+
import { ensurePagesUnifiedGraphBuilt, shouldBuildPagesUnifiedGraph, } from '../build/cache/pages-unified-graph-build.js';
|
|
9
|
+
import { clearProductionPageBrowserGraphSession, prebuildProductionPageBrowserGraphs, shouldPrebuildProductionPageBrowserGraphs, } from './production-page-browser-graph-prebuild.js';
|
|
10
|
+
import { PageModuleLoaderService } from '../route-renderer/page-loading/page-module-loader.js';
|
|
11
|
+
import { renderSitemap } from './sitemap.js';
|
|
12
|
+
import { resolveSitemapLocations } from './sitemap-routes.js';
|
|
13
|
+
import { toEcopagesRouteInfo } from '../utils/ecopages-route-info.js';
|
|
14
|
+
import { normalizePathname } from '../utils/path-pattern.js';
|
|
15
|
+
export const STATIC_SITE_GENERATOR_ERRORS = {
|
|
16
|
+
ROUTE_RENDERER_FACTORY_REQUIRED: 'RouteRendererFactory is required for render strategy',
|
|
17
|
+
unsupportedBodyType: (bodyType) => `Unsupported body type for static generation: ${bodyType}`,
|
|
18
|
+
missingIntegration: (routePath) => `View at ${routePath} is missing __eco.integration. Ensure it's defined with eco.page().`,
|
|
19
|
+
noRendererForIntegration: (integrationName) => `No renderer found for integration: ${integrationName}`,
|
|
20
|
+
dynamicRouteRequiresStaticPaths: (routePath) => `Dynamic route ${routePath} requires staticPaths to be defined on the view.`,
|
|
31
21
|
};
|
|
32
22
|
function resolveStaticPageConcurrency() {
|
|
33
|
-
|
|
23
|
+
return Math.max(1, availableParallelism() - 1);
|
|
34
24
|
}
|
|
35
25
|
async function runWithConcurrency(items, concurrency, worker) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
const limit = Math.max(1, concurrency);
|
|
40
|
-
let nextIndex = 0;
|
|
41
|
-
const runners = Array.from({ length: Math.min(limit, items.length) }, async () => {
|
|
42
|
-
while (nextIndex < items.length) {
|
|
43
|
-
const currentIndex = nextIndex++;
|
|
44
|
-
await worker(items[currentIndex]);
|
|
26
|
+
if (items.length === 0) {
|
|
27
|
+
return;
|
|
45
28
|
}
|
|
46
|
-
|
|
47
|
-
|
|
29
|
+
const limit = Math.max(1, concurrency);
|
|
30
|
+
let nextIndex = 0;
|
|
31
|
+
const runners = Array.from({ length: Math.min(limit, items.length) }, async () => {
|
|
32
|
+
while (nextIndex < items.length) {
|
|
33
|
+
const currentIndex = nextIndex++;
|
|
34
|
+
await worker(items[currentIndex]);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
await Promise.all(runners);
|
|
48
38
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
appConfig
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
async shouldSkipStaticPageFile(filePath, routeRendererFactory) {
|
|
73
|
-
const pageModule = await routeRendererFactory.getPageRenderer(filePath).loadPageModule(filePath);
|
|
74
|
-
const Page = pageModule.default;
|
|
75
|
-
return Page.cache === "dynamic";
|
|
76
|
-
}
|
|
77
|
-
shouldSkipStaticView(_routePath, view) {
|
|
78
|
-
return view.cache === "dynamic";
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Writes the robots.txt file declared by the app config.
|
|
82
|
-
*/
|
|
83
|
-
generateRobotsTxt() {
|
|
84
|
-
let data = "";
|
|
85
|
-
const preferences = this.appConfig.robotsTxt.preferences;
|
|
86
|
-
for (const userAgent in preferences) {
|
|
87
|
-
data += `user-agent: ${userAgent}
|
|
88
|
-
`;
|
|
89
|
-
for (const path2 of preferences[userAgent]) {
|
|
90
|
-
data += `disallow: ${path2}
|
|
91
|
-
`;
|
|
92
|
-
}
|
|
93
|
-
data += "\n";
|
|
39
|
+
/**
|
|
40
|
+
* Generates static output files from the finalized app config and route graph.
|
|
41
|
+
*
|
|
42
|
+
* @remarks
|
|
43
|
+
* This class intentionally reuses the same routing, renderer, and server-module
|
|
44
|
+
* loading seams used by runtime rendering. Static generation should be a build
|
|
45
|
+
* loop over the normal app model, not a parallel rendering stack with different
|
|
46
|
+
* semantics.
|
|
47
|
+
*/
|
|
48
|
+
export class StaticSiteGenerator {
|
|
49
|
+
appConfig;
|
|
50
|
+
routeModuleBuildCacheOverride;
|
|
51
|
+
staticRenderCacheContext;
|
|
52
|
+
forceFullStaticGeneration = false;
|
|
53
|
+
pageModuleLoader;
|
|
54
|
+
/**
|
|
55
|
+
* Creates the static-site generator for one app config.
|
|
56
|
+
*/
|
|
57
|
+
constructor({ appConfig, routeModuleBuildCache, }) {
|
|
58
|
+
this.appConfig = appConfig;
|
|
59
|
+
this.routeModuleBuildCacheOverride = routeModuleBuildCache;
|
|
60
|
+
this.staticRenderCacheContext = createRouteModuleStaticRenderCacheContext(appConfig);
|
|
94
61
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Writes the configured sitemap file to the export directory.
|
|
100
|
-
*/
|
|
101
|
-
generateSitemap(locations, sitemap) {
|
|
102
|
-
const fileName = sitemap.fileName ?? "sitemap.xml";
|
|
103
|
-
fileSystem.ensureDir(this.getExportDir());
|
|
104
|
-
fileSystem.write(path.join(this.getExportDir(), fileName), renderSitemap(locations));
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Returns whether the input path points at the root directory.
|
|
108
|
-
*/
|
|
109
|
-
isRootDir(path2) {
|
|
110
|
-
const slashes = path2.match(/\//g);
|
|
111
|
-
return slashes && slashes.length === 1;
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Collects parent directories that must exist for the generated route set.
|
|
115
|
-
*/
|
|
116
|
-
getDirectories(routes) {
|
|
117
|
-
const directories = /* @__PURE__ */ new Set();
|
|
118
|
-
for (const route of routes) {
|
|
119
|
-
const path2 = route.startsWith("http") ? new URL(route).pathname : route;
|
|
120
|
-
const segments = path2.split("/");
|
|
121
|
-
if (segments.length > 2) {
|
|
122
|
-
directories.add(segments.slice(0, segments.length - 1).join("/"));
|
|
123
|
-
}
|
|
62
|
+
getRouteModuleBuildCache() {
|
|
63
|
+
return (this.routeModuleBuildCacheOverride ??
|
|
64
|
+
getSharedRouteModuleBuildCache(getServerModuleBuildCacheOutdir(this.appConfig), this.appConfig));
|
|
124
65
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
writeStaticOutput(routePath, contents, directories = []) {
|
|
128
|
-
const outputPath = this.getOutputPath(routePath, directories);
|
|
129
|
-
fileSystem.ensureDir(path.dirname(outputPath));
|
|
130
|
-
fileSystem.write(outputPath, contents);
|
|
131
|
-
return outputPath;
|
|
132
|
-
}
|
|
133
|
-
async writeStaticPageArtifact(options) {
|
|
134
|
-
const directories = options.directories ?? this.getDirectories([options.pathname]);
|
|
135
|
-
const renderedOutputPath = this.getOutputPath(options.pathname, directories);
|
|
136
|
-
const routeModuleBuildCache = this.getRouteModuleBuildCache();
|
|
137
|
-
if (options.reuseRenderedOutput !== false && options.sourceFile && routeModuleBuildCache.canReuseStaticRender({
|
|
138
|
-
sourceFile: options.sourceFile,
|
|
139
|
-
pathname: options.pathname,
|
|
140
|
-
renderedOutputPath,
|
|
141
|
-
context: this.staticRenderCacheContext,
|
|
142
|
-
force: this.forceFullStaticGeneration
|
|
143
|
-
})) {
|
|
144
|
-
options.activeStaticPathnames?.add(options.pathname);
|
|
145
|
-
await options.onSuccessfulExport?.();
|
|
146
|
-
appLogger.debug(`Skipped unchanged static page: ${options.debugLabel ?? options.pathname}`);
|
|
147
|
-
return;
|
|
66
|
+
getExportDir() {
|
|
67
|
+
return this.appConfig.absolutePaths?.distDir ?? path.join(this.appConfig.rootDir, this.appConfig.distDir);
|
|
148
68
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
69
|
+
async shouldSkipStaticPageFile(filePath, routeRendererFactory) {
|
|
70
|
+
const pageModule = await routeRendererFactory.getPageRenderer(filePath).loadPageModule(filePath);
|
|
71
|
+
const Page = pageModule.default;
|
|
72
|
+
return Page.cache === 'dynamic';
|
|
152
73
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
if (options.sourceFile) {
|
|
156
|
-
try {
|
|
157
|
-
routeModuleBuildCache.recordStaticRender({
|
|
158
|
-
filePath: options.sourceFile,
|
|
159
|
-
pathname: options.pathname,
|
|
160
|
-
sourceHash: fileSystem.hash(options.sourceFile),
|
|
161
|
-
renderedOutputPath: outputPath,
|
|
162
|
-
context: this.staticRenderCacheContext
|
|
163
|
-
});
|
|
164
|
-
} catch (error) {
|
|
165
|
-
appLogger.debug(
|
|
166
|
-
`Failed to record static render cache for ${options.pathname}`,
|
|
167
|
-
error instanceof Error ? error.message : String(error)
|
|
168
|
-
);
|
|
169
|
-
}
|
|
74
|
+
shouldSkipStaticView(_routePath, view) {
|
|
75
|
+
return view.cache === 'dynamic';
|
|
170
76
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
77
|
+
/**
|
|
78
|
+
* Writes the robots.txt file declared by the app config.
|
|
79
|
+
*/
|
|
80
|
+
generateRobotsTxt() {
|
|
81
|
+
let data = '';
|
|
82
|
+
const preferences = this.appConfig.robotsTxt.preferences;
|
|
83
|
+
for (const userAgent in preferences) {
|
|
84
|
+
data += `user-agent: ${userAgent}\n`;
|
|
85
|
+
for (const path of preferences[userAgent]) {
|
|
86
|
+
data += `disallow: ${path}\n`;
|
|
87
|
+
}
|
|
88
|
+
data += '\n';
|
|
89
|
+
}
|
|
90
|
+
fileSystem.ensureDir(this.getExportDir());
|
|
91
|
+
fileSystem.write(path.join(this.getExportDir(), 'robots.txt'), data);
|
|
184
92
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
appLogger.debug(
|
|
193
|
-
`Sitemap eligibility skipped for ${input.pathname}; metadata resolution failed`,
|
|
194
|
-
error instanceof Error ? error.message : String(error)
|
|
195
|
-
);
|
|
93
|
+
/**
|
|
94
|
+
* Writes the configured sitemap file to the export directory.
|
|
95
|
+
*/
|
|
96
|
+
generateSitemap(locations, sitemap) {
|
|
97
|
+
const fileName = sitemap.fileName ?? 'sitemap.xml';
|
|
98
|
+
fileSystem.ensureDir(this.getExportDir());
|
|
99
|
+
fileSystem.write(path.join(this.getExportDir(), fileName), renderSitemap(locations));
|
|
196
100
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
const loader = this.getPageModuleLoader(input.baseUrl);
|
|
204
|
-
const pageModule = await loader.resolvePageModule({
|
|
205
|
-
file: input.filePath,
|
|
206
|
-
importPageFileFn: (file) => input.routeRendererFactory.getPageRenderer(file).loadPageModule(file)
|
|
207
|
-
});
|
|
208
|
-
const { metadata } = await loader.resolvePageData({
|
|
209
|
-
pageModule,
|
|
210
|
-
routeOptions: {
|
|
211
|
-
file: input.filePath,
|
|
212
|
-
params: input.params
|
|
213
|
-
}
|
|
214
|
-
});
|
|
215
|
-
return metadata;
|
|
216
|
-
}
|
|
217
|
-
async resolveExplicitViewMetadata(input) {
|
|
218
|
-
if (!input.view.metadata) {
|
|
219
|
-
return this.appConfig.defaultMetadata;
|
|
101
|
+
/**
|
|
102
|
+
* Returns whether the input path points at the root directory.
|
|
103
|
+
*/
|
|
104
|
+
isRootDir(path) {
|
|
105
|
+
const slashes = path.match(/\//g);
|
|
106
|
+
return slashes && slashes.length === 1;
|
|
220
107
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
fileSystem.remove(resolvedOutputPath);
|
|
235
|
-
appLogger.debug(`Removed stale static output: ${resolvedOutputPath}`);
|
|
236
|
-
}
|
|
108
|
+
/**
|
|
109
|
+
* Collects parent directories that must exist for the generated route set.
|
|
110
|
+
*/
|
|
111
|
+
getDirectories(routes) {
|
|
112
|
+
const directories = new Set();
|
|
113
|
+
for (const route of routes) {
|
|
114
|
+
const path = route.startsWith('http') ? new URL(route).pathname : route;
|
|
115
|
+
const segments = path.split('/');
|
|
116
|
+
if (segments.length > 2) {
|
|
117
|
+
directories.add(segments.slice(0, segments.length - 1).join('/'));
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return Array.from(directories);
|
|
237
121
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
params
|
|
244
|
-
},
|
|
245
|
-
routeRendererFactory,
|
|
246
|
-
skipped
|
|
247
|
-
} = input;
|
|
248
|
-
if (!routeRendererFactory) {
|
|
249
|
-
throw new Error(STATIC_SITE_GENERATOR_ERRORS.ROUTE_RENDERER_FACTORY_REQUIRED);
|
|
122
|
+
writeStaticOutput(routePath, contents, directories = []) {
|
|
123
|
+
const outputPath = this.getOutputPath(routePath, directories);
|
|
124
|
+
fileSystem.ensureDir(path.dirname(outputPath));
|
|
125
|
+
fileSystem.write(outputPath, contents);
|
|
126
|
+
return outputPath;
|
|
250
127
|
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
128
|
+
async writeStaticPageArtifact(options) {
|
|
129
|
+
const directories = options.directories ?? this.getDirectories([options.pathname]);
|
|
130
|
+
const renderedOutputPath = this.getOutputPath(options.pathname, directories);
|
|
131
|
+
const routeModuleBuildCache = this.getRouteModuleBuildCache();
|
|
132
|
+
if (options.reuseRenderedOutput !== false &&
|
|
133
|
+
options.sourceFile &&
|
|
134
|
+
routeModuleBuildCache.canReuseStaticRender({
|
|
135
|
+
sourceFile: options.sourceFile,
|
|
136
|
+
pathname: options.pathname,
|
|
137
|
+
renderedOutputPath,
|
|
138
|
+
context: this.staticRenderCacheContext,
|
|
139
|
+
force: this.forceFullStaticGeneration,
|
|
140
|
+
})) {
|
|
141
|
+
options.activeStaticPathnames?.add(options.pathname);
|
|
142
|
+
await options.onSuccessfulExport?.();
|
|
143
|
+
appLogger.debug(`Skipped unchanged static page: ${options.debugLabel ?? options.pathname}`);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const contents = await options.createContents();
|
|
147
|
+
if (contents === null) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const outputPath = this.writeStaticOutput(options.pathname, contents, directories);
|
|
151
|
+
options.activeStaticPathnames?.add(options.pathname);
|
|
152
|
+
if (options.sourceFile) {
|
|
153
|
+
try {
|
|
154
|
+
routeModuleBuildCache.recordStaticRender({
|
|
155
|
+
filePath: options.sourceFile,
|
|
156
|
+
pathname: options.pathname,
|
|
157
|
+
sourceHash: fileSystem.hash(options.sourceFile),
|
|
158
|
+
renderedOutputPath: outputPath,
|
|
159
|
+
context: this.staticRenderCacheContext,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
appLogger.debug(`Failed to record static render cache for ${options.pathname}`, error instanceof Error ? error.message : String(error));
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
await options.onSuccessfulExport?.();
|
|
254
167
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
168
|
+
/**
|
|
169
|
+
* Marks a successfully exported pathname as sitemap-eligible when robots allow indexing.
|
|
170
|
+
*
|
|
171
|
+
* @remarks
|
|
172
|
+
* Fail-closed: metadata resolution errors omit the URL. `robots.index === false`
|
|
173
|
+
* also omits it. Eligibility is decided during generation, not by reloading modules
|
|
174
|
+
* after `afterStaticExport`.
|
|
175
|
+
*/
|
|
176
|
+
async considerSitemapEligibility(input) {
|
|
177
|
+
if (!input.sitemapEligiblePathnames || !this.appConfig.sitemap?.enabled) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
try {
|
|
181
|
+
const metadata = await input.resolveMetadata();
|
|
182
|
+
if (metadata.robots?.index === false) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
input.sitemapEligiblePathnames.add(normalizePathname(input.pathname));
|
|
186
|
+
}
|
|
187
|
+
catch (error) {
|
|
188
|
+
appLogger.debug(`Sitemap eligibility skipped for ${input.pathname}; metadata resolution failed`, error instanceof Error ? error.message : String(error));
|
|
189
|
+
}
|
|
263
190
|
}
|
|
264
|
-
|
|
265
|
-
|
|
191
|
+
getPageModuleLoader(baseUrl) {
|
|
192
|
+
this.pageModuleLoader ??= new PageModuleLoaderService(this.appConfig, baseUrl);
|
|
193
|
+
return this.pageModuleLoader;
|
|
266
194
|
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
* @remarks
|
|
273
|
-
* Routes are rendered through the normal route renderer directly.
|
|
274
|
-
*/
|
|
275
|
-
async generateStaticPages(input) {
|
|
276
|
-
const { router, baseUrl, routeRendererFactory, skipped, activeStaticPathnames, sitemapEligiblePathnames } = input;
|
|
277
|
-
const routes = input.preloadedRoutes ?? await router.listStaticGenerationRoutes({ runtimeOrigin: baseUrl });
|
|
278
|
-
appLogger.debug(
|
|
279
|
-
"Static Pages",
|
|
280
|
-
routes.map((route) => route.requestUrl)
|
|
281
|
-
);
|
|
282
|
-
const directories = this.getDirectories(routes.map((route) => route.requestUrl));
|
|
283
|
-
await runWithConcurrency(routes, resolveStaticPageConcurrency(), async (route) => {
|
|
284
|
-
try {
|
|
285
|
-
await this.writeStaticPageArtifact({
|
|
286
|
-
pathname: route.pathname,
|
|
287
|
-
sourceFile: route.templateRoute.filePath,
|
|
288
|
-
directories,
|
|
289
|
-
debugLabel: route.requestUrl,
|
|
290
|
-
activeStaticPathnames,
|
|
291
|
-
onSuccessfulExport: () => this.considerSitemapEligibility({
|
|
292
|
-
pathname: route.pathname,
|
|
293
|
-
sitemapEligiblePathnames,
|
|
294
|
-
resolveMetadata: () => {
|
|
295
|
-
if (!routeRendererFactory) {
|
|
296
|
-
throw new Error(STATIC_SITE_GENERATOR_ERRORS.ROUTE_RENDERER_FACTORY_REQUIRED);
|
|
297
|
-
}
|
|
298
|
-
return this.resolveFilesystemPageMetadata({
|
|
299
|
-
filePath: route.templateRoute.filePath,
|
|
300
|
-
params: route.params,
|
|
301
|
-
baseUrl,
|
|
302
|
-
routeRendererFactory
|
|
303
|
-
});
|
|
304
|
-
}
|
|
305
|
-
}),
|
|
306
|
-
createContents: () => this.createFilesystemStaticContents({
|
|
307
|
-
route,
|
|
308
|
-
baseUrl,
|
|
309
|
-
routeRendererFactory,
|
|
310
|
-
skipped
|
|
311
|
-
})
|
|
195
|
+
async resolveFilesystemPageMetadata(input) {
|
|
196
|
+
const loader = this.getPageModuleLoader(input.baseUrl);
|
|
197
|
+
const pageModule = await loader.resolvePageModule({
|
|
198
|
+
file: input.filePath,
|
|
199
|
+
importPageFileFn: (file) => input.routeRendererFactory.getPageRenderer(file).loadPageModule(file),
|
|
312
200
|
});
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
createStaticExportContext(input) {
|
|
322
|
-
return {
|
|
323
|
-
appConfig: this.appConfig,
|
|
324
|
-
router: input.router,
|
|
325
|
-
baseUrl: input.baseUrl,
|
|
326
|
-
routeRendererFactory: input.routeRendererFactory,
|
|
327
|
-
staticRoutes: input.staticRoutes,
|
|
328
|
-
force: input.force,
|
|
329
|
-
preserveExportDirectory: input.preserveExportDirectory,
|
|
330
|
-
routes: input.routes
|
|
331
|
-
};
|
|
332
|
-
}
|
|
333
|
-
async invokeStaticExportHook(hook, context) {
|
|
334
|
-
for (const integration of this.appConfig.integrations) {
|
|
335
|
-
const handler = integration[hook];
|
|
336
|
-
if (typeof handler === "function") {
|
|
337
|
-
await handler.call(integration, context);
|
|
338
|
-
}
|
|
201
|
+
const { metadata } = await loader.resolvePageData({
|
|
202
|
+
pageModule,
|
|
203
|
+
routeOptions: {
|
|
204
|
+
file: input.filePath,
|
|
205
|
+
params: input.params,
|
|
206
|
+
},
|
|
207
|
+
});
|
|
208
|
+
return metadata;
|
|
339
209
|
}
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
}) {
|
|
352
|
-
const skippedDynamicPages = [];
|
|
353
|
-
const activeStaticPathnames = /* @__PURE__ */ new Set();
|
|
354
|
-
const sitemapEligiblePathnames = this.appConfig.sitemap?.enabled ? /* @__PURE__ */ new Set() : void 0;
|
|
355
|
-
this.forceFullStaticGeneration = force;
|
|
356
|
-
this.staticRenderCacheContext = createRouteModuleStaticRenderCacheContext(this.appConfig);
|
|
357
|
-
this.pageModuleLoader = void 0;
|
|
358
|
-
if (!force) {
|
|
359
|
-
this.getRouteModuleBuildCache().ensureIncrementalStaticGenerationContext(this.staticRenderCacheContext);
|
|
210
|
+
async resolveExplicitViewMetadata(input) {
|
|
211
|
+
if (!input.view.metadata) {
|
|
212
|
+
return this.appConfig.defaultMetadata;
|
|
213
|
+
}
|
|
214
|
+
const dynamicMetadata = await input.view.metadata({
|
|
215
|
+
params: input.params,
|
|
216
|
+
query: {},
|
|
217
|
+
props: input.props,
|
|
218
|
+
appConfig: this.appConfig,
|
|
219
|
+
});
|
|
220
|
+
return { ...this.appConfig.defaultMetadata, ...dynamicMetadata };
|
|
360
221
|
}
|
|
361
|
-
|
|
362
|
-
|
|
222
|
+
pruneStaleStaticOutputs(activeStaticPathnames) {
|
|
223
|
+
const removedOutputPaths = this.getRouteModuleBuildCache().pruneStaleRenderedOutputs(activeStaticPathnames);
|
|
224
|
+
for (const outputPath of removedOutputPaths) {
|
|
225
|
+
const resolvedOutputPath = path.isAbsolute(outputPath) ? outputPath : path.resolve(outputPath);
|
|
226
|
+
if (fileSystem.exists(resolvedOutputPath)) {
|
|
227
|
+
fileSystem.remove(resolvedOutputPath);
|
|
228
|
+
appLogger.debug(`Removed stale static output: ${resolvedOutputPath}`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
363
231
|
}
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
232
|
+
async createFilesystemStaticContents(input) {
|
|
233
|
+
const { route: { templateRoute: { filePath }, params, }, routeRendererFactory, skipped, } = input;
|
|
234
|
+
if (!routeRendererFactory) {
|
|
235
|
+
throw new Error(STATIC_SITE_GENERATOR_ERRORS.ROUTE_RENDERER_FACTORY_REQUIRED);
|
|
236
|
+
}
|
|
237
|
+
if (await this.shouldSkipStaticPageFile(filePath, routeRendererFactory)) {
|
|
238
|
+
skipped?.push(filePath);
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
const renderer = routeRendererFactory.getPageRenderer(filePath);
|
|
242
|
+
const result = await renderer.execute({
|
|
243
|
+
file: filePath,
|
|
244
|
+
params: params,
|
|
245
|
+
});
|
|
246
|
+
const body = result.body;
|
|
247
|
+
if (typeof body === 'string' || Buffer.isBuffer(body)) {
|
|
248
|
+
return body;
|
|
249
|
+
}
|
|
250
|
+
if (body instanceof ReadableStream) {
|
|
251
|
+
return new Response(body).text();
|
|
252
|
+
}
|
|
253
|
+
throw new Error(STATIC_SITE_GENERATOR_ERRORS.unsupportedBodyType(typeof body));
|
|
373
254
|
}
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
255
|
+
/**
|
|
256
|
+
* Generates static output for all filesystem-discovered routes.
|
|
257
|
+
*
|
|
258
|
+
* @remarks
|
|
259
|
+
* Routes are rendered through the normal route renderer directly.
|
|
260
|
+
*/
|
|
261
|
+
async generateStaticPages(input) {
|
|
262
|
+
const { router, baseUrl, routeRendererFactory, skipped, activeStaticPathnames, sitemapEligiblePathnames } = input;
|
|
263
|
+
const routes = input.preloadedRoutes ?? (await router.listStaticGenerationRoutes({ runtimeOrigin: baseUrl }));
|
|
264
|
+
appLogger.debug('Static Pages', routes.map((route) => route.requestUrl));
|
|
265
|
+
const directories = this.getDirectories(routes.map((route) => route.requestUrl));
|
|
266
|
+
await runWithConcurrency(routes, resolveStaticPageConcurrency(), async (route) => {
|
|
267
|
+
try {
|
|
268
|
+
await this.writeStaticPageArtifact({
|
|
269
|
+
pathname: route.pathname,
|
|
270
|
+
sourceFile: route.templateRoute.filePath,
|
|
271
|
+
directories,
|
|
272
|
+
debugLabel: route.requestUrl,
|
|
273
|
+
activeStaticPathnames,
|
|
274
|
+
onSuccessfulExport: () => this.considerSitemapEligibility({
|
|
275
|
+
pathname: route.pathname,
|
|
276
|
+
sitemapEligiblePathnames,
|
|
277
|
+
resolveMetadata: () => {
|
|
278
|
+
if (!routeRendererFactory) {
|
|
279
|
+
throw new Error(STATIC_SITE_GENERATOR_ERRORS.ROUTE_RENDERER_FACTORY_REQUIRED);
|
|
280
|
+
}
|
|
281
|
+
return this.resolveFilesystemPageMetadata({
|
|
282
|
+
filePath: route.templateRoute.filePath,
|
|
283
|
+
params: route.params,
|
|
284
|
+
baseUrl,
|
|
285
|
+
routeRendererFactory,
|
|
286
|
+
});
|
|
287
|
+
},
|
|
288
|
+
}),
|
|
289
|
+
createContents: () => this.createFilesystemStaticContents({
|
|
290
|
+
route,
|
|
291
|
+
baseUrl,
|
|
292
|
+
routeRendererFactory,
|
|
293
|
+
skipped,
|
|
294
|
+
}),
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
catch (error) {
|
|
298
|
+
appLogger.error(`Error generating static page for ${route.requestUrl}:`, error instanceof Error ? error : String(error));
|
|
299
|
+
}
|
|
408
300
|
});
|
|
409
|
-
}
|
|
410
|
-
if (preserveExportDirectory) {
|
|
411
|
-
this.pruneStaleStaticOutputs(activeStaticPathnames);
|
|
412
|
-
}
|
|
413
|
-
} catch (error) {
|
|
414
|
-
if (shouldPrebuildProductionPageBrowserGraphs()) {
|
|
415
|
-
clearProductionPageBrowserGraphSession(this.appConfig);
|
|
416
|
-
}
|
|
417
|
-
throw error;
|
|
418
|
-
} finally {
|
|
419
|
-
await this.invokeStaticExportHook("afterStaticExport", staticExportContext);
|
|
420
301
|
}
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
302
|
+
createStaticExportContext(input) {
|
|
303
|
+
return {
|
|
304
|
+
appConfig: this.appConfig,
|
|
305
|
+
router: input.router,
|
|
306
|
+
baseUrl: input.baseUrl,
|
|
307
|
+
routeRendererFactory: input.routeRendererFactory,
|
|
308
|
+
staticRoutes: input.staticRoutes,
|
|
309
|
+
force: input.force,
|
|
310
|
+
preserveExportDirectory: input.preserveExportDirectory,
|
|
311
|
+
routes: input.routes,
|
|
312
|
+
};
|
|
428
313
|
}
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
314
|
+
async invokeStaticExportHook(hook, context) {
|
|
315
|
+
for (const integration of this.appConfig.integrations) {
|
|
316
|
+
const handler = integration[hook];
|
|
317
|
+
if (typeof handler === 'function') {
|
|
318
|
+
await handler.call(integration, context);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
434
321
|
}
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
if (
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
322
|
+
/**
|
|
323
|
+
* Executes the full static-generation workflow for one app run.
|
|
324
|
+
*/
|
|
325
|
+
async run({ router, baseUrl, routeRendererFactory, staticRoutes, force = false, preserveExportDirectory = false, }) {
|
|
326
|
+
const skippedDynamicPages = [];
|
|
327
|
+
const activeStaticPathnames = new Set();
|
|
328
|
+
const sitemapEligiblePathnames = this.appConfig.sitemap?.enabled ? new Set() : undefined;
|
|
329
|
+
this.forceFullStaticGeneration = force;
|
|
330
|
+
this.staticRenderCacheContext = createRouteModuleStaticRenderCacheContext(this.appConfig);
|
|
331
|
+
this.pageModuleLoader = undefined;
|
|
332
|
+
if (!force) {
|
|
333
|
+
this.getRouteModuleBuildCache().ensureIncrementalStaticGenerationContext(this.staticRenderCacheContext);
|
|
334
|
+
}
|
|
335
|
+
if (shouldPrebuildProductionPageBrowserGraphs() && force) {
|
|
336
|
+
clearProductionPageBrowserGraphSession(this.appConfig);
|
|
337
|
+
}
|
|
338
|
+
const routes = await router.listStaticGenerationRoutes({ runtimeOrigin: baseUrl });
|
|
339
|
+
const exportRoutes = routes.map((route) => toEcopagesRouteInfo(route));
|
|
340
|
+
if (shouldBuildPagesUnifiedGraph()) {
|
|
341
|
+
await ensurePagesUnifiedGraphBuilt({
|
|
342
|
+
appConfig: this.appConfig,
|
|
343
|
+
entryPaths: routes.map((route) => route.templateRoute.filePath),
|
|
344
|
+
outdir: getServerModuleBuildCacheOutdir(this.appConfig),
|
|
345
|
+
force,
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
const staticExportContext = this.createStaticExportContext({
|
|
349
|
+
router,
|
|
350
|
+
baseUrl,
|
|
351
|
+
routeRendererFactory,
|
|
352
|
+
staticRoutes,
|
|
353
|
+
force,
|
|
354
|
+
preserveExportDirectory,
|
|
355
|
+
routes: exportRoutes,
|
|
455
356
|
});
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
357
|
+
await this.invokeStaticExportHook('beforeStaticExport', staticExportContext);
|
|
358
|
+
try {
|
|
359
|
+
if (shouldPrebuildProductionPageBrowserGraphs() && routeRendererFactory) {
|
|
360
|
+
await prebuildProductionPageBrowserGraphs(routes.map((route) => route.templateRoute.filePath), routeRendererFactory);
|
|
361
|
+
}
|
|
362
|
+
this.generateRobotsTxt();
|
|
363
|
+
await this.generateStaticPages({
|
|
364
|
+
router,
|
|
365
|
+
baseUrl,
|
|
366
|
+
routeRendererFactory,
|
|
367
|
+
skipped: skippedDynamicPages,
|
|
368
|
+
activeStaticPathnames,
|
|
369
|
+
preloadedRoutes: routes,
|
|
370
|
+
sitemapEligiblePathnames,
|
|
371
|
+
});
|
|
372
|
+
if (staticRoutes && staticRoutes.length > 0 && routeRendererFactory) {
|
|
373
|
+
await this.generateExplicitStaticPages({
|
|
374
|
+
staticRoutes,
|
|
375
|
+
routeRendererFactory,
|
|
376
|
+
skipped: skippedDynamicPages,
|
|
377
|
+
activeStaticPathnames,
|
|
378
|
+
sitemapEligiblePathnames,
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
if (preserveExportDirectory) {
|
|
382
|
+
this.pruneStaleStaticOutputs(activeStaticPathnames);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
catch (error) {
|
|
386
|
+
if (shouldPrebuildProductionPageBrowserGraphs()) {
|
|
387
|
+
clearProductionPageBrowserGraphSession(this.appConfig);
|
|
388
|
+
}
|
|
389
|
+
throw error;
|
|
390
|
+
}
|
|
391
|
+
finally {
|
|
392
|
+
await this.invokeStaticExportHook('afterStaticExport', staticExportContext);
|
|
393
|
+
}
|
|
394
|
+
if (this.appConfig.sitemap?.enabled && sitemapEligiblePathnames) {
|
|
395
|
+
const locations = resolveSitemapLocations({
|
|
396
|
+
eligiblePathnames: [...sitemapEligiblePathnames],
|
|
397
|
+
sitemap: this.appConfig.sitemap,
|
|
398
|
+
baseUrl,
|
|
399
|
+
});
|
|
400
|
+
this.generateSitemap(locations, this.appConfig.sitemap);
|
|
401
|
+
}
|
|
402
|
+
if (skippedDynamicPages.length > 0) {
|
|
403
|
+
appLogger.debug(`Skipped ${skippedDynamicPages.length} page(s) with cache: 'dynamic' (not supported in static generation)`, skippedDynamicPages);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
async generateExplicitStaticPages(input) {
|
|
407
|
+
appLogger.debug('Generating explicit static routes', input.staticRoutes.map((r) => r.path));
|
|
408
|
+
for (const route of input.staticRoutes) {
|
|
409
|
+
try {
|
|
410
|
+
const mod = await route.loader();
|
|
411
|
+
const view = mod.default;
|
|
412
|
+
if (this.shouldSkipStaticView(route.path, view)) {
|
|
413
|
+
input.skipped?.push(route.path);
|
|
414
|
+
continue;
|
|
415
|
+
}
|
|
416
|
+
await this.generateExplicitStaticRoute({
|
|
417
|
+
routePath: route.path,
|
|
418
|
+
view,
|
|
419
|
+
routeRendererFactory: input.routeRendererFactory,
|
|
420
|
+
activeStaticPathnames: input.activeStaticPathnames,
|
|
421
|
+
sitemapEligiblePathnames: input.sitemapEligiblePathnames,
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
catch (error) {
|
|
425
|
+
appLogger.error(`Error generating explicit static page for ${route.path}:`, error instanceof Error ? error : String(error));
|
|
426
|
+
}
|
|
427
|
+
}
|
|
462
428
|
}
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
429
|
+
resolveExplicitViewSourceFile(view) {
|
|
430
|
+
const sourceFile = view.config?.__eco?.file;
|
|
431
|
+
if (!sourceFile) {
|
|
432
|
+
return undefined;
|
|
433
|
+
}
|
|
434
|
+
return path.isAbsolute(sourceFile) ? sourceFile : path.join(this.appConfig.rootDir, sourceFile);
|
|
468
435
|
}
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
436
|
+
async generateExplicitStaticRoute(input) {
|
|
437
|
+
const { routePath, view, routeRendererFactory, activeStaticPathnames, sitemapEligiblePathnames } = input;
|
|
438
|
+
const { renderer, routeEntries } = await this.planExplicitStaticRoute({
|
|
439
|
+
routePath,
|
|
440
|
+
view,
|
|
441
|
+
routeRendererFactory,
|
|
442
|
+
});
|
|
443
|
+
const sourceFile = this.resolveExplicitViewSourceFile(view);
|
|
444
|
+
for (const { pathname, params } of routeEntries) {
|
|
445
|
+
await this.writeStaticPageArtifact({
|
|
446
|
+
pathname,
|
|
447
|
+
sourceFile,
|
|
448
|
+
debugLabel: pathname,
|
|
449
|
+
activeStaticPathnames,
|
|
450
|
+
onSuccessfulExport: () => this.considerSitemapEligibility({
|
|
451
|
+
pathname,
|
|
452
|
+
sitemapEligiblePathnames,
|
|
453
|
+
resolveMetadata: async () => {
|
|
454
|
+
const { props } = await prepareExplicitStaticRender({
|
|
455
|
+
routePath,
|
|
456
|
+
view,
|
|
457
|
+
params,
|
|
458
|
+
appConfig: this.appConfig,
|
|
459
|
+
runtimeOrigin: this.appConfig.baseUrl,
|
|
460
|
+
routeRendererFactory,
|
|
461
|
+
errors: STATIC_SITE_GENERATOR_ERRORS,
|
|
462
|
+
});
|
|
463
|
+
return this.resolveExplicitViewMetadata({ view, params, props });
|
|
464
|
+
},
|
|
465
|
+
}),
|
|
466
|
+
createContents: () => this.createExplicitStaticContents({
|
|
467
|
+
routePath,
|
|
468
|
+
view,
|
|
469
|
+
params,
|
|
470
|
+
routeRendererFactory,
|
|
471
|
+
renderer,
|
|
472
|
+
}),
|
|
497
473
|
});
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
}),
|
|
501
|
-
createContents: () => this.createExplicitStaticContents({
|
|
502
|
-
routePath,
|
|
503
|
-
view,
|
|
504
|
-
params,
|
|
505
|
-
routeRendererFactory,
|
|
506
|
-
renderer
|
|
507
|
-
})
|
|
508
|
-
});
|
|
509
|
-
appLogger.debug(`Generated static page: ${pathname}`);
|
|
474
|
+
appLogger.debug(`Generated static page: ${pathname}`);
|
|
475
|
+
}
|
|
510
476
|
}
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
};
|
|
526
|
-
}
|
|
527
|
-
async createExplicitStaticContents(input) {
|
|
528
|
-
const { props, view: renderableView } = await prepareExplicitStaticRender({
|
|
529
|
-
routePath: input.routePath,
|
|
530
|
-
view: input.view,
|
|
531
|
-
params: input.params,
|
|
532
|
-
appConfig: this.appConfig,
|
|
533
|
-
runtimeOrigin: this.appConfig.baseUrl,
|
|
534
|
-
routeRendererFactory: input.routeRendererFactory,
|
|
535
|
-
errors: STATIC_SITE_GENERATOR_ERRORS
|
|
536
|
-
});
|
|
537
|
-
const response = await input.renderer.renderToResponse(renderableView, props, {});
|
|
538
|
-
return response.text();
|
|
539
|
-
}
|
|
540
|
-
async listExplicitStaticRouteEntries(routePath, view) {
|
|
541
|
-
const isDynamic = routePath.includes(":") || routePath.includes("[");
|
|
542
|
-
if (!isDynamic) {
|
|
543
|
-
return [{ pathname: routePath, params: {} }];
|
|
477
|
+
async planExplicitStaticRoute(input) {
|
|
478
|
+
const { renderer } = await prepareExplicitStaticRender({
|
|
479
|
+
routePath: input.routePath,
|
|
480
|
+
view: input.view,
|
|
481
|
+
params: {},
|
|
482
|
+
appConfig: this.appConfig,
|
|
483
|
+
runtimeOrigin: this.appConfig.baseUrl,
|
|
484
|
+
routeRendererFactory: input.routeRendererFactory,
|
|
485
|
+
errors: STATIC_SITE_GENERATOR_ERRORS,
|
|
486
|
+
});
|
|
487
|
+
return {
|
|
488
|
+
renderer,
|
|
489
|
+
routeEntries: await this.listExplicitStaticRouteEntries(input.routePath, input.view),
|
|
490
|
+
};
|
|
544
491
|
}
|
|
545
|
-
|
|
546
|
-
|
|
492
|
+
async createExplicitStaticContents(input) {
|
|
493
|
+
const { props, view: renderableView } = await prepareExplicitStaticRender({
|
|
494
|
+
routePath: input.routePath,
|
|
495
|
+
view: input.view,
|
|
496
|
+
params: input.params,
|
|
497
|
+
appConfig: this.appConfig,
|
|
498
|
+
runtimeOrigin: this.appConfig.baseUrl,
|
|
499
|
+
routeRendererFactory: input.routeRendererFactory,
|
|
500
|
+
errors: STATIC_SITE_GENERATOR_ERRORS,
|
|
501
|
+
});
|
|
502
|
+
const response = await input.renderer.renderToResponse(renderableView, props, {});
|
|
503
|
+
return response.text();
|
|
547
504
|
}
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
505
|
+
async listExplicitStaticRouteEntries(routePath, view) {
|
|
506
|
+
const isDynamic = routePath.includes(':') || routePath.includes('[');
|
|
507
|
+
if (!isDynamic) {
|
|
508
|
+
return [{ pathname: routePath, params: {} }];
|
|
509
|
+
}
|
|
510
|
+
if (!view.staticPaths) {
|
|
511
|
+
throw new Error(STATIC_SITE_GENERATOR_ERRORS.dynamicRouteRequiresStaticPaths(routePath));
|
|
512
|
+
}
|
|
513
|
+
const { paths } = await view.staticPaths({
|
|
514
|
+
appConfig: this.appConfig,
|
|
515
|
+
runtimeOrigin: this.appConfig.baseUrl,
|
|
516
|
+
});
|
|
517
|
+
return paths.map(({ params }) => ({
|
|
518
|
+
pathname: this.resolveRoutePath(routePath, params),
|
|
519
|
+
params,
|
|
520
|
+
}));
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Resolve a route path template with actual params.
|
|
524
|
+
* Supports both :param and [param] syntax.
|
|
525
|
+
*/
|
|
526
|
+
resolveRoutePath(routePath, params) {
|
|
527
|
+
let resolved = routePath;
|
|
528
|
+
for (const [key, value] of Object.entries(params)) {
|
|
529
|
+
const paramValue = Array.isArray(value) ? value.join('/') : value;
|
|
530
|
+
resolved = resolved.replace(`:${key}`, paramValue);
|
|
531
|
+
resolved = resolved.replace(`[${key}]`, paramValue);
|
|
532
|
+
resolved = resolved.replace(`[...${key}]`, paramValue);
|
|
533
|
+
}
|
|
534
|
+
return resolved;
|
|
568
535
|
}
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
536
|
+
/**
|
|
537
|
+
* Get the output file path for a given route.
|
|
538
|
+
*/
|
|
539
|
+
getOutputPath(routePath, directories = []) {
|
|
540
|
+
let outputName;
|
|
541
|
+
if (routePath === '/') {
|
|
542
|
+
outputName = 'index.html';
|
|
543
|
+
}
|
|
544
|
+
else if (directories.includes(routePath)) {
|
|
545
|
+
outputName = `${routePath}/index.html`;
|
|
546
|
+
}
|
|
547
|
+
else if (routePath.endsWith('/')) {
|
|
548
|
+
outputName = `${routePath}index.html`;
|
|
549
|
+
}
|
|
550
|
+
else {
|
|
551
|
+
outputName = `${routePath}.html`;
|
|
552
|
+
}
|
|
553
|
+
return path.join(this.getExportDir(), outputName);
|
|
584
554
|
}
|
|
585
|
-
return path.join(this.getExportDir(), outputName);
|
|
586
|
-
}
|
|
587
555
|
}
|
|
588
|
-
export {
|
|
589
|
-
STATIC_SITE_GENERATOR_ERRORS,
|
|
590
|
-
StaticSiteGenerator
|
|
591
|
-
};
|