@absolutejs/absolute 0.19.0-beta.999 → 0.20.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (341) hide show
  1. package/LICENSE +21 -13
  2. package/README.md +48 -2
  3. package/dist/angular/browser.js +82 -77
  4. package/dist/angular/browser.js.map +11 -11
  5. package/dist/angular/components/constants.js +43 -0
  6. package/dist/angular/components/core/streamingSlotRegistrar.js +1 -1
  7. package/dist/angular/components/core/streamingSlotRegistry.js +2 -2
  8. package/dist/angular/hmrPreserveCore.ts +132 -134
  9. package/dist/angular/index.js +1719 -844
  10. package/dist/angular/index.js.map +34 -26
  11. package/dist/angular/server.js +1620 -768
  12. package/dist/angular/server.js.map +28 -20
  13. package/dist/build.js +4935 -2593
  14. package/dist/build.js.map +72 -57
  15. package/dist/cli/config/client.js +578 -0
  16. package/dist/cli/config/server.js +39587 -0
  17. package/dist/cli/htmx/htmx.min.js +1 -0
  18. package/dist/cli/index.js +16828 -3511
  19. package/dist/client/index.js +49 -46
  20. package/dist/client/index.js.map +12 -12
  21. package/dist/core/streamingSlotRegistrar.js +1 -19
  22. package/dist/core/streamingSlotRegistrar.js.map +2 -2
  23. package/dist/core/streamingSlotRegistry.js +1 -19
  24. package/dist/core/streamingSlotRegistry.js.map +2 -2
  25. package/dist/dev/client/cssUtils.ts +98 -41
  26. package/dist/dev/client/domState.ts +2 -0
  27. package/dist/dev/client/errorOverlay.ts +14 -13
  28. package/dist/dev/client/handlers/angularHmrShim.ts +20 -20
  29. package/dist/dev/client/handlers/angularRemount.ts +74 -55
  30. package/dist/dev/client/handlers/angularRemountWiring.ts +1 -2
  31. package/dist/dev/client/handlers/html.ts +144 -41
  32. package/dist/dev/client/handlers/htmx.ts +43 -8
  33. package/dist/dev/client/handlers/react.ts +114 -32
  34. package/dist/dev/client/handlers/rebuild.ts +28 -8
  35. package/dist/dev/client/handlers/svelte.ts +92 -51
  36. package/dist/dev/client/handlers/vue.ts +36 -45
  37. package/dist/dev/client/hmrClient.ts +101 -26
  38. package/dist/dev/client/hmrTiming.ts +141 -0
  39. package/dist/dev/client/hmrToast.ts +22 -24
  40. package/dist/dev/client/reactRefreshSetup.ts +4 -0
  41. package/dist/dev/client/vendor/reactRefreshRuntime.d.ts +12 -0
  42. package/dist/dev/client/vendor/reactRefreshRuntime.js +313 -0
  43. package/dist/dev/serverBootstrap.js +45 -0
  44. package/dist/index.js +7153 -3224
  45. package/dist/index.js.map +118 -86
  46. package/dist/islands/browser.js +1 -19
  47. package/dist/islands/browser.js.map +3 -3
  48. package/dist/islands/index.js +709 -120
  49. package/dist/islands/index.js.map +18 -13
  50. package/dist/mobile/browser.js +428 -0
  51. package/dist/mobile/browser.js.map +12 -0
  52. package/dist/mobile/index.js +3058 -0
  53. package/dist/mobile/index.js.map +35 -0
  54. package/dist/react/browser.js +13 -62
  55. package/dist/react/browser.js.map +5 -6
  56. package/dist/react/components/browser/index.js +23 -13
  57. package/dist/react/components/index.js +30 -34
  58. package/dist/react/components/index.js.map +8 -7
  59. package/dist/react/hooks/index.js +1 -19
  60. package/dist/react/hooks/index.js.map +3 -3
  61. package/dist/react/index.js +1643 -679
  62. package/dist/react/index.js.map +29 -20
  63. package/dist/react/jsxDevRuntimeCompat.js +22 -20
  64. package/dist/react/jsxDevRuntimeCompat.js.map +5 -4
  65. package/dist/react/jsxRuntimeCompat.js +90 -0
  66. package/dist/react/jsxRuntimeCompat.js.map +10 -0
  67. package/dist/react/router/browser.js +77 -0
  68. package/dist/react/router/browser.js.map +10 -0
  69. package/dist/react/router/index.js +77 -0
  70. package/dist/react/router/index.js.map +10 -0
  71. package/dist/react/server.js +950 -565
  72. package/dist/react/server.js.map +16 -11
  73. package/dist/src/angular/components/constants.d.ts +21 -0
  74. package/dist/src/angular/hmrPreserveCore.d.ts +7 -20
  75. package/dist/src/angular/islands.d.ts +1 -1
  76. package/dist/src/angular/pageHandler.d.ts +2 -0
  77. package/dist/src/angular/ssrRender.d.ts +4 -1
  78. package/dist/src/build/bunStringRawUnicodePlugin.d.ts +12 -0
  79. package/dist/src/build/chainInlineSourcemaps.d.ts +1 -0
  80. package/dist/src/build/compileAngular.d.ts +5 -7
  81. package/dist/src/build/compileSvelte.d.ts +3 -0
  82. package/dist/src/build/compileVue.d.ts +3 -1
  83. package/dist/src/build/generateReactIndexes.d.ts +1 -0
  84. package/dist/src/build/islandRegistryTransform.d.ts +17 -0
  85. package/dist/src/build/maskLiterals.d.ts +28 -0
  86. package/dist/src/build/parseVueSpaRoutes.d.ts +5 -0
  87. package/dist/src/build/resolveBuildMode.d.ts +7 -0
  88. package/dist/src/build/serverExternals.d.ts +14 -0
  89. package/dist/src/build/spaSideManifests.d.ts +16 -0
  90. package/dist/src/build/tailwindCompiler.d.ts +0 -1
  91. package/dist/src/cli/add/dependencies.d.ts +13 -0
  92. package/dist/src/cli/config/absolute/AbsoluteConfigPanel.d.ts +6 -0
  93. package/dist/src/cli/config/absolute/editAbsoluteConfig.d.ts +5 -0
  94. package/dist/src/cli/config/absolute/resolveAbsoluteConfig.d.ts +19 -0
  95. package/dist/src/cli/config/auth/AuthPanel.d.ts +6 -0
  96. package/dist/src/cli/config/auth/authCatalog.d.ts +10 -0
  97. package/dist/src/cli/config/auth/authScaffolds.d.ts +16 -0
  98. package/dist/src/cli/config/auth/editAuthConfig.d.ts +5 -0
  99. package/dist/src/cli/config/auth/resolveAuthSettings.d.ts +14 -0
  100. package/dist/src/cli/config/auth/resolveAuthState.d.ts +2 -0
  101. package/dist/src/cli/config/auth/scaffoldAuthFeature.d.ts +6 -0
  102. package/dist/src/cli/config/client.d.ts +1 -0
  103. package/dist/src/cli/config/configCert.d.ts +12 -0
  104. package/dist/src/cli/config/eslint/EslintPanel.d.ts +6 -0
  105. package/dist/src/cli/config/eslint/configAst.d.ts +18 -0
  106. package/dist/src/cli/config/eslint/editConfigRule.d.ts +6 -0
  107. package/dist/src/cli/config/eslint/eslintStyles.d.ts +1 -0
  108. package/dist/src/cli/config/eslint/resolveConfig.d.ts +3 -0
  109. package/dist/src/cli/config/eslint/serializeValue.d.ts +9 -0
  110. package/dist/src/cli/config/guards.d.ts +4 -0
  111. package/dist/src/cli/config/integrations/IntegrationsPanel.d.ts +6 -0
  112. package/dist/src/cli/config/packageJson/PackageJsonPanel.d.ts +6 -0
  113. package/dist/src/cli/config/packageJson/editPackageJson.d.ts +9 -0
  114. package/dist/src/cli/config/packageJson/resolvePackageJson.d.ts +8 -0
  115. package/dist/src/cli/config/page/ConfigShell.d.ts +6 -0
  116. package/dist/src/cli/config/page/FieldEditor.d.ts +9 -0
  117. package/dist/src/cli/config/page/PanelHost.d.ts +6 -0
  118. package/dist/src/cli/config/page/configStyles.d.ts +1 -0
  119. package/dist/src/cli/config/panels.d.ts +7 -0
  120. package/dist/src/cli/config/prettier/PrettierPanel.d.ts +6 -0
  121. package/dist/src/cli/config/prettier/editPrettier.d.ts +5 -0
  122. package/dist/src/cli/config/prettier/resolvePrettier.d.ts +11 -0
  123. package/dist/src/cli/config/schema/fromJsonSchema.d.ts +3 -0
  124. package/dist/src/cli/config/schema/fromType.d.ts +1 -0
  125. package/dist/src/cli/config/schema/serialize.d.ts +1 -0
  126. package/dist/src/cli/config/server.d.ts +527 -0
  127. package/dist/src/cli/config/tsconfig/TsconfigPanel.d.ts +6 -0
  128. package/dist/src/cli/config/tsconfig/editTsconfig.d.ts +5 -0
  129. package/dist/src/cli/config/tsconfig/resolveTsconfig.d.ts +8 -0
  130. package/dist/src/cli/config/tsconfig/tsconfigStyles.d.ts +1 -0
  131. package/dist/src/cli/discoverInstances.d.ts +5 -0
  132. package/dist/src/cli/elysiaOpenApiTypeboxPlugin.d.ts +8 -0
  133. package/dist/src/cli/generate/componentTemplates.d.ts +7 -0
  134. package/dist/src/cli/generate/context.d.ts +30 -0
  135. package/dist/src/cli/generate/cssStrategy.d.ts +20 -0
  136. package/dist/src/cli/generate/frameworkKey.d.ts +3 -0
  137. package/dist/src/cli/generate/frameworks.d.ts +40 -0
  138. package/dist/src/cli/generate/generateApi.d.ts +3 -0
  139. package/dist/src/cli/generate/generateComponent.d.ts +4 -0
  140. package/dist/src/cli/generate/generatePage.d.ts +4 -0
  141. package/dist/src/cli/generate/naming.d.ts +5 -0
  142. package/dist/src/cli/generate/navData.d.ts +10 -0
  143. package/dist/src/cli/generate/outcome.d.ts +17 -0
  144. package/dist/src/cli/generate/pageTemplates.d.ts +11 -0
  145. package/dist/src/cli/generate/routeWiring.d.ts +40 -0
  146. package/dist/src/cli/generate/staticNav.d.ts +5 -0
  147. package/dist/src/cli/heapDiff.d.ts +1 -0
  148. package/dist/src/cli/htmx/install.d.ts +6 -0
  149. package/dist/src/cli/inspectData.d.ts +12 -0
  150. package/dist/src/cli/inspectTui.d.ts +1 -0
  151. package/dist/src/cli/instanceStatus.d.ts +22 -0
  152. package/dist/src/cli/integrations/addPlugin.d.ts +8 -0
  153. package/dist/src/cli/integrations/catalog.d.ts +20 -0
  154. package/dist/src/cli/psTui.d.ts +1 -0
  155. package/dist/src/cli/scripts/add.d.ts +1 -0
  156. package/dist/src/cli/scripts/analyze.d.ts +1 -0
  157. package/dist/src/cli/scripts/api.d.ts +1 -0
  158. package/dist/src/cli/scripts/build.d.ts +1 -1
  159. package/dist/src/cli/scripts/db.d.ts +20 -0
  160. package/dist/src/cli/scripts/dev.d.ts +5 -1
  161. package/dist/src/cli/scripts/doctor.d.ts +1 -0
  162. package/dist/src/cli/scripts/env.d.ts +7 -0
  163. package/dist/src/cli/scripts/eslint.d.ts +37 -2
  164. package/dist/src/cli/scripts/eslintChunked.d.ts +37 -0
  165. package/dist/src/cli/scripts/generate.d.ts +1 -0
  166. package/dist/src/cli/scripts/htmx.d.ts +1 -0
  167. package/dist/src/cli/scripts/inspect.d.ts +1 -0
  168. package/dist/src/cli/scripts/islands.d.ts +1 -0
  169. package/dist/src/cli/scripts/lintProof.d.ts +42 -0
  170. package/dist/src/cli/scripts/logs.d.ts +1 -0
  171. package/dist/src/cli/scripts/ls.d.ts +1 -0
  172. package/dist/src/cli/scripts/mem.d.ts +1 -0
  173. package/dist/src/cli/scripts/mobile.d.ts +1 -0
  174. package/dist/src/cli/scripts/prettier.d.ts +2 -0
  175. package/dist/src/cli/scripts/ps.d.ts +1 -0
  176. package/dist/src/cli/scripts/remove.d.ts +1 -0
  177. package/dist/src/cli/scripts/routes.d.ts +1 -0
  178. package/dist/src/cli/scripts/start.d.ts +6 -1
  179. package/dist/src/cli/scripts/tunnelRelay.d.ts +9 -0
  180. package/dist/src/cli/scripts/workspace.d.ts +3 -1
  181. package/dist/src/cli/serverBundleExternals.d.ts +2 -0
  182. package/dist/src/cli/tuiPrimitives.d.ts +14 -0
  183. package/dist/src/cli/typeGraphCoherence.d.ts +32 -0
  184. package/dist/src/cli/utils.d.ts +3 -1
  185. package/dist/src/cli/workspaceTui.d.ts +2 -1
  186. package/dist/src/client/hydrators/react.d.ts +1 -1
  187. package/dist/src/client/hydrators/svelte.d.ts +1 -1
  188. package/dist/src/client/hydrators/vue.d.ts +1 -1
  189. package/dist/src/client/islandStore.d.ts +3 -3
  190. package/dist/src/client/preserveIslandMarkup.d.ts +4 -1
  191. package/dist/src/constants.d.ts +21 -0
  192. package/dist/src/core/angularServerModule.d.ts +1 -0
  193. package/dist/src/core/build.d.ts +11 -3
  194. package/dist/src/core/devRouteRegistrationCallsite.d.ts +1 -5
  195. package/dist/src/core/index.d.ts +1 -0
  196. package/dist/src/core/pageResponseCache.d.ts +23 -0
  197. package/dist/src/core/prepare.d.ts +192 -154
  198. package/dist/src/core/requestContext.d.ts +18 -0
  199. package/dist/src/dev/angular/fastHmrCompiler.d.ts +5 -3
  200. package/dist/src/dev/angular/hmrCompiler.d.ts +1 -1
  201. package/dist/src/dev/angular/resolveOwningComponents.d.ts +1 -1
  202. package/dist/src/dev/clientManager.d.ts +10 -1
  203. package/dist/src/dev/configResolver.d.ts +2 -0
  204. package/dist/src/dev/moduleMapper.d.ts +1 -1
  205. package/dist/src/dev/moduleServer.d.ts +2 -1
  206. package/dist/src/dev/pathUtils.d.ts +1 -1
  207. package/dist/src/dev/reactComponentClassifier.d.ts +1 -1
  208. package/dist/src/dev/rebuildTrigger.d.ts +4 -0
  209. package/dist/src/dev/requestInspector.d.ts +31 -0
  210. package/dist/src/dev/serverBootstrap.d.ts +1 -0
  211. package/dist/src/dev/serverEntryWatcher.d.ts +3 -3
  212. package/dist/src/dev/tunnel/client.d.ts +20 -0
  213. package/dist/src/dev/tunnel/protocol.d.ts +85 -0
  214. package/dist/src/dev/tunnel/relay.d.ts +28 -0
  215. package/dist/src/dev/webSocket.d.ts +1 -1
  216. package/dist/src/mobile/androidConformance.d.ts +42 -0
  217. package/dist/src/mobile/androidEmulatorController.d.ts +99 -0
  218. package/dist/src/mobile/androidNativeWatcher.d.ts +19 -0
  219. package/dist/src/mobile/androidRelease.d.ts +47 -0
  220. package/dist/src/mobile/androidWebView.d.ts +46 -0
  221. package/dist/src/mobile/artifactStore.d.ts +47 -0
  222. package/dist/src/mobile/associationFiles.d.ts +49 -0
  223. package/dist/src/mobile/browser.d.ts +2 -0
  224. package/dist/src/mobile/buildMetadata.d.ts +10 -0
  225. package/dist/src/mobile/buildPipeline.d.ts +8 -0
  226. package/dist/src/mobile/buildRelease.d.ts +24 -0
  227. package/dist/src/mobile/capacitorBundle.d.ts +28 -0
  228. package/dist/src/mobile/capacitorProject.d.ts +9 -0
  229. package/dist/src/mobile/client.d.ts +35 -0
  230. package/dist/src/mobile/compatibilityDispatcher.d.ts +26 -0
  231. package/dist/src/mobile/config.d.ts +16 -0
  232. package/dist/src/mobile/emulatorDoctor.d.ts +25 -0
  233. package/dist/src/mobile/emulatorInstaller.d.ts +41 -0
  234. package/dist/src/mobile/index.d.ts +19 -0
  235. package/dist/src/mobile/materializedBundle.d.ts +36 -0
  236. package/dist/src/mobile/nativeDeepLinks.d.ts +5 -0
  237. package/dist/src/mobile/pageProtocol.d.ts +89 -0
  238. package/dist/src/mobile/producerContext.d.ts +4 -0
  239. package/dist/src/mobile/producerContextState.d.ts +10 -0
  240. package/dist/src/mobile/releaseArtifact.d.ts +75 -0
  241. package/dist/src/mobile/releaseDoctor.d.ts +13 -0
  242. package/dist/src/mobile/routeMatcher.d.ts +3 -0
  243. package/dist/src/mobile/routeMetadataTransform.d.ts +13 -0
  244. package/dist/src/mobile/shellBootstrap.d.ts +1 -0
  245. package/dist/src/mobile/transport.d.ts +31 -0
  246. package/dist/src/plugins/devtoolsJson.d.ts +6 -47
  247. package/dist/src/plugins/hmr.d.ts +22 -96
  248. package/dist/src/plugins/imageOptimizer.d.ts +150 -62
  249. package/dist/src/plugins/networking.d.ts +2 -2
  250. package/dist/src/plugins/openApiPlugin.d.ts +4 -0
  251. package/dist/src/plugins/telemetryPlugin.d.ts +36 -0
  252. package/dist/src/react/browser.d.ts +0 -2
  253. package/dist/src/react/hooks/useMediaQuery.d.ts +1 -1
  254. package/dist/src/react/index.d.ts +0 -2
  255. package/dist/src/react/jsxDevRuntimeCompat.d.ts +1 -1
  256. package/dist/src/react/jsxRuntimeCompat.d.ts +7 -0
  257. package/dist/src/react/pageHandler.d.ts +8 -0
  258. package/dist/src/react/router/UniversalRouter.d.ts +43 -0
  259. package/dist/src/react/router/browser.d.ts +2 -0
  260. package/dist/src/react/router/index.d.ts +2 -0
  261. package/dist/src/svelte/pageHandler.d.ts +5 -0
  262. package/dist/src/svelte/router/hashMode.d.ts +1 -6
  263. package/dist/src/svelte/router/matchPath.d.ts +4 -24
  264. package/dist/src/svelte/router/page.svelte.d.ts +1 -10
  265. package/dist/src/svelte/router/prefetchCache.d.ts +2 -6
  266. package/dist/src/utils/cleanup.d.ts +1 -0
  267. package/dist/src/utils/defineConvention.d.ts +2 -2
  268. package/dist/src/utils/defineEnv.d.ts +4 -4
  269. package/dist/src/utils/formatBytes.d.ts +2 -0
  270. package/dist/src/utils/generatedDir.d.ts +1 -1
  271. package/dist/src/utils/iconVersion.d.ts +5 -0
  272. package/dist/src/utils/imageProcessing.d.ts +1 -1
  273. package/dist/src/utils/index.d.ts +2 -0
  274. package/dist/src/utils/inlinePageCss.d.ts +9 -0
  275. package/dist/src/utils/instanceRegistry.d.ts +13 -0
  276. package/dist/src/utils/isTestSourcePath.d.ts +1 -0
  277. package/dist/src/utils/jsonLd.d.ts +1 -1
  278. package/dist/src/utils/loadConfig.d.ts +11 -3
  279. package/dist/src/utils/logger.d.ts +2 -0
  280. package/dist/src/utils/portScan.d.ts +22 -0
  281. package/dist/src/utils/projectRoot.d.ts +17 -0
  282. package/dist/src/utils/resolveConvention.d.ts +1 -1
  283. package/dist/src/utils/resolveDevPort.d.ts +4 -1
  284. package/dist/src/utils/runtimeMode.d.ts +1 -1
  285. package/dist/src/utils/spaRouteCss.d.ts +10 -0
  286. package/dist/src/utils/spaRouteManifest.d.ts +8 -0
  287. package/dist/src/utils/stripStringsAndComments.d.ts +18 -0
  288. package/dist/src/utils/userAgentFunctions.d.ts +1 -1
  289. package/dist/src/utils/vueCompiler.d.ts +1 -0
  290. package/dist/src/vue/components/Image.d.ts +2 -2
  291. package/dist/src/vue/defineVuePage.d.ts +1 -11
  292. package/dist/src/vue/index.d.ts +3 -0
  293. package/dist/src/vue/pageHandler.d.ts +5 -0
  294. package/dist/src/vue/resolveGeneratedVueModulePath.d.ts +1 -0
  295. package/dist/src/vue/teleports.d.ts +2 -0
  296. package/dist/src/vue/useResource.d.ts +65 -0
  297. package/dist/svelte/browser.js +1 -19
  298. package/dist/svelte/browser.js.map +3 -3
  299. package/dist/svelte/components/Head.svelte +7 -1
  300. package/dist/svelte/index.js +1281 -543
  301. package/dist/svelte/index.js.map +27 -19
  302. package/dist/svelte/router/Link.svelte.d.ts +3 -3
  303. package/dist/svelte/router/Route.svelte.d.ts +5 -5
  304. package/dist/svelte/router/Router.svelte.d.ts +3 -3
  305. package/dist/svelte/router/hashMode.ts +6 -12
  306. package/dist/svelte/router/matchPath.ts +44 -61
  307. package/dist/svelte/router/page.d.ts +1 -10
  308. package/dist/svelte/router/page.js +6 -6
  309. package/dist/svelte/router/prefetchCache.ts +21 -23
  310. package/dist/svelte/router/viewTransitions.ts +22 -12
  311. package/dist/svelte/server.js +697 -565
  312. package/dist/svelte/server.js.map +14 -11
  313. package/dist/types/absoluteConfig.d.ts +22 -0
  314. package/dist/types/angular.d.ts +4 -1
  315. package/dist/types/authPanel.d.ts +62 -0
  316. package/dist/types/build.d.ts +116 -0
  317. package/dist/types/cli.d.ts +57 -0
  318. package/dist/types/config.d.ts +52 -0
  319. package/dist/types/eslintConfig.d.ts +68 -0
  320. package/dist/types/globals.d.ts +31 -10
  321. package/dist/types/image.d.ts +2 -0
  322. package/dist/types/index.d.ts +1 -0
  323. package/dist/types/integrationsPanel.d.ts +29 -0
  324. package/dist/types/messages.d.ts +12 -0
  325. package/dist/types/packageJson.d.ts +74 -0
  326. package/dist/types/packageJsonPanel.d.ts +29 -0
  327. package/dist/types/prettier.d.ts +26 -0
  328. package/dist/types/tsconfig.d.ts +31 -0
  329. package/dist/types/vue.d.ts +13 -15
  330. package/dist/vue/browser.js +14 -36
  331. package/dist/vue/browser.js.map +5 -5
  332. package/dist/vue/components/Image.js +3 -20
  333. package/dist/vue/components/Image.js.map +3 -3
  334. package/dist/vue/components/index.js +3 -20
  335. package/dist/vue/components/index.js.map +3 -3
  336. package/dist/vue/index.js +1573 -620
  337. package/dist/vue/index.js.map +34 -22
  338. package/dist/vue/server.js +800 -520
  339. package/dist/vue/server.js.map +17 -11
  340. package/package.json +145 -68
  341. package/dist/src/react/UniversalRouter.d.ts +0 -12
@@ -17,6 +17,7 @@ import { detectCurrentFramework } from '../frameworkDetect';
17
17
  import type { ScriptInfo } from '../../../types/client';
18
18
  import { restoreDOMChanges, snapshotDOMChanges } from '../domTracker';
19
19
  import { hmrState } from '../hmrState';
20
+ import { sendAbsoluteHmrTiming } from '../hmrTiming';
20
21
 
21
22
  const parseHTMLMessage = (
22
23
  html: string | { body?: string; head?: string } | null | undefined
@@ -57,11 +58,10 @@ const handleHTMLBodyWithHead = (
57
58
 
58
59
  const cssResult = processCSSLinks(htmlHead);
59
60
 
60
- const updateBodyAfterCSS = () => {
61
+ const updateBodyAfterCSS = () =>
61
62
  updateHTMLBody(htmlBody, htmlDomState, document.body);
62
- };
63
63
 
64
- waitForCSSAndUpdate(cssResult, updateBodyAfterCSS);
64
+ return waitForCSSAndUpdate(cssResult, updateBodyAfterCSS);
65
65
  };
66
66
 
67
67
  const handleHTMLBodyWithoutHead = (
@@ -72,17 +72,21 @@ const handleHTMLBodyWithoutHead = (
72
72
  if (!container) {
73
73
  sessionStorage.removeItem('__HMR_ACTIVE__');
74
74
 
75
- return;
75
+ return Promise.resolve();
76
76
  }
77
77
 
78
- updateHTMLBodyDirect(htmlBody, htmlDomState, container);
78
+ const updated = updateHTMLBodyDirect(htmlBody, htmlDomState, container);
79
79
  restoreDOMState(container, htmlDomState);
80
+
81
+ return updated;
80
82
  };
81
83
 
82
84
  export const handleHTMLUpdate = (message: {
83
85
  data: {
84
86
  html?: string | { body?: string; head?: string } | null;
87
+ serverDuration?: number;
85
88
  };
89
+ timestamp?: number;
86
90
  }) => {
87
91
  const htmlFrameworkCheck = detectCurrentFramework();
88
92
  if (htmlFrameworkCheck !== 'html') {
@@ -94,6 +98,7 @@ export const handleHTMLUpdate = (message: {
94
98
  }
95
99
 
96
100
  sessionStorage.setItem('__HMR_ACTIVE__', 'true');
101
+ const clientStart = performance.now();
97
102
 
98
103
  const htmlDomState = saveDOMState(document.body);
99
104
  const { body: htmlBody, head: htmlHead } = parseHTMLMessage(
@@ -102,18 +107,48 @@ export const handleHTMLUpdate = (message: {
102
107
 
103
108
  if (!htmlBody) {
104
109
  sessionStorage.removeItem('__HMR_ACTIVE__');
110
+ sendAbsoluteHmrTiming({
111
+ clientStart,
112
+ kind: 'html',
113
+ outcome: 'failed',
114
+ serverMs: message.data.serverDuration,
115
+ updateId: message.timestamp
116
+ });
105
117
 
106
118
  return;
107
119
  }
108
120
 
109
- if (htmlHead) {
110
- handleHTMLBodyWithHead(htmlBody, htmlHead, htmlDomState);
111
- } else {
112
- handleHTMLBodyWithoutHead(htmlBody, htmlDomState);
113
- }
121
+ const update = htmlHead
122
+ ? handleHTMLBodyWithHead(htmlBody, htmlHead, htmlDomState)
123
+ : handleHTMLBodyWithoutHead(htmlBody, htmlDomState);
124
+ void update.then(
125
+ () => {
126
+ sendAbsoluteHmrTiming({
127
+ clientStart,
128
+ kind: 'html',
129
+ serverMs: message.data.serverDuration,
130
+ updateId: message.timestamp
131
+ });
132
+ },
133
+ () => {
134
+ sendAbsoluteHmrTiming({
135
+ clientStart,
136
+ kind: 'html',
137
+ outcome: 'reloaded',
138
+ serverMs: message.data.serverDuration,
139
+ updateId: message.timestamp
140
+ });
141
+ window.location.reload();
142
+ }
143
+ );
114
144
  };
115
145
  export const handleScriptUpdate = (message: {
116
- data: { framework?: string; scriptPath?: string };
146
+ data: {
147
+ framework?: string;
148
+ scriptPath?: string;
149
+ serverDuration?: number;
150
+ };
151
+ timestamp?: number;
117
152
  }) => {
118
153
  const scriptFramework = message.data.framework;
119
154
  const currentFw = detectCurrentFramework();
@@ -139,13 +174,30 @@ export const handleScriptUpdate = (message: {
139
174
  });
140
175
 
141
176
  const cacheBustedPath = `${scriptPath}?t=${Date.now()}`;
177
+ const clientStart = performance.now();
142
178
  import(cacheBustedPath)
143
- .then(() => true)
179
+ .then(() => {
180
+ sendAbsoluteHmrTiming({
181
+ clientStart,
182
+ kind: 'script',
183
+ serverMs: message.data.serverDuration,
184
+ updateId: message.timestamp
185
+ });
186
+
187
+ return true;
188
+ })
144
189
  .catch((err: unknown) => {
145
190
  console.error(
146
191
  '[HMR] Script hot-reload failed, falling back to page reload:',
147
192
  err
148
193
  );
194
+ sendAbsoluteHmrTiming({
195
+ clientStart,
196
+ kind: 'script',
197
+ outcome: 'reloaded',
198
+ serverMs: message.data.serverDuration,
199
+ updateId: message.timestamp
200
+ });
149
201
  window.location.reload();
150
202
  });
151
203
  };
@@ -172,21 +224,30 @@ const updateHTMLBody = (
172
224
  container: HTMLElement
173
225
  ) => {
174
226
  if (!container) {
175
- return;
227
+ return Promise.resolve();
176
228
  }
229
+ const { promise, resolve } = Promise.withResolvers<void>();
177
230
 
178
231
  const savedState = saveHTMLState();
179
232
  const domSnapshot = snapshotDOMChanges(container);
180
233
 
181
234
  const existingScripts = collectScripts(container);
235
+ const oldInlineScripts = collectInlineScripts(container);
182
236
  const hmrScript = container.querySelector('script[data-hmr-client]');
183
237
  const tempDiv = document.createElement('div');
184
238
  tempDiv.innerHTML = htmlBody;
185
239
  const newScripts = collectScriptsFromElement(tempDiv);
240
+ const newInlineScripts = collectInlineScripts(tempDiv);
186
241
 
187
242
  const htmlStructureChanged = didHTMLStructureChange(container, tempDiv);
243
+ const inlineScriptsChanged = didInlineScriptsChange(
244
+ oldInlineScripts,
245
+ newInlineScripts
246
+ );
247
+ const scriptsChanged =
248
+ didScriptsChange(existingScripts, newScripts) || inlineScriptsChanged;
188
249
 
189
- if (htmlStructureChanged || didScriptsChange(existingScripts, newScripts)) {
250
+ if (htmlStructureChanged || scriptsChanged) {
190
251
  patchDOMInPlace(container, htmlBody);
191
252
  restoreDOMChanges(container, domSnapshot, htmlBody);
192
253
  }
@@ -198,29 +259,27 @@ const updateHTMLBody = (
198
259
  restoreFormState(savedState.forms);
199
260
  restoreScrollState(savedState.scroll);
200
261
 
201
- if (
202
- didScriptsChange(existingScripts, newScripts) ||
203
- htmlStructureChanged
204
- ) {
205
- cloneInteractiveElements(container);
206
- reExecuteScripts(container, newScripts);
262
+ // Only touch scripts/interactive elements when a script actually
263
+ // changed. A pure markup edit (e.g. a heading) leaves inline-script
264
+ // state and `addEventListener` handlers intact.
265
+ if (scriptsChanged) {
266
+ // Clone (which strips listeners via cloneNode) ONLY when an inline
267
+ // script changed: a changed inline script re-runs in place below
268
+ // and would otherwise double-bind on elements that still carry the
269
+ // old handler. Unchanged inline scripts are skipped on re-exec, and
270
+ // external modules are re-imported via `import()` whose module cache
271
+ // means an unchanged body never re-runs — cloning for those would
272
+ // orphan their listeners forever (the regression this fixes).
273
+ if (inlineScriptsChanged) {
274
+ cloneInteractiveElements(container);
275
+ }
276
+ reExecuteScripts(container, newScripts, oldInlineScripts);
207
277
  }
278
+ sessionStorage.removeItem('__HMR_ACTIVE__');
279
+ resolve();
208
280
  });
209
- sessionStorage.removeItem('__HMR_ACTIVE__');
210
- };
211
281
 
212
- const cloneHmrListenerElements = (container: HTMLElement) => {
213
- container
214
- .querySelectorAll('[data-hmr-listeners-attached]')
215
- .forEach((elem) => {
216
- const cloned = elem.cloneNode(true);
217
- if (elem.parentNode) {
218
- elem.parentNode.replaceChild(cloned, elem);
219
- }
220
- if (cloned instanceof Element) {
221
- cloned.removeAttribute('data-hmr-listeners-attached');
222
- }
223
- });
282
+ return promise;
224
283
  };
225
284
 
226
285
  const replaceInlineScript = (script: Element) => {
@@ -242,9 +301,11 @@ const updateHTMLBodyDirect = (
242
301
  htmlDomState: ReturnType<typeof saveDOMState>,
243
302
  container: HTMLElement
244
303
  ) => {
304
+ const { promise, resolve } = Promise.withResolvers<void>();
245
305
  const savedState = saveHTMLState();
246
306
  const domSnapshot = snapshotDOMChanges(container);
247
307
 
308
+ const oldInlineScripts = collectInlineScripts(container);
248
309
  const tempDiv = document.createElement('div');
249
310
  tempDiv.innerHTML = htmlBody;
250
311
  const newScripts = collectScriptsFromElement(tempDiv);
@@ -260,7 +321,13 @@ const updateHTMLBodyDirect = (
260
321
  restoreFormState(savedState.forms);
261
322
  restoreScrollState(savedState.scroll);
262
323
 
263
- cloneHmrListenerElements(container);
324
+ // Unlike `updateHTMLBody` (which re-imports externals as ES modules and
325
+ // must not clone unchanged ones), this path rebuilds EVERY external
326
+ // script below as a fresh `<script src?t=>` tag that always
327
+ // re-executes. So a single clone here is correct and necessary: it
328
+ // gives each re-running script a pristine element to bind once, with no
329
+ // double-binding.
330
+ cloneInteractiveElements(container);
264
331
 
265
332
  removeOldScripts(container);
266
333
  newScripts.forEach((scriptInfo) => {
@@ -271,10 +338,12 @@ const updateHTMLBodyDirect = (
271
338
  container.appendChild(newScript);
272
339
  });
273
340
 
274
- const inlineScripts = container.querySelectorAll('script:not([src])');
275
- inlineScripts.forEach(replaceInlineScript);
341
+ reExecuteInlineScripts(container, oldInlineScripts);
342
+ sessionStorage.removeItem('__HMR_ACTIVE__');
343
+ resolve();
276
344
  });
277
- sessionStorage.removeItem('__HMR_ACTIVE__');
345
+
346
+ return promise;
278
347
  };
279
348
 
280
349
  /* Shared helpers for HTML body updates */
@@ -291,6 +360,18 @@ const collectScriptsFromElement = (elem: HTMLElement) =>
291
360
  type: script.getAttribute('type') || 'text/javascript'
292
361
  }));
293
362
 
363
+ /* Inline (non-src) scripts, excluding the HMR client. Captured by ordinal so
364
+ * an unchanged inline script can be skipped on re-execution — re-running it
365
+ * would reset its module/global state (e.g. `let count = 0`) on every edit. */
366
+ const collectInlineScripts = (elem: HTMLElement) =>
367
+ Array.from(
368
+ elem.querySelectorAll('script:not([src]):not([data-hmr-client])')
369
+ ).map((script) => script.textContent || '');
370
+
371
+ const didInlineScriptsChange = (oldInline: string[], newInline: string[]) =>
372
+ oldInline.length !== newInline.length ||
373
+ oldInline.some((content, idx) => content !== newInline[idx]);
374
+
294
375
  const didScriptsChange = (oldScripts: ScriptInfo[], newScripts: ScriptInfo[]) =>
295
376
  oldScripts.length !== newScripts.length ||
296
377
  oldScripts.some((oldScript, idx) => {
@@ -348,7 +429,11 @@ const removeOldScripts = (container: HTMLElement) => {
348
429
  });
349
430
  };
350
431
 
351
- const reExecuteScripts = (container: HTMLElement, newScripts: ScriptInfo[]) => {
432
+ const reExecuteScripts = (
433
+ container: HTMLElement,
434
+ newScripts: ScriptInfo[],
435
+ oldInlineScripts: string[]
436
+ ) => {
352
437
  removeOldScripts(container);
353
438
 
354
439
  newScripts.forEach((scriptInfo) => {
@@ -359,6 +444,24 @@ const reExecuteScripts = (container: HTMLElement, newScripts: ScriptInfo[]) => {
359
444
  container.appendChild(newScript);
360
445
  });
361
446
 
362
- const inlineScripts = container.querySelectorAll('script:not([src])');
363
- inlineScripts.forEach(replaceInlineScript);
447
+ reExecuteInlineScripts(container, oldInlineScripts);
448
+ };
449
+
450
+ /* Re-execute inline scripts by replacing them with fresh nodes, but skip any
451
+ * whose textContent is byte-identical to its previous counterpart (matched by
452
+ * ordinal). Skipping leaves the original execution's global bindings intact,
453
+ * so unrelated edits don't reset inline-script state. */
454
+ const reExecuteInlineScripts = (
455
+ container: HTMLElement,
456
+ oldInlineScripts: string[]
457
+ ) => {
458
+ const inlineScripts = container.querySelectorAll(
459
+ 'script:not([src]):not([data-hmr-client])'
460
+ );
461
+ inlineScripts.forEach((script, idx) => {
462
+ if (oldInlineScripts[idx] === (script.textContent || '')) {
463
+ return;
464
+ }
465
+ replaceInlineScript(script);
466
+ });
364
467
  };
@@ -16,6 +16,7 @@ import { patchHeadInPlace } from '../headPatch';
16
16
  import { detectCurrentFramework } from '../frameworkDetect';
17
17
  import { type HTMXSavedState, type ScriptInfo } from '../../../types/client';
18
18
  import { hmrState } from '../hmrState';
19
+ import { sendAbsoluteHmrTiming } from '../hmrTiming';
19
20
 
20
21
  const parseHTMXMessage = (
21
22
  html: string | { body?: string; head?: string } | null | undefined
@@ -52,23 +53,26 @@ const handleHTMXBodyUpdate = (
52
53
  htmxHead: string | null,
53
54
  htmxDomState: ReturnType<typeof saveDOMState>
54
55
  ) => {
55
- const updateHTMXBodyAfterCSS = () => {
56
+ const updateHTMXBodyAfterCSS = () =>
56
57
  updateHTMXBody(htmxBody, htmxDomState, document.body);
57
- };
58
58
 
59
59
  if (htmxHead) {
60
60
  applyHeadPatch(htmxHead);
61
+
61
62
  const cssResult = processCSSLinks(htmxHead);
62
- waitForCSSAndUpdate(cssResult, updateHTMXBodyAfterCSS);
63
- } else {
64
- updateHTMXBodyAfterCSS();
63
+
64
+ return waitForCSSAndUpdate(cssResult, updateHTMXBodyAfterCSS);
65
65
  }
66
+
67
+ return updateHTMXBodyAfterCSS();
66
68
  };
67
69
 
68
70
  export const handleHTMXUpdate = (message: {
69
71
  data: {
70
72
  html?: string | { body?: string; head?: string } | null;
73
+ serverDuration?: number;
71
74
  };
75
+ timestamp?: number;
72
76
  }) => {
73
77
  const htmxFrameworkCheck = detectCurrentFramework();
74
78
  if (htmxFrameworkCheck !== 'htmx') return;
@@ -78,6 +82,7 @@ export const handleHTMXUpdate = (message: {
78
82
  }
79
83
 
80
84
  sessionStorage.setItem('__HMR_ACTIVE__', 'true');
85
+ const clientStart = performance.now();
81
86
 
82
87
  const htmxDomState = saveDOMState(document.body);
83
88
  const { body: htmxBody, head: htmxHead } = parseHTMXMessage(
@@ -86,11 +91,37 @@ export const handleHTMXUpdate = (message: {
86
91
 
87
92
  if (!htmxBody) {
88
93
  sessionStorage.removeItem('__HMR_ACTIVE__');
94
+ sendAbsoluteHmrTiming({
95
+ clientStart,
96
+ kind: 'htmx',
97
+ outcome: 'failed',
98
+ serverMs: message.data.serverDuration,
99
+ updateId: message.timestamp
100
+ });
89
101
 
90
102
  return;
91
103
  }
92
104
 
93
- handleHTMXBodyUpdate(htmxBody, htmxHead, htmxDomState);
105
+ void handleHTMXBodyUpdate(htmxBody, htmxHead, htmxDomState).then(
106
+ () => {
107
+ sendAbsoluteHmrTiming({
108
+ clientStart,
109
+ kind: 'htmx',
110
+ serverMs: message.data.serverDuration,
111
+ updateId: message.timestamp
112
+ });
113
+ },
114
+ () => {
115
+ sendAbsoluteHmrTiming({
116
+ clientStart,
117
+ kind: 'htmx',
118
+ outcome: 'reloaded',
119
+ serverMs: message.data.serverDuration,
120
+ updateId: message.timestamp
121
+ });
122
+ window.location.reload();
123
+ }
124
+ );
94
125
  };
95
126
 
96
127
  const cloneHmrListenerElements = (container: HTMLElement) => {
@@ -169,7 +200,8 @@ const updateHTMXBody = (
169
200
  htmxDomState: ReturnType<typeof saveDOMState>,
170
201
  container: HTMLElement
171
202
  ) => {
172
- if (!container) return;
203
+ if (!container) return Promise.resolve();
204
+ const { promise, resolve } = Promise.withResolvers<void>();
173
205
 
174
206
  const countSpan = container.querySelector('#count');
175
207
  const countValue = countSpan
@@ -218,8 +250,11 @@ const updateHTMXBody = (
218
250
  if (window.htmx) {
219
251
  window.htmx.process(container);
220
252
  }
253
+ sessionStorage.removeItem('__HMR_ACTIVE__');
254
+ resolve();
221
255
  });
222
- sessionStorage.removeItem('__HMR_ACTIVE__');
256
+
257
+ return promise;
223
258
  };
224
259
 
225
260
  /* Shared helpers */
@@ -6,9 +6,18 @@ import type {} from '../../../types/globals';
6
6
 
7
7
  import { hideErrorOverlay } from '../errorOverlay';
8
8
  import { detectCurrentFramework } from '../frameworkDetect';
9
+ import { sendAbsoluteHmrTiming } from '../hmrTiming';
10
+ import { swapCSSStylesheet } from '../cssUtils';
11
+
12
+ const reloadReactPage = () => {
13
+ const url = new URL(window.location.href);
14
+ url.searchParams.set('__absolute_hmr', Date.now().toString());
15
+ window.location.replace(url.href);
16
+ };
9
17
 
10
18
  export const handleReactUpdate = (message: {
11
19
  data: {
20
+ fastRefreshSupported?: boolean;
12
21
  hasCSSChanges?: boolean;
13
22
  hasComponentChanges?: boolean;
14
23
  manifest?: Record<string, string>;
@@ -16,6 +25,7 @@ export const handleReactUpdate = (message: {
16
25
  primarySource?: string;
17
26
  serverDuration?: number;
18
27
  };
28
+ timestamp?: number;
19
29
  }) => {
20
30
  const currentFramework = detectCurrentFramework();
21
31
  if (currentFramework !== 'react') return;
@@ -24,52 +34,99 @@ export const handleReactUpdate = (message: {
24
34
  const hasCSSChanges = message.data.hasCSSChanges === true;
25
35
  const cssPath =
26
36
  message.data.manifest && message.data.manifest.ReactExampleCSS;
27
-
28
37
  if (!hasComponentChanges && hasCSSChanges && cssPath) {
29
- reloadReactCSS(cssPath);
38
+ const clientStart = performance.now();
39
+ void reloadReactCSS(cssPath).then((applied) => {
40
+ sendAbsoluteHmrTiming({
41
+ clientStart,
42
+ kind: 'css',
43
+ outcome: applied ? 'applied' : 'failed',
44
+ serverMs: message.data.serverDuration,
45
+ updateId: message.timestamp
46
+ });
47
+ });
30
48
 
31
49
  return;
32
50
  }
51
+ if (message.data.fastRefreshSupported === false) {
52
+ const { pageModuleUrl } = message.data;
53
+ const remount = window.__ABS_REACT_REMOUNT__;
54
+ if (pageModuleUrl && remount) {
55
+ applyRemountImport(
56
+ pageModuleUrl,
57
+ remount,
58
+ message.data.serverDuration,
59
+ message.timestamp
60
+ );
61
+ } else {
62
+ const clientStart = performance.now();
63
+ sendAbsoluteHmrTiming({
64
+ clientStart,
65
+ kind: 'component',
66
+ outcome: 'reloaded',
67
+ serverMs: message.data.serverDuration,
68
+ updateId: message.timestamp
69
+ });
70
+ reloadReactPage();
71
+ }
33
72
 
73
+ return;
74
+ }
34
75
  const refreshRuntime = window.$RefreshRuntime$;
35
76
  const { serverDuration } = message.data;
36
77
  const { pageModuleUrl } = message.data;
37
78
 
38
79
  if (pageModuleUrl && refreshRuntime) {
39
- applyRefreshImport(pageModuleUrl, refreshRuntime, serverDuration);
80
+ applyRefreshImport(
81
+ pageModuleUrl,
82
+ refreshRuntime,
83
+ serverDuration,
84
+ message.timestamp
85
+ );
40
86
 
41
87
  return;
42
88
  }
43
89
 
44
90
  // No module URL — shouldn't happen, but reload as safety fallback
91
+ const clientStart = performance.now();
92
+ sendAbsoluteHmrTiming({
93
+ clientStart,
94
+ kind: 'component',
95
+ outcome: 'reloaded',
96
+ serverMs: message.data.serverDuration,
97
+ updateId: message.timestamp
98
+ });
45
99
  window.location.reload();
46
100
  };
47
101
 
48
- const sendTiming = (clientStart: number, serverDuration?: number) => {
49
- if (window.__HMR_WS__) {
50
- const clientMs = Math.round(performance.now() - clientStart);
51
- const total = (serverDuration ?? 0) + clientMs;
52
- window.__HMR_WS__.send(
53
- JSON.stringify({ duration: total, type: 'hmr-timing' })
54
- );
55
- }
102
+ const finishUpdate = (
103
+ clientStart: number,
104
+ serverDuration?: number,
105
+ updateId?: number
106
+ ) => {
107
+ sendAbsoluteHmrTiming({
108
+ clientStart,
109
+ kind: 'component',
110
+ serverMs: serverDuration,
111
+ updateId
112
+ });
56
113
  if (window.__ERROR_BOUNDARY__) {
57
114
  window.__ERROR_BOUNDARY__.reset();
58
- } else {
59
- hideErrorOverlay();
60
115
  }
116
+ hideErrorOverlay();
61
117
  };
62
118
 
63
119
  const applyRefreshImport = (
64
120
  moduleUrl: string,
65
121
  refreshRuntime: { performReactRefresh: () => unknown },
66
- serverDuration?: number
122
+ serverDuration?: number,
123
+ updateId?: number
67
124
  ) => {
68
125
  const clientStart = performance.now();
69
126
  import(`${moduleUrl}?t=${Date.now()}`)
70
127
  .then(() => {
71
128
  refreshRuntime.performReactRefresh();
72
- sendTiming(clientStart, serverDuration);
129
+ finishUpdate(clientStart, serverDuration, updateId);
73
130
 
74
131
  return undefined;
75
132
  })
@@ -78,31 +135,56 @@ const applyRefreshImport = (
78
135
  '[HMR] React Fast Refresh failed, falling back to reload:',
79
136
  err
80
137
  );
138
+ sendAbsoluteHmrTiming({
139
+ clientStart,
140
+ kind: 'component',
141
+ outcome: 'reloaded',
142
+ serverMs: serverDuration,
143
+ updateId
144
+ });
81
145
  window.location.reload();
82
146
  });
83
147
  };
84
148
 
85
- const reloadReactCSS = (cssPath: string) => {
86
- const existingCSSLinks = document.head.querySelectorAll<HTMLLinkElement>(
87
- 'link[rel="stylesheet"]'
88
- );
89
- existingCSSLinks.forEach((link) => {
90
- const href = link.getAttribute('href');
91
- if (!href) {
92
- return;
93
- }
149
+ const applyRemountImport = (
150
+ moduleUrl: string,
151
+ remount: (module: Record<string, unknown>) => void,
152
+ serverDuration?: number,
153
+ updateId?: number
154
+ ) => {
155
+ const clientStart = performance.now();
156
+ import(`${moduleUrl}?t=${Date.now()}`)
157
+ .then((module) => {
158
+ remount(module);
159
+ finishUpdate(clientStart, serverDuration, updateId);
160
+
161
+ return undefined;
162
+ })
163
+ .catch((err) => {
164
+ console.warn(
165
+ '[HMR] React remount failed, falling back to reload:',
166
+ err
167
+ );
168
+ sendAbsoluteHmrTiming({
169
+ clientStart,
170
+ kind: 'component',
171
+ outcome: 'reloaded',
172
+ serverMs: serverDuration,
173
+ updateId
174
+ });
175
+ reloadReactPage();
176
+ });
177
+ };
178
+
179
+ const reloadReactCSS = (cssPath: string) =>
180
+ swapCSSStylesheet(cssPath, (href) => {
94
181
  const hrefBase = (href.split('?')[0] ?? '').split('/').pop() ?? '';
95
182
  const cssPathBase =
96
183
  (cssPath.split('?')[0] ?? '').split('/').pop() ?? '';
97
- if (
184
+
185
+ return (
98
186
  hrefBase === cssPathBase ||
99
187
  href.includes('react-example') ||
100
188
  cssPathBase.includes(hrefBase)
101
- ) {
102
- const newHref = `${
103
- cssPath + (cssPath.includes('?') ? '&' : '?')
104
- }t=${Date.now()}`;
105
- link.href = newHref;
106
- }
189
+ );
107
190
  });
108
- };
@@ -7,8 +7,20 @@ import {
7
7
  isRuntimeErrorOverlay,
8
8
  showErrorOverlay
9
9
  } from '../errorOverlay';
10
+ import { sendAbsoluteHmrTiming } from '../hmrTiming';
10
11
 
11
- export const handleFullReload = () => {
12
+ export const handleFullReload = (message?: {
13
+ data: { serverDuration?: number };
14
+ timestamp?: number;
15
+ }) => {
16
+ const clientStart = performance.now();
17
+ sendAbsoluteHmrTiming({
18
+ clientStart,
19
+ kind: 'full-reload',
20
+ outcome: 'reloaded',
21
+ serverMs: message?.data.serverDuration,
22
+ updateId: message?.timestamp
23
+ });
12
24
  setTimeout(() => {
13
25
  window.location.reload();
14
26
  }, REBUILD_RELOAD_DELAY_MS);
@@ -33,7 +45,18 @@ export const handleManifest = (message: {
33
45
  window.__HMR_MODULE_UPDATES__ = [];
34
46
  };
35
47
 
36
- const HMR_FRAMEWORKS = ['angular', 'react', 'vue', 'svelte', 'html', 'htmx'];
48
+ const HMR_FRAMEWORKS = [
49
+ 'angular',
50
+ 'assets',
51
+ 'ember',
52
+ 'html',
53
+ 'htmx',
54
+ 'react',
55
+ 'styles',
56
+ 'svelte',
57
+ 'tailwind',
58
+ 'vue'
59
+ ];
37
60
 
38
61
  const mergeRecord = (
39
62
  source: Record<string, string | number>,
@@ -115,12 +138,9 @@ export const handleRebuildComplete = (message: {
115
138
 
116
139
  if (
117
140
  message.data.affectedFrameworks &&
118
- !message.data.affectedFrameworks.includes('angular') &&
119
- !message.data.affectedFrameworks.includes('react') &&
120
- !message.data.affectedFrameworks.includes('html') &&
121
- !message.data.affectedFrameworks.includes('htmx') &&
122
- !message.data.affectedFrameworks.includes('vue') &&
123
- !message.data.affectedFrameworks.includes('svelte')
141
+ !message.data.affectedFrameworks.some((framework) =>
142
+ HMR_FRAMEWORKS.includes(framework)
143
+ )
124
144
  ) {
125
145
  const url = new URL(window.location.href);
126
146
  url.searchParams.set('_cb', Date.now().toString());