@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.
- package/.claude/settings.local.json +11 -0
- package/CLAUDE.md +11 -2
- package/LICENSE +74 -18
- package/README.md +4 -4
- package/THIRD_PARTY_NOTICES.md +61 -0
- package/dist/cli/index.js +24 -8
- package/dist/dev/client/cssUtils.ts +288 -0
- package/dist/dev/client/domDiff.ts +261 -0
- package/dist/dev/client/domState.ts +271 -0
- package/dist/dev/client/errorOverlay.ts +145 -0
- package/dist/dev/client/frameworkDetect.ts +63 -0
- package/dist/dev/client/handlers/html.ts +415 -0
- package/dist/dev/client/handlers/htmx.ts +248 -0
- package/dist/dev/client/handlers/react.ts +80 -0
- package/dist/dev/client/handlers/rebuild.ts +147 -0
- package/dist/dev/client/handlers/svelte.ts +129 -0
- package/dist/dev/client/handlers/vue.ts +254 -0
- package/dist/dev/client/headPatch.ts +213 -0
- package/dist/dev/client/hmrClient.ts +204 -0
- package/dist/dev/client/moduleVersions.ts +57 -0
- package/dist/dev/client/reactRefreshSetup.ts +21 -0
- package/dist/index.js +3028 -478
- package/dist/index.js.map +49 -19
- package/dist/{build → src/build}/compileSvelte.d.ts +2 -1
- package/dist/src/build/compileVue.d.ts +33 -0
- package/dist/src/build/generateReactIndexes.d.ts +1 -0
- package/dist/src/build/htmlScriptHMRPlugin.d.ts +13 -0
- package/dist/src/build/wrapHTMLScript.d.ts +24 -0
- package/dist/{core → src/core}/build.d.ts +2 -2
- package/dist/src/core/devBuild.d.ts +6 -0
- package/dist/{core → src/core}/index.d.ts +2 -1
- package/dist/src/core/lookup.d.ts +3 -0
- package/dist/{core → src/core}/pageHandlers.d.ts +4 -4
- package/dist/src/dev/assetStore.d.ts +12 -0
- package/dist/src/dev/buildHMRClient.d.ts +1 -0
- package/dist/src/dev/clientManager.d.ts +26 -0
- package/dist/src/dev/configResolver.d.ts +13 -0
- package/dist/src/dev/dependencyGraph.d.ts +13 -0
- package/dist/src/dev/fileHashTracker.d.ts +2 -0
- package/dist/src/dev/fileWatcher.d.ts +3 -0
- package/dist/src/dev/moduleMapper.d.ts +21 -0
- package/dist/src/dev/moduleVersionTracker.d.ts +7 -0
- package/dist/src/dev/pathUtils.d.ts +5 -0
- package/dist/src/dev/reactComponentClassifier.d.ts +2 -0
- package/dist/src/dev/rebuildTrigger.d.ts +10 -0
- package/dist/src/dev/simpleHTMLHMR.d.ts +4 -0
- package/dist/src/dev/simpleHTMXHMR.d.ts +4 -0
- package/dist/src/dev/simpleSvelteHMR.d.ts +1 -0
- package/dist/src/dev/simpleVueHMR.d.ts +1 -0
- package/dist/src/dev/webSocket.d.ts +9 -0
- package/dist/{index.d.ts → src/index.d.ts} +1 -0
- package/dist/src/plugins/hmr.d.ts +62 -0
- package/dist/{plugins → src/plugins}/index.d.ts +2 -1
- package/dist/{svelte → src/svelte}/renderToReadableStream.d.ts +3 -1
- package/dist/src/utils/getRegisterClientScript.d.ts +10 -0
- package/dist/{utils → src/utils}/index.d.ts +2 -0
- package/dist/src/utils/logger.d.ts +45 -0
- package/dist/src/utils/networking.d.ts +2 -0
- package/dist/src/utils/normalizePath.d.ts +9 -0
- package/dist/src/utils/registerClientScript.d.ts +51 -0
- package/dist/{types.d.ts → types/build.d.ts} +6 -0
- package/dist/types/client.d.ts +104 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/messages.d.ts +138 -0
- package/dist/types/websocket.d.ts +6 -0
- package/eslint.config.mjs +5 -1
- package/package.json +19 -14
- package/tsconfig.build.json +1 -1
- package/types/build.ts +46 -0
- package/types/client.ts +109 -0
- package/types/index.ts +4 -0
- package/types/messages.ts +205 -0
- package/types/websocket.ts +12 -0
- package/types/window-globals.ts +53 -0
- package/dist/build/compileVue.d.ts +0 -5
- package/dist/build/generateReactIndexes.d.ts +0 -1
- package/dist/core/lookup.d.ts +0 -1
- package/dist/utils/networking.d.ts +0 -1
- /package/dist/{build → src/build}/generateManifest.d.ts +0 -0
- /package/dist/{build → src/build}/outputLogs.d.ts +0 -0
- /package/dist/{build → src/build}/scanEntryPoints.d.ts +0 -0
- /package/dist/{build → src/build}/updateAssetPaths.d.ts +0 -0
- /package/dist/{cli → src/cli}/index.d.ts +0 -0
- /package/dist/{constants.d.ts → src/constants.d.ts} +0 -0
- /package/dist/{plugins → src/plugins}/networking.d.ts +0 -0
- /package/dist/{plugins → src/plugins}/pageRouter.d.ts +0 -0
- /package/dist/{svelte → src/svelte}/renderToPipeableStream.d.ts +0 -0
- /package/dist/{svelte → src/svelte}/renderToString.d.ts +0 -0
- /package/dist/{utils → src/utils}/cleanup.d.ts +0 -0
- /package/dist/{utils → src/utils}/commonAncestor.d.ts +0 -0
- /package/dist/{utils → src/utils}/escapeScriptContent.d.ts +0 -0
- /package/dist/{utils → src/utils}/generateHeadElement.d.ts +0 -0
- /package/dist/{utils → src/utils}/getDurationString.d.ts +0 -0
- /package/dist/{utils → src/utils}/getEnv.d.ts +0 -0
- /package/dist/{utils → src/utils}/stringModifiers.d.ts +0 -0
- /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
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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/
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
56
|
-
|
|
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
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
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
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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) =>
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
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
|
-
|
|
250
|
-
const
|
|
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
|
-
"
|
|
299
|
-
|
|
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/
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
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/
|
|
393
|
-
var
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
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/
|
|
407
|
-
var
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
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(
|
|
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(
|
|
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
|
|
1461
|
+
import { resolve as resolve5, relative as relative3 } from "path";
|
|
492
1462
|
var validateSafePath = (targetPath, baseDirectory) => {
|
|
493
|
-
const absoluteBase =
|
|
494
|
-
const absoluteTarget =
|
|
495
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
560
|
-
|
|
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
|
-
|
|
564
|
-
|
|
565
|
-
|
|
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
|
-
|
|
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
|
-
|
|
573
|
-
const
|
|
574
|
-
const
|
|
575
|
-
const
|
|
576
|
-
const
|
|
577
|
-
const
|
|
578
|
-
const
|
|
579
|
-
const
|
|
580
|
-
const
|
|
581
|
-
const
|
|
582
|
-
const
|
|
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
|
|
585
|
-
|
|
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 &&
|
|
598
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
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:
|
|
1669
|
+
minify: !isDev,
|
|
634
1670
|
naming: `[dir]/[name].[hash].[ext]`,
|
|
635
1671
|
outdir: buildPath,
|
|
636
1672
|
root: clientRoot,
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
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
|
-
|
|
643
|
-
|
|
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
|
|
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
|
-
|
|
654
|
-
|
|
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
|
-
|
|
658
|
-
|
|
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
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
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
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
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
|
-
|
|
2507
|
+
grouped.get(update.framework).push(update);
|
|
689
2508
|
}
|
|
690
|
-
|
|
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/
|
|
710
|
-
var
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
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/
|
|
724
|
-
var
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
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
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
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
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
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
|
-
|
|
751
|
-
|
|
752
|
-
|
|
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
|
-
|
|
761
|
-
|
|
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/
|
|
766
|
-
var
|
|
767
|
-
const
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
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
|
-
|
|
807
|
-
|
|
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
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
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
|
|
817
|
-
|
|
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
|
|
3302
|
+
var getAllNetworkIPs = () => {
|
|
830
3303
|
const interfaces = os.networkInterfaces();
|
|
831
3304
|
const addresses = Object.values(interfaces).flat().filter((iface) => iface !== undefined);
|
|
832
|
-
const
|
|
833
|
-
|
|
834
|
-
|
|
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
|
-
|
|
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=
|
|
3470
|
+
//# debugId=74202B6229702A7564756E2164756E21
|
|
921
3471
|
//# sourceMappingURL=index.js.map
|