@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.
Files changed (338) hide show
  1. package/README.md +1 -0
  2. package/package.json +82 -3
  3. package/src/adapters/abstract/application-adapter.d.ts +0 -8
  4. package/src/adapters/abstract/application-adapter.js +252 -261
  5. package/src/adapters/abstract/router-adapter.js +12 -4
  6. package/src/adapters/abstract/segment-path-matcher.js +132 -134
  7. package/src/adapters/abstract/server-adapter.js +22 -14
  8. package/src/adapters/abstract/ws-pattern-matcher.js +24 -26
  9. package/src/adapters/bun/bun-user-websocket-lifecycle.js +83 -86
  10. package/src/adapters/bun/client-bridge.js +51 -50
  11. package/src/adapters/bun/create-app.js +171 -161
  12. package/src/adapters/bun/hmr-manager.js +62 -57
  13. package/src/adapters/bun/index.js +2 -31
  14. package/src/adapters/bun/runtime-host.js +61 -54
  15. package/src/adapters/bun/server-adapter.d.ts +0 -1
  16. package/src/adapters/bun/server-adapter.js +561 -561
  17. package/src/adapters/bun/static-preview-host.js +43 -46
  18. package/src/adapters/create-app.js +11 -14
  19. package/src/adapters/index.js +2 -30
  20. package/src/adapters/node/create-app.js +123 -129
  21. package/src/adapters/node/http-request-bridge.js +147 -106
  22. package/src/adapters/node/node-client-bridge.js +62 -64
  23. package/src/adapters/node/node-hmr-manager.js +58 -48
  24. package/src/adapters/node/runtime-host.js +96 -89
  25. package/src/adapters/node/server-adapter-dependencies.js +18 -21
  26. package/src/adapters/node/server-adapter.d.ts +0 -1
  27. package/src/adapters/node/server-adapter.js +347 -326
  28. package/src/adapters/node/static-content-server.js +172 -191
  29. package/src/adapters/node/static-preview-host.js +87 -78
  30. package/src/adapters/shared/hmr/dev-transform-entrypoint-registry.d.ts +16 -0
  31. package/src/adapters/shared/hmr/dev-transform-entrypoint-registry.js +32 -0
  32. package/src/adapters/shared/hmr/hmr-html-response.js +46 -32
  33. package/src/adapters/shared/hmr/shared-hmr-manager.d.ts +29 -38
  34. package/src/adapters/shared/hmr/shared-hmr-manager.js +439 -425
  35. package/src/adapters/shared/http/api-request-pipeline.js +122 -119
  36. package/src/adapters/shared/http/api-response.js +77 -77
  37. package/src/adapters/shared/http/create-body-response.js +22 -19
  38. package/src/adapters/shared/http/define-api-handler.js +41 -55
  39. package/src/adapters/shared/http/explicit-static-render-preparation.js +26 -23
  40. package/src/adapters/shared/http/explicit-static-route-matcher.js +55 -62
  41. package/src/adapters/shared/http/file-route-middleware-pipeline.js +81 -75
  42. package/src/adapters/shared/http/fs-server-response-factory.js +101 -96
  43. package/src/adapters/shared/http/fs-server-response-matcher.js +239 -257
  44. package/src/adapters/shared/http/run-middleware-chain.js +15 -15
  45. package/src/adapters/shared/runtime/application-adapter.js +72 -87
  46. package/src/adapters/shared/runtime/copy-runtime-public-dir.js +25 -22
  47. package/src/adapters/shared/runtime/port-manager.js +207 -177
  48. package/src/adapters/shared/runtime/render-context.js +94 -79
  49. package/src/adapters/shared/runtime/runtime-app-bootstrap.js +33 -38
  50. package/src/adapters/shared/runtime/runtime-host.js +1 -0
  51. package/src/adapters/shared/runtime/runtime-server-lifecycle.d.ts +2 -3
  52. package/src/adapters/shared/runtime/runtime-server-lifecycle.js +65 -51
  53. package/src/adapters/shared/runtime/server-adapter.d.ts +1 -0
  54. package/src/adapters/shared/runtime/server-adapter.js +233 -217
  55. package/src/adapters/shared/runtime/server-route-handler.js +74 -70
  56. package/src/adapters/shared/runtime/server-static-builder.js +165 -184
  57. package/src/adapters/shared/runtime/static-preview-host.js +1 -0
  58. package/src/adapters/shared/ws/node-http-websocket-upgrades.js +97 -88
  59. package/src/adapters/shared/ws/websocket-lifecycle.js +57 -50
  60. package/src/build/README.md +52 -1
  61. package/src/build/app-build-manifest-runtime.js +129 -108
  62. package/src/build/browser/browser-runtime-manifest.js +47 -50
  63. package/src/build/browser/browser-runtime-plugin-helpers.js +32 -12
  64. package/src/build/browser/browser-runtime-plugin.js +206 -160
  65. package/src/build/browser/jsx-ownership-plugins.js +51 -37
  66. package/src/build/browser/lit-static-render-worker-context.js +3 -5
  67. package/src/build/build-adapter.js +276 -139
  68. package/src/build/cache/build-input-fingerprint.js +28 -26
  69. package/src/build/cache/cache-constants.js +4 -6
  70. package/src/build/cache/cache-keys.js +64 -56
  71. package/src/build/cache/pages-unified-graph-build.js +179 -178
  72. package/src/build/cache/production-build-cache.js +47 -54
  73. package/src/build/cache/server-entry-build-cache.js +134 -146
  74. package/src/build/contracts/build-contracts.d.ts +4 -4
  75. package/src/build/contracts/build-contracts.js +1 -0
  76. package/src/build/contracts/build-manifest.js +58 -43
  77. package/src/build/contracts/build-types.js +1 -0
  78. package/src/build/rolldown/rolldown-adapter-helpers.d.ts +9 -0
  79. package/src/build/rolldown/rolldown-adapter-helpers.js +405 -298
  80. package/src/build/rolldown/rolldown-build-adapter.js +53 -61
  81. package/src/build/rolldown/rolldown-build-invocation-metrics.js +31 -35
  82. package/src/build/rolldown/rolldown-plugin-bridge.js +264 -194
  83. package/src/build/rolldown/rolldown-source-transform-pass.js +59 -50
  84. package/src/build/rolldown/runtime-build-output-normalizer.js +227 -175
  85. package/src/build/rolldown/server-side-css-shim-plugin.js +54 -31
  86. package/src/build/runtime/build-profile-options.js +36 -36
  87. package/src/build/runtime/build-request-identity.js +70 -45
  88. package/src/build/runtime/build-request-policy.js +80 -42
  89. package/src/build/runtime/build-runtime.js +64 -54
  90. package/src/build/runtime/deduping-build-executor.js +38 -32
  91. package/src/build/runtime/parallel-build-executor.js +58 -50
  92. package/src/build/runtime/serialized-build-executor.js +78 -62
  93. package/src/cache/index.js +6 -6
  94. package/src/cache/module-parse-cache.js +99 -68
  95. package/src/client/navigation-scripts/classification.js +45 -37
  96. package/src/client/navigation-scripts/index.js +3 -23
  97. package/src/client/navigation-scripts/navigation-scripts.test.browser.js +58 -62
  98. package/src/client/navigation-scripts/registry.js +15 -11
  99. package/src/client/navigation-scripts/rerun-queue.js +81 -64
  100. package/src/client/scroll.js +32 -24
  101. package/src/client/scroll.test.browser.js +27 -33
  102. package/src/client/view-transitions.js +68 -55
  103. package/src/config/config-builder.d.ts +8 -0
  104. package/src/config/config-builder.js +637 -642
  105. package/src/config/constants.js +44 -24
  106. package/src/declarations.d.ts +1 -0
  107. package/src/dev/README.md +24 -0
  108. package/src/dev/client-bridge-registry.js +7 -12
  109. package/src/dev/dev-client-ownership.js +7 -5
  110. package/src/dev/hmr-manager-registry.js +7 -12
  111. package/src/dev/host-runtime.js +25 -30
  112. package/src/dev/runtime-server-started-message.js +2 -5
  113. package/src/dev/sc-server.js +106 -103
  114. package/src/dev/transform-server/dev-transform-bundler.d.ts +24 -0
  115. package/src/dev/transform-server/dev-transform-bundler.js +79 -0
  116. package/src/dev/transform-server/dev-transform-externalize-plugin.d.ts +12 -0
  117. package/src/dev/transform-server/dev-transform-externalize-plugin.js +29 -0
  118. package/src/dev/transform-server/dev-transform-import-rewriter.d.ts +16 -0
  119. package/src/dev/transform-server/dev-transform-import-rewriter.js +110 -0
  120. package/src/dev/transform-server/dev-transform-module-kind.d.ts +13 -0
  121. package/src/dev/transform-server/dev-transform-module-kind.js +17 -0
  122. package/src/dev/transform-server/dev-transform-runtime-specifiers.d.ts +5 -0
  123. package/src/dev/transform-server/dev-transform-runtime-specifiers.js +16 -0
  124. package/src/dev/transform-server/dev-transform-server.d.ts +41 -0
  125. package/src/dev/transform-server/dev-transform-server.js +191 -0
  126. package/src/dev/transform-server/dev-transform-url.d.ts +13 -0
  127. package/src/dev/transform-server/dev-transform-url.js +58 -0
  128. package/src/dev/transform-server/dev-transform-vendor-registry.d.ts +27 -0
  129. package/src/dev/transform-server/dev-transform-vendor-registry.js +145 -0
  130. package/src/dev/transform-server/index.d.ts +6 -0
  131. package/src/dev/transform-server/index.js +4 -0
  132. package/src/dev/transform-server/types.d.ts +15 -0
  133. package/src/dev/transform-server/types.js +1 -0
  134. package/src/dev-toolbar/README.md +51 -0
  135. package/src/dev-toolbar/define-dev-tool.d.ts +21 -0
  136. package/src/dev-toolbar/define-dev-tool.js +9 -0
  137. package/src/dev-toolbar/dev-toolbar-config.d.ts +25 -0
  138. package/src/dev-toolbar/dev-toolbar-config.js +19 -0
  139. package/src/dev-toolbar/dev-toolbar-host.d.ts +49 -0
  140. package/src/dev-toolbar/dev-toolbar-host.js +117 -0
  141. package/src/dev-toolbar/dev-toolbar-html-response.d.ts +11 -0
  142. package/src/dev-toolbar/dev-toolbar-html-response.js +14 -0
  143. package/src/dev-toolbar/dev-toolbar-manifest.d.ts +15 -0
  144. package/src/dev-toolbar/dev-toolbar-manifest.js +52 -0
  145. package/src/dev-toolbar/dev-toolbar-package.d.ts +31 -0
  146. package/src/dev-toolbar/dev-toolbar-package.js +72 -0
  147. package/src/dev-toolbar/dev-toolbar-runtime-paths.d.ts +10 -0
  148. package/src/dev-toolbar/dev-toolbar-runtime-paths.js +13 -0
  149. package/src/diagnostics/request-build-dedupe.js +34 -28
  150. package/src/diagnostics/startup-trace.d.ts +10 -1
  151. package/src/diagnostics/startup-trace.js +269 -241
  152. package/src/eco/README.md +6 -0
  153. package/src/eco/eco-declared-component.js +19 -14
  154. package/src/eco/eco.browser.js +56 -69
  155. package/src/eco/eco.js +156 -96
  156. package/src/eco/eco.types.js +5 -0
  157. package/src/eco/eco.utils.js +1 -10
  158. package/src/eco/global-injector-map.js +55 -41
  159. package/src/eco/lazy-injector-map.js +90 -60
  160. package/src/eco/module-dependencies.js +52 -44
  161. package/src/eco/page-layout-normalization.js +59 -49
  162. package/src/errors/http-error.js +50 -49
  163. package/src/errors/index.js +3 -12
  164. package/src/errors/locals-access-error.js +5 -8
  165. package/src/errors/undeclared-component-dependency-error.js +15 -15
  166. package/src/global/app-logger.js +3 -6
  167. package/src/hmr/README.md +10 -0
  168. package/src/hmr/client/hmr-runtime.js +117 -113
  169. package/src/hmr/client/module-update.d.ts +13 -0
  170. package/src/hmr/client/module-update.js +39 -0
  171. package/src/hmr/hmr-asset-paths.d.ts +14 -0
  172. package/src/hmr/hmr-asset-paths.js +22 -0
  173. package/src/hmr/hmr-entrypoint-output.d.ts +11 -39
  174. package/src/hmr/hmr-entrypoint-output.js +28 -54
  175. package/src/hmr/hmr-file-change-prep.js +13 -16
  176. package/src/hmr/hmr-registered-entrypoints-context.d.ts +7 -0
  177. package/src/hmr/hmr-registered-entrypoints-context.js +1 -0
  178. package/src/hmr/hmr-runtime-paths.d.ts +10 -0
  179. package/src/hmr/hmr-runtime-paths.js +13 -0
  180. package/src/hmr/hmr-strategy.d.ts +5 -11
  181. package/src/hmr/hmr-strategy.js +113 -61
  182. package/src/hmr/strategies/default-hmr-strategy.js +55 -33
  183. package/src/hmr/strategies/js-hmr-strategy.d.ts +6 -95
  184. package/src/hmr/strategies/js-hmr-strategy.js +104 -217
  185. package/src/hmr/strategies/server-rendered-template-hmr-strategy.js +33 -27
  186. package/src/index.browser.js +1 -4
  187. package/src/index.d.ts +1 -0
  188. package/src/index.js +6 -47
  189. package/src/integrations/ghtml/ghtml-renderer.js +12 -7
  190. package/src/integrations/ghtml/ghtml.constants.js +1 -4
  191. package/src/integrations/ghtml/ghtml.plugin.js +9 -12
  192. package/src/islands/README.md +25 -0
  193. package/src/islands/island-host.d.ts +37 -0
  194. package/src/islands/island-host.js +55 -0
  195. package/src/plugins/alias-resolver-cache.js +114 -97
  196. package/src/plugins/alias-resolver-plugin.js +33 -47
  197. package/src/plugins/define-integration.js +18 -17
  198. package/src/plugins/eco-component-meta-plugin.js +387 -145
  199. package/src/plugins/foreign-jsx-override-plugin.js +49 -35
  200. package/src/plugins/integration-plugin.js +212 -203
  201. package/src/plugins/jsx-import-source.utils.js +16 -21
  202. package/src/plugins/processor.js +159 -149
  203. package/src/plugins/runtime-capability.js +1 -0
  204. package/src/plugins/source-transform.js +109 -79
  205. package/src/plugins/tsconfig-import-resolver.d.ts +17 -0
  206. package/src/plugins/tsconfig-import-resolver.js +218 -142
  207. package/src/route-renderer/README.md +12 -1
  208. package/src/route-renderer/orchestration/document-shell/document-shell-render.service.js +143 -136
  209. package/src/route-renderer/orchestration/document-shell/layout-shell-props.service.js +33 -27
  210. package/src/route-renderer/orchestration/foreign-child/component-render-context.js +173 -126
  211. package/src/route-renderer/orchestration/foreign-child/foreign-child-output.utils.js +165 -154
  212. package/src/route-renderer/orchestration/foreign-child/foreign-subtree-execution.service.js +329 -341
  213. package/src/route-renderer/orchestration/foreign-child/owning-renderer-resolution.js +33 -32
  214. package/src/route-renderer/orchestration/integration-renderer.d.ts +1 -0
  215. package/src/route-renderer/orchestration/integration-renderer.js +731 -750
  216. package/src/route-renderer/orchestration/integration-renderer.test-fixtures.js +168 -172
  217. package/src/route-renderer/orchestration/ownership-graph/component-graph-collectors.js +119 -131
  218. package/src/route-renderer/orchestration/ownership-graph/component-graph.js +82 -91
  219. package/src/route-renderer/orchestration/ownership-graph/ownership-validation.service.js +82 -76
  220. package/src/route-renderer/orchestration/page-browser-graph/global-injector-assets.service.js +29 -31
  221. package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph-contribution.loader.js +10 -6
  222. package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph-merge.utils.js +31 -28
  223. package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph-session.d.ts +3 -0
  224. package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph-session.js +430 -413
  225. package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph.service.js +191 -212
  226. package/src/route-renderer/orchestration/page-browser-graph/processed-asset-dedupe.js +20 -24
  227. package/src/route-renderer/orchestration/route-pipeline/integration-route-render-adapter.d.ts +4 -0
  228. package/src/route-renderer/orchestration/route-pipeline/integration-route-render-adapter.js +24 -24
  229. package/src/route-renderer/orchestration/route-pipeline/marker-artifact.utils.js +22 -24
  230. package/src/route-renderer/orchestration/route-pipeline/robots-meta.contribution.js +41 -34
  231. package/src/route-renderer/orchestration/route-pipeline/route-html-finalization.service.d.ts +5 -0
  232. package/src/route-renderer/orchestration/route-pipeline/route-html-finalization.service.js +42 -22
  233. package/src/route-renderer/orchestration/route-pipeline/route-prepared-options.builder.js +50 -48
  234. package/src/route-renderer/orchestration/route-pipeline/route-prepared-options.utils.js +29 -32
  235. package/src/route-renderer/orchestration/route-pipeline/route-render-orchestrator.js +150 -156
  236. package/src/route-renderer/orchestration/string-markup-renderer.js +48 -51
  237. package/src/route-renderer/page-loading/component-dependency-collection.js +120 -124
  238. package/src/route-renderer/page-loading/declared-asset-collection.js +66 -94
  239. package/src/route-renderer/page-loading/dependency-resolver.js +101 -104
  240. package/src/route-renderer/page-loading/ecopages-virtual-imports.js +68 -54
  241. package/src/route-renderer/page-loading/lazy-entry-collection.js +75 -98
  242. package/src/route-renderer/page-loading/lazy-trigger-planning.js +46 -36
  243. package/src/route-renderer/page-loading/module-declaration-aggregation.js +38 -31
  244. package/src/route-renderer/page-loading/module-declaration-scripts.js +10 -15
  245. package/src/route-renderer/page-loading/page-dependency-bundling.js +156 -113
  246. package/src/route-renderer/page-loading/page-module-loader.js +130 -124
  247. package/src/route-renderer/route-renderer.js +74 -76
  248. package/src/router/client/link-intent.js +55 -39
  249. package/src/router/client/link-intent.test.browser.js +49 -49
  250. package/src/router/client/link-navigation-policy.js +114 -93
  251. package/src/router/client/link-navigation-policy.test.browser.js +70 -80
  252. package/src/router/client/navigation-coordinator.js +235 -211
  253. package/src/router/server/route-registry.js +237 -242
  254. package/src/services/assets/asset-processing-service/asset-dependency-keys.js +64 -53
  255. package/src/services/assets/asset-processing-service/asset-processing.service.js +287 -303
  256. package/src/services/assets/asset-processing-service/asset.factory.js +78 -81
  257. package/src/services/assets/asset-processing-service/assets.types.js +1 -0
  258. package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.js +57 -46
  259. package/src/services/assets/asset-processing-service/browser-runtime-entry-resolution.js +106 -69
  260. package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.js +53 -53
  261. package/src/services/assets/asset-processing-service/finalize-processed-asset.js +4 -6
  262. package/src/services/assets/asset-processing-service/grouped-content-bundles.js +79 -80
  263. package/src/services/assets/asset-processing-service/index.js +8 -8
  264. package/src/services/assets/asset-processing-service/inline-content-script-body.js +22 -16
  265. package/src/services/assets/asset-processing-service/materialize-content-script-asset.js +21 -17
  266. package/src/services/assets/asset-processing-service/page-package.js +70 -72
  267. package/src/services/assets/asset-processing-service/processor.interface.js +7 -5
  268. package/src/services/assets/asset-processing-service/processor.registry.js +11 -14
  269. package/src/services/assets/asset-processing-service/processors/base/base-processor.js +59 -62
  270. package/src/services/assets/asset-processing-service/processors/base/base-script-processor.js +102 -117
  271. package/src/services/assets/asset-processing-service/processors/index.js +5 -5
  272. package/src/services/assets/asset-processing-service/processors/script/content-script.processor.js +110 -115
  273. package/src/services/assets/asset-processing-service/processors/script/file-script.processor.js +95 -97
  274. package/src/services/assets/asset-processing-service/processors/script/node-module-script.processor.js +136 -135
  275. package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.js +27 -29
  276. package/src/services/assets/asset-processing-service/processors/stylesheet/file-stylesheet.processor.js +34 -40
  277. package/src/services/assets/asset-processing-service/processors/stylesheet/stylesheet-processor-pipeline.js +36 -35
  278. package/src/services/assets/asset-processing-service/resolve-integration-plugin.js +14 -16
  279. package/src/services/assets/asset-processing-service/ungrouped-dependency-processing.js +27 -39
  280. package/src/services/assets/browser-bundle.service.js +52 -47
  281. package/src/services/cache/cache.types.js +5 -0
  282. package/src/services/cache/index.js +6 -7
  283. package/src/services/cache/memory-cache-store.js +101 -89
  284. package/src/services/cache/page-cache-service.js +156 -145
  285. package/src/services/cache/page-request-cache-coordinator.service.js +102 -102
  286. package/src/services/html/html-rewriter-provider.service.js +61 -61
  287. package/src/services/html/html-transformer.service.js +249 -266
  288. package/src/services/invalidation/development-invalidation.service.js +252 -241
  289. package/src/services/module-loading/app-module-loader.service.js +1 -0
  290. package/src/services/module-loading/app-server-module-transpiler.service.js +107 -101
  291. package/src/services/module-loading/host-module-loader-registry.js +6 -11
  292. package/src/services/module-loading/module-loading-types.js +1 -0
  293. package/src/services/module-loading/page-module-import.service.js +235 -243
  294. package/src/services/module-loading/route-module-build-cache-registry.js +47 -33
  295. package/src/services/module-loading/route-module-build-cache.js +3 -38
  296. package/src/services/module-loading/route-module-build-cache.store.js +195 -200
  297. package/src/services/module-loading/route-module-build-manifest.js +61 -74
  298. package/src/services/module-loading/route-module-dependency-hasher.js +136 -110
  299. package/src/services/module-loading/server-module-transpiler.service.js +68 -62
  300. package/src/services/module-loading/source-module-support.js +15 -7
  301. package/src/services/runtime-state/dev-graph.service.js +165 -157
  302. package/src/services/runtime-state/entrypoint-dependency-graph.service.js +85 -76
  303. package/src/services/runtime-state/server-invalidation-state.service.js +38 -30
  304. package/src/services/validation/schema-validation-service.js +157 -95
  305. package/src/services/validation/standard-schema.types.js +1 -0
  306. package/src/services/validation/validate-standard-schema.js +13 -13
  307. package/src/static-site-generator/production-page-browser-graph-prebuild.js +35 -19
  308. package/src/static-site-generator/sitemap-routes.js +33 -28
  309. package/src/static-site-generator/sitemap.js +38 -29
  310. package/src/static-site-generator/static-build-invalidation.js +34 -56
  311. package/src/static-site-generator/static-export-context.js +1 -0
  312. package/src/static-site-generator/static-site-generator.js +517 -553
  313. package/src/types/internal-types.d.ts +19 -3
  314. package/src/types/internal-types.js +1 -0
  315. package/src/types/public-types.d.ts +16 -46
  316. package/src/types/public-types.js +1 -0
  317. package/src/utils/deep-merge.js +39 -26
  318. package/src/utils/ecopages-route-info.js +27 -23
  319. package/src/utils/hash.js +3 -6
  320. package/src/utils/html-escaping.js +21 -8
  321. package/src/utils/html.js +1 -4
  322. package/src/utils/invariant.js +11 -10
  323. package/src/utils/locals-utils.js +32 -22
  324. package/src/utils/parse-cli-args.js +73 -65
  325. package/src/utils/path-pattern.js +38 -23
  326. package/src/utils/path-utils.module.js +8 -11
  327. package/src/utils/resolve-entry-file.js +70 -38
  328. package/src/utils/resolve-work-dir.js +23 -27
  329. package/src/utils/runtime.js +24 -33
  330. package/src/utils/server-utils.module.js +60 -52
  331. package/src/utils/static-file-extensions.js +52 -46
  332. package/src/watchers/project-watcher-ignore.js +16 -15
  333. package/src/watchers/project-watcher.js +385 -366
  334. package/src/watchers/project-watcher.test-helpers.js +45 -50
  335. package/src/adapters/shared/hmr/hmr-entrypoint-registrar.d.ts +0 -56
  336. package/src/adapters/shared/hmr/hmr-entrypoint-registrar.js +0 -106
  337. package/src/build/cache/dev-browser-script-cache.d.ts +0 -34
  338. 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
+ };