@akanjs/devkit 3.0.0-beta.22 → 3.0.0-beta.24

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.
@@ -1,5 +1,6 @@
1
1
  import path from "node:path";
2
2
  import { optimize } from "@tailwindcss/node";
3
+ import type { AkanWebConfig } from "akanjs";
3
4
  import type { BaseBuildArtifact } from "akanjs/server";
4
5
  import { resolveSsrPageEntriesForApp } from "../artifact/implicitRootLayout";
5
6
  import { computeRouteSeedIndex, type RouteSeedIndex, saveRouteSeedIndex } from "../artifact/routeSeedIndex";
@@ -36,6 +37,12 @@ export class SsrBaseArtifactBuilder {
36
37
  this.#absArtifactDir = path.resolve(this.#artifactDir);
37
38
  }
38
39
 
40
+ //? The web router reads this, so `akan start` writes the whole surface: a native shell asks the dev server for the
41
+ //? CSR page even when the app ships none, and a narrowed dev artifact hands it the SSR page, which cannot run there.
42
+ static servedWeb(command: "build" | "start", web: AkanWebConfig): AkanWebConfig {
43
+ return command === "start" ? { ssr: true, csr: true } : web;
44
+ }
45
+
39
46
  async build(): Promise<BuildSsrBaseArtifactResult> {
40
47
  const akanConfig = await this.#app.getConfig();
41
48
  const { rscClientUrl, rscRuntimeClientManifest, rscRuntimeSsrManifest, vendorMap } =
@@ -77,7 +84,7 @@ export class SsrBaseArtifactBuilder {
77
84
  branches: [...akanConfig.branches],
78
85
  i18n: akanConfig.i18n,
79
86
  imageConfig: akanConfig.images,
80
- web: akanConfig.web,
87
+ web: SsrBaseArtifactBuilder.servedWeb(this.#command, akanConfig.web),
81
88
  deepLinkAssociations: Object.values(akanConfig.mobile.targets)
82
89
  .filter((target) => (target.deepLinks?.domains?.length ?? 0) > 0)
83
90
  .map((target) => ({
@@ -7,6 +7,7 @@ import type { App } from "@akanjs/devkit/commandDecorators";
7
7
  import { AppExecutor, WorkspaceExecutor } from "@akanjs/devkit/executors";
8
8
  import {
9
9
  CsrArtifactBuilder,
10
+ CsrDevBundler,
10
11
  CssCompiler,
11
12
  FontOptimizer,
12
13
  PagesBundleBuilder,
@@ -14,6 +15,7 @@ import {
14
15
  } from "@akanjs/devkit/frontendBuild";
15
16
  import { Logger } from "akanjs/common";
16
17
  import type { BuilderMessage, BuildPhase } from "akanjs/server";
18
+ import { resolveDevCsrMode } from "akanjs/server/hmr/csrDevManifest";
17
19
  import type { BuildBatchRequest, BuildBatchResult, OptimizedFonts, PagesBatchCssAssets } from "./buildBatchProtocol";
18
20
 
19
21
  // `Bun.build` keeps native bundler arenas that `Bun.gc(true)` cannot reclaim; only exiting returns them.
@@ -80,14 +82,47 @@ class BuildBatch {
80
82
  async #buildCsr(): Promise<void> {
81
83
  const started = Date.now();
82
84
  try {
83
- await new CsrArtifactBuilder(this.#app).build();
84
- this.#logger.verbose(`csr-rebundle ok (${Date.now() - started}ms)`);
85
+ if (resolveDevCsrMode() === "registry") await this.#updateCsrRegistry(started);
86
+ else await this.#rebuildCsrArtifact(started);
85
87
  this.#emitStatus("csr");
86
88
  } catch (err) {
87
89
  this.#fail("csr", "csr-rebundle", err);
88
90
  }
89
91
  }
90
92
 
93
+ async #rebuildCsrArtifact(started: number): Promise<void> {
94
+ await new CsrArtifactBuilder(this.#app).build();
95
+ this.#logger.verbose(`csr-rebundle ok (${Date.now() - started}ms)`);
96
+ // A CSR tab takes none of the SSR refresh messages, so a rebuilt artifact reaches it only as this reload.
97
+ if (this.#request.changedFiles.length === 0) return;
98
+ this.#emit({
99
+ type: "csr-updated",
100
+ data: { generation: Date.now(), mode: "artifact", reload: true, reason: "the CSR artifact was rebuilt" },
101
+ });
102
+ }
103
+
104
+ async #updateCsrRegistry(started: number): Promise<void> {
105
+ const update = await new CsrDevBundler(this.#app).update(this.#request.changedFiles);
106
+ if (!update) {
107
+ this.#logger.verbose(`csr-dev unchanged (${Date.now() - started}ms)`);
108
+ return;
109
+ }
110
+ this.#logger.verbose(
111
+ `csr-dev generation=${update.generation} ${update.reload ? `reload (${update.reason})` : `patch modules=${update.changedIds.length}`} graph=${update.moduleCount} (${Date.now() - started}ms)`,
112
+ );
113
+ this.#emit({
114
+ type: "csr-updated",
115
+ data: {
116
+ generation: update.generation,
117
+ mode: "registry",
118
+ reload: update.reload,
119
+ reason: update.reason,
120
+ patchUrl: update.patchUrl,
121
+ changedIds: update.changedIds,
122
+ },
123
+ });
124
+ }
125
+
91
126
  // Rewritten with the bundle: the backend rereads it on `pages-updated` to pick up added, moved or deleted routes.
92
127
  async #buildPages(): Promise<void> {
93
128
  const started = Date.now();
@@ -11,6 +11,7 @@ const builderMsgTypeSet = new Set<BuilderMessage["type"]>([
11
11
  "invalidate",
12
12
  "css-updated",
13
13
  "pages-updated",
14
+ "csr-updated",
14
15
  "build-status",
15
16
  "builder-metrics",
16
17
  ]);
@@ -487,7 +487,7 @@ describe("dev resource budgets", () => {
487
487
  `csr-armed-marker-${attempt}`,
488
488
  ),
489
489
  );
490
- await host.waitForLogSince(resyncMark, /csr-rebundle ok/, WAIT_MS);
490
+ await host.waitForLogSince(resyncMark, /csr-rebundle ok|csr-dev generation=\d+ patch/, WAIT_MS);
491
491
  });
492
492
 
493
493
  budgetTest("bounds the rsc worker and the tree across repeated saves", async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akanjs/devkit",
3
- "version": "3.0.0-beta.22",
3
+ "version": "3.0.0-beta.24",
4
4
  "sourceType": "module",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -47,7 +47,7 @@
47
47
  "@earendil-works/pi-tui": "0.86.1",
48
48
  "@inquirer/prompts": "^8.4.3",
49
49
  "@tailwindcss/node": "^4.3.0",
50
- "akanjs": "3.0.0-beta.22",
50
+ "akanjs": "3.0.0-beta.24",
51
51
  "chalk": "^5.6.2",
52
52
  "commander": "^14.0.3",
53
53
  "dayjs": "^1.11.20",
@@ -63,7 +63,7 @@
63
63
  "typescript": "^6.0.3"
64
64
  },
65
65
  "peerDependencies": {
66
- "react": "19.2.7"
66
+ "react": "19.3.0"
67
67
  },
68
68
  "peerDependenciesMeta": {
69
69
  "react": {