hadars 0.1.15 → 0.1.17
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/dist/cli.js +45 -28
- package/dist/ssr-watch.js +3 -0
- package/package.json +1 -1
- package/src/build.ts +50 -27
- package/src/utils/rspack.ts +3 -0
package/dist/cli.js
CHANGED
|
@@ -507,6 +507,9 @@ var buildCompilerConfig = (entry, opts, includeHotPlugin) => {
|
|
|
507
507
|
clean: false
|
|
508
508
|
},
|
|
509
509
|
mode: opts.mode,
|
|
510
|
+
// Persist transformed modules to disk — subsequent starts only recompile
|
|
511
|
+
// changed files, making repeat dev starts significantly faster.
|
|
512
|
+
cache: true,
|
|
510
513
|
externals,
|
|
511
514
|
...optimization !== void 0 ? { optimization } : {},
|
|
512
515
|
plugins: [
|
|
@@ -794,6 +797,14 @@ async function processHtmlTemplate(templatePath) {
|
|
|
794
797
|
}
|
|
795
798
|
if (matches.length === 0)
|
|
796
799
|
return templatePath;
|
|
800
|
+
await ensureHadarsTmpDir();
|
|
801
|
+
const sourceHash = crypto.createHash("md5").update(html).digest("hex").slice(0, 8);
|
|
802
|
+
const cachedPath = pathMod3.join(HADARS_TMP_DIR, `template-${sourceHash}.html`);
|
|
803
|
+
try {
|
|
804
|
+
await fs.access(cachedPath);
|
|
805
|
+
return cachedPath;
|
|
806
|
+
} catch {
|
|
807
|
+
}
|
|
797
808
|
const { default: postcss } = await import("postcss");
|
|
798
809
|
let plugins = [];
|
|
799
810
|
try {
|
|
@@ -805,15 +816,14 @@ async function processHtmlTemplate(templatePath) {
|
|
|
805
816
|
let processedHtml = html;
|
|
806
817
|
for (const { full, attrs, css } of matches) {
|
|
807
818
|
try {
|
|
808
|
-
const result = await postcss(plugins).process(css, { from:
|
|
819
|
+
const result = await postcss(plugins).process(css, { from: templatePath });
|
|
809
820
|
processedHtml = processedHtml.replace(full, `<style${attrs}>${result.css}</style>`);
|
|
810
821
|
} catch (err) {
|
|
811
822
|
console.warn("[hadars] PostCSS error processing <style> block in HTML template:", err);
|
|
812
823
|
}
|
|
813
824
|
}
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
return tmpPath;
|
|
825
|
+
await fs.writeFile(cachedPath, processedHtml);
|
|
826
|
+
return cachedPath;
|
|
817
827
|
}
|
|
818
828
|
var HEAD_MARKER = '<meta name="HADARS_HEAD">';
|
|
819
829
|
var BODY_MARKER = '<meta name="HADARS_BODY">';
|
|
@@ -1072,6 +1082,8 @@ var __dirname2 = process.cwd();
|
|
|
1072
1082
|
var getSuffix = (mode) => mode === "development" ? `?v=${Date.now()}` : "";
|
|
1073
1083
|
var HadarsFolder = "./.hadars";
|
|
1074
1084
|
var StaticPath = `${HadarsFolder}/static`;
|
|
1085
|
+
var HADARS_TMP_DIR = pathMod3.join(os.tmpdir(), "hadars");
|
|
1086
|
+
var ensureHadarsTmpDir = () => fs.mkdir(HADARS_TMP_DIR, { recursive: true });
|
|
1075
1087
|
var validateOptions = (options) => {
|
|
1076
1088
|
if (!options.entry) {
|
|
1077
1089
|
throw new Error("Entry file is required");
|
|
@@ -1127,7 +1139,8 @@ var dev = async (options) => {
|
|
|
1127
1139
|
console.error("Failed to read client script from package dist, falling back to src", err);
|
|
1128
1140
|
throw err;
|
|
1129
1141
|
}
|
|
1130
|
-
|
|
1142
|
+
await ensureHadarsTmpDir();
|
|
1143
|
+
const tmpFilePath = pathMod3.join(HADARS_TMP_DIR, `client-${Date.now()}.tsx`);
|
|
1131
1144
|
await fs.writeFile(tmpFilePath, clientScript);
|
|
1132
1145
|
let ssrBuildId = crypto.randomBytes(4).toString("hex");
|
|
1133
1146
|
const resolvedHtmlTemplate = options.htmlTemplate ? await processHtmlTemplate(pathMod3.resolve(__dirname2, options.htmlTemplate)) : void 0;
|
|
@@ -1234,29 +1247,31 @@ var dev = async (options) => {
|
|
|
1234
1247
|
stdoutReader = null;
|
|
1235
1248
|
}
|
|
1236
1249
|
})();
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1250
|
+
const readyPromise = Promise.all([clientBuildDone, ssrBuildDone]);
|
|
1251
|
+
readyPromise.then(() => {
|
|
1252
|
+
if (stdoutReader) {
|
|
1253
|
+
const reader = stdoutReader;
|
|
1254
|
+
(async () => {
|
|
1255
|
+
try {
|
|
1256
|
+
while (true) {
|
|
1257
|
+
const { done, value } = await reader.read();
|
|
1258
|
+
if (done)
|
|
1259
|
+
break;
|
|
1260
|
+
const chunk = decoder.decode(value, { stream: true });
|
|
1261
|
+
try {
|
|
1262
|
+
process.stdout.write(chunk);
|
|
1263
|
+
} catch (e) {
|
|
1264
|
+
}
|
|
1265
|
+
if (chunk.includes(rebuildMarker)) {
|
|
1266
|
+
ssrBuildId = crypto.randomBytes(4).toString("hex");
|
|
1267
|
+
console.log("[hadars] SSR bundle updated, build id:", ssrBuildId);
|
|
1268
|
+
}
|
|
1254
1269
|
}
|
|
1270
|
+
} catch (e) {
|
|
1255
1271
|
}
|
|
1256
|
-
}
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
}
|
|
1272
|
+
})();
|
|
1273
|
+
}
|
|
1274
|
+
});
|
|
1260
1275
|
(async () => {
|
|
1261
1276
|
try {
|
|
1262
1277
|
const r = stderrWebStream.getReader();
|
|
@@ -1273,9 +1288,10 @@ var dev = async (options) => {
|
|
|
1273
1288
|
}
|
|
1274
1289
|
})();
|
|
1275
1290
|
const getPrecontentHtml = makePrecontentHtmlGetter(
|
|
1276
|
-
fs.readFile(pathMod3.join(__dirname2, StaticPath, "out.html"), "utf-8")
|
|
1291
|
+
readyPromise.then(() => fs.readFile(pathMod3.join(__dirname2, StaticPath, "out.html"), "utf-8"))
|
|
1277
1292
|
);
|
|
1278
1293
|
await serve(port, async (req, ctx) => {
|
|
1294
|
+
await readyPromise;
|
|
1279
1295
|
const request = parseRequest(req);
|
|
1280
1296
|
if (handler) {
|
|
1281
1297
|
const res = await handler(request);
|
|
@@ -1338,7 +1354,8 @@ var build = async (options) => {
|
|
|
1338
1354
|
const srcClientPath = pathMod3.resolve(packageDir2, "utils", "clientScript.tsx");
|
|
1339
1355
|
clientScript = (await fs.readFile(srcClientPath, "utf-8")).replace("$_MOD_PATH$", entry + `?v=${Date.now()}`);
|
|
1340
1356
|
}
|
|
1341
|
-
|
|
1357
|
+
await ensureHadarsTmpDir();
|
|
1358
|
+
const tmpFilePath = pathMod3.join(HADARS_TMP_DIR, `client-${Date.now()}.tsx`);
|
|
1342
1359
|
await fs.writeFile(tmpFilePath, clientScript);
|
|
1343
1360
|
const resolvedHtmlTemplate = options.htmlTemplate ? await processHtmlTemplate(pathMod3.resolve(__dirname2, options.htmlTemplate)) : void 0;
|
|
1344
1361
|
console.log("Building client and server bundles in parallel...");
|
package/dist/ssr-watch.js
CHANGED
|
@@ -233,6 +233,9 @@ var buildCompilerConfig = (entry2, opts, includeHotPlugin) => {
|
|
|
233
233
|
clean: false
|
|
234
234
|
},
|
|
235
235
|
mode: opts.mode,
|
|
236
|
+
// Persist transformed modules to disk — subsequent starts only recompile
|
|
237
|
+
// changed files, making repeat dev starts significantly faster.
|
|
238
|
+
cache: true,
|
|
236
239
|
externals,
|
|
237
240
|
...optimization !== void 0 ? { optimization } : {},
|
|
238
241
|
plugins: [
|
package/package.json
CHANGED
package/src/build.ts
CHANGED
|
@@ -36,6 +36,16 @@ async function processHtmlTemplate(templatePath: string): Promise<string> {
|
|
|
36
36
|
}
|
|
37
37
|
if (matches.length === 0) return templatePath;
|
|
38
38
|
|
|
39
|
+
await ensureHadarsTmpDir();
|
|
40
|
+
|
|
41
|
+
// Cache by content hash — same template content → skip Tailwind re-scan on restart.
|
|
42
|
+
const sourceHash = crypto.createHash('md5').update(html).digest('hex').slice(0, 8);
|
|
43
|
+
const cachedPath = pathMod.join(HADARS_TMP_DIR, `template-${sourceHash}.html`);
|
|
44
|
+
try {
|
|
45
|
+
await fs.access(cachedPath);
|
|
46
|
+
return cachedPath; // cache hit
|
|
47
|
+
} catch { /* cache miss — process below */ }
|
|
48
|
+
|
|
39
49
|
const { default: postcss } = await import('postcss');
|
|
40
50
|
let plugins: any[] = [];
|
|
41
51
|
try {
|
|
@@ -49,16 +59,15 @@ async function processHtmlTemplate(templatePath: string): Promise<string> {
|
|
|
49
59
|
let processedHtml = html;
|
|
50
60
|
for (const { full, attrs, css } of matches) {
|
|
51
61
|
try {
|
|
52
|
-
const result = await postcss(plugins).process(css, { from:
|
|
62
|
+
const result = await postcss(plugins).process(css, { from: templatePath });
|
|
53
63
|
processedHtml = processedHtml.replace(full, `<style${attrs}>${result.css}</style>`);
|
|
54
64
|
} catch (err) {
|
|
55
65
|
console.warn('[hadars] PostCSS error processing <style> block in HTML template:', err);
|
|
56
66
|
}
|
|
57
67
|
}
|
|
58
68
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
return tmpPath;
|
|
69
|
+
await fs.writeFile(cachedPath, processedHtml);
|
|
70
|
+
return cachedPath;
|
|
62
71
|
}
|
|
63
72
|
|
|
64
73
|
const HEAD_MARKER = '<meta name="HADARS_HEAD">';
|
|
@@ -395,6 +404,11 @@ const getSuffix = (mode: Mode) => mode === 'development' ? `?v=${Date.now()}` :
|
|
|
395
404
|
|
|
396
405
|
const HadarsFolder = './.hadars';
|
|
397
406
|
const StaticPath = `${HadarsFolder}/static`;
|
|
407
|
+
// Dedicated temp directory — keeps all hadars temp files out of the root of
|
|
408
|
+
// os.tmpdir() so rspack's file watcher doesn't traverse unrelated system files
|
|
409
|
+
// (e.g. Steam/Chrome shared-memory device files) in that directory.
|
|
410
|
+
const HADARS_TMP_DIR = pathMod.join(os.tmpdir(), 'hadars');
|
|
411
|
+
const ensureHadarsTmpDir = () => fs.mkdir(HADARS_TMP_DIR, { recursive: true });
|
|
398
412
|
|
|
399
413
|
const validateOptions = (options: HadarsRuntimeOptions) => {
|
|
400
414
|
if (!options.entry) {
|
|
@@ -481,7 +495,8 @@ export const dev = async (options: HadarsRuntimeOptions) => {
|
|
|
481
495
|
throw err;
|
|
482
496
|
}
|
|
483
497
|
|
|
484
|
-
|
|
498
|
+
await ensureHadarsTmpDir();
|
|
499
|
+
const tmpFilePath = pathMod.join(HADARS_TMP_DIR, `client-${Date.now()}.tsx`);
|
|
485
500
|
await fs.writeFile(tmpFilePath, clientScript);
|
|
486
501
|
|
|
487
502
|
// SSR live-reload id to force re-import
|
|
@@ -601,27 +616,32 @@ export const dev = async (options: HadarsRuntimeOptions) => {
|
|
|
601
616
|
}
|
|
602
617
|
})();
|
|
603
618
|
|
|
604
|
-
//
|
|
605
|
-
await
|
|
606
|
-
|
|
607
|
-
//
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
619
|
+
// Both builds run in parallel — this promise resolves when they're both done.
|
|
620
|
+
// We do NOT await it here; the server starts immediately below so that the
|
|
621
|
+
// port is bound right away. Incoming requests await this promise before
|
|
622
|
+
// processing, so they hold in-flight and all resolve together once ready.
|
|
623
|
+
const readyPromise = Promise.all([clientBuildDone, ssrBuildDone]);
|
|
624
|
+
|
|
625
|
+
readyPromise.then(() => {
|
|
626
|
+
// Continue reading stdout to forward logs and pick up SSR rebuild signals.
|
|
627
|
+
if (stdoutReader) {
|
|
628
|
+
const reader = stdoutReader as ReadableStreamDefaultReader<Uint8Array>;
|
|
629
|
+
(async () => {
|
|
630
|
+
try {
|
|
631
|
+
while (true) {
|
|
632
|
+
const { done, value } = await reader.read();
|
|
633
|
+
if (done) break;
|
|
634
|
+
const chunk = decoder.decode(value, { stream: true });
|
|
635
|
+
try { process.stdout.write(chunk); } catch (e) { }
|
|
636
|
+
if (chunk.includes(rebuildMarker)) {
|
|
637
|
+
ssrBuildId = crypto.randomBytes(4).toString('hex');
|
|
638
|
+
console.log('[hadars] SSR bundle updated, build id:', ssrBuildId);
|
|
639
|
+
}
|
|
620
640
|
}
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
}
|
|
641
|
+
} catch (e) { }
|
|
642
|
+
})();
|
|
643
|
+
}
|
|
644
|
+
});
|
|
625
645
|
|
|
626
646
|
// Forward stderr asynchronously
|
|
627
647
|
(async () => {
|
|
@@ -636,10 +656,12 @@ export const dev = async (options: HadarsRuntimeOptions) => {
|
|
|
636
656
|
})();
|
|
637
657
|
|
|
638
658
|
const getPrecontentHtml = makePrecontentHtmlGetter(
|
|
639
|
-
fs.readFile(pathMod.join(__dirname, StaticPath, 'out.html'), 'utf-8')
|
|
659
|
+
readyPromise.then(() => fs.readFile(pathMod.join(__dirname, StaticPath, 'out.html'), 'utf-8'))
|
|
640
660
|
);
|
|
641
661
|
|
|
642
662
|
await serve(port, async (req, ctx) => {
|
|
663
|
+
// Hold requests until both builds are ready. Once resolved this is a no-op.
|
|
664
|
+
await readyPromise;
|
|
643
665
|
const request = parseRequest(req);
|
|
644
666
|
if (handler) {
|
|
645
667
|
const res = await handler(request);
|
|
@@ -716,7 +738,8 @@ export const build = async (options: HadarsRuntimeOptions) => {
|
|
|
716
738
|
.replace('$_MOD_PATH$', entry + `?v=${Date.now()}`);
|
|
717
739
|
}
|
|
718
740
|
|
|
719
|
-
|
|
741
|
+
await ensureHadarsTmpDir();
|
|
742
|
+
const tmpFilePath = pathMod.join(HADARS_TMP_DIR, `client-${Date.now()}.tsx`);
|
|
720
743
|
await fs.writeFile(tmpFilePath, clientScript);
|
|
721
744
|
|
|
722
745
|
// Pre-process the HTML template's <style> blocks through PostCSS (e.g. Tailwind).
|
package/src/utils/rspack.ts
CHANGED
|
@@ -288,6 +288,9 @@ const buildCompilerConfig = (
|
|
|
288
288
|
clean: false,
|
|
289
289
|
},
|
|
290
290
|
mode: opts.mode,
|
|
291
|
+
// Persist transformed modules to disk — subsequent starts only recompile
|
|
292
|
+
// changed files, making repeat dev starts significantly faster.
|
|
293
|
+
cache: true,
|
|
291
294
|
externals,
|
|
292
295
|
...(optimization !== undefined ? { optimization } : {}),
|
|
293
296
|
plugins: [
|