@absolutejs/absolute 0.14.0 → 0.15.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 (96) hide show
  1. package/.claude/settings.local.json +11 -0
  2. package/CLAUDE.md +11 -2
  3. package/LICENSE +74 -18
  4. package/README.md +4 -4
  5. package/THIRD_PARTY_NOTICES.md +61 -0
  6. package/dist/cli/index.js +24 -8
  7. package/dist/dev/client/cssUtils.ts +288 -0
  8. package/dist/dev/client/domDiff.ts +261 -0
  9. package/dist/dev/client/domState.ts +271 -0
  10. package/dist/dev/client/errorOverlay.ts +145 -0
  11. package/dist/dev/client/frameworkDetect.ts +63 -0
  12. package/dist/dev/client/handlers/html.ts +415 -0
  13. package/dist/dev/client/handlers/htmx.ts +248 -0
  14. package/dist/dev/client/handlers/react.ts +80 -0
  15. package/dist/dev/client/handlers/rebuild.ts +147 -0
  16. package/dist/dev/client/handlers/svelte.ts +129 -0
  17. package/dist/dev/client/handlers/vue.ts +254 -0
  18. package/dist/dev/client/headPatch.ts +213 -0
  19. package/dist/dev/client/hmrClient.ts +204 -0
  20. package/dist/dev/client/moduleVersions.ts +57 -0
  21. package/dist/dev/client/reactRefreshSetup.ts +21 -0
  22. package/dist/index.js +3028 -478
  23. package/dist/index.js.map +49 -19
  24. package/dist/{build → src/build}/compileSvelte.d.ts +2 -1
  25. package/dist/src/build/compileVue.d.ts +33 -0
  26. package/dist/src/build/generateReactIndexes.d.ts +1 -0
  27. package/dist/src/build/htmlScriptHMRPlugin.d.ts +13 -0
  28. package/dist/src/build/wrapHTMLScript.d.ts +24 -0
  29. package/dist/{core → src/core}/build.d.ts +2 -2
  30. package/dist/src/core/devBuild.d.ts +6 -0
  31. package/dist/{core → src/core}/index.d.ts +2 -1
  32. package/dist/src/core/lookup.d.ts +3 -0
  33. package/dist/{core → src/core}/pageHandlers.d.ts +4 -4
  34. package/dist/src/dev/assetStore.d.ts +12 -0
  35. package/dist/src/dev/buildHMRClient.d.ts +1 -0
  36. package/dist/src/dev/clientManager.d.ts +26 -0
  37. package/dist/src/dev/configResolver.d.ts +13 -0
  38. package/dist/src/dev/dependencyGraph.d.ts +13 -0
  39. package/dist/src/dev/fileHashTracker.d.ts +2 -0
  40. package/dist/src/dev/fileWatcher.d.ts +3 -0
  41. package/dist/src/dev/moduleMapper.d.ts +21 -0
  42. package/dist/src/dev/moduleVersionTracker.d.ts +7 -0
  43. package/dist/src/dev/pathUtils.d.ts +5 -0
  44. package/dist/src/dev/reactComponentClassifier.d.ts +2 -0
  45. package/dist/src/dev/rebuildTrigger.d.ts +10 -0
  46. package/dist/src/dev/simpleHTMLHMR.d.ts +4 -0
  47. package/dist/src/dev/simpleHTMXHMR.d.ts +4 -0
  48. package/dist/src/dev/simpleSvelteHMR.d.ts +1 -0
  49. package/dist/src/dev/simpleVueHMR.d.ts +1 -0
  50. package/dist/src/dev/webSocket.d.ts +9 -0
  51. package/dist/{index.d.ts → src/index.d.ts} +1 -0
  52. package/dist/src/plugins/hmr.d.ts +62 -0
  53. package/dist/{plugins → src/plugins}/index.d.ts +2 -1
  54. package/dist/{svelte → src/svelte}/renderToReadableStream.d.ts +3 -1
  55. package/dist/src/utils/getRegisterClientScript.d.ts +10 -0
  56. package/dist/{utils → src/utils}/index.d.ts +2 -0
  57. package/dist/src/utils/logger.d.ts +45 -0
  58. package/dist/src/utils/networking.d.ts +2 -0
  59. package/dist/src/utils/normalizePath.d.ts +9 -0
  60. package/dist/src/utils/registerClientScript.d.ts +51 -0
  61. package/dist/{types.d.ts → types/build.d.ts} +6 -0
  62. package/dist/types/client.d.ts +104 -0
  63. package/dist/types/index.d.ts +4 -0
  64. package/dist/types/messages.d.ts +138 -0
  65. package/dist/types/websocket.d.ts +6 -0
  66. package/eslint.config.mjs +5 -1
  67. package/package.json +19 -14
  68. package/tsconfig.build.json +1 -1
  69. package/types/build.ts +46 -0
  70. package/types/client.ts +109 -0
  71. package/types/index.ts +4 -0
  72. package/types/messages.ts +205 -0
  73. package/types/websocket.ts +12 -0
  74. package/types/window-globals.ts +53 -0
  75. package/dist/build/compileVue.d.ts +0 -5
  76. package/dist/build/generateReactIndexes.d.ts +0 -1
  77. package/dist/core/lookup.d.ts +0 -1
  78. package/dist/utils/networking.d.ts +0 -1
  79. /package/dist/{build → src/build}/generateManifest.d.ts +0 -0
  80. /package/dist/{build → src/build}/outputLogs.d.ts +0 -0
  81. /package/dist/{build → src/build}/scanEntryPoints.d.ts +0 -0
  82. /package/dist/{build → src/build}/updateAssetPaths.d.ts +0 -0
  83. /package/dist/{cli → src/cli}/index.d.ts +0 -0
  84. /package/dist/{constants.d.ts → src/constants.d.ts} +0 -0
  85. /package/dist/{plugins → src/plugins}/networking.d.ts +0 -0
  86. /package/dist/{plugins → src/plugins}/pageRouter.d.ts +0 -0
  87. /package/dist/{svelte → src/svelte}/renderToPipeableStream.d.ts +0 -0
  88. /package/dist/{svelte → src/svelte}/renderToString.d.ts +0 -0
  89. /package/dist/{utils → src/utils}/cleanup.d.ts +0 -0
  90. /package/dist/{utils → src/utils}/commonAncestor.d.ts +0 -0
  91. /package/dist/{utils → src/utils}/escapeScriptContent.d.ts +0 -0
  92. /package/dist/{utils → src/utils}/generateHeadElement.d.ts +0 -0
  93. /package/dist/{utils → src/utils}/getDurationString.d.ts +0 -0
  94. /package/dist/{utils → src/utils}/getEnv.d.ts +0 -0
  95. /package/dist/{utils → src/utils}/stringModifiers.d.ts +0 -0
  96. /package/dist/{utils → src/utils}/validateSafePath.d.ts +0 -0
package/dist/index.js CHANGED
@@ -1,143 +1,48 @@
1
1
  // @bun
2
+ var __defProp = Object.defineProperty;
3
+ var __export = (target, all) => {
4
+ for (var name in all)
5
+ __defProp(target, name, {
6
+ get: all[name],
7
+ enumerable: true,
8
+ configurable: true,
9
+ set: (newValue) => all[name] = () => newValue
10
+ });
11
+ };
12
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
13
+ var __require = import.meta.require;
14
+
2
15
  // src/constants.ts
3
- var UNFOUND_INDEX = -1;
4
- var SECONDS_IN_A_MINUTE = 60;
5
- var MILLISECONDS_IN_A_SECOND = 1000;
6
- var MILLISECONDS_IN_A_MINUTE = MILLISECONDS_IN_A_SECOND * SECONDS_IN_A_MINUTE;
7
- var MINUTES_IN_AN_HOUR = 60;
8
- var HOURS_IN_DAY = 24;
9
- var MILLISECONDS_IN_A_DAY = MILLISECONDS_IN_A_SECOND * SECONDS_IN_A_MINUTE * MINUTES_IN_AN_HOUR * HOURS_IN_DAY;
10
- var TIME_PRECISION = 2;
11
- var TWO_THIRDS = 2 / 3;
12
- var DEFAULT_PORT = 3000;
13
- var DEFAULT_CHUNK_SIZE = 16384;
14
- var BUN_BUILD_WARNING_SUPPRESSION = "wildcard sideEffects are not supported yet";
15
- // src/core/build.ts
16
- import { copyFileSync, cpSync, mkdirSync } from "fs";
17
- import { rm as rm3 } from "fs/promises";
18
- import { basename as basename4, join as join5 } from "path";
19
- import { cwd, env as env2, exit } from "process";
20
- var {$, build: bunBuild, Glob: Glob3 } = globalThis.Bun;
16
+ var UNFOUND_INDEX = -1, SECONDS_IN_A_MINUTE = 60, MILLISECONDS_IN_A_SECOND = 1000, MILLISECONDS_IN_A_MINUTE, MINUTES_IN_AN_HOUR = 60, HOURS_IN_DAY = 24, MILLISECONDS_IN_A_DAY, TIME_PRECISION = 2, TWO_THIRDS, DEFAULT_PORT = 3000, DEFAULT_CHUNK_SIZE = 16384, BUN_BUILD_WARNING_SUPPRESSION = "wildcard sideEffects are not supported yet";
17
+ var init_constants = __esm(() => {
18
+ MILLISECONDS_IN_A_MINUTE = MILLISECONDS_IN_A_SECOND * SECONDS_IN_A_MINUTE;
19
+ MILLISECONDS_IN_A_DAY = MILLISECONDS_IN_A_SECOND * SECONDS_IN_A_MINUTE * MINUTES_IN_AN_HOUR * HOURS_IN_DAY;
20
+ TWO_THIRDS = 2 / 3;
21
+ });
21
22
 
22
- // src/build/compileSvelte.ts
23
- import { mkdir, stat } from "fs/promises";
24
- import {
25
- dirname,
26
- join,
27
- basename,
28
- extname,
29
- resolve,
30
- relative,
31
- sep
32
- } from "path";
33
- import { env } from "process";
34
- var {write, file, Transpiler } = globalThis.Bun;
35
- import { compile, compileModule, preprocess } from "svelte/compiler";
36
- var transpiler = new Transpiler({ loader: "ts", target: "browser" });
37
- var exists = async (path) => {
38
- try {
39
- await stat(path);
40
- return true;
41
- } catch {
42
- return false;
43
- }
44
- };
45
- var resolveSvelte = async (spec, from) => {
46
- const basePath = resolve(dirname(from), spec);
47
- const explicit = /\.(svelte|svelte\.(?:ts|js))$/.test(basePath);
48
- if (!explicit) {
49
- const extensions = [".svelte", ".svelte.ts", ".svelte.js"];
50
- const paths = extensions.map((ext) => `${basePath}${ext}`);
51
- const checks = await Promise.all(paths.map(exists));
52
- const match = paths.find((_, index) => checks[index]);
53
- return match ?? null;
23
+ // src/utils/stringModifiers.ts
24
+ var exports_stringModifiers = {};
25
+ __export(exports_stringModifiers, {
26
+ toPascal: () => toPascal,
27
+ toKebab: () => toKebab
28
+ });
29
+ var normalizeSlug = (str) => str.trim().replace(/\s+/g, "-").replace(/[^A-Za-z0-9\-_]+/g, "").replace(/[-_]{2,}/g, "-"), toPascal = (str) => {
30
+ if (!str.includes("-") && !str.includes("_")) {
31
+ return str.charAt(0).toUpperCase() + str.slice(1);
54
32
  }
55
- if (await exists(basePath))
56
- return basePath;
57
- if (!basePath.endsWith(".svelte"))
58
- return null;
59
- const tsPath = `${basePath}.ts`;
60
- if (await exists(tsPath))
61
- return tsPath;
62
- const jsPath = `${basePath}.js`;
63
- if (await exists(jsPath))
64
- return jsPath;
65
- return null;
66
- };
67
- var compileSvelte = async (entryPoints, svelteRoot, cache = new Map) => {
68
- const compiledRoot = join(svelteRoot, "compiled");
69
- const clientDir = join(compiledRoot, "client");
70
- const indexDir = join(compiledRoot, "indexes");
71
- const pagesDir = join(compiledRoot, "pages");
72
- await Promise.all([clientDir, indexDir, pagesDir].map((dir) => mkdir(dir, { recursive: true })));
73
- const dev = env.NODE_ENV === "development";
74
- const build = async (src) => {
75
- const memoized = cache.get(src);
76
- if (memoized)
77
- return memoized;
78
- const raw = await file(src).text();
79
- const isModule = src.endsWith(".svelte.ts") || src.endsWith(".svelte.js");
80
- const preprocessed = isModule ? raw : (await preprocess(raw, {})).code;
81
- const transpiled = src.endsWith(".ts") || src.endsWith(".svelte.ts") ? transpiler.transformSync(preprocessed) : preprocessed;
82
- const relDir = dirname(relative(svelteRoot, src)).replace(/\\/g, "/");
83
- const baseName = basename(src).replace(/\.svelte(\.(ts|js))?$/, "");
84
- const importPaths = Array.from(transpiled.matchAll(/from\s+['"]([^'"]+)['"]/g)).map((match) => match[1]).filter((path) => path !== undefined);
85
- const resolvedImports = await Promise.all(importPaths.map((importPath) => resolveSvelte(importPath, src)));
86
- const childSources = resolvedImports.filter((path) => path !== null);
87
- await Promise.all(childSources.map((child) => build(child)));
88
- const generate = (mode) => (isModule ? compileModule(transpiled, { dev, filename: src }).js.code : compile(transpiled, {
89
- css: "injected",
90
- dev,
91
- filename: src,
92
- generate: mode
93
- }).js.code).replace(/\.svelte(?:\.(?:ts|js))?(['"])/g, ".js$1");
94
- const ssrPath = join(pagesDir, relDir, `${baseName}.js`);
95
- const clientPath = join(clientDir, relDir, `${baseName}.js`);
96
- await Promise.all([
97
- mkdir(dirname(ssrPath), { recursive: true }),
98
- mkdir(dirname(clientPath), { recursive: true })
99
- ]);
100
- if (isModule) {
101
- const bundle = generate("client");
102
- await Promise.all([
103
- write(ssrPath, bundle),
104
- write(clientPath, bundle)
105
- ]);
106
- } else {
107
- const serverBundle = generate("server");
108
- const clientBundle = generate("client");
109
- await Promise.all([
110
- write(ssrPath, serverBundle),
111
- write(clientPath, clientBundle)
112
- ]);
113
- }
114
- const built = { client: clientPath, ssr: ssrPath };
115
- cache.set(src, built);
116
- return built;
117
- };
118
- const roots = await Promise.all(entryPoints.map(build));
119
- await Promise.all(roots.map(async ({ client }) => {
120
- const relClientDir = dirname(relative(clientDir, client));
121
- const name = basename(client, extname(client));
122
- const indexPath = join(indexDir, relClientDir, `${name}.js`);
123
- const importRaw = relative(dirname(indexPath), client).split(sep).join("/");
124
- const importPath = importRaw.startsWith(".") || importRaw.startsWith("/") ? importRaw : `./${importRaw}`;
125
- const bootstrap = `import C from "${importPath}";
126
- import { hydrate } from "svelte";
127
- hydrate(C,{target:document.body,props:window.__INITIAL_PROPS__??{}});`;
128
- await mkdir(dirname(indexPath), { recursive: true });
129
- return write(indexPath, bootstrap);
130
- }));
131
- return {
132
- svelteClientPaths: roots.map(({ client }) => {
133
- const rel = dirname(relative(clientDir, client));
134
- return join(indexDir, rel, basename(client));
135
- }),
136
- svelteServerPaths: roots.map(({ ssr }) => ssr)
137
- };
138
- };
33
+ return normalizeSlug(str).split(/[-_]/).filter(Boolean).map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1).toLowerCase()).join("");
34
+ }, toKebab = (str) => normalizeSlug(str).replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
139
35
 
140
36
  // src/build/compileVue.ts
37
+ var exports_compileVue = {};
38
+ __export(exports_compileVue, {
39
+ vueHmrMetadata: () => vueHmrMetadata,
40
+ generateVueHmrId: () => generateVueHmrId,
41
+ detectVueChangeType: () => detectVueChangeType,
42
+ compileVue: () => compileVue,
43
+ clearVueHmrCaches: () => clearVueHmrCaches
44
+ });
45
+ import { existsSync as existsSync2 } from "fs";
141
46
  import { mkdir as mkdir2 } from "fs/promises";
142
47
  import { basename as basename2, dirname as dirname2, join as join2, relative as relative2, resolve as resolve2 } from "path";
143
48
  import {
@@ -147,29 +52,51 @@ import {
147
52
  compileStyle
148
53
  } from "@vue/compiler-sfc";
149
54
  var {file: file2, write: write2, Transpiler: Transpiler2 } = globalThis.Bun;
150
-
151
- // src/utils/stringModifiers.ts
152
- var normalizeSlug = (str) => str.trim().replace(/\s+/g, "-").replace(/[^A-Za-z0-9\-_]+/g, "").replace(/[-_]{2,}/g, "-");
153
- var toPascal = (str) => {
154
- if (!str.includes("-") && !str.includes("_")) {
155
- return str.charAt(0).toUpperCase() + str.slice(1);
55
+ var devClientDir2, hmrClientPath2, transpiler2, scriptCache, scriptSetupCache, templateCache, styleCache, vueHmrMetadata, detectVueChangeType = (filePath, descriptor) => {
56
+ const prevScript = scriptCache.get(filePath);
57
+ const prevScriptSetup = scriptSetupCache.get(filePath);
58
+ const prevTemplate = templateCache.get(filePath);
59
+ const prevStyle = styleCache.get(filePath);
60
+ const currentScript = descriptor.script?.content ?? "";
61
+ const currentScriptSetup = descriptor.scriptSetup?.content ?? "";
62
+ const currentTemplate = descriptor.template?.content ?? "";
63
+ const currentStyle = descriptor.styles.map((s) => `${s.scoped ? "scoped:" : ""}${s.content}`).join("|||");
64
+ scriptCache.set(filePath, currentScript);
65
+ scriptSetupCache.set(filePath, currentScriptSetup);
66
+ templateCache.set(filePath, currentTemplate);
67
+ styleCache.set(filePath, currentStyle);
68
+ if (prevScript === undefined && prevScriptSetup === undefined) {
69
+ return "full";
156
70
  }
157
- return normalizeSlug(str).split(/[-_]/).filter(Boolean).map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1).toLowerCase()).join("");
158
- };
159
- var toKebab = (str) => normalizeSlug(str).replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
160
-
161
- // src/build/compileVue.ts
162
- var transpiler2 = new Transpiler2({ loader: "ts", target: "browser" });
163
- var extractImports = (sourceCode) => Array.from(sourceCode.matchAll(/import\s+[\s\S]+?['"]([^'"]+)['"]/g)).map((match) => match[1]).filter((importPath) => importPath !== undefined);
164
- var toJs = (filePath) => {
71
+ const scriptChanged = prevScript !== currentScript;
72
+ const scriptSetupChanged = prevScriptSetup !== currentScriptSetup;
73
+ const templateChanged = prevTemplate !== currentTemplate;
74
+ const styleChanged = prevStyle !== currentStyle;
75
+ if (scriptChanged || scriptSetupChanged) {
76
+ return "script";
77
+ }
78
+ if (styleChanged && !templateChanged) {
79
+ return "style-only";
80
+ }
81
+ if (templateChanged) {
82
+ return "template-only";
83
+ }
84
+ return "full";
85
+ }, generateVueHmrId = (sourceFilePath, vueRootDir) => {
86
+ return relative2(vueRootDir, sourceFilePath).replace(/\\/g, "/").replace(/\.vue$/, "");
87
+ }, clearVueHmrCaches = () => {
88
+ scriptCache.clear();
89
+ scriptSetupCache.clear();
90
+ templateCache.clear();
91
+ styleCache.clear();
92
+ vueHmrMetadata.clear();
93
+ }, extractImports = (sourceCode) => Array.from(sourceCode.matchAll(/import\s+[\s\S]+?['"]([^'"]+)['"]/g)).map((match) => match[1]).filter((importPath) => importPath !== undefined), toJs = (filePath) => {
165
94
  if (filePath.endsWith(".vue"))
166
95
  return filePath.replace(/\.vue$/, ".js");
167
96
  if (filePath.endsWith(".ts"))
168
97
  return filePath.replace(/\.ts$/, ".js");
169
98
  return `${filePath}.js`;
170
- };
171
- var stripExports = (code) => code.replace(/export\s+default/, "const script =").replace(/^export\s+/gm, "");
172
- var mergeVueImports = (code) => {
99
+ }, stripExports = (code) => code.replace(/export\s+default/, "const script =").replace(/^export\s+/gm, ""), mergeVueImports = (code) => {
173
100
  const lines = code.split(`
174
101
  `);
175
102
  const specifierSet = new Set;
@@ -186,8 +113,7 @@ var mergeVueImports = (code) => {
186
113
  ].join(`
187
114
  `) : nonVueLines.join(`
188
115
  `);
189
- };
190
- var compileVueFile = async (sourceFilePath, outputDirs, cacheMap, isEntryPoint, vueRootDir) => {
116
+ }, compileVueFile = async (sourceFilePath, outputDirs, cacheMap, isEntryPoint, vueRootDir) => {
191
117
  const cachedResult = cacheMap.get(sourceFilePath);
192
118
  if (cachedResult)
193
119
  return cachedResult;
@@ -197,6 +123,9 @@ var compileVueFile = async (sourceFilePath, outputDirs, cacheMap, isEntryPoint,
197
123
  const componentId = toKebab(fileBaseName);
198
124
  const sourceContent = await file2(sourceFilePath).text();
199
125
  const { descriptor } = parse(sourceContent, { filename: sourceFilePath });
126
+ const hmrId = generateVueHmrId(sourceFilePath, vueRootDir);
127
+ const changeType = detectVueChangeType(sourceFilePath, descriptor);
128
+ vueHmrMetadata.set(sourceFilePath, { hmrId, changeType });
200
129
  const scriptSource = descriptor.scriptSetup?.content ?? descriptor.script?.content ?? "";
201
130
  const importPaths = extractImports(scriptSource);
202
131
  const childComponentPaths = importPaths.filter((path) => path.startsWith(".") && path.endsWith(".vue"));
@@ -239,15 +168,31 @@ var compileVueFile = async (sourceFilePath, outputDirs, cacheMap, isEntryPoint,
239
168
  `));
240
169
  cssOutputPaths = [cssOutputFile];
241
170
  }
242
- const assembleModule = (renderCode, renderFnName) => mergeVueImports([
243
- transpiledScript,
244
- renderCode,
245
- `script.${renderFnName} = ${renderFnName};`,
246
- "export default script;"
247
- ].join(`
171
+ const assembleModule = (renderCode, renderFnName, includeHmr) => {
172
+ const hasScoped = descriptor.styles.some((styleBlock) => styleBlock.scoped);
173
+ const scopeIdCode = hasScoped ? `script.__scopeId = "data-v-${componentId}";` : "";
174
+ const hmrCode = includeHmr ? `
175
+ // Vue Native HMR Registration
176
+ script.__hmrId = ${JSON.stringify(hmrId)};
177
+ if (typeof __VUE_HMR_RUNTIME__ !== 'undefined') {
178
+ __VUE_HMR_RUNTIME__.createRecord(script.__hmrId, script);
179
+ if (typeof window !== 'undefined') {
180
+ window.__VUE_HMR_COMPONENTS__ = window.__VUE_HMR_COMPONENTS__ || {};
181
+ window.__VUE_HMR_COMPONENTS__[script.__hmrId] = script;
182
+ }
183
+ }` : "";
184
+ return mergeVueImports([
185
+ transpiledScript,
186
+ renderCode,
187
+ `script.${renderFnName} = ${renderFnName};`,
188
+ scopeIdCode,
189
+ hmrCode,
190
+ "export default script;"
191
+ ].join(`
248
192
  `));
249
- const clientCode = assembleModule(generateRenderFunction(false), "render");
250
- const serverCode = assembleModule(generateRenderFunction(true), "ssrRender");
193
+ };
194
+ const clientCode = assembleModule(generateRenderFunction(false), "render", true);
195
+ const serverCode = assembleModule(generateRenderFunction(true), "ssrRender", false);
251
196
  const clientOutputPath = join2(outputDirs.client, `${relativeWithoutExtension}.js`);
252
197
  const serverOutputPath = join2(outputDirs.server, `${relativeWithoutExtension}.js`);
253
198
  await mkdir2(dirname2(clientOutputPath), { recursive: true });
@@ -262,12 +207,12 @@ var compileVueFile = async (sourceFilePath, outputDirs, cacheMap, isEntryPoint,
262
207
  tsHelperPaths: [
263
208
  ...helperModulePaths.map((helper) => resolve2(dirname2(sourceFilePath), helper.endsWith(".ts") ? helper : `${helper}.ts`)),
264
209
  ...childBuildResults.flatMap((child) => child.tsHelperPaths)
265
- ]
210
+ ],
211
+ hmrId
266
212
  };
267
213
  cacheMap.set(sourceFilePath, result);
268
214
  return result;
269
- };
270
- var compileVue = async (entryPoints, vueRootDir) => {
215
+ }, compileVue = async (entryPoints, vueRootDir, isDev = false) => {
271
216
  const compiledOutputRoot = join2(vueRootDir, "compiled");
272
217
  const clientOutputDir = join2(compiledOutputRoot, "client");
273
218
  const indexOutputDir = join2(compiledOutputRoot, "indexes");
@@ -292,14 +237,92 @@ var compileVue = async (entryPoints, vueRootDir) => {
292
237
  const indexOutputFile = join2(indexOutputDir, `${entryBaseName}.js`);
293
238
  const clientOutputFile = join2(clientOutputDir, relative2(vueRootDir, entryPath).replace(/\\/g, "/").replace(/\.vue$/, ".js"));
294
239
  await mkdir2(dirname2(indexOutputFile), { recursive: true });
240
+ const vueHmrImports = isDev ? [
241
+ `window.__HMR_FRAMEWORK__ = "vue";`,
242
+ `import "${hmrClientPath2}";`
243
+ ] : [];
295
244
  await write2(indexOutputFile, [
245
+ ...vueHmrImports,
296
246
  `import Comp from "${relative2(dirname2(indexOutputFile), clientOutputFile).replace(/\\/g, "/")}";`,
297
247
  'import { createSSRApp } from "vue";',
298
- "const props = window.__INITIAL_PROPS__ ?? {};",
299
- 'createSSRApp(Comp, props).mount("#root");'
248
+ "",
249
+ "// HMR State Preservation: Check for preserved state from HMR",
250
+ 'let preservedState = (typeof window !== "undefined" && window.__HMR_PRESERVED_STATE__) ? window.__HMR_PRESERVED_STATE__ : {};',
251
+ "",
252
+ "// Fallback: check sessionStorage if window state is empty",
253
+ 'if (typeof window !== "undefined" && Object.keys(preservedState).length === 0) {',
254
+ " try {",
255
+ ' const stored = sessionStorage.getItem("__VUE_HMR_STATE__");',
256
+ " if (stored) {",
257
+ " preservedState = JSON.parse(stored);",
258
+ ' sessionStorage.removeItem("__VUE_HMR_STATE__");',
259
+ " }",
260
+ " } catch (e) {}",
261
+ "}",
262
+ "",
263
+ "const mergedProps = { ...(window.__INITIAL_PROPS__ ?? {}), ...preservedState };",
264
+ "",
265
+ "// Use createSSRApp for proper hydration of server-rendered content",
266
+ "const app = createSSRApp(Comp, mergedProps);",
267
+ 'app.mount("#root");',
268
+ "",
269
+ "// Store app instance for HMR - used for manual component updates",
270
+ 'if (typeof window !== "undefined") {',
271
+ " window.__VUE_APP__ = app;",
272
+ "}",
273
+ "",
274
+ "// Post-mount: Apply preserved state to reactive refs in component tree",
275
+ "// This restores state that lives in refs (like count) rather than props",
276
+ 'if (typeof window !== "undefined" && Object.keys(preservedState).length > 0) {',
277
+ " requestAnimationFrame(function() {",
278
+ " if (window.__VUE_APP__ && window.__VUE_APP__._instance) {",
279
+ " applyPreservedState(window.__VUE_APP__._instance, preservedState);",
280
+ " }",
281
+ " });",
282
+ "}",
283
+ "",
284
+ "function applyPreservedState(instance, state) {",
285
+ " // Apply to root component setupState",
286
+ " if (instance.setupState) {",
287
+ " Object.keys(state).forEach(function(key) {",
288
+ " const ref = instance.setupState[key];",
289
+ ' if (ref && typeof ref === "object" && "value" in ref) {',
290
+ " ref.value = state[key];",
291
+ " }",
292
+ " });",
293
+ " }",
294
+ " // Also apply to child components",
295
+ " if (instance.subTree) {",
296
+ " walkAndApply(instance.subTree, state);",
297
+ " }",
298
+ "}",
299
+ "",
300
+ "function walkAndApply(vnode, state) {",
301
+ " if (!vnode) return;",
302
+ " if (vnode.component && vnode.component.setupState) {",
303
+ " Object.keys(state).forEach(function(key) {",
304
+ " const ref = vnode.component.setupState[key];",
305
+ ' if (ref && typeof ref === "object" && "value" in ref) {',
306
+ " ref.value = state[key];",
307
+ " }",
308
+ " });",
309
+ " }",
310
+ " if (vnode.children && Array.isArray(vnode.children)) {",
311
+ " vnode.children.forEach(function(child) { walkAndApply(child, state); });",
312
+ " }",
313
+ " if (vnode.component && vnode.component.subTree) {",
314
+ " walkAndApply(vnode.component.subTree, state);",
315
+ " }",
316
+ "}",
317
+ "",
318
+ "// Clear preserved state after applying",
319
+ 'if (typeof window !== "undefined") {',
320
+ " window.__HMR_PRESERVED_STATE__ = undefined;",
321
+ "}"
300
322
  ].join(`
301
323
  `));
302
324
  return {
325
+ clientPath: clientOutputFile,
303
326
  cssPaths: result.cssPaths,
304
327
  indexPath: indexOutputFile,
305
328
  serverPath: result.serverPath
@@ -317,97 +340,921 @@ var compileVue = async (entryPoints, vueRootDir) => {
317
340
  await write2(outServerPath, transpiledCode);
318
341
  }));
319
342
  return {
343
+ vueClientPaths: compiledPages.map((result) => result.clientPath),
320
344
  vueCssPaths: compiledPages.flatMap((result) => result.cssPaths),
321
345
  vueIndexPaths: compiledPages.map((result) => result.indexPath),
322
- vueServerPaths: compiledPages.map((result) => result.serverPath)
346
+ vueServerPaths: compiledPages.map((result) => result.serverPath),
347
+ hmrMetadata: new Map(vueHmrMetadata)
323
348
  };
324
349
  };
350
+ var init_compileVue = __esm(() => {
351
+ devClientDir2 = (() => {
352
+ const fromSource = resolve2(import.meta.dir, "../dev/client");
353
+ if (existsSync2(fromSource))
354
+ return fromSource;
355
+ return resolve2(import.meta.dir, "./dev/client");
356
+ })();
357
+ hmrClientPath2 = join2(devClientDir2, "hmrClient.ts").replace(/\\/g, "/");
358
+ transpiler2 = new Transpiler2({ loader: "ts", target: "browser" });
359
+ scriptCache = new Map;
360
+ scriptSetupCache = new Map;
361
+ templateCache = new Map;
362
+ styleCache = new Map;
363
+ vueHmrMetadata = new Map;
364
+ });
325
365
 
326
- // src/build/generateManifest.ts
327
- import { extname as extname2 } from "path";
328
- var generateManifest = (outputs, buildPath) => outputs.reduce((manifest, artifact) => {
329
- let relative3 = artifact.path.startsWith(buildPath) ? artifact.path.slice(buildPath.length) : artifact.path;
330
- relative3 = relative3.replace(/\\/g, "/").replace(/^\/+/, "");
331
- const segments = relative3.split("/");
332
- const fileWithHash = segments.pop();
333
- if (!fileWithHash)
334
- return manifest;
335
- const [baseName] = fileWithHash.split(`.${artifact.hash}.`);
336
- if (!baseName)
337
- return manifest;
338
- const pascalName = toPascal(baseName);
339
- const ext = extname2(fileWithHash);
340
- if (ext === ".css") {
341
- manifest[`${pascalName}CSS`] = `/${relative3}`;
342
- return manifest;
343
- }
344
- const idx = segments.findIndex((seg) => seg === "indexes" || seg === "pages");
345
- const folder = idx > UNFOUND_INDEX ? segments[idx] : segments[0];
346
- if (folder === "indexes") {
347
- manifest[`${pascalName}Index`] = `/${relative3}`;
348
- } else if (folder === "pages") {
349
- manifest[pascalName] = artifact.path;
350
- } else {
351
- manifest[pascalName] = `/${relative3}`;
352
- }
353
- return manifest;
354
- }, {});
355
-
356
- // src/build/generateReactIndexes.ts
357
- import { mkdir as mkdir3, rm, writeFile } from "fs/promises";
358
- import { basename as basename3, join as join3 } from "path";
359
- var {Glob } = globalThis.Bun;
360
- var generateReactIndexFiles = async (reactPagesDirectory, reactIndexesDirectory) => {
361
- await rm(reactIndexesDirectory, { force: true, recursive: true });
362
- await mkdir3(reactIndexesDirectory);
363
- const pagesGlob = new Glob("*.*");
364
- const files = [];
365
- for await (const file3 of pagesGlob.scan({ cwd: reactPagesDirectory })) {
366
- files.push(file3);
366
+ // src/dev/simpleHTMLHMR.ts
367
+ var exports_simpleHTMLHMR = {};
368
+ __export(exports_simpleHTMLHMR, {
369
+ handleHTMLUpdate: () => handleHTMLUpdate
370
+ });
371
+ import { readFileSync as readFileSync4, existsSync as existsSync6 } from "fs";
372
+ import { resolve as resolve13 } from "path";
373
+ var handleHTMLUpdate = async (htmlFilePath) => {
374
+ try {
375
+ const resolvedPath = resolve13(htmlFilePath);
376
+ if (!existsSync6(resolvedPath)) {
377
+ return null;
378
+ }
379
+ const htmlContent = readFileSync4(resolvedPath, "utf-8");
380
+ const headMatch = htmlContent.match(/<head[^>]*>([\s\S]*?)<\/head>/i);
381
+ const bodyMatch = htmlContent.match(/<body[^>]*>([\s\S]*)<\/body>/i);
382
+ if (bodyMatch && bodyMatch[1]) {
383
+ const bodyContent = bodyMatch[1].trim();
384
+ const headContent = headMatch && headMatch[1] ? headMatch[1].trim() : null;
385
+ return {
386
+ body: bodyContent,
387
+ head: headContent
388
+ };
389
+ }
390
+ return htmlContent;
391
+ } catch {
392
+ return null;
367
393
  }
368
- const promises = files.map(async (file3) => {
369
- const fileName = basename3(file3);
370
- const [componentName] = fileName.split(".");
371
- const content = [
372
- `import { hydrateRoot } from 'react-dom/client';`,
373
- `import type { ComponentType } from 'react'`,
374
- `import { ${componentName} } from '../pages/${componentName}';
375
- `,
376
- `type PropsOf<C> = C extends ComponentType<infer P> ? P : never;
377
- `,
378
- `declare global {`,
379
- ` interface Window {`,
380
- ` __INITIAL_PROPS__: PropsOf<typeof ${componentName}>`,
381
- ` }`,
382
- `}
383
- `,
384
- `hydrateRoot(document, <${componentName} {...window.__INITIAL_PROPS__} />);`
385
- ].join(`
386
- `);
387
- return writeFile(join3(reactIndexesDirectory, `${componentName}.tsx`), content);
388
- });
389
- await Promise.all(promises);
390
394
  };
395
+ var init_simpleHTMLHMR = () => {};
391
396
 
392
- // src/build/outputLogs.ts
393
- var outputLogs = (logs) => {
394
- for (const log of logs) {
395
- if (log.message.includes(BUN_BUILD_WARNING_SUPPRESSION))
396
- continue;
397
- if (log.level === "error")
398
- console.error(log);
399
- else if (log.level === "warning")
400
- console.warn(log);
401
- else
402
- console.info(log);
397
+ // src/utils/escapeScriptContent.ts
398
+ var ESCAPE_LOOKUP, ESCAPE_REGEX, escapeScriptContent = (content) => content.replace(ESCAPE_REGEX, (char) => {
399
+ const escaped = ESCAPE_LOOKUP[char];
400
+ return escaped !== undefined ? escaped : char;
401
+ });
402
+ var init_escapeScriptContent = __esm(() => {
403
+ ESCAPE_LOOKUP = {
404
+ "\u2028": "\\u2028",
405
+ "\u2029": "\\u2029",
406
+ "&": "\\u0026",
407
+ "<": "\\u003C",
408
+ ">": "\\u003E"
409
+ };
410
+ ESCAPE_REGEX = /[&><\u2028\u2029]/g;
411
+ });
412
+
413
+ // src/svelte/renderToReadableStream.ts
414
+ import { render } from "svelte/server";
415
+ var renderToReadableStream = async (component, props, {
416
+ bootstrapScriptContent,
417
+ bootstrapScripts = [],
418
+ bootstrapModules = [],
419
+ nonce,
420
+ onError = console.error,
421
+ progressiveChunkSize = DEFAULT_CHUNK_SIZE,
422
+ signal,
423
+ headContent,
424
+ bodyContent
425
+ } = {}) => {
426
+ try {
427
+ const { head, body } = typeof props === "undefined" ? render(component) : render(component, { props });
428
+ const nonceAttr = nonce ? ` nonce="${nonce}"` : "";
429
+ const scripts = (bootstrapScriptContent ? `<script${nonceAttr}>${escapeScriptContent(bootstrapScriptContent)}</script>` : "") + bootstrapScripts.map((src) => `<script${nonceAttr} src="${src}"></script>`).join("") + bootstrapModules.map((src) => `<script${nonceAttr} type="module" src="${src}"></script>`).join("");
430
+ const encoder = new TextEncoder;
431
+ const full = encoder.encode(`<!DOCTYPE html><html lang="en"><head>${head}${headContent ?? ""}</head><body>${body}${scripts}${bodyContent ?? ""}</body></html>`);
432
+ let offset = 0;
433
+ return new ReadableStream({
434
+ type: "bytes",
435
+ cancel(reason) {
436
+ onError?.(reason);
437
+ },
438
+ pull(controller) {
439
+ if (signal?.aborted) {
440
+ controller.close();
441
+ return;
442
+ }
443
+ if (offset >= full.length) {
444
+ controller.close();
445
+ return;
446
+ }
447
+ const end = Math.min(offset + progressiveChunkSize, full.length);
448
+ controller.enqueue(full.subarray(offset, end));
449
+ offset = end;
450
+ }
451
+ });
452
+ } catch (error) {
453
+ onError?.(error);
454
+ throw error;
403
455
  }
404
456
  };
457
+ var init_renderToReadableStream = __esm(() => {
458
+ init_constants();
459
+ init_escapeScriptContent();
460
+ });
405
461
 
406
- // src/build/scanEntryPoints.ts
407
- var {Glob: Glob2 } = globalThis.Bun;
408
- var scanEntryPoints = async (dir, pattern) => {
409
- const entryPaths = [];
410
- const glob = new Glob2(pattern);
462
+ // src/core/pageHandlers.ts
463
+ var exports_pageHandlers = {};
464
+ __export(exports_pageHandlers, {
465
+ handleVuePageRequest: () => handleVuePageRequest,
466
+ handleSveltePageRequest: () => handleSveltePageRequest,
467
+ handleReactPageRequest: () => handleReactPageRequest,
468
+ handlePageRequest: () => handlePageRequest,
469
+ handleHTMXPageRequest: () => handleHTMXPageRequest,
470
+ handleHTMLPageRequest: () => handleHTMLPageRequest
471
+ });
472
+ var {file: file3 } = globalThis.Bun;
473
+ import { createElement } from "react";
474
+ import { renderToReadableStream as renderReactToReadableStream } from "react-dom/server";
475
+ import { createSSRApp, h } from "vue";
476
+ import { renderToWebStream as renderVueToWebStream } from "vue/server-renderer";
477
+ var handleReactPageRequest = async (PageComponent, index, ...props) => {
478
+ const [maybeProps] = props;
479
+ const element = maybeProps !== undefined ? createElement(PageComponent, maybeProps) : createElement(PageComponent);
480
+ const stream = await renderReactToReadableStream(element, {
481
+ bootstrapModules: [index],
482
+ bootstrapScriptContent: maybeProps ? `window.__INITIAL_PROPS__=${JSON.stringify(maybeProps)}` : undefined
483
+ });
484
+ return new Response(stream, {
485
+ headers: { "Content-Type": "text/html" }
486
+ });
487
+ }, handleSveltePageRequest = async (_PageComponent, pagePath, indexPath, props) => {
488
+ const { default: ImportedPageComponent } = await import(pagePath);
489
+ const stream = await renderToReadableStream(ImportedPageComponent, props, {
490
+ bootstrapModules: indexPath ? [indexPath] : [],
491
+ bootstrapScriptContent: `window.__INITIAL_PROPS__=${JSON.stringify(props)}`
492
+ });
493
+ return new Response(stream, {
494
+ headers: { "Content-Type": "text/html" }
495
+ });
496
+ }, handleVuePageRequest = async (_PageComponent, pagePath, indexPath, headTag = "<head></head>", ...props) => {
497
+ const [maybeProps] = props;
498
+ const { default: ImportedPageComponent } = await import(pagePath);
499
+ const app = createSSRApp({
500
+ render: () => h(ImportedPageComponent, maybeProps ?? null)
501
+ });
502
+ const bodyStream = renderVueToWebStream(app);
503
+ const head = `<!DOCTYPE html><html>${headTag}<body><div id="root">`;
504
+ const tail = `</div><script>window.__INITIAL_PROPS__=${JSON.stringify(maybeProps ?? {})}</script><script type="module" src="${indexPath}"></script></body></html>`;
505
+ const stream = new ReadableStream({
506
+ start(controller) {
507
+ controller.enqueue(head);
508
+ const reader = bodyStream.getReader();
509
+ const pumpLoop = () => {
510
+ reader.read().then(({ done, value }) => done ? (controller.enqueue(tail), controller.close()) : (controller.enqueue(value), pumpLoop())).catch((err) => controller.error(err));
511
+ };
512
+ pumpLoop();
513
+ }
514
+ });
515
+ return new Response(stream, {
516
+ headers: { "Content-Type": "text/html" }
517
+ });
518
+ }, handleHTMLPageRequest = (pagePath) => file3(pagePath), handleHTMXPageRequest = (pagePath) => file3(pagePath), handlePageRequest = (PageComponent, ...props) => {
519
+ console.log("handlePageRequest coming soon.", PageComponent, props);
520
+ };
521
+ var init_pageHandlers = __esm(() => {
522
+ init_renderToReadableStream();
523
+ });
524
+
525
+ // src/utils/generateHeadElement.ts
526
+ var exports_generateHeadElement = {};
527
+ __export(exports_generateHeadElement, {
528
+ generateHeadElement: () => generateHeadElement
529
+ });
530
+ var generateHeadElement = ({
531
+ cssPath,
532
+ title = "AbsoluteJS",
533
+ description = "A page created using AbsoluteJS",
534
+ font,
535
+ icon = "/assets/ico/favicon.ico"
536
+ } = {}) => `<head>
537
+ <meta charset="UTF-8">
538
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
539
+ <title>${title}</title>
540
+ <meta name="description" content="${description}">
541
+ <link rel="icon" href="${icon}" type="image/x-icon">
542
+ ${font ? `<link rel="preconnect" href="https://fonts.googleapis.com">
543
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
544
+ <link href="https://fonts.googleapis.com/css2?family=${font}:wght@100..900&display=swap" rel="stylesheet">` : ""}
545
+ ${cssPath ? `<link rel="stylesheet" href="${cssPath}" type="text/css">` : ""}
546
+ </head>`;
547
+
548
+ // src/dev/simpleVueHMR.ts
549
+ var exports_simpleVueHMR = {};
550
+ __export(exports_simpleVueHMR, {
551
+ handleVueUpdate: () => handleVueUpdate
552
+ });
553
+ import { basename as basename6, join as join7, resolve as resolve14 } from "path";
554
+ var handleVueUpdate = async (vueFilePath, manifest, buildDir) => {
555
+ try {
556
+ const resolvedPath = resolve14(vueFilePath);
557
+ const fileName = basename6(resolvedPath);
558
+ const baseName = fileName.replace(/\.vue$/, "");
559
+ const pascalName = toPascal(baseName);
560
+ const componentKey = pascalName;
561
+ const indexKey = `${pascalName}Index`;
562
+ const cssKey = `${pascalName}CSS`;
563
+ const serverPath = manifest[componentKey];
564
+ if (!serverPath) {
565
+ console.warn("[Vue HMR] Server path not found in manifest for:", componentKey);
566
+ console.warn("[Vue HMR] Available manifest keys:", Object.keys(manifest).join(", "));
567
+ return null;
568
+ }
569
+ const absoluteServerPath = resolve14(serverPath) === serverPath || serverPath.startsWith("/") || /^[A-Za-z]:[\\/]/.test(serverPath) ? serverPath : join7(buildDir || process.cwd(), serverPath.replace(/^\//, ""));
570
+ const cacheBuster = `?t=${Date.now()}`;
571
+ const serverModule = await import(`${absoluteServerPath}${cacheBuster}`);
572
+ if (!serverModule || !serverModule.default) {
573
+ console.warn("[Vue HMR] Module has no default export:", absoluteServerPath);
574
+ return null;
575
+ }
576
+ const indexPath = manifest[indexKey];
577
+ if (!indexPath) {
578
+ console.warn("[Vue HMR] Index path not found in manifest for:", indexKey);
579
+ return null;
580
+ }
581
+ const { handleVuePageRequest: handleVuePageRequest2 } = await Promise.resolve().then(() => (init_pageHandlers(), exports_pageHandlers));
582
+ const { generateHeadElement: generateHeadElement2 } = await Promise.resolve().then(() => exports_generateHeadElement);
583
+ const response = await handleVuePageRequest2(serverModule.default, serverPath, indexPath, generateHeadElement2({
584
+ cssPath: manifest[cssKey] || "",
585
+ title: "AbsoluteJS + Vue"
586
+ }), { initialCount: 0 });
587
+ const html = await response.text();
588
+ const bodyMatch = html.match(/<body[^>]*>([\s\S]*)<\/body>/i);
589
+ if (bodyMatch && bodyMatch[1]) {
590
+ const bodyContent = bodyMatch[1].trim();
591
+ return bodyContent;
592
+ }
593
+ return html;
594
+ } catch (err) {
595
+ console.error("[Vue HMR] Error in handleVueUpdate:", err);
596
+ return null;
597
+ }
598
+ };
599
+ var init_simpleVueHMR = () => {};
600
+
601
+ // src/dev/simpleSvelteHMR.ts
602
+ var exports_simpleSvelteHMR = {};
603
+ __export(exports_simpleSvelteHMR, {
604
+ handleSvelteUpdate: () => handleSvelteUpdate
605
+ });
606
+ import { basename as basename7, join as join8, resolve as resolve15 } from "path";
607
+ var handleSvelteUpdate = async (svelteFilePath, manifest, buildDir) => {
608
+ try {
609
+ const resolvedPath = resolve15(svelteFilePath);
610
+ const fileName = basename7(resolvedPath);
611
+ const baseName = fileName.replace(/\.svelte$/, "");
612
+ const pascalName = toPascal(baseName);
613
+ const componentKey = pascalName;
614
+ const indexKey = `${pascalName}Index`;
615
+ const cssKey = `${pascalName}CSS`;
616
+ const serverPath = manifest[componentKey];
617
+ if (!serverPath) {
618
+ console.warn("[Svelte HMR] Server path not found in manifest for:", componentKey);
619
+ console.warn("[Svelte HMR] Available manifest keys:", Object.keys(manifest).join(", "));
620
+ return null;
621
+ }
622
+ const absoluteServerPath = resolve15(serverPath) === serverPath || serverPath.startsWith("/") || /^[A-Za-z]:[\\/]/.test(serverPath) ? serverPath : join8(buildDir || process.cwd(), serverPath.replace(/^\//, ""));
623
+ const cacheBuster = `?t=${Date.now()}`;
624
+ const serverModule = await import(`${absoluteServerPath}${cacheBuster}`);
625
+ if (!serverModule || !serverModule.default) {
626
+ console.warn("[Svelte HMR] Module has no default export:", absoluteServerPath);
627
+ return null;
628
+ }
629
+ const indexPath = manifest[indexKey];
630
+ if (!indexPath) {
631
+ console.warn("[Svelte HMR] Index path not found in manifest for:", indexKey);
632
+ return null;
633
+ }
634
+ const { handleSveltePageRequest: handleSveltePageRequest2 } = await Promise.resolve().then(() => (init_pageHandlers(), exports_pageHandlers));
635
+ const response = await handleSveltePageRequest2(serverModule.default, serverPath, indexPath, {
636
+ cssPath: manifest[cssKey] || "",
637
+ initialCount: 0
638
+ });
639
+ const html = await response.text();
640
+ const bodyMatch = html.match(/<body[^>]*>([\s\S]*)<\/body>/i);
641
+ if (bodyMatch && bodyMatch[1]) {
642
+ const bodyContent = bodyMatch[1].trim();
643
+ return bodyContent;
644
+ }
645
+ return html;
646
+ } catch (err) {
647
+ console.error("[Svelte HMR] Error in handleSvelteUpdate:", err);
648
+ return null;
649
+ }
650
+ };
651
+ var init_simpleSvelteHMR = () => {};
652
+
653
+ // src/dev/simpleHTMXHMR.ts
654
+ var exports_simpleHTMXHMR = {};
655
+ __export(exports_simpleHTMXHMR, {
656
+ handleHTMXUpdate: () => handleHTMXUpdate
657
+ });
658
+ import { readFileSync as readFileSync5, existsSync as existsSync7 } from "fs";
659
+ import { resolve as resolve16 } from "path";
660
+ var handleHTMXUpdate = async (htmxFilePath) => {
661
+ try {
662
+ const resolvedPath = resolve16(htmxFilePath);
663
+ if (!existsSync7(resolvedPath)) {
664
+ return null;
665
+ }
666
+ const htmlContent = readFileSync5(resolvedPath, "utf-8");
667
+ const headMatch = htmlContent.match(/<head[^>]*>([\s\S]*?)<\/head>/i);
668
+ const bodyMatch = htmlContent.match(/<body[^>]*>([\s\S]*)<\/body>/i);
669
+ if (bodyMatch && bodyMatch[1]) {
670
+ const bodyContent = bodyMatch[1].trim();
671
+ const headContent = headMatch && headMatch[1] ? headMatch[1].trim() : null;
672
+ return {
673
+ body: bodyContent,
674
+ head: headContent
675
+ };
676
+ }
677
+ return htmlContent;
678
+ } catch {
679
+ return null;
680
+ }
681
+ };
682
+ var init_simpleHTMXHMR = () => {};
683
+ // types/client.ts
684
+ var hmrState = {
685
+ isConnected: false,
686
+ isFirstHMRUpdate: true,
687
+ isHMRUpdating: false,
688
+ pingInterval: null,
689
+ reconnectTimeout: null
690
+ };
691
+ // types/messages.ts
692
+ var isValidHMRClientMessage = (data) => {
693
+ if (!data || typeof data !== "object") {
694
+ return false;
695
+ }
696
+ const message = data;
697
+ if (!("type" in message) || typeof message.type !== "string") {
698
+ return false;
699
+ }
700
+ switch (message.type) {
701
+ case "ping":
702
+ return true;
703
+ case "ready":
704
+ return true;
705
+ case "request-rebuild":
706
+ return true;
707
+ case "hydration-error":
708
+ return true;
709
+ default:
710
+ return false;
711
+ }
712
+ };
713
+ // types/websocket.ts
714
+ var WS_READY_STATE_OPEN = 1;
715
+ // src/index.ts
716
+ init_constants();
717
+
718
+ // src/core/build.ts
719
+ import {
720
+ copyFileSync,
721
+ cpSync,
722
+ mkdirSync,
723
+ readFileSync,
724
+ writeFileSync
725
+ } from "fs";
726
+ import { rm as rm3 } from "fs/promises";
727
+ import { basename as basename4, join as join5, resolve as resolve6 } from "path";
728
+ import { cwd, env as env2, exit } from "process";
729
+ var {$, build: bunBuild2, Glob: Glob3 } = globalThis.Bun;
730
+
731
+ // src/build/compileSvelte.ts
732
+ import { existsSync } from "fs";
733
+ import { mkdir, stat } from "fs/promises";
734
+ import {
735
+ dirname,
736
+ join,
737
+ basename,
738
+ extname,
739
+ resolve,
740
+ relative,
741
+ sep
742
+ } from "path";
743
+ import { env } from "process";
744
+ var {write, file, Transpiler } = globalThis.Bun;
745
+ import { compile, compileModule, preprocess } from "svelte/compiler";
746
+ var devClientDir = (() => {
747
+ const fromSource = resolve(import.meta.dir, "../dev/client");
748
+ if (existsSync(fromSource))
749
+ return fromSource;
750
+ return resolve(import.meta.dir, "./dev/client");
751
+ })();
752
+ var hmrClientPath = join(devClientDir, "hmrClient.ts").replace(/\\/g, "/");
753
+ var transpiler = new Transpiler({ loader: "ts", target: "browser" });
754
+ var exists = async (path) => {
755
+ try {
756
+ await stat(path);
757
+ return true;
758
+ } catch {
759
+ return false;
760
+ }
761
+ };
762
+ var resolveSvelte = async (spec, from) => {
763
+ const basePath = resolve(dirname(from), spec);
764
+ const explicit = /\.(svelte|svelte\.(?:ts|js))$/.test(basePath);
765
+ if (!explicit) {
766
+ const extensions = [".svelte", ".svelte.ts", ".svelte.js"];
767
+ const paths = extensions.map((ext) => `${basePath}${ext}`);
768
+ const checks = await Promise.all(paths.map(exists));
769
+ const match = paths.find((_, index) => checks[index]);
770
+ return match ?? null;
771
+ }
772
+ if (await exists(basePath))
773
+ return basePath;
774
+ if (!basePath.endsWith(".svelte"))
775
+ return null;
776
+ const tsPath = `${basePath}.ts`;
777
+ if (await exists(tsPath))
778
+ return tsPath;
779
+ const jsPath = `${basePath}.js`;
780
+ if (await exists(jsPath))
781
+ return jsPath;
782
+ return null;
783
+ };
784
+ var compileSvelte = async (entryPoints, svelteRoot, cache = new Map, isDev = false) => {
785
+ const compiledRoot = join(svelteRoot, "compiled");
786
+ const clientDir = join(compiledRoot, "client");
787
+ const indexDir = join(compiledRoot, "indexes");
788
+ const pagesDir = join(compiledRoot, "pages");
789
+ await Promise.all([clientDir, indexDir, pagesDir].map((dir) => mkdir(dir, { recursive: true })));
790
+ const dev = env.NODE_ENV !== "production";
791
+ const build2 = async (src) => {
792
+ const memoized = cache.get(src);
793
+ if (memoized)
794
+ return memoized;
795
+ const raw = await file(src).text();
796
+ const isModule = src.endsWith(".svelte.ts") || src.endsWith(".svelte.js");
797
+ const preprocessed = isModule ? raw : (await preprocess(raw, {})).code;
798
+ const transpiled = src.endsWith(".ts") || src.endsWith(".svelte.ts") ? transpiler.transformSync(preprocessed) : preprocessed;
799
+ const relDir = dirname(relative(svelteRoot, src)).replace(/\\/g, "/");
800
+ const baseName = basename(src).replace(/\.svelte(\.(ts|js))?$/, "");
801
+ const importPaths = Array.from(transpiled.matchAll(/from\s+['"]([^'"]+)['"]/g)).map((match) => match[1]).filter((path) => path !== undefined);
802
+ const resolvedImports = await Promise.all(importPaths.map((importPath) => resolveSvelte(importPath, src)));
803
+ const childSources = resolvedImports.filter((path) => path !== null);
804
+ await Promise.all(childSources.map((child) => build2(child)));
805
+ const generate = (mode) => (isModule ? compileModule(transpiled, { dev, filename: src }).js.code : compile(transpiled, {
806
+ css: "injected",
807
+ dev,
808
+ filename: src,
809
+ generate: mode
810
+ }).js.code).replace(/\.svelte(?:\.(?:ts|js))?(['"])/g, ".js$1");
811
+ const ssrPath = join(pagesDir, relDir, `${baseName}.js`);
812
+ const clientPath = join(clientDir, relDir, `${baseName}.js`);
813
+ await Promise.all([
814
+ mkdir(dirname(ssrPath), { recursive: true }),
815
+ mkdir(dirname(clientPath), { recursive: true })
816
+ ]);
817
+ if (isModule) {
818
+ const bundle = generate("client");
819
+ await Promise.all([
820
+ write(ssrPath, bundle),
821
+ write(clientPath, bundle)
822
+ ]);
823
+ } else {
824
+ const serverBundle = generate("server");
825
+ const clientBundle = generate("client");
826
+ await Promise.all([
827
+ write(ssrPath, serverBundle),
828
+ write(clientPath, clientBundle)
829
+ ]);
830
+ }
831
+ const built = { client: clientPath, ssr: ssrPath };
832
+ cache.set(src, built);
833
+ return built;
834
+ };
835
+ const roots = await Promise.all(entryPoints.map(build2));
836
+ await Promise.all(roots.map(async ({ client: client2 }) => {
837
+ const relClientDir = dirname(relative(clientDir, client2));
838
+ const name = basename(client2, extname(client2));
839
+ const indexPath = join(indexDir, relClientDir, `${name}.js`);
840
+ const importRaw = relative(dirname(indexPath), client2).split(sep).join("/");
841
+ const importPath = importRaw.startsWith(".") || importRaw.startsWith("/") ? importRaw : `./${importRaw}`;
842
+ const hmrImports = isDev ? `window.__HMR_FRAMEWORK__ = "svelte";
843
+ import "${hmrClientPath}";
844
+ ` : "";
845
+ const bootstrap = `${hmrImports}import Component from "${importPath}";
846
+ import { hydrate, mount, unmount } from "svelte";
847
+
848
+ var initialProps = (typeof window !== "undefined" && window.__INITIAL_PROPS__) ? window.__INITIAL_PROPS__ : {};
849
+ var isHMR = typeof window !== "undefined" && window.__SVELTE_COMPONENT__ !== undefined;
850
+ var component;
851
+
852
+ if (isHMR) {
853
+ var headLinks = document.querySelectorAll('link[rel="stylesheet"]');
854
+ var preservedLinks = [];
855
+ headLinks.forEach(function(link) {
856
+ var clone = link.cloneNode(true);
857
+ clone.setAttribute("data-hmr-preserve", "true");
858
+ document.head.appendChild(clone);
859
+ preservedLinks.push(clone);
860
+ });
861
+ if (typeof window.__SVELTE_UNMOUNT__ === "function") {
862
+ try { window.__SVELTE_UNMOUNT__(); } catch (err) { console.warn("[HMR] unmount error:", err); }
863
+ }
864
+ var preservedState = window.__HMR_PRESERVED_STATE__;
865
+ if (!preservedState) {
866
+ try {
867
+ var stored = sessionStorage.getItem("__SVELTE_HMR_STATE__");
868
+ if (stored) preservedState = JSON.parse(stored);
869
+ } catch (err) { /* ignore */ }
870
+ }
871
+ var mergedProps = preservedState ? Object.assign({}, initialProps, preservedState) : initialProps;
872
+ component = mount(Component, { target: document.body, props: mergedProps });
873
+ requestAnimationFrame(function() {
874
+ preservedLinks.forEach(function(link) { link.remove(); });
875
+ });
876
+ window.__HMR_PRESERVED_STATE__ = undefined;
877
+ } else {
878
+ component = hydrate(Component, { target: document.body, props: initialProps });
879
+ }
880
+
881
+ if (typeof window !== "undefined") {
882
+ window.__SVELTE_COMPONENT__ = component;
883
+ window.__SVELTE_UNMOUNT__ = function() { unmount(component); };
884
+ }`;
885
+ await mkdir(dirname(indexPath), { recursive: true });
886
+ return write(indexPath, bootstrap);
887
+ }));
888
+ return {
889
+ svelteIndexPaths: roots.map(({ client: client2 }) => {
890
+ const rel = dirname(relative(clientDir, client2));
891
+ return join(indexDir, rel, basename(client2));
892
+ }),
893
+ svelteClientPaths: roots.map(({ client: client2 }) => client2),
894
+ svelteServerPaths: roots.map(({ ssr }) => ssr)
895
+ };
896
+ };
897
+
898
+ // src/core/build.ts
899
+ init_compileVue();
900
+
901
+ // src/build/generateManifest.ts
902
+ init_constants();
903
+ import { extname as extname2 } from "path";
904
+
905
+ // src/utils/normalizePath.ts
906
+ var normalizePath = (path) => path.replace(/\\/g, "/");
907
+
908
+ // src/build/generateManifest.ts
909
+ var generateManifest = (outputs, buildPath) => outputs.reduce((manifest, artifact) => {
910
+ const normalizedArtifactPath = normalizePath(artifact.path);
911
+ const normalizedBuildPath = normalizePath(buildPath);
912
+ let relative3 = normalizedArtifactPath.startsWith(normalizedBuildPath) ? normalizedArtifactPath.slice(normalizedBuildPath.length) : normalizedArtifactPath;
913
+ relative3 = relative3.replace(/^\/+/, "");
914
+ const segments = relative3.split("/");
915
+ const fileWithHash = segments.pop();
916
+ if (!fileWithHash)
917
+ return manifest;
918
+ const [baseName] = fileWithHash.split(`.${artifact.hash}.`);
919
+ if (!baseName)
920
+ return manifest;
921
+ const pascalName = toPascal(baseName);
922
+ const ext = extname2(fileWithHash);
923
+ if (ext === ".css") {
924
+ manifest[`${pascalName}CSS`] = `/${relative3}`;
925
+ return manifest;
926
+ }
927
+ const idx = segments.findIndex((seg) => seg === "indexes" || seg === "pages" || seg === "client");
928
+ const folder = idx > UNFOUND_INDEX ? segments[idx] : segments[0];
929
+ const isReact = segments.some((seg) => seg === "react");
930
+ const isVue = segments.some((seg) => seg === "vue");
931
+ const isSvelte = segments.some((seg) => seg === "svelte");
932
+ const isClientComponent = segments.includes("client");
933
+ if (folder === "indexes") {
934
+ manifest[`${pascalName}Index`] = `/${relative3}`;
935
+ } else if (isClientComponent) {
936
+ manifest[`${pascalName}Client`] = `/${relative3}`;
937
+ } else if (folder === "pages") {
938
+ if (isReact) {
939
+ manifest[`${pascalName}Page`] = `/${relative3}`;
940
+ } else if (isVue || isSvelte) {
941
+ manifest[pascalName] = `/${relative3}`;
942
+ } else {
943
+ manifest[`${pascalName}Page`] = `/${relative3}`;
944
+ }
945
+ } else {
946
+ manifest[pascalName] = `/${relative3}`;
947
+ }
948
+ return manifest;
949
+ }, {});
950
+
951
+ // src/build/generateReactIndexes.ts
952
+ import { existsSync as existsSync3 } from "fs";
953
+ import { mkdir as mkdir3, rm, writeFile } from "fs/promises";
954
+ import { basename as basename3, join as join3, resolve as resolve3 } from "path";
955
+ var {Glob } = globalThis.Bun;
956
+ var devClientDir3 = (() => {
957
+ const fromSource = resolve3(import.meta.dir, "../dev/client");
958
+ if (existsSync3(fromSource))
959
+ return fromSource;
960
+ return resolve3(import.meta.dir, "./dev/client");
961
+ })();
962
+ var hmrClientPath3 = join3(devClientDir3, "hmrClient.ts").replace(/\\/g, "/");
963
+ var refreshSetupPath = join3(devClientDir3, "reactRefreshSetup.ts").replace(/\\/g, "/");
964
+ var generateReactIndexFiles = async (reactPagesDirectory, reactIndexesDirectory, isDev = false) => {
965
+ await rm(reactIndexesDirectory, { force: true, recursive: true });
966
+ await mkdir3(reactIndexesDirectory);
967
+ const pagesGlob = new Glob("*.*");
968
+ const files = [];
969
+ for await (const file3 of pagesGlob.scan({ cwd: reactPagesDirectory })) {
970
+ files.push(file3);
971
+ }
972
+ const promises = files.map(async (file3) => {
973
+ const fileName = basename3(file3);
974
+ const [componentName] = fileName.split(".");
975
+ const hmrPreamble = isDev ? [
976
+ `window.__HMR_FRAMEWORK__ = "react";`,
977
+ `window.__REACT_COMPONENT_KEY__ = "${componentName}Index";`,
978
+ `import '${refreshSetupPath}';`,
979
+ `import '${hmrClientPath3}';
980
+ `
981
+ ] : [];
982
+ const content = [
983
+ ...hmrPreamble,
984
+ `import { hydrateRoot, createRoot } from 'react-dom/client';`,
985
+ `import { createElement } from 'react';`,
986
+ `import type { ComponentType } from 'react'`,
987
+ `import { ${componentName} } from '../pages/${componentName}';
988
+ `,
989
+ `type PropsOf<C> = C extends ComponentType<infer P> ? P : never;
990
+ `,
991
+ `declare global {`,
992
+ ` interface Window {`,
993
+ ` __INITIAL_PROPS__?: PropsOf<typeof ${componentName}>`,
994
+ ` __REACT_ROOT__?: ReturnType<typeof hydrateRoot | typeof createRoot>`,
995
+ ` __HMR_CLIENT_ONLY_MODE__?: boolean`,
996
+ ` }`,
997
+ `}
998
+ `,
999
+ `// Hydration with error handling and fallback`,
1000
+ `const isDev = ${isDev};`,
1001
+ `const componentPath = '../pages/${componentName}';
1002
+ `,
1003
+ `function isHydrationError(error) {`,
1004
+ ` if (!error) return false;`,
1005
+ ` const errorMessage = error instanceof Error ? error.message : String(error);`,
1006
+ ` const errorString = String(error);`,
1007
+ ` const fullMessage = errorMessage + ' ' + errorString;`,
1008
+ ` const hydrationKeywords = ['hydration', 'Hydration', 'mismatch', 'Mismatch', 'did not match', 'server rendered HTML', 'server HTML', 'client HTML', 'Hydration failed'];`,
1009
+ ` const isHydration = hydrationKeywords.some(keyword => fullMessage.includes(keyword));`,
1010
+ ` `,
1011
+ ` // Ignore whitespace-only mismatches in <head> - these are harmless formatting differences`,
1012
+ ` // The error often shows: + <link...> vs - {"\\n "} which is just formatting`,
1013
+ ` if (isHydration) {`,
1014
+ ` // Check if this is a head/link/stylesheet related mismatch`,
1015
+ ` const isHeadRelated = fullMessage.includes('<head') || fullMessage.includes('</head>') || fullMessage.includes('head>') || fullMessage.includes('<link') || fullMessage.includes('link>') || fullMessage.includes('stylesheet') || fullMessage.includes('fonts.googleapis') || fullMessage.includes('rel="stylesheet"');`,
1016
+ ` `,
1017
+ ` // Check if the mismatch involves only whitespace/newlines`,
1018
+ ` // Pattern: looks for {"\\n"} or {"\\n "} or similar whitespace-only content`,
1019
+ ` // Also check for patterns like: - {"\\n "} or + <link...>`,
1020
+ ` const hasWhitespacePattern = /\\{\\s*["']\\\\n[^"']*["']\\s*\\}/.test(fullMessage) || /\\{\\s*["'][\\\\n\\\\r\\\\s]+["']\\s*\\}/.test(fullMessage) || /-\\s*\\{\\s*["'][\\\\n\\\\r\\\\s]+["']\\s*\\}/.test(fullMessage);`,
1021
+ ` const isWhitespaceOnly = /^[\\s\\n\\r]*$/.test(errorString) || /^[\\s\\n\\r]*$/.test(errorMessage);`,
1022
+ ` const hasNewlinePattern = fullMessage.includes('\\\\n') || fullMessage.includes('\\\\r') || fullMessage.includes('\\n') || fullMessage.includes('\\r');`,
1023
+ ` `,
1024
+ ` // If it's head-related and involves whitespace/newlines, ignore it`,
1025
+ ` if (isHeadRelated && (hasWhitespacePattern || isWhitespaceOnly || hasNewlinePattern)) {`,
1026
+ ` return false; // Don't treat whitespace-only head mismatches as errors`,
1027
+ ` }`,
1028
+ ` }`,
1029
+ ` return isHydration;`,
1030
+ `}
1031
+ `,
1032
+ `function logHydrationError(error, componentName) {`,
1033
+ ` if (!isDev) return;`,
1034
+ ` if (window.__HMR_WS__ && window.__HMR_WS__.readyState === WebSocket.OPEN) {`,
1035
+ ` try {`,
1036
+ ` window.__HMR_WS__.send(JSON.stringify({`,
1037
+ ` type: 'hydration-error',`,
1038
+ ` data: {`,
1039
+ ` componentName: '${componentName}',`,
1040
+ ` componentPath: componentPath,`,
1041
+ ` error: error instanceof Error ? error.message : String(error),`,
1042
+ ` timestamp: Date.now()`,
1043
+ ` }`,
1044
+ ` }));`,
1045
+ ` } catch (err) {}`,
1046
+ ` }`,
1047
+ `}
1048
+ `,
1049
+ `// Track if we've already switched to client-only mode`,
1050
+ `let hasSwitchedToClientOnly = false;`,
1051
+ `let hydrationErrorDetected = false;
1052
+ `,
1053
+ `function handleHydrationFallback(error) {`,
1054
+ ` if (hasSwitchedToClientOnly) return; // Already handled`,
1055
+ ` hasSwitchedToClientOnly = true;`,
1056
+ ` hydrationErrorDetected = true;
1057
+ `,
1058
+ ` logHydrationError(error, '${componentName}');
1059
+ `,
1060
+ ` // Fallback: client-only render (no hydration)`,
1061
+ ` try {`,
1062
+ ` // Unmount existing root if it exists`,
1063
+ ` if (window.__REACT_ROOT__ && typeof window.__REACT_ROOT__.unmount === 'function') {`,
1064
+ ` try {`,
1065
+ ` window.__REACT_ROOT__.unmount();`,
1066
+ ` } catch (e) {`,
1067
+ ` // Ignore unmount errors`,
1068
+ ` }`,
1069
+ ` }
1070
+ `,
1071
+ ` // Render into the same root container when falling back to client-only`,
1072
+ ` const root = createRoot(container);`,
1073
+ ` root.render(createElement(${componentName}, mergedProps));`,
1074
+ ` window.__REACT_ROOT__ = root;`,
1075
+ ` window.__HMR_CLIENT_ONLY_MODE__ = true;`,
1076
+ ` } catch (fallbackError) {`,
1077
+ ` window.location.reload();`,
1078
+ ` }`,
1079
+ `}
1080
+ `,
1081
+ `// HMR State Preservation: Check for preserved state and merge with initial props`,
1082
+ `// This allows state to be preserved across HMR updates without modifying component files`,
1083
+ `let preservedState = (typeof window !== 'undefined' && window.__HMR_PRESERVED_STATE__) ? window.__HMR_PRESERVED_STATE__ : {};
1084
+ `,
1085
+ `// Also check sessionStorage for state that survived a page reload (for React HMR)`,
1086
+ `if (typeof window !== 'undefined' && typeof sessionStorage !== 'undefined') {`,
1087
+ ` const hmrStateJson = sessionStorage.getItem('__REACT_HMR_STATE__');`,
1088
+ ` if (hmrStateJson) {`,
1089
+ ` try {`,
1090
+ ` const hmrState = JSON.parse(hmrStateJson);`,
1091
+ ` preservedState = { ...preservedState, ...hmrState };`,
1092
+ ` sessionStorage.removeItem('__REACT_HMR_STATE__');`,
1093
+ ` } catch (e) {}`,
1094
+ ` }`,
1095
+ `}
1096
+ `,
1097
+ `const mergedProps = { ...(window.__INITIAL_PROPS__ || {}), ...preservedState };`,
1098
+ `// Clear preserved state after using it (so it doesn't persist across multiple updates)`,
1099
+ `if (typeof window !== 'undefined') {`,
1100
+ ` window.__HMR_PRESERVED_STATE__ = undefined;`,
1101
+ `}
1102
+ `,
1103
+ `// Attempt hydration with error handling`,
1104
+ `// Use document (not document.body) when the page renders <html><head><body>`,
1105
+ `// to avoid "In HTML, <html> cannot be a child of <body>" hydration error`,
1106
+ `const container = typeof document !== 'undefined' ? document : null;`,
1107
+ `if (!container) {`,
1108
+ ` throw new Error('React root container not found: document is null');`,
1109
+ `}
1110
+ `,
1111
+ `// Guard: only hydrate on first load. During HMR re-imports, skip hydration`,
1112
+ `// so React Fast Refresh can swap components in-place and preserve state.`,
1113
+ `if (!window.__REACT_ROOT__) {`,
1114
+ ` let root;`,
1115
+ ` try {`,
1116
+ ` // Use onRecoverableError to catch hydration errors (React 19)`,
1117
+ ` root = hydrateRoot(`,
1118
+ ` container,`,
1119
+ ` createElement(${componentName}, mergedProps),`,
1120
+ ` {`,
1121
+ ` onRecoverableError: (error) => {`,
1122
+ ` // Check if this is a hydration error (isHydrationError filters out whitespace-only head mismatches)`,
1123
+ ` if (isDev && isHydrationError(error)) {`,
1124
+ ` // Real hydration error - handle it`,
1125
+ ` handleHydrationFallback(error);`,
1126
+ ` } else {`,
1127
+ ` // Not a hydration error, or it's a whitespace-only mismatch that was filtered out`,
1128
+ ` // Check if it's a whitespace-only head mismatch using the same logic as isHydrationError`,
1129
+ ` const errorMessage = error instanceof Error ? error.message : String(error);`,
1130
+ ` const errorString = String(error);`,
1131
+ ` const fullMessage = errorMessage + ' ' + errorString;`,
1132
+ ` const hydrationKeywords = ['hydration', 'Hydration', 'mismatch', 'Mismatch', 'did not match', 'server rendered HTML', 'server HTML', 'client HTML', 'Hydration failed'];`,
1133
+ ` const isHydration = hydrationKeywords.some(keyword => fullMessage.includes(keyword));`,
1134
+ ` if (isHydration) {`,
1135
+ ` // Check if this is a head/link/stylesheet related mismatch`,
1136
+ ` const isHeadRelated = fullMessage.includes('<head') || fullMessage.includes('</head>') || fullMessage.includes('head>') || fullMessage.includes('<link') || fullMessage.includes('link>') || fullMessage.includes('stylesheet') || fullMessage.includes('fonts.googleapis') || fullMessage.includes('rel="stylesheet"');`,
1137
+ ` // Check if the mismatch involves only whitespace/newlines`,
1138
+ ` const hasWhitespacePattern = /\\{\\s*["']\\\\n[^"']*["']\\s*\\}/.test(fullMessage) || /\\{\\s*["'][\\\\n\\\\r\\\\s]+["']\\s*\\}/.test(fullMessage) || /-\\s*\\{\\s*["'][\\\\n\\\\r\\\\s]+["']\\s*\\}/.test(fullMessage);`,
1139
+ ` const isWhitespaceOnly = /^[\\s\\n\\r]*$/.test(errorString) || /^[\\s\\n\\r]*$/.test(errorMessage);`,
1140
+ ` const hasNewlinePattern = fullMessage.includes('\\\\n') || fullMessage.includes('\\\\r') || fullMessage.includes('\\n') || fullMessage.includes('\\r');`,
1141
+ ` // If it's head-related and involves whitespace/newlines, silently ignore it`,
1142
+ ` if (isHeadRelated && (hasWhitespacePattern || isWhitespaceOnly || hasNewlinePattern)) {`,
1143
+ ` // Already logged by isHydrationError, just return silently`,
1144
+ ` return;`,
1145
+ ` }`,
1146
+ ` }`,
1147
+ ` // Log other recoverable errors`,
1148
+ ` console.error('React recoverable error:', error);`,
1149
+ ` }`,
1150
+ ` }`,
1151
+ ` }`,
1152
+ ` );`,
1153
+ ` window.__REACT_ROOT__ = root;`,
1154
+ ` } catch (error) {`,
1155
+ ` // Catch synchronous errors (shouldn't happen with hydrateRoot, but safety net)`,
1156
+ ` if (isDev && isHydrationError(error)) {`,
1157
+ ` handleHydrationFallback(error);`,
1158
+ ` } else {`,
1159
+ ` throw error;`,
1160
+ ` }`,
1161
+ ` }
1162
+ `,
1163
+ ` // Also listen for hydration errors via console.error (React logs them there)`,
1164
+ ` if (isDev) {`,
1165
+ ` const originalError = console.error;`,
1166
+ ` console.error = function(...args) {`,
1167
+ ` const errorMessage = args.map(arg => {`,
1168
+ ` if (arg instanceof Error) return arg.message;`,
1169
+ ` return String(arg);`,
1170
+ ` }).join(' ');`,
1171
+ ` `,
1172
+ ` // Check if this is a hydration error`,
1173
+ ` if (isHydrationError({ message: errorMessage }) && !hydrationErrorDetected) {`,
1174
+ ` hydrationErrorDetected = true;`,
1175
+ ` // Create a synthetic error for fallback`,
1176
+ ` const syntheticError = new Error(errorMessage);`,
1177
+ ` // Use setTimeout to ensure this happens after React's error handling`,
1178
+ ` setTimeout(() => {`,
1179
+ ` handleHydrationFallback(syntheticError);`,
1180
+ ` }, 0);`,
1181
+ ` }`,
1182
+ ` `,
1183
+ ` // Call original console.error`,
1184
+ ` originalError.apply(console, args);`,
1185
+ ` };`,
1186
+ ` }`,
1187
+ `}`
1188
+ ].join(`
1189
+ `);
1190
+ return writeFile(join3(reactIndexesDirectory, `${componentName}.tsx`), content);
1191
+ });
1192
+ await Promise.all(promises);
1193
+ if (isDev) {
1194
+ await writeFile(join3(reactIndexesDirectory, "_refresh.tsx"), `import 'react';
1195
+ import 'react-dom/client';
1196
+ `);
1197
+ }
1198
+ };
1199
+
1200
+ // src/build/wrapHTMLScript.ts
1201
+ var wrapHTMLScriptWithHMR = (code, scriptId) => {
1202
+ const escapedId = JSON.stringify(scriptId);
1203
+ return `${code}
1204
+
1205
+ // HMR acceptance - allows this script to be hot-reloaded
1206
+ if (typeof import.meta !== "undefined" && import.meta.hot) {
1207
+ import.meta.hot.accept();
1208
+ console.log('[HMR] Script ready:', ${escapedId});
1209
+ }
1210
+ `;
1211
+ };
1212
+
1213
+ // src/build/htmlScriptHMRPlugin.ts
1214
+ var createHTMLScriptHMRPlugin = (htmlDir, htmxDir) => {
1215
+ return {
1216
+ name: "html-script-hmr",
1217
+ setup(build2) {
1218
+ build2.onLoad({ filter: /\.(ts|js|tsx|jsx)$/ }, async (args) => {
1219
+ const normalizedPath = args.path.replace(/\\/g, "/");
1220
+ const isHtmlScript = htmlDir && normalizedPath.includes(htmlDir.replace(/\\/g, "/")) && normalizedPath.includes("/scripts/");
1221
+ const isHtmxScript = htmxDir && normalizedPath.includes(htmxDir.replace(/\\/g, "/")) && normalizedPath.includes("/scripts/");
1222
+ if (!isHtmlScript && !isHtmxScript) {
1223
+ return;
1224
+ }
1225
+ const text = await Bun.file(args.path).text();
1226
+ const wrapped = wrapHTMLScriptWithHMR(text, normalizedPath);
1227
+ const ext = args.path.split(".").pop() || "ts";
1228
+ const loader = ext;
1229
+ return {
1230
+ contents: wrapped,
1231
+ loader
1232
+ };
1233
+ });
1234
+ }
1235
+ };
1236
+ };
1237
+
1238
+ // src/build/outputLogs.ts
1239
+ init_constants();
1240
+ var outputLogs = (logs) => {
1241
+ for (const log of logs) {
1242
+ if (log.message.includes(BUN_BUILD_WARNING_SUPPRESSION))
1243
+ continue;
1244
+ if (log.level === "error")
1245
+ console.error(log);
1246
+ else if (log.level === "warning")
1247
+ console.warn(log);
1248
+ else
1249
+ console.info(log);
1250
+ }
1251
+ };
1252
+
1253
+ // src/build/scanEntryPoints.ts
1254
+ var {Glob: Glob2 } = globalThis.Bun;
1255
+ var scanEntryPoints = async (dir, pattern) => {
1256
+ const entryPaths = [];
1257
+ const glob = new Glob2(pattern);
411
1258
  for await (const file3 of glob.scan({ absolute: true, cwd: dir })) {
412
1259
  entryPaths.push(file3);
413
1260
  }
@@ -433,6 +1280,13 @@ var updateAssetPaths = async (manifest, directory) => {
433
1280
  }
434
1281
  const newPath = manifest[key];
435
1282
  if (newPath) {
1283
+ if (ext === ".js" || ext === ".ts") {
1284
+ const hasTypeModule = /type\s*=\s*["']module["']/i.test(match);
1285
+ if (!hasTypeModule) {
1286
+ const newSuffix = suffix.replace(/>$/, ' type="module">');
1287
+ return `${prefix}${newPath}${newSuffix}`;
1288
+ }
1289
+ }
436
1290
  return `${prefix}${newPath}${suffix}`;
437
1291
  }
438
1292
  console.error(`error: no manifest entry for ${ext.slice(1)} "${name}" referenced in ${filePath}`);
@@ -443,6 +1297,24 @@ var updateAssetPaths = async (manifest, directory) => {
443
1297
  await Promise.all(tasks);
444
1298
  };
445
1299
 
1300
+ // src/dev/buildHMRClient.ts
1301
+ var {build: bunBuild } = globalThis.Bun;
1302
+ import { resolve as resolve4 } from "path";
1303
+ var buildHMRClient = async () => {
1304
+ const entryPoint = resolve4(import.meta.dir, "client/hmrClient.ts");
1305
+ const result = await bunBuild({
1306
+ entrypoints: [entryPoint],
1307
+ format: "iife",
1308
+ minify: false,
1309
+ target: "browser"
1310
+ });
1311
+ if (!result.success) {
1312
+ console.error("Failed to build HMR client:", result.logs);
1313
+ return "// HMR client build failed";
1314
+ }
1315
+ return await result.outputs[0].text();
1316
+ };
1317
+
446
1318
  // src/utils/cleanup.ts
447
1319
  import { rm as rm2 } from "fs/promises";
448
1320
  import { join as join4 } from "path";
@@ -462,19 +1334,19 @@ var cleanup = async ({
462
1334
  };
463
1335
 
464
1336
  // src/utils/commonAncestor.ts
465
- import { sep as sep2 } from "path";
466
1337
  var commonAncestor = (paths, fallback) => {
467
1338
  if (paths.length === 0)
468
1339
  return fallback;
469
- const segmentsList = paths.map((p) => p.split(sep2));
1340
+ const segmentsList = paths.map((p) => normalizePath(p).split("/"));
470
1341
  const [first] = segmentsList;
471
1342
  if (!first)
472
1343
  return fallback;
473
1344
  const commonSegments = first.filter((segment, index) => segmentsList.every((pathSegs) => pathSegs[index] === segment));
474
- return commonSegments.length ? commonSegments.join(sep2) : fallback;
1345
+ return commonSegments.length ? commonSegments.join("/") : fallback;
475
1346
  };
476
1347
 
477
1348
  // src/utils/getDurationString.ts
1349
+ init_constants();
478
1350
  var getDurationString = (duration) => {
479
1351
  let durationString;
480
1352
  if (duration < MILLISECONDS_IN_A_SECOND) {
@@ -487,25 +1359,124 @@ var getDurationString = (duration) => {
487
1359
  return durationString;
488
1360
  };
489
1361
 
1362
+ // src/utils/logger.ts
1363
+ var colors = {
1364
+ reset: "\x1B[0m",
1365
+ bold: "\x1B[1m",
1366
+ dim: "\x1B[2m",
1367
+ cyan: "\x1B[36m",
1368
+ green: "\x1B[32m",
1369
+ yellow: "\x1B[33m",
1370
+ red: "\x1B[31m",
1371
+ blue: "\x1B[34m",
1372
+ magenta: "\x1B[35m",
1373
+ white: "\x1B[37m"
1374
+ };
1375
+ var frameworkColors = {
1376
+ react: colors.blue,
1377
+ vue: colors.green,
1378
+ svelte: colors.yellow,
1379
+ angular: colors.magenta,
1380
+ html: colors.white,
1381
+ htmx: colors.white,
1382
+ css: colors.cyan,
1383
+ assets: colors.dim
1384
+ };
1385
+ var formatTimestamp = () => {
1386
+ const now = new Date;
1387
+ let hours = now.getHours();
1388
+ const minutes = now.getMinutes().toString().padStart(2, "0");
1389
+ const seconds = now.getSeconds().toString().padStart(2, "0");
1390
+ const ampm = hours >= 12 ? "PM" : "AM";
1391
+ hours = hours % 12 || 12;
1392
+ return `${hours}:${minutes}:${seconds} ${ampm}`;
1393
+ };
1394
+ var formatPath = (filePath) => {
1395
+ const cwd = process.cwd();
1396
+ let relative3 = filePath.startsWith(cwd) ? filePath.slice(cwd.length + 1) : filePath;
1397
+ relative3 = relative3.replace(/\\/g, "/");
1398
+ if (!relative3.startsWith("/")) {
1399
+ relative3 = "/" + relative3;
1400
+ }
1401
+ return relative3;
1402
+ };
1403
+ var getFrameworkColor = (framework) => {
1404
+ return frameworkColors[framework] || colors.white;
1405
+ };
1406
+ var log = (action, options) => {
1407
+ const timestamp = `${colors.dim}${formatTimestamp()}${colors.reset}`;
1408
+ const tag = `${colors.cyan}[hmr]${colors.reset}`;
1409
+ let message = action;
1410
+ if (options?.path) {
1411
+ const pathColor = options.framework ? getFrameworkColor(options.framework) : colors.white;
1412
+ message += ` ${pathColor}${formatPath(options.path)}${colors.reset}`;
1413
+ }
1414
+ if (options?.duration !== undefined) {
1415
+ message += ` ${colors.dim}(${options.duration}ms)${colors.reset}`;
1416
+ }
1417
+ console.log(`${timestamp} ${tag} ${message}`);
1418
+ };
1419
+ var logError = (message, error) => {
1420
+ const timestamp = `${colors.dim}${formatTimestamp()}${colors.reset}`;
1421
+ const tag = `${colors.red}[hmr]${colors.reset}`;
1422
+ const errorMsg = error instanceof Error ? error.message : error;
1423
+ const fullMessage = `${colors.red}error${colors.reset} ${message}${errorMsg ? `: ${errorMsg}` : ""}`;
1424
+ console.error(`${timestamp} ${tag} ${fullMessage}`);
1425
+ };
1426
+ var logWarn = (message) => {
1427
+ const timestamp = `${colors.dim}${formatTimestamp()}${colors.reset}`;
1428
+ const tag = `${colors.yellow}[hmr]${colors.reset}`;
1429
+ console.warn(`${timestamp} ${tag} ${colors.yellow}warning${colors.reset} ${message}`);
1430
+ };
1431
+ var logger = {
1432
+ hmrUpdate(path, framework) {
1433
+ log("hmr update", { path, framework });
1434
+ },
1435
+ pageReload(path, framework) {
1436
+ log("page reload", { path, framework });
1437
+ },
1438
+ cssUpdate(path, framework) {
1439
+ log("css update", { path, framework: framework ?? "css" });
1440
+ },
1441
+ scriptUpdate(path, framework) {
1442
+ log("script update", { path, framework });
1443
+ },
1444
+ rebuilt(duration) {
1445
+ const timestamp = `${colors.dim}${formatTimestamp()}${colors.reset}`;
1446
+ const tag = `${colors.cyan}[hmr]${colors.reset}`;
1447
+ const message = `${colors.green}rebuilt${colors.reset} ${colors.dim}(${duration}ms)${colors.reset}`;
1448
+ console.log(`${timestamp} ${tag} ${message}`);
1449
+ },
1450
+ error(message, error) {
1451
+ logError(message, error);
1452
+ },
1453
+ warn(message) {
1454
+ logWarn(message);
1455
+ },
1456
+ info(message) {
1457
+ log(message);
1458
+ }
1459
+ };
490
1460
  // src/utils/validateSafePath.ts
491
- import { resolve as resolve3, relative as relative3, sep as sep3 } from "path";
1461
+ import { resolve as resolve5, relative as relative3 } from "path";
492
1462
  var validateSafePath = (targetPath, baseDirectory) => {
493
- const absoluteBase = resolve3(baseDirectory);
494
- const absoluteTarget = resolve3(baseDirectory, targetPath);
495
- if (relative3(absoluteBase, absoluteTarget).startsWith(`..${sep3}`)) {
1463
+ const absoluteBase = resolve5(baseDirectory);
1464
+ const absoluteTarget = resolve5(baseDirectory, targetPath);
1465
+ const relativePath = normalizePath(relative3(absoluteBase, absoluteTarget));
1466
+ if (relativePath.startsWith("../") || relativePath === "..") {
496
1467
  throw new Error(`Unsafe path: ${targetPath}`);
497
1468
  }
498
1469
  return absoluteTarget;
499
1470
  };
500
1471
 
501
1472
  // src/core/build.ts
502
- var isDev = env2.NODE_ENV === "development";
1473
+ var isDev = env2.NODE_ENV !== "production";
503
1474
  var vueFeatureFlags = {
504
1475
  __VUE_OPTIONS_API__: "true",
505
1476
  __VUE_PROD_DEVTOOLS__: isDev ? "true" : "false",
506
1477
  __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: isDev ? "true" : "false"
507
1478
  };
508
- var build = async ({
1479
+ var build2 = async ({
509
1480
  buildDirectory = "build",
510
1481
  assetsDirectory,
511
1482
  publicDirectory,
@@ -516,10 +1487,17 @@ var build = async ({
516
1487
  svelteDirectory,
517
1488
  vueDirectory,
518
1489
  tailwind,
519
- options
1490
+ options,
1491
+ incrementalFiles
520
1492
  }) => {
521
1493
  const buildStart = performance.now();
522
1494
  const projectRoot = cwd();
1495
+ const isIncremental = incrementalFiles && incrementalFiles.length > 0;
1496
+ const normalizedIncrementalFiles = incrementalFiles?.map(normalizePath);
1497
+ if (isIncremental) {
1498
+ console.log(`\u26A1 Incremental build: ${incrementalFiles.length} file(s) to rebuild`);
1499
+ }
1500
+ const throwOnError = options?.throwOnError === true;
523
1501
  const buildPath = validateSafePath(buildDirectory, projectRoot);
524
1502
  const assetsPath = assetsDirectory && validateSafePath(assetsDirectory, projectRoot);
525
1503
  const reactDir = reactDirectory && validateSafePath(reactDirectory, projectRoot);
@@ -545,6 +1523,14 @@ var build = async ({
545
1523
  angularDir
546
1524
  ].filter(Boolean);
547
1525
  const isSingle = frontends.length === 1;
1526
+ const clientRoots = [
1527
+ reactDir,
1528
+ svelteDir,
1529
+ htmlDir,
1530
+ vueDir,
1531
+ angularDir
1532
+ ].filter((dir) => Boolean(dir));
1533
+ const clientRoot = isSingle ? clientRoots[0] ?? projectRoot : commonAncestor(clientRoots, projectRoot);
548
1534
  let serverOutDir;
549
1535
  if (svelteDir)
550
1536
  serverOutDir = join5(buildPath, basename4(svelteDir), "pages");
@@ -556,36 +1542,82 @@ var build = async ({
556
1542
  else if (vuePagesPath)
557
1543
  serverRoot = vuePagesPath;
558
1544
  const publicPath = publicDirectory && validateSafePath(publicDirectory, projectRoot);
559
- await rm3(buildPath, { force: true, recursive: true });
560
- mkdirSync(buildPath);
1545
+ if (!isIncremental) {
1546
+ await rm3(buildPath, { force: true, recursive: true });
1547
+ }
1548
+ mkdirSync(buildPath, { recursive: true });
561
1549
  if (publicPath)
562
1550
  cpSync(publicPath, buildPath, { force: true, recursive: true });
563
- if (reactIndexesPath && reactPagesPath)
564
- await generateReactIndexFiles(reactPagesPath, reactIndexesPath);
565
- if (assetsPath)
1551
+ const filterToIncrementalEntries = (entryPoints, mapToSource) => {
1552
+ if (!isIncremental || !incrementalFiles)
1553
+ return entryPoints;
1554
+ const normalizedIncremental = new Set(incrementalFiles.map((f) => resolve6(f)));
1555
+ const matchingEntries = [];
1556
+ for (const entry of entryPoints) {
1557
+ const sourceFile = mapToSource(entry);
1558
+ if (sourceFile && normalizedIncremental.has(resolve6(sourceFile))) {
1559
+ matchingEntries.push(entry);
1560
+ }
1561
+ }
1562
+ return matchingEntries;
1563
+ };
1564
+ if (reactIndexesPath && reactPagesPath) {
1565
+ await generateReactIndexFiles(reactPagesPath, reactIndexesPath, isDev);
1566
+ }
1567
+ if (assetsPath && (!isIncremental || normalizedIncrementalFiles?.some((f) => f.includes("/assets/")))) {
566
1568
  cpSync(assetsPath, join5(buildPath, "assets"), {
567
1569
  force: true,
568
1570
  recursive: true
569
1571
  });
570
- if (tailwind)
1572
+ }
1573
+ if (tailwind && (!isIncremental || normalizedIncrementalFiles?.some((f) => f.endsWith(".css")))) {
571
1574
  await $`bunx @tailwindcss/cli -i ${tailwind.input} -o ${join5(buildPath, tailwind.output)}`;
572
- const reactEntries = reactIndexesPath ? await scanEntryPoints(reactIndexesPath, "*.tsx") : [];
573
- const htmlEntries = htmlScriptsPath ? await scanEntryPoints(htmlScriptsPath, "*.{js,ts}") : [];
574
- const svelteEntries = sveltePagesPath ? await scanEntryPoints(sveltePagesPath, "*.svelte") : [];
575
- const vueEntries = vuePagesPath ? await scanEntryPoints(vuePagesPath, "*.vue") : [];
576
- const angularEntries = angularPagesPath ? await scanEntryPoints(angularPagesPath, "*.ts") : [];
577
- const htmlCssEntries = htmlDir ? await scanEntryPoints(join5(htmlDir, "styles"), "*.css") : [];
578
- const htmxCssEntries = htmxDir ? await scanEntryPoints(join5(htmxDir, "styles"), "*.css") : [];
579
- const reactCssEntries = reactDir ? await scanEntryPoints(join5(reactDir, "styles"), "*.css") : [];
580
- const svelteCssEntries = svelteDir ? await scanEntryPoints(join5(svelteDir, "styles"), "*.css") : [];
581
- const { svelteServerPaths, svelteClientPaths } = svelteDir ? await compileSvelte(svelteEntries, svelteDir) : { svelteClientPaths: [], svelteServerPaths: [] };
582
- const { vueServerPaths, vueIndexPaths, vueCssPaths } = vueDir ? await compileVue(vueEntries, vueDir) : { vueCssPaths: [], vueIndexPaths: [], vueServerPaths: [] };
1575
+ }
1576
+ const allReactEntries = reactIndexesPath ? await scanEntryPoints(reactIndexesPath, "*.tsx") : [];
1577
+ const allHtmlEntries = htmlScriptsPath ? await scanEntryPoints(htmlScriptsPath, "*.{js,ts}") : [];
1578
+ const allSvelteEntries = sveltePagesPath ? await scanEntryPoints(sveltePagesPath, "*.svelte") : [];
1579
+ const allVueEntries = vuePagesPath ? await scanEntryPoints(vuePagesPath, "*.vue") : [];
1580
+ const allAngularEntries = angularPagesPath ? await scanEntryPoints(angularPagesPath, "*.ts") : [];
1581
+ const allHtmlCssEntries = htmlDir ? await scanEntryPoints(join5(htmlDir, "styles"), "*.css") : [];
1582
+ const allHtmxCssEntries = htmxDir ? await scanEntryPoints(join5(htmxDir, "styles"), "*.css") : [];
1583
+ const allReactCssEntries = reactDir ? await scanEntryPoints(join5(reactDir, "styles"), "*.css") : [];
1584
+ const allSvelteCssEntries = svelteDir ? await scanEntryPoints(join5(svelteDir, "styles"), "*.css") : [];
1585
+ const shouldIncludeHtmlAssets = !isIncremental || normalizedIncrementalFiles?.some((f) => f.includes("/html/") && (f.endsWith(".html") || f.endsWith(".css")));
1586
+ const shouldIncludeHtmxAssets = !isIncremental || normalizedIncrementalFiles?.some((f) => f.includes("/htmx/") && (f.endsWith(".html") || f.endsWith(".css")));
1587
+ const reactEntries = isIncremental && reactIndexesPath && reactPagesPath ? filterToIncrementalEntries(allReactEntries, (entry) => {
1588
+ if (entry.startsWith(resolve6(reactIndexesPath))) {
1589
+ const pageName = basename4(entry, ".tsx");
1590
+ return join5(reactPagesPath, `${pageName}.tsx`);
1591
+ }
1592
+ return null;
1593
+ }) : allReactEntries;
1594
+ const htmlEntries = isIncremental && htmlScriptsPath && !shouldIncludeHtmlAssets ? filterToIncrementalEntries(allHtmlEntries, (entry) => entry) : allHtmlEntries;
1595
+ const svelteEntries = isIncremental ? filterToIncrementalEntries(allSvelteEntries, (entry) => entry) : allSvelteEntries;
1596
+ const vueEntries = isIncremental ? filterToIncrementalEntries(allVueEntries, (entry) => entry) : allVueEntries;
1597
+ const angularEntries = isIncremental ? filterToIncrementalEntries(allAngularEntries, (entry) => entry) : allAngularEntries;
1598
+ const htmlCssEntries = isIncremental && !shouldIncludeHtmlAssets ? filterToIncrementalEntries(allHtmlCssEntries, (entry) => entry) : allHtmlCssEntries;
1599
+ const htmxCssEntries = isIncremental && !shouldIncludeHtmxAssets ? filterToIncrementalEntries(allHtmxCssEntries, (entry) => entry) : allHtmxCssEntries;
1600
+ const reactCssEntries = isIncremental ? filterToIncrementalEntries(allReactCssEntries, (entry) => entry) : allReactCssEntries;
1601
+ const svelteCssEntries = isIncremental ? filterToIncrementalEntries(allSvelteCssEntries, (entry) => entry) : allSvelteCssEntries;
1602
+ const { svelteServerPaths, svelteIndexPaths, svelteClientPaths } = svelteDir ? await compileSvelte(svelteEntries, svelteDir, new Map, isDev) : {
1603
+ svelteClientPaths: [],
1604
+ svelteIndexPaths: [],
1605
+ svelteServerPaths: []
1606
+ };
1607
+ const { vueServerPaths, vueIndexPaths, vueClientPaths, vueCssPaths } = vueDir ? await compileVue(vueEntries, vueDir, isDev) : {
1608
+ vueClientPaths: [],
1609
+ vueCssPaths: [],
1610
+ vueIndexPaths: [],
1611
+ vueServerPaths: []
1612
+ };
583
1613
  const serverEntryPoints = [...svelteServerPaths, ...vueServerPaths];
584
- const clientEntryPoints = [
585
- ...reactEntries,
1614
+ const reactClientEntryPoints = [...reactEntries];
1615
+ const nonReactClientEntryPoints = [
1616
+ ...svelteIndexPaths,
586
1617
  ...svelteClientPaths,
587
1618
  ...htmlEntries,
588
- ...vueIndexPaths
1619
+ ...vueIndexPaths,
1620
+ ...vueClientPaths
589
1621
  ];
590
1622
  const cssEntryPoints = [
591
1623
  ...vueCssPaths,
@@ -594,244 +1626,1697 @@ var build = async ({
594
1626
  ...htmlCssEntries,
595
1627
  ...htmxCssEntries
596
1628
  ];
597
- if (serverEntryPoints.length === 0 && clientEntryPoints.length === 0 && htmxDir === undefined) {
598
- console.warn("No entry points found, manifest will be empty.");
1629
+ if (serverEntryPoints.length === 0 && reactClientEntryPoints.length === 0 && nonReactClientEntryPoints.length === 0 && htmxDir === undefined && htmlDir === undefined) {
1630
+ logger.warn("No entry points found, manifest will be empty");
599
1631
  return {};
600
1632
  }
601
1633
  let serverLogs = [];
602
1634
  let serverOutputs = [];
603
1635
  if (serverEntryPoints.length > 0) {
604
- const { logs, outputs } = await bunBuild({
1636
+ const result = await bunBuild2({
605
1637
  entrypoints: serverEntryPoints,
606
1638
  format: "esm",
607
1639
  naming: `[dir]/[name].[hash].[ext]`,
608
1640
  outdir: serverOutDir,
609
1641
  root: serverRoot,
610
- target: "bun"
611
- }).catch((err) => {
612
- console.error("Server build failed:", err);
613
- exit(1);
1642
+ target: "bun",
1643
+ throw: false
614
1644
  });
615
- serverLogs = logs;
616
- serverOutputs = outputs;
617
- }
618
- let clientLogs = [];
619
- let clientOutputs = [];
620
- if (clientEntryPoints.length > 0) {
621
- const roots = [
622
- reactDir,
623
- svelteDir,
624
- htmlDir,
625
- vueDir,
626
- angularDir
627
- ].filter((dir) => Boolean(dir));
628
- const clientRoot = isSingle ? roots[0] ?? projectRoot : commonAncestor(roots, projectRoot);
629
- const { logs, outputs } = await bunBuild({
630
- define: vueDirectory ? vueFeatureFlags : undefined,
631
- entrypoints: clientEntryPoints,
1645
+ serverLogs = result.logs;
1646
+ serverOutputs = result.outputs;
1647
+ if (!result.success && result.logs.length > 0) {
1648
+ const errLog = result.logs.find((l) => l.level === "error") ?? result.logs[0];
1649
+ const err = new Error(typeof errLog.message === "string" ? errLog.message : String(errLog.message));
1650
+ err.logs = result.logs;
1651
+ logger.error("Server build failed", err);
1652
+ if (throwOnError)
1653
+ throw err;
1654
+ exit(1);
1655
+ }
1656
+ }
1657
+ let reactClientLogs = [];
1658
+ let reactClientOutputs = [];
1659
+ if (isDev && reactIndexesPath && reactClientEntryPoints.length > 0) {
1660
+ const refreshEntry = join5(reactIndexesPath, "_refresh.tsx");
1661
+ if (!reactClientEntryPoints.includes(refreshEntry)) {
1662
+ reactClientEntryPoints.push(refreshEntry);
1663
+ }
1664
+ }
1665
+ if (reactClientEntryPoints.length > 0) {
1666
+ const reactBuildConfig = {
1667
+ entrypoints: reactClientEntryPoints,
632
1668
  format: "esm",
633
- minify: true,
1669
+ minify: !isDev,
634
1670
  naming: `[dir]/[name].[hash].[ext]`,
635
1671
  outdir: buildPath,
636
1672
  root: clientRoot,
637
- target: "browser"
638
- }).catch((err) => {
639
- console.error("Client build failed:", err);
1673
+ splitting: true,
1674
+ target: "browser",
1675
+ throw: false
1676
+ };
1677
+ if (isDev) {
1678
+ reactBuildConfig.reactFastRefresh = true;
1679
+ }
1680
+ const reactClientResult = await bunBuild2(reactBuildConfig);
1681
+ reactClientLogs = reactClientResult.logs;
1682
+ reactClientOutputs = reactClientResult.outputs;
1683
+ if (!reactClientResult.success && reactClientResult.logs.length > 0) {
1684
+ const errLog = reactClientResult.logs.find((l) => l.level === "error") ?? reactClientResult.logs[0];
1685
+ const err = new Error(typeof errLog.message === "string" ? errLog.message : String(errLog.message));
1686
+ err.logs = reactClientResult.logs;
1687
+ logger.error("React client build failed", err);
1688
+ if (throwOnError)
1689
+ throw err;
640
1690
  exit(1);
1691
+ }
1692
+ }
1693
+ let nonReactClientLogs = [];
1694
+ let nonReactClientOutputs = [];
1695
+ if (nonReactClientEntryPoints.length > 0) {
1696
+ const htmlScriptPlugin = isDev ? createHTMLScriptHMRPlugin(htmlDir, htmxDir) : undefined;
1697
+ const nonReactClientResult = await bunBuild2({
1698
+ define: vueDirectory ? vueFeatureFlags : undefined,
1699
+ entrypoints: nonReactClientEntryPoints,
1700
+ format: "esm",
1701
+ minify: !isDev,
1702
+ naming: `[dir]/[name].[hash].[ext]`,
1703
+ outdir: buildPath,
1704
+ plugins: htmlScriptPlugin ? [htmlScriptPlugin] : undefined,
1705
+ root: clientRoot,
1706
+ target: "browser",
1707
+ splitting: !isDev,
1708
+ throw: false
641
1709
  });
642
- clientLogs = logs;
643
- clientOutputs = outputs;
1710
+ nonReactClientLogs = nonReactClientResult.logs;
1711
+ nonReactClientOutputs = nonReactClientResult.outputs;
1712
+ if (!nonReactClientResult.success && nonReactClientResult.logs.length > 0) {
1713
+ const errLog = nonReactClientResult.logs.find((l) => l.level === "error") ?? nonReactClientResult.logs[0];
1714
+ const err = new Error(typeof errLog.message === "string" ? errLog.message : String(errLog.message));
1715
+ err.logs = nonReactClientResult.logs;
1716
+ logger.error("Non-React client build failed", err);
1717
+ if (throwOnError)
1718
+ throw err;
1719
+ exit(1);
1720
+ }
644
1721
  }
645
1722
  let cssLogs = [];
646
1723
  let cssOutputs = [];
647
1724
  if (cssEntryPoints.length > 0) {
648
- const { logs, outputs } = await bunBuild({
1725
+ const cssResult = await bunBuild2({
649
1726
  entrypoints: cssEntryPoints,
650
1727
  naming: `[name].[hash].[ext]`,
651
1728
  outdir: join5(buildPath, assetsPath ? basename4(assetsPath) : "assets", "css"),
652
- target: "browser"
653
- }).catch((err) => {
654
- console.error("CSS build failed:", err);
1729
+ target: "browser",
1730
+ throw: false
1731
+ });
1732
+ cssLogs = cssResult.logs;
1733
+ cssOutputs = cssResult.outputs;
1734
+ if (!cssResult.success && cssResult.logs.length > 0) {
1735
+ const errLog = cssResult.logs.find((l) => l.level === "error") ?? cssResult.logs[0];
1736
+ const err = new Error(typeof errLog.message === "string" ? errLog.message : String(errLog.message));
1737
+ err.logs = cssResult.logs;
1738
+ logger.error("CSS build failed", err);
1739
+ if (throwOnError)
1740
+ throw err;
655
1741
  exit(1);
1742
+ }
1743
+ }
1744
+ const allLogs = [
1745
+ ...serverLogs,
1746
+ ...reactClientLogs,
1747
+ ...nonReactClientLogs,
1748
+ ...cssLogs
1749
+ ];
1750
+ outputLogs(allLogs);
1751
+ const manifest = generateManifest([
1752
+ ...serverOutputs,
1753
+ ...reactClientOutputs,
1754
+ ...nonReactClientOutputs,
1755
+ ...cssOutputs
1756
+ ], buildPath);
1757
+ for (const artifact of serverOutputs) {
1758
+ const fileWithHash = basename4(artifact.path);
1759
+ const [baseName] = fileWithHash.split(`.${artifact.hash}.`);
1760
+ if (!baseName)
1761
+ continue;
1762
+ manifest[toPascal(baseName)] = artifact.path;
1763
+ }
1764
+ const htmlOrHtmlCssChanged = !isIncremental || normalizedIncrementalFiles?.some((f) => f.includes("/html/") && (f.endsWith(".html") || f.endsWith(".css")));
1765
+ const htmxOrHtmxCssChanged = !isIncremental || normalizedIncrementalFiles?.some((f) => f.includes("/htmx/") && (f.endsWith(".html") || f.endsWith(".css")));
1766
+ const shouldCopyHtml = htmlOrHtmlCssChanged;
1767
+ const shouldCopyHtmx = htmxOrHtmxCssChanged;
1768
+ const shouldUpdateHtmlAssetPaths = !isIncremental || normalizedIncrementalFiles?.some((f) => f.includes("/html/") && (f.endsWith(".html") || f.endsWith(".css")));
1769
+ const shouldUpdateHtmxAssetPaths = !isIncremental || normalizedIncrementalFiles?.some((f) => f.includes("/htmx/") && (f.endsWith(".html") || f.endsWith(".css")));
1770
+ const hmrClientBundle = isDev && (htmlDir || htmxDir) ? await buildHMRClient() : null;
1771
+ const injectHMRIntoHTMLFile = (filePath, framework) => {
1772
+ if (!hmrClientBundle)
1773
+ return;
1774
+ let html = readFileSync(filePath, "utf-8");
1775
+ if (html.includes("data-hmr-client"))
1776
+ return;
1777
+ const tag = `<script>window.__HMR_FRAMEWORK__="${framework}";</script>` + `<script data-hmr-client>${hmrClientBundle}</script>`;
1778
+ const bodyClose = /<\/body\s*>/i.exec(html);
1779
+ html = bodyClose ? html.slice(0, bodyClose.index) + tag + html.slice(bodyClose.index) : html + tag;
1780
+ writeFileSync(filePath, html);
1781
+ };
1782
+ if (htmlDir && htmlPagesPath) {
1783
+ const outputHtmlPages = isSingle ? join5(buildPath, "pages") : join5(buildPath, basename4(htmlDir), "pages");
1784
+ if (shouldCopyHtml) {
1785
+ mkdirSync(outputHtmlPages, { recursive: true });
1786
+ cpSync(htmlPagesPath, outputHtmlPages, {
1787
+ force: true,
1788
+ recursive: true
1789
+ });
1790
+ }
1791
+ if (shouldUpdateHtmlAssetPaths) {
1792
+ await updateAssetPaths(manifest, outputHtmlPages);
1793
+ }
1794
+ const htmlPageFiles = await scanEntryPoints(outputHtmlPages, "*.html");
1795
+ for (const htmlFile of htmlPageFiles) {
1796
+ if (isDev)
1797
+ injectHMRIntoHTMLFile(htmlFile, "html");
1798
+ const fileName = basename4(htmlFile, ".html");
1799
+ manifest[fileName] = htmlFile;
1800
+ }
1801
+ }
1802
+ if (htmxDir && htmxPagesPath) {
1803
+ const outputHtmxPages = isSingle ? join5(buildPath, "pages") : join5(buildPath, basename4(htmxDir), "pages");
1804
+ if (shouldCopyHtmx) {
1805
+ mkdirSync(outputHtmxPages, { recursive: true });
1806
+ cpSync(htmxPagesPath, outputHtmxPages, {
1807
+ force: true,
1808
+ recursive: true
1809
+ });
1810
+ }
1811
+ if (shouldCopyHtmx) {
1812
+ const htmxDestDir = isSingle ? buildPath : join5(buildPath, basename4(htmxDir));
1813
+ mkdirSync(htmxDestDir, { recursive: true });
1814
+ const glob = new Glob3("htmx*.min.js");
1815
+ for (const relPath of glob.scanSync({ cwd: htmxDir })) {
1816
+ const src = join5(htmxDir, relPath);
1817
+ const dest = join5(htmxDestDir, "htmx.min.js");
1818
+ copyFileSync(src, dest);
1819
+ break;
1820
+ }
1821
+ }
1822
+ if (shouldUpdateHtmxAssetPaths) {
1823
+ await updateAssetPaths(manifest, outputHtmxPages);
1824
+ }
1825
+ const htmxPageFiles = await scanEntryPoints(outputHtmxPages, "*.html");
1826
+ for (const htmxFile of htmxPageFiles) {
1827
+ if (isDev)
1828
+ injectHMRIntoHTMLFile(htmxFile, "htmx");
1829
+ const fileName = basename4(htmxFile, ".html");
1830
+ manifest[fileName] = htmxFile;
1831
+ }
1832
+ }
1833
+ if (!options?.preserveIntermediateFiles)
1834
+ await cleanup({
1835
+ reactIndexesPath,
1836
+ svelteDir,
1837
+ vueDir
1838
+ });
1839
+ console.log(`Build completed in ${getDurationString(performance.now() - buildStart)}`);
1840
+ return manifest;
1841
+ };
1842
+ // src/core/devBuild.ts
1843
+ import { statSync } from "fs";
1844
+ import { resolve as resolve18 } from "path";
1845
+
1846
+ // src/dev/dependencyGraph.ts
1847
+ import { readFileSync as readFileSync2, readdirSync, existsSync as existsSync4 } from "fs";
1848
+ import { resolve as resolve7 } from "path";
1849
+ var createDependencyGraph = () => ({
1850
+ dependencies: new Map,
1851
+ dependents: new Map
1852
+ });
1853
+ var extractDependencies = (filePath) => {
1854
+ try {
1855
+ if (!existsSync4(filePath)) {
1856
+ return [];
1857
+ }
1858
+ const content = readFileSync2(filePath, "utf-8");
1859
+ const dependencies = [];
1860
+ const lowerPath = filePath.toLowerCase();
1861
+ const isHtml = lowerPath.endsWith(".html") || lowerPath.endsWith(".htm");
1862
+ if (isHtml) {
1863
+ const linkRegex = /<link\s+[^>]*rel=["']stylesheet["'][^>]*href=["']([^"']+)["'][^>]*>/gi;
1864
+ let matchLink;
1865
+ while ((matchLink = linkRegex.exec(content)) !== null) {
1866
+ const href = matchLink[1];
1867
+ if (!href)
1868
+ continue;
1869
+ const resolvedHref = resolveImportPath(href, filePath);
1870
+ if (resolvedHref) {
1871
+ dependencies.push(resolvedHref);
1872
+ }
1873
+ }
1874
+ return dependencies;
1875
+ }
1876
+ const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
1877
+ const importWithoutFromRegex = /import\s+['"]([^'"]+)['"]/g;
1878
+ const requireRegex = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
1879
+ const dynamicImportRegex = /import\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
1880
+ let match;
1881
+ while ((match = importRegex.exec(content)) !== null) {
1882
+ if (match[1]) {
1883
+ const resolved = resolveImportPath(match[1], filePath);
1884
+ if (resolved)
1885
+ dependencies.push(resolved);
1886
+ }
1887
+ }
1888
+ while ((match = importWithoutFromRegex.exec(content)) !== null) {
1889
+ if (match[1]) {
1890
+ const resolved = resolveImportPath(match[1], filePath);
1891
+ if (resolved)
1892
+ dependencies.push(resolved);
1893
+ }
1894
+ }
1895
+ while ((match = requireRegex.exec(content)) !== null) {
1896
+ if (match[1]) {
1897
+ const resolved = resolveImportPath(match[1], filePath);
1898
+ if (resolved)
1899
+ dependencies.push(resolved);
1900
+ }
1901
+ }
1902
+ while ((match = dynamicImportRegex.exec(content)) !== null) {
1903
+ if (match[1]) {
1904
+ const resolved = resolveImportPath(match[1], filePath);
1905
+ if (resolved)
1906
+ dependencies.push(resolved);
1907
+ }
1908
+ }
1909
+ return dependencies;
1910
+ } catch {
1911
+ return [];
1912
+ }
1913
+ };
1914
+ var resolveImportPath = (importPath, fromFile) => {
1915
+ if (!importPath.startsWith(".") && !importPath.startsWith("/")) {
1916
+ return null;
1917
+ }
1918
+ const fromDir = resolve7(fromFile, "..");
1919
+ const resolved = resolve7(fromDir, importPath);
1920
+ const normalized = resolve7(resolved);
1921
+ const extensions = [
1922
+ ".ts",
1923
+ ".tsx",
1924
+ ".js",
1925
+ ".jsx",
1926
+ ".vue",
1927
+ ".svelte",
1928
+ ".css",
1929
+ ".html"
1930
+ ];
1931
+ for (const ext of extensions) {
1932
+ const withExt = normalized + ext;
1933
+ try {
1934
+ readFileSync2(withExt);
1935
+ return normalized + ext;
1936
+ } catch {}
1937
+ }
1938
+ try {
1939
+ readFileSync2(normalized);
1940
+ return normalized;
1941
+ } catch {
1942
+ return null;
1943
+ }
1944
+ };
1945
+ var addFileToGraph = (graph, filePath) => {
1946
+ const normalizedPath = resolve7(filePath);
1947
+ if (!existsSync4(normalizedPath)) {
1948
+ return;
1949
+ }
1950
+ const dependencies = extractDependencies(normalizedPath);
1951
+ const existingDeps = graph.dependencies.get(normalizedPath);
1952
+ if (existingDeps) {
1953
+ for (const dep of existingDeps) {
1954
+ const dependents = graph.dependents.get(dep);
1955
+ if (dependents) {
1956
+ dependents.delete(normalizedPath);
1957
+ }
1958
+ }
1959
+ }
1960
+ const newDeps = new Set(dependencies);
1961
+ graph.dependencies.set(normalizedPath, newDeps);
1962
+ for (const dep of dependencies) {
1963
+ if (!graph.dependents.has(dep)) {
1964
+ graph.dependents.set(dep, new Set);
1965
+ }
1966
+ graph.dependents.get(dep).add(normalizedPath);
1967
+ }
1968
+ };
1969
+ var getAffectedFiles = (graph, changedFile) => {
1970
+ const normalizedPath = resolve7(changedFile);
1971
+ const affected = new Set;
1972
+ const toProcess = [normalizedPath];
1973
+ while (toProcess.length > 0) {
1974
+ const current = toProcess.pop();
1975
+ if (affected.has(current)) {
1976
+ continue;
1977
+ }
1978
+ affected.add(current);
1979
+ const dependents = graph.dependents.get(current);
1980
+ if (dependents) {
1981
+ for (const dependent of dependents) {
1982
+ toProcess.push(dependent);
1983
+ }
1984
+ }
1985
+ }
1986
+ return Array.from(affected);
1987
+ };
1988
+ var removeFileFromGraph = (graph, filePath) => {
1989
+ const normalizedPath = resolve7(filePath);
1990
+ const deps = graph.dependencies.get(normalizedPath);
1991
+ if (deps) {
1992
+ for (const dep of deps) {
1993
+ const dependents2 = graph.dependents.get(dep);
1994
+ if (dependents2) {
1995
+ dependents2.delete(normalizedPath);
1996
+ }
1997
+ }
1998
+ graph.dependencies.delete(normalizedPath);
1999
+ }
2000
+ const dependents = graph.dependents.get(normalizedPath);
2001
+ if (dependents) {
2002
+ for (const dependent of dependents) {
2003
+ const depList = graph.dependencies.get(dependent);
2004
+ if (depList) {
2005
+ depList.delete(normalizedPath);
2006
+ }
2007
+ }
2008
+ graph.dependents.delete(normalizedPath);
2009
+ }
2010
+ };
2011
+ var buildInitialDependencyGraph = (graph, directories) => {
2012
+ const processedFiles = new Set;
2013
+ const scanDirectory = (dir) => {
2014
+ const normalizedDir = resolve7(dir);
2015
+ try {
2016
+ const entries = readdirSync(normalizedDir, { withFileTypes: true });
2017
+ for (const entry of entries) {
2018
+ const fullPath = resolve7(normalizedDir, entry.name);
2019
+ if (fullPath.includes("/node_modules/") || fullPath.includes("/.git/") || fullPath.includes("/build/") || fullPath.includes("/compiled/") || fullPath.includes("/indexes/") || entry.name.startsWith(".")) {
2020
+ continue;
2021
+ }
2022
+ if (entry.isDirectory()) {
2023
+ scanDirectory(fullPath);
2024
+ } else if (entry.isFile()) {
2025
+ const ext = entry.name.split(".").pop()?.toLowerCase();
2026
+ if ([
2027
+ "ts",
2028
+ "tsx",
2029
+ "js",
2030
+ "jsx",
2031
+ "vue",
2032
+ "svelte",
2033
+ "html",
2034
+ "htm"
2035
+ ].includes(ext || "")) {
2036
+ if (!processedFiles.has(fullPath)) {
2037
+ addFileToGraph(graph, fullPath);
2038
+ processedFiles.add(fullPath);
2039
+ }
2040
+ }
2041
+ }
2042
+ }
2043
+ } catch {}
2044
+ };
2045
+ for (const dir of directories) {
2046
+ const resolvedDir = resolve7(dir);
2047
+ if (existsSync4(resolvedDir)) {
2048
+ scanDirectory(resolvedDir);
2049
+ }
2050
+ }
2051
+ };
2052
+
2053
+ // src/dev/moduleVersionTracker.ts
2054
+ var globalVersionCounter = 0;
2055
+ var getNextVersion = () => ++globalVersionCounter;
2056
+ var createModuleVersionTracker = () => new Map;
2057
+ var incrementModuleVersion = (versions, modulePath) => {
2058
+ const newVersion = getNextVersion();
2059
+ versions.set(modulePath, newVersion);
2060
+ return newVersion;
2061
+ };
2062
+ var incrementModuleVersions = (versions, modulePaths) => {
2063
+ const updated = new Map;
2064
+ for (const path of modulePaths) {
2065
+ const version = incrementModuleVersion(versions, path);
2066
+ updated.set(path, version);
2067
+ }
2068
+ return updated;
2069
+ };
2070
+ var serializeModuleVersions = (versions) => {
2071
+ const serialized = {};
2072
+ for (const [path, version] of versions.entries()) {
2073
+ serialized[path] = version;
2074
+ }
2075
+ return serialized;
2076
+ };
2077
+
2078
+ // src/dev/configResolver.ts
2079
+ import { resolve as resolve8 } from "path";
2080
+ var resolveBuildPaths = (config) => {
2081
+ const cwd2 = process.cwd();
2082
+ const normalize = (path) => path.replace(/\\/g, "/");
2083
+ const withDefault = (value, fallback) => normalize(resolve8(cwd2, value ?? fallback));
2084
+ const optional = (value) => value ? normalize(resolve8(cwd2, value)) : undefined;
2085
+ return {
2086
+ buildDir: withDefault(config.buildDirectory, "build"),
2087
+ assetsDir: optional(config.assetsDirectory),
2088
+ reactDir: optional(config.reactDirectory),
2089
+ svelteDir: optional(config.svelteDirectory),
2090
+ vueDir: optional(config.vueDirectory),
2091
+ angularDir: optional(config.angularDirectory),
2092
+ htmlDir: optional(config.htmlDirectory),
2093
+ htmxDir: optional(config.htmxDirectory)
2094
+ };
2095
+ };
2096
+
2097
+ // src/dev/clientManager.ts
2098
+ var createHMRState = (config) => ({
2099
+ connectedClients: new Set,
2100
+ debounceTimeout: null,
2101
+ dependencyGraph: createDependencyGraph(),
2102
+ fileChangeQueue: new Map,
2103
+ fileHashes: new Map,
2104
+ isRebuilding: false,
2105
+ moduleVersions: createModuleVersionTracker(),
2106
+ rebuildQueue: new Set,
2107
+ rebuildTimeout: null,
2108
+ sourceFileVersions: new Map,
2109
+ watchers: [],
2110
+ config,
2111
+ resolvedPaths: resolveBuildPaths(config),
2112
+ vueChangeTypes: new Map,
2113
+ assetStore: new Map
2114
+ });
2115
+ var incrementSourceFileVersion = (state, filePath) => {
2116
+ const currentVersion = state.sourceFileVersions.get(filePath) || 0;
2117
+ const newVersion = currentVersion + 1;
2118
+ state.sourceFileVersions.set(filePath, newVersion);
2119
+ return newVersion;
2120
+ };
2121
+ var incrementSourceFileVersions = (state, filePaths) => {
2122
+ for (const filePath of filePaths) {
2123
+ incrementSourceFileVersion(state, filePath);
2124
+ }
2125
+ };
2126
+
2127
+ // src/dev/fileWatcher.ts
2128
+ import { watch } from "fs";
2129
+ import { existsSync as existsSync5 } from "fs";
2130
+ import { join as join6, resolve as resolve9 } from "path";
2131
+
2132
+ // src/dev/pathUtils.ts
2133
+ var getWatchPaths = (config, resolved) => {
2134
+ const paths = [];
2135
+ const push = (base, sub) => {
2136
+ if (!base)
2137
+ return;
2138
+ const normalizedBase = normalizePath(base);
2139
+ paths.push(sub ? `${normalizedBase}/${sub}` : normalizedBase);
2140
+ };
2141
+ const cfg = resolved ?? {
2142
+ reactDir: config.reactDirectory,
2143
+ svelteDir: config.svelteDirectory,
2144
+ vueDir: config.vueDirectory,
2145
+ angularDir: config.angularDirectory,
2146
+ htmlDir: config.htmlDirectory,
2147
+ htmxDir: config.htmxDirectory,
2148
+ assetsDir: config.assetsDirectory
2149
+ };
2150
+ push(cfg.reactDir, "components");
2151
+ push(cfg.reactDir, "pages");
2152
+ push(cfg.reactDir, "styles");
2153
+ push(cfg.svelteDir, "components");
2154
+ push(cfg.svelteDir, "pages");
2155
+ push(cfg.svelteDir, "composables");
2156
+ push(cfg.svelteDir, "styles");
2157
+ push(cfg.vueDir, "components");
2158
+ push(cfg.vueDir, "pages");
2159
+ push(cfg.vueDir, "composables");
2160
+ push(cfg.vueDir, "styles");
2161
+ push(cfg.angularDir, "components");
2162
+ push(cfg.angularDir, "pages");
2163
+ push(cfg.angularDir, "styles");
2164
+ push(cfg.htmlDir, "pages");
2165
+ push(cfg.htmlDir, "scripts");
2166
+ push(cfg.htmlDir, "styles");
2167
+ push(cfg.htmxDir, "pages");
2168
+ push(cfg.htmxDir, "styles");
2169
+ push(cfg.assetsDir);
2170
+ return paths;
2171
+ };
2172
+ var shouldIgnorePath = (path) => {
2173
+ const normalizedPath = path.replace(/\\/g, "/");
2174
+ return normalizedPath.includes("/build/") || normalizedPath.includes("/compiled/") || normalizedPath.includes("/indexes/") || normalizedPath.includes("/node_modules/") || normalizedPath.includes("/.git/") || normalizedPath.endsWith(".log") || normalizedPath.endsWith(".tmp") || normalizedPath.startsWith(".") || normalizedPath === "compiled" || normalizedPath.endsWith("/compiled") || normalizedPath.endsWith("/compiled/");
2175
+ };
2176
+ var detectFramework = (filePath, resolved) => {
2177
+ if (shouldIgnorePath(filePath)) {
2178
+ return "ignored";
2179
+ }
2180
+ const normalized = filePath.replace(/\\/g, "/");
2181
+ const startsWithDir = (dir) => dir ? normalized.startsWith(dir.replace(/\\/g, "/")) : false;
2182
+ if (resolved) {
2183
+ if (startsWithDir(resolved.htmxDir))
2184
+ return "htmx";
2185
+ if (startsWithDir(resolved.reactDir))
2186
+ return "react";
2187
+ if (startsWithDir(resolved.svelteDir))
2188
+ return "svelte";
2189
+ if (startsWithDir(resolved.vueDir))
2190
+ return "vue";
2191
+ if (startsWithDir(resolved.angularDir))
2192
+ return "angular";
2193
+ if (startsWithDir(resolved.htmlDir))
2194
+ return "html";
2195
+ if (startsWithDir(resolved.assetsDir))
2196
+ return "assets";
2197
+ } else {
2198
+ if (normalized.includes("/htmx/"))
2199
+ return "htmx";
2200
+ if (normalized.includes("/react/"))
2201
+ return "react";
2202
+ if (normalized.includes("/svelte/"))
2203
+ return "svelte";
2204
+ if (normalized.includes("/vue/"))
2205
+ return "vue";
2206
+ if (normalized.includes("/angular/"))
2207
+ return "angular";
2208
+ if (normalized.includes("/html/"))
2209
+ return "html";
2210
+ }
2211
+ if (normalized.endsWith(".tsx") || normalized.endsWith(".jsx"))
2212
+ return "react";
2213
+ if (normalized.endsWith(".svelte"))
2214
+ return "svelte";
2215
+ if (normalized.endsWith(".vue"))
2216
+ return "vue";
2217
+ if (normalized.endsWith(".html"))
2218
+ return "html";
2219
+ if (normalized.endsWith(".ts") && normalized.includes("angular"))
2220
+ return "angular";
2221
+ if (normalized.includes("/assets/"))
2222
+ return "assets";
2223
+ if (normalized.endsWith(".css")) {
2224
+ if (normalized.includes("/vue/") || normalized.includes("/vue-"))
2225
+ return "vue";
2226
+ if (normalized.includes("/svelte/") || normalized.includes("/svelte-"))
2227
+ return "svelte";
2228
+ if (normalized.includes("/react/") || normalized.includes("/react-"))
2229
+ return "react";
2230
+ if (normalized.includes("/angular/") || normalized.includes("/angular-"))
2231
+ return "angular";
2232
+ if (normalized.includes("/html/") || normalized.includes("/html-"))
2233
+ return "html";
2234
+ if (normalized.includes("/htmx/") || normalized.includes("/htmx-"))
2235
+ return "htmx";
2236
+ return "assets";
2237
+ }
2238
+ return "unknown";
2239
+ };
2240
+
2241
+ // src/dev/fileWatcher.ts
2242
+ var startFileWatching = (state, config, onFileChange) => {
2243
+ const watchPaths = getWatchPaths(config, state.resolvedPaths);
2244
+ for (const path of watchPaths) {
2245
+ const absolutePath = resolve9(path).replace(/\\/g, "/");
2246
+ if (!existsSync5(absolutePath)) {
2247
+ continue;
2248
+ }
2249
+ const watcher = watch(absolutePath, { recursive: true }, (event, filename) => {
2250
+ if (!filename)
2251
+ return;
2252
+ if (filename === "compiled" || filename === "build" || filename === "indexes" || filename.includes("/compiled") || filename.includes("/build") || filename.includes("/indexes") || filename.endsWith("/")) {
2253
+ return;
2254
+ }
2255
+ const fullPath = join6(absolutePath, filename).replace(/\\/g, "/");
2256
+ if (shouldIgnorePath(fullPath)) {
2257
+ return;
2258
+ }
2259
+ if (event === "rename" && !existsSync5(fullPath)) {
2260
+ try {
2261
+ removeFileFromGraph(state.dependencyGraph, fullPath);
2262
+ } catch {}
2263
+ onFileChange(fullPath);
2264
+ return;
2265
+ }
2266
+ if (existsSync5(fullPath)) {
2267
+ onFileChange(fullPath);
2268
+ try {
2269
+ addFileToGraph(state.dependencyGraph, fullPath);
2270
+ } catch {}
2271
+ }
656
2272
  });
657
- cssLogs = logs;
658
- cssOutputs = outputs;
2273
+ state.watchers.push(watcher);
2274
+ }
2275
+ };
2276
+
2277
+ // src/dev/assetStore.ts
2278
+ import { resolve as resolve10 } from "path";
2279
+ import { readdir, unlink } from "fs/promises";
2280
+ var mimeTypes = {
2281
+ ".css": "text/css",
2282
+ ".html": "text/html",
2283
+ ".js": "application/javascript",
2284
+ ".mjs": "application/javascript",
2285
+ ".json": "application/json",
2286
+ ".svg": "image/svg+xml",
2287
+ ".woff": "font/woff",
2288
+ ".woff2": "font/woff2"
2289
+ };
2290
+ var getMimeType = (filePath) => {
2291
+ const ext = filePath.slice(filePath.lastIndexOf("."));
2292
+ return mimeTypes[ext] ?? "application/octet-stream";
2293
+ };
2294
+ var HASHED_FILE_RE = /\.[a-z0-9]{8}\.(js|css|mjs)$/;
2295
+ var stripHash = (webPath) => webPath.replace(/\.[a-z0-9]{8}(\.(js|css|mjs))$/, "$1");
2296
+ var populateAssetStore = async (store, manifest, buildDir) => {
2297
+ const loadPromises = [];
2298
+ const newIdentities = new Map;
2299
+ for (const webPath of Object.values(manifest)) {
2300
+ if (!webPath.startsWith("/"))
2301
+ continue;
2302
+ newIdentities.set(stripHash(webPath), webPath);
2303
+ }
2304
+ for (const existingPath of store.keys()) {
2305
+ const identity = stripHash(existingPath);
2306
+ const replacement = newIdentities.get(identity);
2307
+ if (replacement && replacement !== existingPath) {
2308
+ store.delete(existingPath);
2309
+ }
2310
+ }
2311
+ for (const webPath of newIdentities.values()) {
2312
+ loadPromises.push(Bun.file(resolve10(buildDir, webPath.slice(1))).bytes().then((bytes) => {
2313
+ store.set(webPath, bytes);
2314
+ }).catch(() => {}));
2315
+ }
2316
+ try {
2317
+ const scanDir = async (dir, prefix) => {
2318
+ const entries = await readdir(dir, { withFileTypes: true });
2319
+ const subTasks = [];
2320
+ for (const entry of entries) {
2321
+ if (entry.isDirectory()) {
2322
+ subTasks.push(scanDir(resolve10(dir, entry.name), `${prefix}${entry.name}/`));
2323
+ } else if (entry.name.startsWith("chunk-")) {
2324
+ const webPath = `/${prefix}${entry.name}`;
2325
+ if (!store.has(webPath)) {
2326
+ subTasks.push(Bun.file(resolve10(dir, entry.name)).bytes().then((bytes) => {
2327
+ store.set(webPath, bytes);
2328
+ }).catch(() => {}));
2329
+ }
2330
+ }
2331
+ }
2332
+ await Promise.all(subTasks);
2333
+ };
2334
+ await scanDir(buildDir, "");
2335
+ } catch {}
2336
+ await Promise.all(loadPromises);
2337
+ };
2338
+ var cleanStaleAssets = async (store, manifest, buildDir) => {
2339
+ const liveByIdentity = new Map;
2340
+ for (const webPath of store.keys()) {
2341
+ const diskPath = resolve10(buildDir, webPath.slice(1));
2342
+ liveByIdentity.set(stripHash(diskPath), diskPath);
2343
+ }
2344
+ const absBuildDir = resolve10(buildDir);
2345
+ for (const val of Object.values(manifest)) {
2346
+ if (!HASHED_FILE_RE.test(val))
2347
+ continue;
2348
+ if (val.startsWith(absBuildDir)) {
2349
+ liveByIdentity.set(stripHash(val), val);
2350
+ }
2351
+ }
2352
+ try {
2353
+ const walkAndClean = async (dir) => {
2354
+ const entries = await readdir(dir, { withFileTypes: true });
2355
+ const tasks = [];
2356
+ for (const entry of entries) {
2357
+ const fullPath = resolve10(dir, entry.name);
2358
+ if (entry.isDirectory()) {
2359
+ tasks.push(walkAndClean(fullPath));
2360
+ } else if (HASHED_FILE_RE.test(entry.name)) {
2361
+ const identity = stripHash(fullPath);
2362
+ const livePath = liveByIdentity.get(identity);
2363
+ if (livePath && livePath !== fullPath) {
2364
+ tasks.push(unlink(fullPath).catch(() => {}));
2365
+ }
2366
+ }
2367
+ }
2368
+ await Promise.all(tasks);
2369
+ };
2370
+ await walkAndClean(buildDir);
2371
+ } catch {}
2372
+ };
2373
+ var lookupAsset = (store, path) => store.get(path);
2374
+
2375
+ // src/dev/rebuildTrigger.ts
2376
+ import { existsSync as existsSync8 } from "fs";
2377
+ import { basename as basename8, resolve as resolve17 } from "path";
2378
+
2379
+ // src/dev/fileHashTracker.ts
2380
+ import { createHash } from "crypto";
2381
+ import { readFileSync as readFileSync3 } from "fs";
2382
+ var computeFileHash = (filePath) => {
2383
+ try {
2384
+ const fileContent = readFileSync3(filePath);
2385
+ const hash = createHash("sha256");
2386
+ hash.update(fileContent);
2387
+ return hash.digest("hex");
2388
+ } catch {
2389
+ return Date.now().toString();
2390
+ }
2391
+ };
2392
+ var hasFileChanged = (filePath, currentHash, previousHashes) => {
2393
+ const normalizedPath = normalizePath(filePath);
2394
+ const previousHash = previousHashes.get(normalizedPath);
2395
+ if (!previousHash) {
2396
+ return true;
2397
+ }
2398
+ return previousHash !== currentHash;
2399
+ };
2400
+
2401
+ // src/dev/moduleMapper.ts
2402
+ import { basename as basename5, resolve as resolve12 } from "path";
2403
+
2404
+ // src/dev/reactComponentClassifier.ts
2405
+ import { resolve as resolve11 } from "path";
2406
+ var classifyComponent = (filePath) => {
2407
+ const normalizedPath = resolve11(filePath);
2408
+ if (normalizedPath.includes("/react/pages/")) {
2409
+ return "server";
2410
+ }
2411
+ if (normalizedPath.includes("/react/components/") || normalizedPath.includes("/react/composables/")) {
2412
+ return "client";
2413
+ }
2414
+ return "client";
2415
+ };
2416
+
2417
+ // src/dev/moduleMapper.ts
2418
+ var mapSourceFileToManifestKeys = (sourceFile, framework, resolvedPaths) => {
2419
+ const normalizedFile = resolve12(sourceFile);
2420
+ const fileName = basename5(normalizedFile);
2421
+ const baseName = fileName.replace(/\.(tsx?|jsx?|vue|svelte|css|html)$/, "");
2422
+ const pascalName = toPascal(baseName);
2423
+ const keys = [];
2424
+ const inSubdir = (dir, sub) => {
2425
+ if (!dir)
2426
+ return false;
2427
+ const prefix = `${dir.replace(/\\/g, "/")}/${sub}/`;
2428
+ return normalizedFile.startsWith(prefix);
2429
+ };
2430
+ switch (framework) {
2431
+ case "react":
2432
+ if (inSubdir(resolvedPaths?.reactDir, "pages") || normalizedFile.includes("/react/pages/")) {
2433
+ keys.push(`${pascalName}Index`);
2434
+ keys.push(`${pascalName}CSS`);
2435
+ }
2436
+ break;
2437
+ case "svelte":
2438
+ if (inSubdir(resolvedPaths?.svelteDir, "pages") || normalizedFile.includes("/svelte/pages/")) {
2439
+ keys.push(pascalName);
2440
+ keys.push(`${pascalName}Index`);
2441
+ keys.push(`${pascalName}CSS`);
2442
+ }
2443
+ break;
2444
+ case "vue":
2445
+ if (inSubdir(resolvedPaths?.vueDir, "pages") || normalizedFile.includes("/vue/pages/")) {
2446
+ keys.push(pascalName);
2447
+ keys.push(`${pascalName}Index`);
2448
+ keys.push(`${pascalName}CSS`);
2449
+ }
2450
+ break;
2451
+ case "angular":
2452
+ if (inSubdir(resolvedPaths?.angularDir, "pages") || normalizedFile.includes("/angular/pages/")) {
2453
+ keys.push(pascalName);
2454
+ keys.push(`${pascalName}Index`);
2455
+ }
2456
+ break;
2457
+ case "html":
2458
+ case "htmx":
2459
+ break;
2460
+ case "assets":
2461
+ if (normalizedFile.endsWith(".css")) {
2462
+ keys.push(`${pascalName}CSS`);
2463
+ }
2464
+ break;
659
2465
  }
660
- const allLogs = [...serverLogs, ...clientLogs, ...cssLogs];
661
- outputLogs(allLogs);
662
- const manifest = generateManifest([...serverOutputs, ...clientOutputs, ...cssOutputs], buildPath);
663
- if (htmlDir && htmlPagesPath) {
664
- const outputHtmlPages = isSingle ? join5(buildPath, "pages") : join5(buildPath, basename4(htmlDir), "pages");
665
- mkdirSync(outputHtmlPages, { recursive: true });
666
- cpSync(htmlPagesPath, outputHtmlPages, {
667
- force: true,
668
- recursive: true
669
- });
670
- await updateAssetPaths(manifest, outputHtmlPages);
2466
+ return keys;
2467
+ };
2468
+ var createModuleUpdates = (changedFiles, framework, manifest, resolvedPaths) => {
2469
+ const updates = [];
2470
+ const processedFiles = new Set;
2471
+ for (const sourceFile of changedFiles) {
2472
+ const normalizedFile = resolve12(sourceFile);
2473
+ const normalizedPath = normalizedFile.replace(/\\/g, "/");
2474
+ if (processedFiles.has(normalizedFile))
2475
+ continue;
2476
+ processedFiles.add(normalizedFile);
2477
+ const moduleKeys = mapSourceFileToManifestKeys(normalizedFile, framework, resolvedPaths);
2478
+ const isReactPage = resolvedPaths?.reactDir ? normalizedPath.startsWith(`${resolvedPaths.reactDir.replace(/\\/g, "/")}/pages/`) : normalizedPath.includes("/react/pages/");
2479
+ if (framework === "react" && !isReactPage) {
2480
+ continue;
2481
+ }
2482
+ const modulePaths = {};
2483
+ for (const key of moduleKeys) {
2484
+ if (manifest[key]) {
2485
+ modulePaths[key] = manifest[key];
2486
+ }
2487
+ }
2488
+ if (Object.keys(modulePaths).length > 0) {
2489
+ const componentType = framework === "react" ? classifyComponent(normalizedFile) : undefined;
2490
+ updates.push({
2491
+ componentType,
2492
+ framework,
2493
+ moduleKeys: Object.keys(modulePaths),
2494
+ modulePaths,
2495
+ sourceFile: normalizedFile
2496
+ });
2497
+ }
671
2498
  }
672
- if (htmxDir && htmxPagesPath) {
673
- const outputHtmxPages = isSingle ? join5(buildPath, "pages") : join5(buildPath, basename4(htmxDir), "pages");
674
- mkdirSync(outputHtmxPages, { recursive: true });
675
- cpSync(htmxPagesPath, outputHtmxPages, {
676
- force: true,
677
- recursive: true
678
- });
679
- const htmxDestDir = isSingle ? buildPath : join5(buildPath, basename4(htmxDir));
680
- mkdirSync(htmxDestDir, { recursive: true });
681
- const glob = new Glob3("htmx*.min.js");
682
- for (const relativePath of glob.scanSync({ cwd: htmxDir })) {
683
- const src = join5(htmxDir, relativePath);
684
- const dest = join5(htmxDestDir, "htmx.min.js");
685
- copyFileSync(src, dest);
686
- break;
2499
+ return updates;
2500
+ };
2501
+ var groupModuleUpdatesByFramework = (updates) => {
2502
+ const grouped = new Map;
2503
+ for (const update of updates) {
2504
+ if (!grouped.has(update.framework)) {
2505
+ grouped.set(update.framework, []);
687
2506
  }
688
- await updateAssetPaths(manifest, outputHtmxPages);
2507
+ grouped.get(update.framework).push(update);
689
2508
  }
690
- if (!options?.preserveIntermediateFiles)
691
- await cleanup({
692
- reactIndexesPath,
693
- svelteDir,
694
- vueDir
695
- });
696
- console.log(`Build completed in ${getDurationString(performance.now() - buildStart)}`);
697
- return manifest;
2509
+ return grouped;
698
2510
  };
699
- // src/core/pageHandlers.ts
700
- var {file: file3 } = globalThis.Bun;
701
- import { createElement } from "react";
702
- import { renderToReadableStream as renderReactToReadableStream } from "react-dom/server";
703
- import { createSSRApp, h } from "vue";
704
- import { renderToWebStream as renderVueToWebStream } from "vue/server-renderer";
705
-
706
- // src/svelte/renderToReadableStream.ts
707
- import { render } from "svelte/server";
708
2511
 
709
- // src/utils/escapeScriptContent.ts
710
- var ESCAPE_LOOKUP = {
711
- "\u2028": "\\u2028",
712
- "\u2029": "\\u2029",
713
- "&": "\\u0026",
714
- "<": "\\u003C",
715
- ">": "\\u003E"
716
- };
717
- var ESCAPE_REGEX = /[&><\u2028\u2029]/g;
718
- var escapeScriptContent = (content) => content.replace(ESCAPE_REGEX, (char) => {
719
- const escaped = ESCAPE_LOOKUP[char];
720
- return escaped !== undefined ? escaped : char;
721
- });
2512
+ // src/dev/webSocket.ts
2513
+ var handleClientConnect = (state, client2, manifest) => {
2514
+ state.connectedClients.add(client2);
2515
+ const serverVersions = serializeModuleVersions(state.moduleVersions);
2516
+ client2.send(JSON.stringify({
2517
+ data: {
2518
+ manifest,
2519
+ serverVersions
2520
+ },
2521
+ timestamp: Date.now(),
2522
+ type: "manifest"
2523
+ }));
2524
+ client2.send(JSON.stringify({
2525
+ message: "HMR client connected successfully",
2526
+ timestamp: Date.now(),
2527
+ type: "connected"
2528
+ }));
2529
+ };
2530
+ var handleClientDisconnect = (state, client2) => {
2531
+ state.connectedClients.delete(client2);
2532
+ };
2533
+ var handleHMRMessage = (state, client2, message) => {
2534
+ try {
2535
+ let parsedData;
2536
+ if (typeof message === "string") {
2537
+ parsedData = JSON.parse(message);
2538
+ } else if (message instanceof Buffer) {
2539
+ parsedData = JSON.parse(message.toString());
2540
+ } else if (message instanceof ArrayBuffer) {
2541
+ parsedData = JSON.parse(new TextDecoder().decode(new Uint8Array(message)));
2542
+ } else if (ArrayBuffer.isView(message)) {
2543
+ parsedData = JSON.parse(new TextDecoder().decode(message));
2544
+ } else if (typeof message === "object" && message !== null) {
2545
+ parsedData = message;
2546
+ } else {
2547
+ return;
2548
+ }
2549
+ if (!isValidHMRClientMessage(parsedData)) {
2550
+ return;
2551
+ }
2552
+ const data = parsedData;
2553
+ switch (data.type) {
2554
+ case "ping":
2555
+ client2.send(JSON.stringify({
2556
+ timestamp: Date.now(),
2557
+ type: "pong"
2558
+ }));
2559
+ break;
2560
+ case "request-rebuild":
2561
+ break;
2562
+ case "ready":
2563
+ break;
2564
+ case "hydration-error":
2565
+ break;
2566
+ }
2567
+ } catch {}
2568
+ };
2569
+ var broadcastToClients = (state, message) => {
2570
+ const messageStr = JSON.stringify({
2571
+ ...message,
2572
+ timestamp: Date.now()
2573
+ });
2574
+ let sentCount = 0;
2575
+ const clientsToRemove = [];
2576
+ for (const client2 of state.connectedClients) {
2577
+ if (client2.readyState === WS_READY_STATE_OPEN) {
2578
+ try {
2579
+ client2.send(messageStr);
2580
+ sentCount++;
2581
+ } catch {
2582
+ clientsToRemove.push(client2);
2583
+ }
2584
+ } else {
2585
+ clientsToRemove.push(client2);
2586
+ }
2587
+ }
2588
+ for (const client2 of clientsToRemove) {
2589
+ state.connectedClients.delete(client2);
2590
+ }
2591
+ };
722
2592
 
723
- // src/svelte/renderToReadableStream.ts
724
- var renderToReadableStream = async (component, props, {
725
- bootstrapScriptContent,
726
- bootstrapScripts = [],
727
- bootstrapModules = [],
728
- nonce,
729
- onError = console.error,
730
- progressiveChunkSize = DEFAULT_CHUNK_SIZE,
731
- signal
732
- } = {}) => {
2593
+ // src/dev/rebuildTrigger.ts
2594
+ var parseErrorLocationFromMessage = (msg) => {
2595
+ const pathLineCol = msg.match(/^([^\s:]+):(\d+)(?::(\d+))?/);
2596
+ if (pathLineCol) {
2597
+ const [, file4, lineStr, colStr] = pathLineCol;
2598
+ return {
2599
+ file: file4,
2600
+ line: lineStr ? parseInt(lineStr, 10) : undefined,
2601
+ column: colStr ? parseInt(colStr, 10) : undefined
2602
+ };
2603
+ }
2604
+ const atMatch = msg.match(/(?:at|in)\s+([^(:\s]+)(?:\s*\([^)]*line\s*(\d+)[^)]*col(?:umn)?\s*(\d+)[^)]*\)|:(\d+):(\d+)?)/i);
2605
+ if (atMatch) {
2606
+ const [, file4, line1, col1, line2, col2] = atMatch;
2607
+ return {
2608
+ file: file4?.trim(),
2609
+ line: line1 ? parseInt(line1, 10) : line2 ? parseInt(line2, 10) : undefined,
2610
+ column: col1 ? parseInt(col1, 10) : col2 ? parseInt(col2, 10) : undefined
2611
+ };
2612
+ }
2613
+ const parenMatch = msg.match(/([^\s(]+)\s*\([^)]*line\s*(\d+)[^)]*col(?:umn)?\s*(\d+)/i);
2614
+ if (parenMatch) {
2615
+ const [, file4, lineStr, colStr] = parenMatch;
2616
+ return {
2617
+ file: file4 ?? undefined,
2618
+ line: lineStr ? parseInt(lineStr, 10) : undefined,
2619
+ column: colStr ? parseInt(colStr, 10) : undefined
2620
+ };
2621
+ }
2622
+ return {};
2623
+ };
2624
+ var extractBuildErrorDetails = (error, affectedFrameworks, resolvedPaths) => {
2625
+ let logs = error?.logs;
2626
+ if (!logs && error instanceof AggregateError && error.errors?.length) {
2627
+ logs = error.errors;
2628
+ }
2629
+ if (logs && Array.isArray(logs) && logs.length > 0) {
2630
+ const errLog = logs.find((l) => l.level === "error") ?? logs[0];
2631
+ const pos = errLog?.position;
2632
+ const file4 = pos && "file" in pos ? pos.file : undefined;
2633
+ const line = pos && "line" in pos ? pos.line : undefined;
2634
+ const column = pos && "column" in pos ? pos.column : undefined;
2635
+ const lineText = pos && "lineText" in pos ? pos.lineText : undefined;
2636
+ const framework = file4 && resolvedPaths ? detectFramework(file4, resolvedPaths) : affectedFrameworks[0] ?? "unknown";
2637
+ return {
2638
+ file: file4,
2639
+ line,
2640
+ column,
2641
+ lineText,
2642
+ framework: framework !== "ignored" ? framework : affectedFrameworks[0]
2643
+ };
2644
+ }
2645
+ const msg = error instanceof Error ? error.message : String(error);
2646
+ const parsed = parseErrorLocationFromMessage(msg);
2647
+ let fw = affectedFrameworks[0];
2648
+ if (parsed.file && resolvedPaths) {
2649
+ const detected = detectFramework(parsed.file, resolvedPaths);
2650
+ fw = detected !== "ignored" ? detected : affectedFrameworks[0];
2651
+ }
2652
+ return { ...parsed, framework: fw };
2653
+ };
2654
+ var queueFileChange = (state, filePath, config, onRebuildComplete) => {
2655
+ const framework = detectFramework(filePath, state.resolvedPaths);
2656
+ if (framework === "ignored") {
2657
+ return;
2658
+ }
2659
+ const currentHash = computeFileHash(filePath);
2660
+ if (!hasFileChanged(filePath, currentHash, state.fileHashes)) {
2661
+ return;
2662
+ }
2663
+ if (!state.fileChangeQueue.has(framework)) {
2664
+ state.fileChangeQueue.set(framework, []);
2665
+ }
2666
+ const queue = state.fileChangeQueue.get(framework);
2667
+ if (!queue.includes(filePath)) {
2668
+ queue.push(filePath);
2669
+ }
2670
+ if (state.isRebuilding) {
2671
+ return;
2672
+ }
2673
+ if (state.rebuildTimeout) {
2674
+ clearTimeout(state.rebuildTimeout);
2675
+ }
2676
+ const DEBOUNCE_MS = config.options?.hmr?.debounceMs ?? 500;
2677
+ state.rebuildTimeout = setTimeout(() => {
2678
+ const filesToProcess = new Map;
2679
+ const uniqueFilesByFramework = new Map;
2680
+ for (const [fwKey, filePaths] of state.fileChangeQueue) {
2681
+ uniqueFilesByFramework.set(fwKey, new Set(filePaths));
2682
+ }
2683
+ for (const [fwKey, filePathSet] of uniqueFilesByFramework) {
2684
+ const validFiles = [];
2685
+ const processedFiles = new Set;
2686
+ for (const filePathInSet of filePathSet) {
2687
+ if (!existsSync8(filePathInSet)) {
2688
+ state.fileHashes.delete(filePathInSet);
2689
+ try {
2690
+ const affectedFiles = getAffectedFiles(state.dependencyGraph, filePathInSet);
2691
+ const deletedPathResolved = resolve17(filePathInSet);
2692
+ for (const affectedFile of affectedFiles) {
2693
+ if (affectedFile !== deletedPathResolved && !processedFiles.has(affectedFile) && existsSync8(affectedFile)) {
2694
+ validFiles.push(affectedFile);
2695
+ processedFiles.add(affectedFile);
2696
+ }
2697
+ }
2698
+ } catch {}
2699
+ continue;
2700
+ }
2701
+ const fileHash = computeFileHash(filePathInSet);
2702
+ const storedHash = state.fileHashes.get(filePathInSet);
2703
+ if (!storedHash || storedHash !== fileHash) {
2704
+ const normalizedFilePath = resolve17(filePathInSet);
2705
+ if (!processedFiles.has(normalizedFilePath)) {
2706
+ validFiles.push(normalizedFilePath);
2707
+ processedFiles.add(normalizedFilePath);
2708
+ }
2709
+ state.fileHashes.set(normalizedFilePath, fileHash);
2710
+ incrementSourceFileVersions(state, [normalizedFilePath]);
2711
+ try {
2712
+ const dependents = state.dependencyGraph.dependents.get(normalizedFilePath);
2713
+ if (dependents && dependents.size > 0) {
2714
+ const dependentFiles = Array.from(dependents).filter((f) => existsSync8(f));
2715
+ if (dependentFiles.length > 0) {
2716
+ incrementSourceFileVersions(state, dependentFiles);
2717
+ }
2718
+ }
2719
+ } catch {}
2720
+ try {
2721
+ const affectedFiles = getAffectedFiles(state.dependencyGraph, normalizedFilePath);
2722
+ for (const affectedFile of affectedFiles) {
2723
+ if (!processedFiles.has(affectedFile) && affectedFile !== normalizedFilePath && existsSync8(affectedFile)) {
2724
+ validFiles.push(affectedFile);
2725
+ processedFiles.add(affectedFile);
2726
+ }
2727
+ }
2728
+ } catch {
2729
+ if (!processedFiles.has(normalizedFilePath)) {
2730
+ validFiles.push(normalizedFilePath);
2731
+ processedFiles.add(normalizedFilePath);
2732
+ }
2733
+ }
2734
+ }
2735
+ }
2736
+ if (validFiles.length > 0) {
2737
+ const firstFile = validFiles[0];
2738
+ if (firstFile) {
2739
+ const detectedFramework = detectFramework(firstFile, state.resolvedPaths);
2740
+ filesToProcess.set(detectedFramework, validFiles);
2741
+ }
2742
+ }
2743
+ }
2744
+ state.fileChangeQueue.clear();
2745
+ if (filesToProcess.size === 0) {
2746
+ return;
2747
+ }
2748
+ const affectedFrameworks = Array.from(filesToProcess.keys());
2749
+ for (const frameworkKey of affectedFrameworks) {
2750
+ state.rebuildQueue.add(frameworkKey);
2751
+ }
2752
+ const filesToRebuild = [];
2753
+ for (const [, filePaths] of filesToProcess) {
2754
+ filesToRebuild.push(...filePaths);
2755
+ }
2756
+ triggerRebuild(state, config, onRebuildComplete, filesToRebuild);
2757
+ }, DEBOUNCE_MS);
2758
+ };
2759
+ var triggerRebuild = async (state, config, onRebuildComplete, filesToRebuild) => {
2760
+ if (state.isRebuilding) {
2761
+ return null;
2762
+ }
2763
+ state.isRebuilding = true;
2764
+ const affectedFrameworks = Array.from(state.rebuildQueue);
2765
+ state.rebuildQueue.clear();
2766
+ const startTime = Date.now();
2767
+ broadcastToClients(state, {
2768
+ data: { affectedFrameworks },
2769
+ message: "Rebuild started...",
2770
+ type: "rebuild-start"
2771
+ });
733
2772
  try {
734
- const { head, body } = typeof props === "undefined" ? render(component) : render(component, { props });
735
- const nonceAttr = nonce ? ` nonce="${nonce}"` : "";
736
- const scripts = (bootstrapScriptContent ? `<script${nonceAttr}>${escapeScriptContent(bootstrapScriptContent)}</script>` : "") + bootstrapScripts.map((src) => `<script${nonceAttr} src="${src}"></script>`).join("") + bootstrapModules.map((src) => `<script${nonceAttr} type="module" src="${src}"></script>`).join("");
737
- const encoder = new TextEncoder;
738
- const full = encoder.encode(`<!DOCTYPE html><html lang="en"><head>${head}</head><body>${body}${scripts}</body></html>`);
739
- let offset = 0;
740
- return new ReadableStream({
741
- type: "bytes",
742
- cancel(reason) {
743
- onError?.(reason);
2773
+ const manifest = await build2({
2774
+ ...config,
2775
+ incrementalFiles: filesToRebuild && filesToRebuild.length > 0 ? filesToRebuild : undefined,
2776
+ options: {
2777
+ ...config.options,
2778
+ preserveIntermediateFiles: true,
2779
+ throwOnError: true
2780
+ }
2781
+ });
2782
+ if (!manifest) {
2783
+ throw new Error("Build failed - no manifest generated");
2784
+ }
2785
+ const duration = Date.now() - startTime;
2786
+ logger.rebuilt(duration);
2787
+ broadcastToClients(state, {
2788
+ data: {
2789
+ affectedFrameworks,
2790
+ manifest
744
2791
  },
745
- pull(controller) {
746
- if (signal?.aborted) {
747
- controller.close();
748
- return;
2792
+ message: "Rebuild completed successfully",
2793
+ type: "rebuild-complete"
2794
+ });
2795
+ if (filesToRebuild && filesToRebuild.length > 0) {
2796
+ const allModuleUpdates = [];
2797
+ for (const framework of affectedFrameworks) {
2798
+ const frameworkFiles = filesToRebuild.filter((file4) => detectFramework(file4, state.resolvedPaths) === framework);
2799
+ if (frameworkFiles.length > 0) {
2800
+ const moduleUpdates = createModuleUpdates(frameworkFiles, framework, manifest, state.resolvedPaths);
2801
+ if (moduleUpdates.length > 0) {
2802
+ allModuleUpdates.push(...moduleUpdates);
2803
+ }
749
2804
  }
750
- if (offset >= full.length) {
751
- controller.close();
752
- return;
2805
+ }
2806
+ if (affectedFrameworks.includes("react") && filesToRebuild && state.resolvedPaths.reactDir) {
2807
+ const reactFiles = filesToRebuild.filter((file4) => detectFramework(file4, state.resolvedPaths) === "react");
2808
+ if (reactFiles.length > 0) {
2809
+ const reactPageFiles = reactFiles.filter((file4) => {
2810
+ const normalized = file4.replace(/\\/g, "/");
2811
+ return normalized.includes("/pages/");
2812
+ });
2813
+ const sourceFiles = reactPageFiles.length > 0 ? reactPageFiles : reactFiles;
2814
+ const primarySource = sourceFiles[0];
2815
+ try {
2816
+ const hasComponentChanges = reactFiles.some((file4) => file4.endsWith(".tsx") || file4.endsWith(".ts") || file4.endsWith(".jsx"));
2817
+ const hasCSSChanges = reactFiles.some((file4) => file4.endsWith(".css"));
2818
+ if (hasCSSChanges && !hasComponentChanges) {
2819
+ logger.cssUpdate(primarySource ?? reactFiles[0] ?? "", "react");
2820
+ } else {
2821
+ logger.hmrUpdate(primarySource ?? reactFiles[0] ?? "", "react");
2822
+ }
2823
+ broadcastToClients(state, {
2824
+ data: {
2825
+ framework: "react",
2826
+ manifest,
2827
+ sourceFiles,
2828
+ primarySource,
2829
+ hasComponentChanges,
2830
+ hasCSSChanges
2831
+ },
2832
+ type: "react-update"
2833
+ });
2834
+ } catch {}
753
2835
  }
754
- const end = Math.min(offset + progressiveChunkSize, full.length);
755
- controller.enqueue(full.subarray(offset, end));
756
- offset = end;
757
2836
  }
758
- });
2837
+ if (affectedFrameworks.includes("html") && filesToRebuild && state.resolvedPaths.htmlDir) {
2838
+ const htmlFrameworkFiles = filesToRebuild.filter((file4) => detectFramework(file4, state.resolvedPaths) === "html");
2839
+ if (htmlFrameworkFiles.length > 0) {
2840
+ const scriptFiles = htmlFrameworkFiles.filter((f) => (f.endsWith(".ts") || f.endsWith(".js") || f.endsWith(".tsx") || f.endsWith(".jsx")) && f.replace(/\\/g, "/").includes("/scripts/"));
2841
+ const htmlPageFiles = htmlFrameworkFiles.filter((f) => f.endsWith(".html"));
2842
+ if (scriptFiles.length > 0 && htmlPageFiles.length === 0) {
2843
+ for (const scriptFile of scriptFiles) {
2844
+ const { basename: basename9 } = await import("path");
2845
+ const { toPascal: toPascal2 } = await Promise.resolve().then(() => exports_stringModifiers);
2846
+ const scriptBaseName = basename9(scriptFile).replace(/\.(ts|js|tsx|jsx)$/, "");
2847
+ const pascalName = toPascal2(scriptBaseName);
2848
+ const manifestKey = pascalName;
2849
+ const scriptPath = manifest[manifestKey] || null;
2850
+ if (scriptPath) {
2851
+ logger.scriptUpdate(scriptFile, "html");
2852
+ broadcastToClients(state, {
2853
+ data: {
2854
+ framework: "html",
2855
+ scriptPath,
2856
+ sourceFile: scriptFile,
2857
+ manifest
2858
+ },
2859
+ type: "script-update"
2860
+ });
2861
+ } else {
2862
+ logger.warn(`Script not found in manifest: ${manifestKey}`);
2863
+ }
2864
+ }
2865
+ }
2866
+ }
2867
+ }
2868
+ if (affectedFrameworks.includes("html") && filesToRebuild && state.resolvedPaths.htmlDir) {
2869
+ const htmlFrameworkFiles = filesToRebuild.filter((file4) => detectFramework(file4, state.resolvedPaths) === "html");
2870
+ if (htmlFrameworkFiles.length > 0) {
2871
+ const htmlPageFiles = htmlFrameworkFiles.filter((f) => f.endsWith(".html"));
2872
+ const pagesToUpdate = htmlPageFiles;
2873
+ const isSingle = !config.reactDirectory && !config.svelteDirectory && !config.vueDirectory && !config.htmxDirectory;
2874
+ const outputHtmlPages = isSingle ? resolve17(state.resolvedPaths.buildDir, "pages") : resolve17(state.resolvedPaths.buildDir, basename8(config.htmlDirectory ?? "html"), "pages");
2875
+ for (const pageFile of pagesToUpdate) {
2876
+ const htmlPageName = basename8(pageFile);
2877
+ const builtHtmlPagePath = resolve17(outputHtmlPages, htmlPageName);
2878
+ try {
2879
+ const { handleHTMLUpdate: handleHTMLUpdate2 } = await Promise.resolve().then(() => (init_simpleHTMLHMR(), exports_simpleHTMLHMR));
2880
+ const newHTML = await handleHTMLUpdate2(builtHtmlPagePath);
2881
+ if (newHTML) {
2882
+ logger.hmrUpdate(pageFile, "html");
2883
+ broadcastToClients(state, {
2884
+ data: {
2885
+ framework: "html",
2886
+ html: newHTML,
2887
+ sourceFile: builtHtmlPagePath
2888
+ },
2889
+ type: "html-update"
2890
+ });
2891
+ }
2892
+ } catch {}
2893
+ }
2894
+ }
2895
+ }
2896
+ if (affectedFrameworks.includes("vue") && filesToRebuild && config.vueDirectory) {
2897
+ const vueFiles = filesToRebuild.filter((file4) => detectFramework(file4, state.resolvedPaths) === "vue");
2898
+ if (vueFiles.length > 0) {
2899
+ const vueComponentFiles = vueFiles.filter((f) => f.endsWith(".vue"));
2900
+ const vueCssFiles = vueFiles.filter((f) => f.endsWith(".css"));
2901
+ const isCssOnlyChange = vueComponentFiles.length === 0 && vueCssFiles.length > 0;
2902
+ const vuePageFiles = vueFiles.filter((f) => f.replace(/\\/g, "/").includes("/pages/"));
2903
+ const pagesToUpdate = vuePageFiles.length > 0 ? vuePageFiles : vueComponentFiles;
2904
+ if (isCssOnlyChange && vueCssFiles.length > 0) {
2905
+ const { basename: basename9 } = await import("path");
2906
+ const { toPascal: toPascal2 } = await Promise.resolve().then(() => exports_stringModifiers);
2907
+ const cssFile = vueCssFiles[0];
2908
+ if (cssFile) {
2909
+ const cssBaseName = basename9(cssFile, ".css");
2910
+ const cssPascalName = toPascal2(cssBaseName);
2911
+ const cssKey = `${cssPascalName}CSS`;
2912
+ const cssUrl = manifest[cssKey] || null;
2913
+ logger.cssUpdate(cssFile, "vue");
2914
+ broadcastToClients(state, {
2915
+ data: {
2916
+ framework: "vue",
2917
+ updateType: "css-only",
2918
+ cssUrl,
2919
+ cssBaseName,
2920
+ manifest,
2921
+ sourceFile: cssFile
2922
+ },
2923
+ type: "vue-update"
2924
+ });
2925
+ }
2926
+ }
2927
+ for (const vuePagePath of pagesToUpdate) {
2928
+ try {
2929
+ const { basename: basename9, relative: relative5 } = await import("path");
2930
+ const { toPascal: toPascal2 } = await Promise.resolve().then(() => exports_stringModifiers);
2931
+ const fileName = basename9(vuePagePath);
2932
+ const baseName = fileName.replace(/\.vue$/, "");
2933
+ const pascalName = toPascal2(baseName);
2934
+ const vueRoot = config.vueDirectory;
2935
+ const hmrId = vueRoot ? relative5(vueRoot, vuePagePath).replace(/\\/g, "/").replace(/\.vue$/, "") : baseName;
2936
+ const cssKey = `${pascalName}CSS`;
2937
+ const cssUrl = manifest[cssKey] || null;
2938
+ const { vueHmrMetadata: vueHmrMetadata2 } = await Promise.resolve().then(() => (init_compileVue(), exports_compileVue));
2939
+ const hmrMeta = vueHmrMetadata2.get(resolve17(vuePagePath));
2940
+ const changeType = hmrMeta?.changeType ?? "full";
2941
+ if (changeType === "style-only") {
2942
+ logger.cssUpdate(vuePagePath, "vue");
2943
+ broadcastToClients(state, {
2944
+ data: {
2945
+ framework: "vue",
2946
+ updateType: "css-only",
2947
+ changeType: "style-only",
2948
+ cssUrl,
2949
+ cssBaseName: baseName,
2950
+ hmrId,
2951
+ manifest,
2952
+ sourceFile: vuePagePath
2953
+ },
2954
+ type: "vue-update"
2955
+ });
2956
+ continue;
2957
+ }
2958
+ const { handleVueUpdate: handleVueUpdate2 } = await Promise.resolve().then(() => (init_simpleVueHMR(), exports_simpleVueHMR));
2959
+ const newHTML = await handleVueUpdate2(vuePagePath, manifest, state.resolvedPaths.buildDir);
2960
+ const componentPath = manifest[`${pascalName}Client`] || null;
2961
+ logger.hmrUpdate(vuePagePath, "vue");
2962
+ broadcastToClients(state, {
2963
+ data: {
2964
+ framework: "vue",
2965
+ html: newHTML,
2966
+ hmrId,
2967
+ changeType,
2968
+ componentPath,
2969
+ cssUrl,
2970
+ updateType: "full",
2971
+ manifest,
2972
+ sourceFile: vuePagePath
2973
+ },
2974
+ type: "vue-update"
2975
+ });
2976
+ } catch {}
2977
+ }
2978
+ }
2979
+ }
2980
+ if (affectedFrameworks.includes("svelte") && filesToRebuild && config.svelteDirectory) {
2981
+ const svelteFiles = filesToRebuild.filter((file4) => detectFramework(file4, state.resolvedPaths) === "svelte");
2982
+ if (svelteFiles.length > 0) {
2983
+ const svelteComponentFiles = svelteFiles.filter((f) => f.endsWith(".svelte"));
2984
+ const svelteCssFiles = svelteFiles.filter((f) => f.endsWith(".css"));
2985
+ const isCssOnlyChange = svelteComponentFiles.length === 0 && svelteCssFiles.length > 0;
2986
+ const sveltePageFiles = svelteFiles.filter((f) => f.replace(/\\/g, "/").includes("/pages/"));
2987
+ const pagesToUpdate = sveltePageFiles.length > 0 ? sveltePageFiles : svelteComponentFiles;
2988
+ if (isCssOnlyChange && svelteCssFiles.length > 0) {
2989
+ const { basename: basename9 } = await import("path");
2990
+ const { toPascal: toPascal2 } = await Promise.resolve().then(() => exports_stringModifiers);
2991
+ const cssFile = svelteCssFiles[0];
2992
+ if (cssFile) {
2993
+ const cssBaseName = basename9(cssFile, ".css");
2994
+ const cssPascalName = toPascal2(cssBaseName);
2995
+ const cssKey = `${cssPascalName}CSS`;
2996
+ const cssUrl = manifest[cssKey] || null;
2997
+ logger.cssUpdate(cssFile, "svelte");
2998
+ broadcastToClients(state, {
2999
+ data: {
3000
+ framework: "svelte",
3001
+ updateType: "css-only",
3002
+ cssUrl,
3003
+ cssBaseName,
3004
+ manifest,
3005
+ sourceFile: cssFile
3006
+ },
3007
+ type: "svelte-update"
3008
+ });
3009
+ }
3010
+ }
3011
+ for (const sveltePagePath of pagesToUpdate) {
3012
+ try {
3013
+ const { handleSvelteUpdate: handleSvelteUpdate2 } = await Promise.resolve().then(() => (init_simpleSvelteHMR(), exports_simpleSvelteHMR));
3014
+ const newHTML = await handleSvelteUpdate2(sveltePagePath, manifest, state.resolvedPaths.buildDir);
3015
+ const { basename: basename9 } = await import("path");
3016
+ const { toPascal: toPascal2 } = await Promise.resolve().then(() => exports_stringModifiers);
3017
+ const fileName = basename9(sveltePagePath);
3018
+ const baseName = fileName.replace(/\.svelte$/, "");
3019
+ const pascalName = toPascal2(baseName);
3020
+ const cssKey = `${pascalName}CSS`;
3021
+ const cssUrl = manifest[cssKey] || null;
3022
+ logger.hmrUpdate(sveltePagePath, "svelte");
3023
+ broadcastToClients(state, {
3024
+ data: {
3025
+ framework: "svelte",
3026
+ html: newHTML,
3027
+ cssUrl,
3028
+ cssBaseName: baseName,
3029
+ updateType: "full",
3030
+ manifest,
3031
+ sourceFile: sveltePagePath
3032
+ },
3033
+ type: "svelte-update"
3034
+ });
3035
+ } catch {}
3036
+ }
3037
+ }
3038
+ }
3039
+ if (affectedFrameworks.includes("htmx") && filesToRebuild && state.resolvedPaths.htmxDir) {
3040
+ const htmxFrameworkFiles = filesToRebuild.filter((file4) => detectFramework(file4, state.resolvedPaths) === "htmx");
3041
+ if (htmxFrameworkFiles.length > 0) {
3042
+ const htmxScriptFiles = htmxFrameworkFiles.filter((f) => (f.endsWith(".ts") || f.endsWith(".js") || f.endsWith(".tsx") || f.endsWith(".jsx")) && f.replace(/\\/g, "/").includes("/scripts/"));
3043
+ const htmxHtmlFiles = htmxFrameworkFiles.filter((f) => f.endsWith(".html"));
3044
+ if (htmxScriptFiles.length > 0 && htmxHtmlFiles.length === 0) {
3045
+ for (const scriptFile of htmxScriptFiles) {
3046
+ const { basename: basename9 } = await import("path");
3047
+ const { toPascal: toPascal2 } = await Promise.resolve().then(() => exports_stringModifiers);
3048
+ const scriptBaseName = basename9(scriptFile).replace(/\.(ts|js|tsx|jsx)$/, "");
3049
+ const pascalName = toPascal2(scriptBaseName);
3050
+ const manifestKey = pascalName;
3051
+ const scriptPath = manifest[manifestKey] || null;
3052
+ if (scriptPath) {
3053
+ logger.scriptUpdate(scriptFile, "htmx");
3054
+ broadcastToClients(state, {
3055
+ data: {
3056
+ framework: "htmx",
3057
+ scriptPath,
3058
+ sourceFile: scriptFile,
3059
+ manifest
3060
+ },
3061
+ type: "script-update"
3062
+ });
3063
+ }
3064
+ }
3065
+ }
3066
+ }
3067
+ }
3068
+ if (affectedFrameworks.includes("htmx") && filesToRebuild && state.resolvedPaths.htmxDir) {
3069
+ const htmxFrameworkFiles = filesToRebuild.filter((file4) => detectFramework(file4, state.resolvedPaths) === "htmx");
3070
+ if (htmxFrameworkFiles.length > 0) {
3071
+ const htmxPageFiles = htmxFrameworkFiles.filter((f) => f.endsWith(".html"));
3072
+ const isSingle = !config.reactDirectory && !config.svelteDirectory && !config.vueDirectory && !config.htmlDirectory;
3073
+ const outputHtmxPages = isSingle ? resolve17(state.resolvedPaths.buildDir, "pages") : resolve17(state.resolvedPaths.buildDir, basename8(config.htmxDirectory ?? "htmx"), "pages");
3074
+ for (const htmxPageFile of htmxPageFiles) {
3075
+ const htmxPageName = basename8(htmxPageFile);
3076
+ const builtHtmxPagePath = resolve17(outputHtmxPages, htmxPageName);
3077
+ try {
3078
+ const { handleHTMXUpdate: handleHTMXUpdate2 } = await Promise.resolve().then(() => (init_simpleHTMXHMR(), exports_simpleHTMXHMR));
3079
+ const newHTML = await handleHTMXUpdate2(builtHtmxPagePath);
3080
+ if (newHTML) {
3081
+ logger.hmrUpdate(htmxPageFile, "htmx");
3082
+ broadcastToClients(state, {
3083
+ data: {
3084
+ framework: "htmx",
3085
+ html: newHTML,
3086
+ sourceFile: builtHtmxPagePath
3087
+ },
3088
+ type: "htmx-update"
3089
+ });
3090
+ }
3091
+ } catch {}
3092
+ }
3093
+ }
3094
+ }
3095
+ const updatedModulePaths = [];
3096
+ for (const update of allModuleUpdates) {
3097
+ updatedModulePaths.push(update.sourceFile);
3098
+ for (const modulePath of Object.values(update.modulePaths)) {
3099
+ updatedModulePaths.push(modulePath);
3100
+ }
3101
+ }
3102
+ if (updatedModulePaths.length > 0) {
3103
+ incrementModuleVersions(state.moduleVersions, updatedModulePaths);
3104
+ }
3105
+ if (allModuleUpdates.length > 0) {
3106
+ const updatesByFramework = groupModuleUpdatesByFramework(allModuleUpdates);
3107
+ const serverVersions = serializeModuleVersions(state.moduleVersions);
3108
+ for (const [framework, updates] of updatesByFramework) {
3109
+ const moduleVersions = {};
3110
+ for (const update of updates) {
3111
+ const sourceVersion = state.moduleVersions.get(update.sourceFile);
3112
+ if (sourceVersion !== undefined) {
3113
+ moduleVersions[update.sourceFile] = sourceVersion;
3114
+ }
3115
+ for (const [, path] of Object.entries(update.modulePaths)) {
3116
+ const pathVersion = state.moduleVersions.get(path);
3117
+ if (pathVersion !== undefined) {
3118
+ moduleVersions[path] = pathVersion;
3119
+ }
3120
+ }
3121
+ }
3122
+ broadcastToClients(state, {
3123
+ data: {
3124
+ framework,
3125
+ manifest,
3126
+ modules: updates.map((update) => ({
3127
+ componentType: update.componentType,
3128
+ moduleKeys: update.moduleKeys,
3129
+ modulePaths: update.modulePaths,
3130
+ sourceFile: update.sourceFile,
3131
+ version: state.moduleVersions.get(update.sourceFile)
3132
+ })),
3133
+ moduleVersions,
3134
+ serverVersions
3135
+ },
3136
+ message: `${framework} modules updated`,
3137
+ type: "module-update"
3138
+ });
3139
+ }
3140
+ }
3141
+ }
3142
+ for (const framework of affectedFrameworks) {
3143
+ broadcastToClients(state, {
3144
+ data: {
3145
+ framework,
3146
+ manifest
3147
+ },
3148
+ message: `${framework} framework updated`,
3149
+ type: "framework-update"
3150
+ });
3151
+ }
3152
+ onRebuildComplete({ manifest, hmrState: state });
3153
+ await populateAssetStore(state.assetStore, manifest, state.resolvedPaths.buildDir);
3154
+ await cleanStaleAssets(state.assetStore, manifest, state.resolvedPaths.buildDir);
3155
+ return manifest;
759
3156
  } catch (error) {
760
- onError?.(error);
761
- throw error;
3157
+ const errorData = extractBuildErrorDetails(error, affectedFrameworks, state.resolvedPaths);
3158
+ broadcastToClients(state, {
3159
+ data: {
3160
+ affectedFrameworks,
3161
+ error: error instanceof Error ? error.message : String(error),
3162
+ ...errorData
3163
+ },
3164
+ message: "Rebuild failed",
3165
+ type: "rebuild-error"
3166
+ });
3167
+ return null;
3168
+ } finally {
3169
+ state.isRebuilding = false;
3170
+ if (state.fileChangeQueue.size > 0) {
3171
+ const pending = Array.from(state.fileChangeQueue.keys());
3172
+ const queuedFiles = [];
3173
+ for (const [, filePaths] of state.fileChangeQueue) {
3174
+ queuedFiles.push(...filePaths);
3175
+ }
3176
+ state.fileChangeQueue.clear();
3177
+ for (const f of pending)
3178
+ state.rebuildQueue.add(f);
3179
+ if (state.rebuildTimeout)
3180
+ clearTimeout(state.rebuildTimeout);
3181
+ state.rebuildTimeout = setTimeout(() => {
3182
+ triggerRebuild(state, config, onRebuildComplete, queuedFiles.length > 0 ? queuedFiles : undefined);
3183
+ }, 50);
3184
+ }
762
3185
  }
763
3186
  };
764
3187
 
765
- // src/core/pageHandlers.ts
766
- var handleReactPageRequest = async (pageComponent, index, ...props) => {
767
- const [maybeProps] = props;
768
- const element = maybeProps !== undefined ? createElement(pageComponent, maybeProps) : createElement(pageComponent);
769
- const stream = await renderReactToReadableStream(element, {
770
- bootstrapModules: [index],
771
- bootstrapScriptContent: maybeProps ? `window.__INITIAL_PROPS__=${JSON.stringify(maybeProps)}` : undefined
772
- });
773
- return new Response(stream, {
774
- headers: { "Content-Type": "text/html" }
775
- });
776
- };
777
- var handleSveltePageRequest = async (_PageComponent, pagePath, indexPath, props) => {
778
- const { default: ImportedPageComponent } = await import(pagePath);
779
- const stream = await renderToReadableStream(ImportedPageComponent, props, {
780
- bootstrapModules: indexPath ? [indexPath] : [],
781
- bootstrapScriptContent: `window.__INITIAL_PROPS__=${JSON.stringify(props)}`
782
- });
783
- return new Response(stream, {
784
- headers: { "Content-Type": "text/html" }
785
- });
786
- };
787
- var handleVuePageRequest = async (_PageComponent, pagePath, indexPath, headTag = "<head></head>", ...props) => {
788
- const [maybeProps] = props;
789
- const { default: ImportedPageComponent } = await import(pagePath);
790
- const app = createSSRApp({
791
- render: () => h(ImportedPageComponent, maybeProps ?? {})
792
- });
793
- const bodyStream = renderVueToWebStream(app);
794
- const head = `<!DOCTYPE html><html>${headTag}<body><div id="root">`;
795
- const tail = `</div><script>window.__INITIAL_PROPS__=${JSON.stringify(maybeProps ?? {})}</script><script type="module" src="${indexPath}"></script></body></html>`;
796
- const stream = new ReadableStream({
797
- start(controller) {
798
- controller.enqueue(head);
799
- const reader = bodyStream.getReader();
800
- const pumpLoop = () => {
801
- reader.read().then(({ done, value }) => done ? (controller.enqueue(tail), controller.close()) : (controller.enqueue(value), pumpLoop())).catch((err) => controller.error(err));
802
- };
803
- pumpLoop();
3188
+ // src/core/devBuild.ts
3189
+ var devBuild = async (config) => {
3190
+ const cached = globalThis.__hmrDevResult;
3191
+ if (cached) {
3192
+ const serverMtime = statSync(resolve18(Bun.main)).mtimeMs;
3193
+ const lastMtime = globalThis.__hmrServerMtime;
3194
+ globalThis.__hmrServerMtime = serverMtime;
3195
+ if (serverMtime !== lastMtime) {
3196
+ console.log("\x1B[36m[hmr] Server module reloaded\x1B[0m");
3197
+ } else {
3198
+ globalThis.__hmrSkipServerRestart = true;
3199
+ console.log("\x1B[36m[hmr] Hot module update detected\x1B[0m");
3200
+ }
3201
+ return cached;
3202
+ }
3203
+ const state = createHMRState(config);
3204
+ const watchPaths = getWatchPaths(config, state.resolvedPaths);
3205
+ buildInitialDependencyGraph(state.dependencyGraph, watchPaths);
3206
+ console.log("\uD83D\uDD28 Building AbsoluteJS with HMR...");
3207
+ const manifest = await build2({
3208
+ ...config,
3209
+ options: {
3210
+ ...config.options,
3211
+ preserveIntermediateFiles: true
804
3212
  }
805
3213
  });
806
- return new Response(stream, {
807
- headers: { "Content-Type": "text/html" }
3214
+ if (!manifest || Object.keys(manifest).length === 0) {
3215
+ console.log("\u26A0\uFE0F Manifest is empty - this is OK for HTML/HTMX-only projects");
3216
+ }
3217
+ await populateAssetStore(state.assetStore, manifest ?? {}, state.resolvedPaths.buildDir);
3218
+ await cleanStaleAssets(state.assetStore, manifest ?? {}, state.resolvedPaths.buildDir);
3219
+ console.log("\u2705 Build completed successfully");
3220
+ startFileWatching(state, config, (filePath) => {
3221
+ queueFileChange(state, filePath, config, (newBuildResult) => {
3222
+ Object.assign(manifest, newBuildResult.manifest);
3223
+ });
808
3224
  });
809
- };
810
- var handleHTMLPageRequest = (html) => file3(html);
811
- var handleHTMXPageRequest = (htmx) => file3(htmx);
812
- var handlePageRequest = (PageComponent, ...props) => {
813
- console.log("handlePageRequest coming soon.", PageComponent, props);
3225
+ console.log("\uD83D\uDC40 File watching: Active");
3226
+ console.log("\uD83D\uDD25 HMR: Ready");
3227
+ const result = {
3228
+ hmrState: state,
3229
+ manifest
3230
+ };
3231
+ globalThis.__hmrServerStartup = Date.now().toString();
3232
+ globalThis.__hmrDevResult = result;
3233
+ globalThis.__hmrServerMtime = statSync(resolve18(Bun.main)).mtimeMs;
3234
+ return result;
814
3235
  };
815
3236
  // src/core/lookup.ts
816
- var asset = (manifest, name) => {
817
- const assetPath = manifest[name];
3237
+ var isWrapped = (source) => ("manifest" in source) && typeof source.manifest === "object" && !Array.isArray(source.manifest);
3238
+ var asset = (source, name) => {
3239
+ const assetPath = isWrapped(source) ? source.manifest[name] : source[name];
818
3240
  if (assetPath === undefined) {
819
3241
  throw new Error(`Asset "${name}" not found in manifest.`);
820
3242
  }
821
3243
  return assetPath;
822
3244
  };
3245
+
3246
+ // src/core/index.ts
3247
+ init_pageHandlers();
3248
+ // src/plugins/pageRouter.ts
3249
+ var pageRouterPlugin = () => {
3250
+ console.log("Page Router Plugin Not Implemented Yet");
3251
+ };
3252
+ // src/plugins/hmr.ts
3253
+ var STORE_KEY = "__elysiaStore";
3254
+ var restoreStore = (app) => {
3255
+ const saved = globalThis[STORE_KEY];
3256
+ if (saved) {
3257
+ const store = app.store;
3258
+ for (const key of Object.keys(saved)) {
3259
+ store[key] = saved[key];
3260
+ }
3261
+ }
3262
+ globalThis[STORE_KEY] = app.store;
3263
+ };
3264
+ var hmr = (hmrState2, manifest) => {
3265
+ return (app) => {
3266
+ restoreStore(app);
3267
+ return app.onBeforeHandle(({ request }) => {
3268
+ const rawUrl = request.url;
3269
+ const qIdx = rawUrl.indexOf("?");
3270
+ const pathEnd = qIdx === -1 ? rawUrl.length : qIdx;
3271
+ const pathStart = rawUrl.indexOf("/", rawUrl.indexOf("//") + 2);
3272
+ const pathname = rawUrl.slice(pathStart, pathEnd);
3273
+ const bytes = lookupAsset(hmrState2.assetStore, pathname);
3274
+ if (bytes) {
3275
+ return new Response(new Uint8Array(bytes).buffer, {
3276
+ headers: {
3277
+ "Cache-Control": "public, max-age=31536000, immutable",
3278
+ "Content-Type": getMimeType(pathname)
3279
+ }
3280
+ });
3281
+ }
3282
+ }).ws("/hmr", {
3283
+ close: (ws) => handleClientDisconnect(hmrState2, ws),
3284
+ message: (ws, msg) => handleHMRMessage(hmrState2, ws, msg),
3285
+ open: (ws) => handleClientConnect(hmrState2, ws, manifest)
3286
+ }).get("/hmr-status", () => ({
3287
+ connectedClients: hmrState2.connectedClients.size,
3288
+ isRebuilding: hmrState2.isRebuilding,
3289
+ manifestKeys: Object.keys(manifest),
3290
+ rebuildQueue: Array.from(hmrState2.rebuildQueue),
3291
+ timestamp: Date.now()
3292
+ }));
3293
+ };
3294
+ };
823
3295
  // src/plugins/networking.ts
3296
+ init_constants();
824
3297
  import { argv } from "process";
825
3298
  var {env: env3 } = globalThis.Bun;
826
3299
 
827
3300
  // src/utils/networking.ts
828
3301
  import os from "os";
829
- var getLocalIPAddress = () => {
3302
+ var getAllNetworkIPs = () => {
830
3303
  const interfaces = os.networkInterfaces();
831
3304
  const addresses = Object.values(interfaces).flat().filter((iface) => iface !== undefined);
832
- const ipAddress = addresses.find((iface) => iface.family === "IPv4" && !iface.internal);
833
- if (ipAddress)
834
- return ipAddress.address;
3305
+ const ipv4Addresses = [];
3306
+ for (const addr of addresses) {
3307
+ if (addr.internal)
3308
+ continue;
3309
+ if (addr.family === "IPv4") {
3310
+ ipv4Addresses.push(addr.address);
3311
+ }
3312
+ }
3313
+ return ipv4Addresses;
3314
+ };
3315
+ var getLocalIPAddress = () => {
3316
+ const allIPs = getAllNetworkIPs();
3317
+ if (allIPs.length > 0 && allIPs[0]) {
3318
+ return allIPs[0];
3319
+ }
835
3320
  console.warn("No IP address found, falling back to localhost");
836
3321
  return "localhost";
837
3322
  };
@@ -857,28 +3342,6 @@ var networking = (app) => app.listen({
857
3342
  console.log(`Server started on http://${host}:${port}`);
858
3343
  }
859
3344
  });
860
- // src/plugins/pageRouter.ts
861
- var pageRouterPlugin = () => {
862
- console.log("Page Router Plugin Not Implemented Yet");
863
- };
864
- // src/utils/generateHeadElement.ts
865
- var generateHeadElement = ({
866
- cssPath,
867
- title = "AbsoluteJS",
868
- description = "A page created using AbsoluteJS",
869
- font,
870
- icon = "/assets/ico/favicon.ico"
871
- } = {}) => `<head>
872
- <meta charset="UTF-8">
873
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
874
- <title>${title}</title>
875
- <meta name="description" content="${description}">
876
- <link rel="icon" href="${icon}" type="image/x-icon">
877
- ${font ? `<link rel="preconnect" href="https://fonts.googleapis.com">
878
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
879
- <link href="https://fonts.googleapis.com/css2?family=${font}:wght@100..900&display=swap" rel="stylesheet">` : ""}
880
- ${cssPath ? `<link rel="stylesheet" href="${cssPath}" type="text/css">` : ""}
881
- </head>`;
882
3345
  // src/utils/getEnv.ts
883
3346
  var {env: env4 } = globalThis.Bun;
884
3347
  var getEnv = (key) => {
@@ -888,21 +3351,108 @@ var getEnv = (key) => {
888
3351
  }
889
3352
  return environmentVariable;
890
3353
  };
3354
+ // src/utils/registerClientScript.ts
3355
+ var scriptRegistry = new Map;
3356
+ var requestCounter = 0;
3357
+ var getRequestId = () => `req_${Date.now()}_${++requestCounter}`;
3358
+ var registerClientScript = (script, requestId) => {
3359
+ const id = requestId || globalThis.__absolutejs_requestId || getRequestId();
3360
+ if (!scriptRegistry.has(id)) {
3361
+ scriptRegistry.set(id, new Set);
3362
+ }
3363
+ scriptRegistry.get(id).add(script);
3364
+ return id;
3365
+ };
3366
+ if (typeof globalThis !== "undefined") {
3367
+ globalThis.registerClientScript = registerClientScript;
3368
+ }
3369
+ var getAndClearClientScripts = (requestId) => {
3370
+ const scripts = scriptRegistry.get(requestId);
3371
+ if (!scripts) {
3372
+ return [];
3373
+ }
3374
+ const scriptArray = Array.from(scripts);
3375
+ scriptRegistry.delete(requestId);
3376
+ return scriptArray;
3377
+ };
3378
+ var generateClientScriptCode = (scripts) => {
3379
+ if (scripts.length === 0) {
3380
+ return "";
3381
+ }
3382
+ const scriptCode = scripts.map((script, index) => {
3383
+ const funcString = script.toString();
3384
+ const bodyMatch = funcString.match(/\{([\s\S]*)\}/);
3385
+ if (!bodyMatch || !bodyMatch[1]) {
3386
+ return "";
3387
+ }
3388
+ const body = bodyMatch[1].trim();
3389
+ return `
3390
+ (function() {
3391
+ function executeScript_${index}() {
3392
+ ${body}
3393
+ }
3394
+
3395
+ // Try executing immediately if DOM is ready
3396
+ if (document.readyState === 'complete' || document.readyState === 'interactive') {
3397
+ executeScript_${index}();
3398
+ } else {
3399
+ document.addEventListener('DOMContentLoaded', executeScript_${index});
3400
+ }
3401
+
3402
+ // Also try with delays to ensure element is available after hydration
3403
+ setTimeout(executeScript_${index}, 100);
3404
+ setTimeout(executeScript_${index}, 300);
3405
+ setTimeout(executeScript_${index}, 500);
3406
+ setTimeout(executeScript_${index}, 1000);
3407
+
3408
+ // Fallback on window load
3409
+ window.addEventListener('load', executeScript_${index});
3410
+ })();`;
3411
+ }).join(`
3412
+ `);
3413
+ return `<script>
3414
+ (function() {
3415
+ ${scriptCode}
3416
+ })();
3417
+ </script>`;
3418
+ };
3419
+ var clearAllClientScripts = () => {
3420
+ scriptRegistry.clear();
3421
+ };
3422
+ // src/utils/getRegisterClientScript.ts
3423
+ var getRegisterClientScript = () => {
3424
+ const globalRegister = globalThis.registerClientScript;
3425
+ if (globalRegister && typeof globalRegister === "function") {
3426
+ return globalRegister;
3427
+ }
3428
+ return null;
3429
+ };
891
3430
  export {
892
3431
  updateAssetPaths,
3432
+ registerClientScript,
893
3433
  pageRouterPlugin,
894
3434
  networking,
3435
+ isValidHMRClientMessage,
3436
+ hmrState,
3437
+ hmr,
895
3438
  handleVuePageRequest,
896
3439
  handleSveltePageRequest,
897
3440
  handleReactPageRequest,
898
3441
  handlePageRequest,
899
3442
  handleHTMXPageRequest,
900
3443
  handleHTMLPageRequest,
3444
+ getRegisterClientScript,
901
3445
  getLocalIPAddress,
902
3446
  getEnv,
3447
+ getAndClearClientScripts,
3448
+ getAllNetworkIPs,
903
3449
  generateHeadElement,
904
- build,
3450
+ generateClientScriptCode,
3451
+ devBuild,
3452
+ clearAllClientScripts,
3453
+ build2 as build,
905
3454
  asset,
3455
+ WS_READY_STATE_OPEN,
906
3456
  UNFOUND_INDEX,
907
3457
  TWO_THIRDS,
908
3458
  TIME_PRECISION,
@@ -917,5 +3467,5 @@ export {
917
3467
  BUN_BUILD_WARNING_SUPPRESSION
918
3468
  };
919
3469
 
920
- //# debugId=C07A521038D2FB1664756E2164756E21
3470
+ //# debugId=74202B6229702A7564756E2164756E21
921
3471
  //# sourceMappingURL=index.js.map