@akanjs/cli 2.4.1-rc.4 → 2.4.1-rc.5
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/.build-stamp +1 -1
- package/buildBatch.proc.js +17 -1
- package/incrementalBuilder.proc.js +66 -33
- package/package.json +2 -2
package/.build-stamp
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
97b051f1849d61848768f6c43d1dbcc90953864ce31504f1f376a61adb4481fb
|
package/buildBatch.proc.js
CHANGED
|
@@ -8,7 +8,8 @@ import {
|
|
|
8
8
|
CsrArtifactBuilder,
|
|
9
9
|
CssCompiler,
|
|
10
10
|
FontOptimizer,
|
|
11
|
-
PagesBundleBuilder
|
|
11
|
+
PagesBundleBuilder,
|
|
12
|
+
SsrBaseArtifactBuilder
|
|
12
13
|
} from "./index-khzzttv1.js";
|
|
13
14
|
import"./index-0fn1r7gg.js";
|
|
14
15
|
import"./index-6pz1j0zj.js";
|
|
@@ -29,6 +30,8 @@ class BuildBatch {
|
|
|
29
30
|
this.#result = { generation: request.generation, errors: {} };
|
|
30
31
|
}
|
|
31
32
|
async run() {
|
|
33
|
+
if (this.#request.needs.includes("base"))
|
|
34
|
+
await this.#buildBase();
|
|
32
35
|
if (this.#request.needs.includes("csr"))
|
|
33
36
|
await this.#buildCsr();
|
|
34
37
|
if (this.#request.needs.includes("pages"))
|
|
@@ -52,6 +55,19 @@ class BuildBatch {
|
|
|
52
55
|
}
|
|
53
56
|
});
|
|
54
57
|
}
|
|
58
|
+
async#buildBase() {
|
|
59
|
+
const started = Date.now();
|
|
60
|
+
try {
|
|
61
|
+
const { artifact, optimizedFonts } = await new SsrBaseArtifactBuilder(this.#app).build();
|
|
62
|
+
this.#result.artifact = artifact;
|
|
63
|
+
this.#result.optimizedFonts = optimizedFonts;
|
|
64
|
+
this.#logger.verbose(`base-artifact ok buildId=${artifact.pagesBundleBuildId} (${Date.now() - started}ms)`);
|
|
65
|
+
} catch (err) {
|
|
66
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
67
|
+
this.#logger.error(`base-artifact failed: ${message}`);
|
|
68
|
+
this.#result.errors.base = message;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
55
71
|
async#buildCsr() {
|
|
56
72
|
const started = Date.now();
|
|
57
73
|
try {
|
|
@@ -12,8 +12,7 @@ import {
|
|
|
12
12
|
DevChangePlanner,
|
|
13
13
|
DevGeneratedIndexSync,
|
|
14
14
|
GraphClientEntryDiscovery,
|
|
15
|
-
RouteClientBuilder
|
|
16
|
-
SsrBaseArtifactBuilder
|
|
15
|
+
RouteClientBuilder
|
|
17
16
|
} from "./index-khzzttv1.js";
|
|
18
17
|
import {
|
|
19
18
|
HmrWatcher,
|
|
@@ -92,20 +91,36 @@ class BuildBatchRunner {
|
|
|
92
91
|
}
|
|
93
92
|
}
|
|
94
93
|
|
|
95
|
-
// pkgs/@akanjs/devkit/incrementalBuilder/
|
|
96
|
-
class
|
|
94
|
+
// pkgs/@akanjs/devkit/incrementalBuilder/builderChannel.ts
|
|
95
|
+
class BuilderChannel {
|
|
97
96
|
static #flushTimeoutMs = 5000;
|
|
98
|
-
static
|
|
97
|
+
static #flushing = new Set;
|
|
98
|
+
static send(message) {
|
|
99
99
|
const send = process.send;
|
|
100
100
|
if (!send)
|
|
101
|
-
return;
|
|
102
|
-
|
|
103
|
-
const timer = setTimeout(resolve,
|
|
104
|
-
send.call(process,
|
|
101
|
+
return Promise.resolve();
|
|
102
|
+
const flushed = new Promise((resolve) => {
|
|
103
|
+
const timer = setTimeout(resolve, BuilderChannel.#flushTimeoutMs);
|
|
104
|
+
send.call(process, message, undefined, undefined, () => {
|
|
105
105
|
clearTimeout(timer);
|
|
106
106
|
resolve();
|
|
107
107
|
});
|
|
108
108
|
});
|
|
109
|
+
BuilderChannel.#flushing.add(flushed);
|
|
110
|
+
flushed.then(() => BuilderChannel.#flushing.delete(flushed));
|
|
111
|
+
return flushed;
|
|
112
|
+
}
|
|
113
|
+
static emit(message) {
|
|
114
|
+
BuilderChannel.send(message);
|
|
115
|
+
}
|
|
116
|
+
static async drain() {
|
|
117
|
+
let flushed = 0;
|
|
118
|
+
while (BuilderChannel.#flushing.size) {
|
|
119
|
+
const pending = [...BuilderChannel.#flushing];
|
|
120
|
+
flushed += pending.length;
|
|
121
|
+
await Promise.all(pending);
|
|
122
|
+
}
|
|
123
|
+
return flushed;
|
|
109
124
|
}
|
|
110
125
|
}
|
|
111
126
|
|
|
@@ -150,7 +165,7 @@ class IncrementalBuilder {
|
|
|
150
165
|
return `${this.#app.cwdPath}/.akan/artifact`;
|
|
151
166
|
}
|
|
152
167
|
async handleBuildRoute(msg) {
|
|
153
|
-
await this.#enqueueWork(`build-route:${msg.routeId}`, async () =>
|
|
168
|
+
await this.#enqueueWork(`build-route:${msg.routeId}`, async () => BuilderChannel.send(await this.#handleBuildRoute(msg)));
|
|
154
169
|
}
|
|
155
170
|
async#handleBuildRoute(msg) {
|
|
156
171
|
try {
|
|
@@ -189,7 +204,7 @@ class IncrementalBuilder {
|
|
|
189
204
|
#sendBuildStatus(phase, { generation, ok, files, message }) {
|
|
190
205
|
if (typeof generation !== "number")
|
|
191
206
|
return;
|
|
192
|
-
|
|
207
|
+
BuilderChannel.emit({
|
|
193
208
|
type: "build-status",
|
|
194
209
|
data: {
|
|
195
210
|
generation,
|
|
@@ -224,7 +239,7 @@ class IncrementalBuilder {
|
|
|
224
239
|
#reportMetrics() {
|
|
225
240
|
if (!this.#idle || this.#shuttingDown)
|
|
226
241
|
return;
|
|
227
|
-
|
|
242
|
+
BuilderChannel.emit({
|
|
228
243
|
type: "builder-metrics",
|
|
229
244
|
data: { rssBytes: process.memoryUsage.rss(), generation: this.#generation, workCount: this.#workCount }
|
|
230
245
|
});
|
|
@@ -246,7 +261,8 @@ class IncrementalBuilder {
|
|
|
246
261
|
await this.#cssRebuildQueue.catch(() => {
|
|
247
262
|
return;
|
|
248
263
|
});
|
|
249
|
-
|
|
264
|
+
const flushed = await BuilderChannel.drain();
|
|
265
|
+
this.#logger.info(`drained in ${Date.now() - started}ms${flushed ? ` after flushing ${flushed} ipc write(s)` : ""}; exiting for recycle`);
|
|
250
266
|
process.exit(0);
|
|
251
267
|
}
|
|
252
268
|
get shuttingDown() {
|
|
@@ -357,7 +373,7 @@ class IncrementalBuilder {
|
|
|
357
373
|
if (hasSyncErrors) {
|
|
358
374
|
this.#sendBuildStatus("barrel", { generation, ok: false, files, message: indexSync.errors.join(`
|
|
359
375
|
`) });
|
|
360
|
-
|
|
376
|
+
BuilderChannel.emit(event);
|
|
361
377
|
return;
|
|
362
378
|
}
|
|
363
379
|
if (indexSync.changedFiles.length > 0)
|
|
@@ -382,7 +398,7 @@ class IncrementalBuilder {
|
|
|
382
398
|
needs.push("pages");
|
|
383
399
|
needs.push("css");
|
|
384
400
|
}
|
|
385
|
-
|
|
401
|
+
BuilderChannel.emit(event);
|
|
386
402
|
if (needs.length > 0)
|
|
387
403
|
await this.#runBatch({ generation, needs, changedFiles: files });
|
|
388
404
|
else if (kinds.includes("css")) {
|
|
@@ -396,14 +412,15 @@ class IncrementalBuilder {
|
|
|
396
412
|
changedFiles
|
|
397
413
|
}) {
|
|
398
414
|
const started = Date.now();
|
|
399
|
-
const result = await this.#batchRunner.run(await this.#batchRequest({ generation, needs, changedFiles }), (msg) =>
|
|
415
|
+
const result = await this.#batchRunner.run(await this.#batchRequest({ generation, needs, changedFiles }), (msg) => BuilderChannel.emit(msg));
|
|
400
416
|
if (result.optimizedFonts)
|
|
401
417
|
this.#optimizedFonts = result.optimizedFonts;
|
|
402
418
|
if (result.cssAssets)
|
|
403
419
|
this.#artifact = { ...this.#artifact, cssAssets: result.cssAssets };
|
|
404
420
|
if (result.crashed) {
|
|
405
421
|
for (const need of needs)
|
|
406
|
-
|
|
422
|
+
if (need !== "base")
|
|
423
|
+
this.#sendBuildStatus(need, { generation, ok: false, files: changedFiles, message: result.errors[need] });
|
|
407
424
|
}
|
|
408
425
|
if (needs.includes("css"))
|
|
409
426
|
this.#logger.verbose(`css-rebuild checked (${Date.now() - started}ms)`);
|
|
@@ -430,7 +447,7 @@ class IncrementalBuilder {
|
|
|
430
447
|
async boot() {
|
|
431
448
|
if (this.#watch)
|
|
432
449
|
await this.installWatcher();
|
|
433
|
-
|
|
450
|
+
BuilderChannel.emit({ type: "builder-ready" });
|
|
434
451
|
this.#logger.verbose(`ready (watch=${this.#watch})`);
|
|
435
452
|
}
|
|
436
453
|
async announceRecoveredState(changedFiles) {
|
|
@@ -442,7 +459,7 @@ class IncrementalBuilder {
|
|
|
442
459
|
async announceBootState() {
|
|
443
460
|
const generation = ++this.#generation;
|
|
444
461
|
const reason = "builder-recycle";
|
|
445
|
-
|
|
462
|
+
await BuilderChannel.send({
|
|
446
463
|
type: "pages-updated",
|
|
447
464
|
data: {
|
|
448
465
|
bundlePath: this.#artifact.pagesBundlePath,
|
|
@@ -457,7 +474,7 @@ class IncrementalBuilder {
|
|
|
457
474
|
cssUrl,
|
|
458
475
|
Buffer.from(await Bun.file(path2.join(this.#artifactDir, cssRelPath)).arrayBuffer()).toString("base64")
|
|
459
476
|
])));
|
|
460
|
-
|
|
477
|
+
await BuilderChannel.send({
|
|
461
478
|
type: "css-updated",
|
|
462
479
|
data: { cssAssets, cssBase64ByUrl, generation, changedFiles: [], reason }
|
|
463
480
|
});
|
|
@@ -470,12 +487,12 @@ class IncrementalBuilder {
|
|
|
470
487
|
const error = result.errors.csr;
|
|
471
488
|
if (error) {
|
|
472
489
|
this.#logger.error(`csr-build failed: ${error}`);
|
|
473
|
-
await
|
|
490
|
+
await BuilderChannel.send({ type: "build-csr-res", id: msg.id, ok: false, error });
|
|
474
491
|
return;
|
|
475
492
|
}
|
|
476
493
|
this.#csrActive = true;
|
|
477
494
|
this.#logger.info(`csr-build ok on demand (${Date.now() - started}ms); rebuilding CSR on every save now`);
|
|
478
|
-
await
|
|
495
|
+
await BuilderChannel.send({ type: "build-csr-res", id: msg.id, ok: true });
|
|
479
496
|
});
|
|
480
497
|
}
|
|
481
498
|
#shouldRebuildCsr() {
|
|
@@ -484,10 +501,25 @@ class IncrementalBuilder {
|
|
|
484
501
|
static #csrArmedByEnv() {
|
|
485
502
|
return process.env.AKAN_DEV_CSR_REBUILD === "1";
|
|
486
503
|
}
|
|
487
|
-
static async#buildBootDeps(app) {
|
|
488
|
-
const
|
|
504
|
+
static async#buildBootDeps(app, runner) {
|
|
505
|
+
const result = await runner.run({
|
|
506
|
+
appName: app.name,
|
|
507
|
+
workspaceRoot: app.workspace.workspaceRoot,
|
|
508
|
+
repoName: app.workspace.repoName,
|
|
509
|
+
generation: 0,
|
|
510
|
+
needs: ["base"],
|
|
511
|
+
changedFiles: [],
|
|
512
|
+
pageKeys: null,
|
|
513
|
+
optimizedFonts: null,
|
|
514
|
+
cssAssets: null,
|
|
515
|
+
artifactDir: path2.resolve(`${app.cwdPath}/.akan/artifact`)
|
|
516
|
+
});
|
|
517
|
+
if (result.errors.base)
|
|
518
|
+
throw new Error(result.errors.base);
|
|
519
|
+
if (!result.artifact || !result.optimizedFonts)
|
|
520
|
+
throw new Error("boot build reported success without an artifact; the build worker likely died");
|
|
489
521
|
const discovery = await GraphClientEntryDiscovery.create(app);
|
|
490
|
-
return { artifact, optimizedFonts, discovery };
|
|
522
|
+
return { artifact: result.artifact, optimizedFonts: result.optimizedFonts, discovery };
|
|
491
523
|
}
|
|
492
524
|
async rearmCsrFromEnv() {
|
|
493
525
|
if (!IncrementalBuilder.#csrArmedByEnv())
|
|
@@ -501,18 +533,18 @@ class IncrementalBuilder {
|
|
|
501
533
|
this.#logger.verbose("csr-rearm ok; this session had CSR armed before the builder restarted");
|
|
502
534
|
});
|
|
503
535
|
}
|
|
504
|
-
static #recoverBoot(app, bootError, logger) {
|
|
536
|
+
static #recoverBoot(app, bootError, logger, runner) {
|
|
505
537
|
const firstMessage = bootError instanceof Error ? bootError.message : String(bootError);
|
|
506
538
|
logger.error(`boot build failed; entering degraded watch mode until the error is fixed: ${firstMessage}`);
|
|
507
539
|
let generation = 0;
|
|
508
540
|
const sendFailure = (files, message) => {
|
|
509
|
-
|
|
541
|
+
BuilderChannel.emit({
|
|
510
542
|
type: "build-status",
|
|
511
543
|
data: { generation, phase: "pages", ok: false, files, message: `Boot build failed: ${message}` }
|
|
512
544
|
});
|
|
513
545
|
};
|
|
514
546
|
sendFailure([], firstMessage);
|
|
515
|
-
|
|
547
|
+
BuilderChannel.emit({ type: "builder-ready" });
|
|
516
548
|
return new Promise((resolve, reject) => {
|
|
517
549
|
(async () => {
|
|
518
550
|
const roots = await new WatchRootResolver(app).resolve();
|
|
@@ -525,7 +557,7 @@ class IncrementalBuilder {
|
|
|
525
557
|
try {
|
|
526
558
|
if (new Set(batch.kinds).has("config"))
|
|
527
559
|
await app.getConfig({ refresh: true });
|
|
528
|
-
const deps = await IncrementalBuilder.#buildBootDeps(app);
|
|
560
|
+
const deps = await IncrementalBuilder.#buildBootDeps(app, runner);
|
|
529
561
|
const builder = new IncrementalBuilder({ app, watch: true, initialGeneration: generation, ...deps });
|
|
530
562
|
watcher.stop();
|
|
531
563
|
logger.info(`boot build recovered generation=${generation}`);
|
|
@@ -567,7 +599,7 @@ class IncrementalBuilder {
|
|
|
567
599
|
if (msg.type === "build-route") {
|
|
568
600
|
const error = builder?.shuttingDown ? recyclingError : bootingError;
|
|
569
601
|
if (!builder || builder.shuttingDown) {
|
|
570
|
-
|
|
602
|
+
BuilderChannel.emit({ type: "build-route-res", id: msg.id, ok: false, error });
|
|
571
603
|
return;
|
|
572
604
|
}
|
|
573
605
|
builder.handleBuildRoute(msg);
|
|
@@ -576,7 +608,7 @@ class IncrementalBuilder {
|
|
|
576
608
|
if (msg.type === "build-csr") {
|
|
577
609
|
const error = builder?.shuttingDown ? recyclingError : bootingError;
|
|
578
610
|
if (!builder || builder.shuttingDown) {
|
|
579
|
-
|
|
611
|
+
BuilderChannel.emit({ type: "build-csr-res", id: msg.id, ok: false, error });
|
|
580
612
|
return;
|
|
581
613
|
}
|
|
582
614
|
builder.handleBuildCsr(msg);
|
|
@@ -587,12 +619,13 @@ class IncrementalBuilder {
|
|
|
587
619
|
process.exit(0);
|
|
588
620
|
});
|
|
589
621
|
let recoveredFiles = null;
|
|
622
|
+
const bootRunner = new BuildBatchRunner({ workspaceRoot, cwd: app.cwdPath });
|
|
590
623
|
try {
|
|
591
|
-
builder = new IncrementalBuilder({ app, watch, ...await IncrementalBuilder.#buildBootDeps(app) });
|
|
624
|
+
builder = new IncrementalBuilder({ app, watch, ...await IncrementalBuilder.#buildBootDeps(app, bootRunner) });
|
|
592
625
|
} catch (err) {
|
|
593
626
|
if (!watch)
|
|
594
627
|
throw err;
|
|
595
|
-
const recovered = await IncrementalBuilder.#recoverBoot(app, err, logger);
|
|
628
|
+
const recovered = await IncrementalBuilder.#recoverBoot(app, err, logger, bootRunner);
|
|
596
629
|
builder = recovered.builder;
|
|
597
630
|
recoveredFiles = recovered.changedFiles;
|
|
598
631
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akanjs/cli",
|
|
3
|
-
"version": "2.4.1-rc.
|
|
3
|
+
"version": "2.4.1-rc.5",
|
|
4
4
|
"sourceType": "module",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"@langchain/openai": "^1.4.6",
|
|
35
35
|
"@tailwindcss/node": "^4.3.0",
|
|
36
36
|
"@trapezedev/project": "^7.1.4",
|
|
37
|
-
"akanjs": "2.4.1-rc.
|
|
37
|
+
"akanjs": "2.4.1-rc.5",
|
|
38
38
|
"chalk": "^5.6.2",
|
|
39
39
|
"commander": "^14.0.3",
|
|
40
40
|
"daisyui": "5.5.23",
|