@vesk/adapter 0.2.61 → 0.2.63

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.
@@ -118,6 +118,15 @@ export declare function stripAndDemoteInOnePass(code: string): string;
118
118
  */
119
119
  export declare function buildHmrEvalSnippet(code: string): string;
120
120
  export declare function removeCompiledNodes(code: string, isTarget: (node: CompiledNode) => boolean): string;
121
+ /** Name of the cross-route shared chunk. Route chunks import from it. */
122
+ export declare const SHARED_CHUNK_NAME = "shared.js";
123
+ /**
124
+ * The chunk file stem for a route: its directory under `app/`, with dynamic
125
+ * segment brackets neutralised. Exported so the dev server can map an incoming
126
+ * chunk request back to its route (see routeFullPathForChunk) without
127
+ * duplicating the naming rule.
128
+ */
129
+ export declare function buildChunkName(appDir: string, node: RouteNode): string;
121
130
  export declare function generateClientBundle(routeTree: RouteNode[], appDir: string, componentMap?: Map<string, string>, options?: ClientBundleOptions): Promise<ClientBundleResult>;
122
131
  export declare function buildRuntimeCode(runtimeDir: string): string;
123
132
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"client-bundle.d.ts","sourceRoot":"","sources":["../src/client-bundle.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,SAAS,EAAE,mBAAmB,EAAE,kBAAkB,EAAmF,MAAM,yBAAyB,CAAC;AAoCnL;;;;;;;;;;;;;GAaG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CA4BhE;AAED;;;;;GAKG;AACH,UAAU,YAAY;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAC7B,EAAE,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACvB,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,EAAE,CAAC,EAAE;YAAE,IAAI,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QAAC,IAAI,CAAC,EAAE;YAAE,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,MAAM,CAAC,EAAE;gBAAE,IAAI,CAAC,EAAE,MAAM,CAAC;gBAAC,IAAI,CAAC,EAAE,MAAM,CAAA;aAAE,CAAA;SAAE,CAAA;KAAE,CAAC,CAAC;IACtH,WAAW,CAAC,EAAE;QACZ,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE;YAAE,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QAC1C,YAAY,CAAC,EAAE,KAAK,CAAC;YAAE,IAAI,CAAC,EAAE;gBAAE,IAAI,CAAC,EAAE,MAAM,CAAC;gBAAC,MAAM,CAAC,EAAE;oBAAE,IAAI,CAAC,EAAE,MAAM,CAAC;oBAAC,IAAI,CAAC,EAAE,MAAM,CAAA;iBAAE,CAAA;aAAE,CAAA;SAAE,CAAC,CAAC;KAC/F,CAAC;IACF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAmDD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAKzD;AAkCD;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA+B7D;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAyBlD;AAuQD;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA+B5D;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASxD;AA4CD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,GAAG,MAAM,CAoBnG;AAED,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,SAAS,EAAE,EACtB,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAClC,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,kBAAkB,CAAC,CA0nB7B;AAMD,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CA+B3D;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAUlE;AAoCD;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAI/F"}
1
+ {"version":3,"file":"client-bundle.d.ts","sourceRoot":"","sources":["../src/client-bundle.ts"],"names":[],"mappings":"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"}
@@ -12,6 +12,42 @@ import { resolveComponentName } from '@vesk/compiler/src/server-codegen';
12
12
  import { collectVskImportPaths, vskImportLines } from '@vesk/compiler/src/vsk-imports';
13
13
  import { inlineMdContentAttrs, guessProjectRoots } from '@vesk/compiler/src/md-inline';
14
14
  import { resolveImportPath, findTsconfigPath } from '@vesk/compiler/src/module-imports';
15
+ import { availableParallelism } from 'node:os';
16
+ /**
17
+ * Run `fn` over `items` with at most `limit` in flight, preserving input
18
+ * order in the result array. The first rejection propagates once the in-flight
19
+ * work settles, so a `--strict` chunk failure still fails the build rather than
20
+ * being swallowed by a sibling's success.
21
+ */
22
+ async function mapWithConcurrency(items, limit, fn) {
23
+ const out = new Array(items.length);
24
+ let next = 0;
25
+ let firstError = null;
26
+ const worker = async () => {
27
+ for (;;) {
28
+ const i = next++;
29
+ if (i >= items.length)
30
+ return;
31
+ if (firstError !== null)
32
+ return;
33
+ try {
34
+ out[i] = await fn(items[i], i);
35
+ }
36
+ catch (e) {
37
+ if (firstError === null)
38
+ firstError = e;
39
+ return;
40
+ }
41
+ }
42
+ };
43
+ const workers = [];
44
+ for (let i = 0; i < Math.min(limit, items.length); i++)
45
+ workers.push(worker());
46
+ await Promise.all(workers);
47
+ if (firstError !== null)
48
+ throw firstError;
49
+ return out;
50
+ }
15
51
  const __dirname = dirname(fileURLToPath(import.meta.url));
16
52
  function fileUnchanged(filePath, cached) {
17
53
  try {
@@ -674,6 +710,20 @@ export function removeCompiledNodes(code, isTarget) {
674
710
  }
675
711
  return code;
676
712
  }
713
+ /** Name of the cross-route shared chunk. Route chunks import from it. */
714
+ export const SHARED_CHUNK_NAME = 'shared.js';
715
+ /**
716
+ * The chunk file stem for a route: its directory under `app/`, with dynamic
717
+ * segment brackets neutralised. Exported so the dev server can map an incoming
718
+ * chunk request back to its route (see routeFullPathForChunk) without
719
+ * duplicating the naming rule.
720
+ */
721
+ export function buildChunkName(appDir, node) {
722
+ const dir = relative(appDir, node.sourceDir || '');
723
+ const parts = dir.split(sep).filter(Boolean);
724
+ const slug = parts.length > 0 ? parts.join('-') : 'index';
725
+ return slug.replace(/[\[\]]/g, '_');
726
+ }
677
727
  export async function generateClientBundle(routeTree, appDir, componentMap, options) {
678
728
  const runtimeDir = findRuntimeSrc(appDir);
679
729
  let seen = new Set();
@@ -682,6 +732,7 @@ export async function generateClientBundle(routeTree, appDir, componentMap, opti
682
732
  const runtimeImportNames = new Set();
683
733
  const cache = options?.cache;
684
734
  const only = options?.only && options.only.length > 0 ? new Set(options.only) : null;
735
+ const onlyRoutes = options?.onlyRoutes && options.onlyRoutes.length > 0 ? new Set(options.onlyRoutes) : null;
685
736
  const returnEdited = !!options?.returnEditedSources && !!only;
686
737
  const editedSources = returnEdited ? new Map() : undefined;
687
738
  const editedNames = returnEdited ? new Map() : undefined;
@@ -880,12 +931,6 @@ export async function generateClientBundle(routeTree, appDir, componentMap, opti
880
931
  });
881
932
  }
882
933
  }
883
- function buildChunkName(node) {
884
- const dir = relative(appDir, node.sourceDir || '');
885
- const parts = dir.split(sep).filter(Boolean);
886
- const slug = parts.length > 0 ? parts.join('-') : 'index';
887
- return slug.replace(/[\[\]]/g, '_');
888
- }
889
934
  const codeSplit = !!(options?.codeSplit);
890
935
  const transformPlugins = options?.plugins || [];
891
936
  // Every `.vsk` component in the bundle shares ONE registry keyed by declared
@@ -950,16 +995,21 @@ export async function generateClientBundle(routeTree, appDir, componentMap, opti
950
995
  compileFile(loadingPath, node.loading, chunkCode, chunkImports);
951
996
  }
952
997
  if (chunkCode.length > 0) {
953
- const chunkName = `page-${buildChunkName(node)}.js`;
954
- // Prepend this chunk's deduped imports (one statement per source, no
955
- // duplicate bindings) so the classic script exposes the bare
956
- // identifiers its file bodies reference, and esbuild can parse and
957
- // inline them.
958
- if (!chunkImports.ok)
959
- console.error('[vesk] chunk import merge aborted for', chunkName + ':', chunkImports.reason);
960
- const head = chunkImports.render();
961
- const code = (head ? head + '\n\n' : '') + chunkCode.join('\n\n');
962
- chunkEntries.push({ name: chunkName, code, node, importsTable: chunkImports, imports: chunkHasImports(head.length, !chunkImports.ok) });
998
+ const chunkName = `page-${buildChunkName(appDir, node)}.js`;
999
+ // Route-level filter for on-demand dev builds. `only` is FILE-level:
1000
+ // it keeps a recompile cheap but still walks every route, so it
1001
+ // cannot make a COLD build lazy.
1002
+ if (!onlyRoutes || onlyRoutes.has(node.fullPath)) {
1003
+ // Prepend this chunk's deduped imports (one statement per source, no
1004
+ // duplicate bindings) so the classic script exposes the bare
1005
+ // identifiers its file bodies reference, and esbuild can parse and
1006
+ // inline them.
1007
+ if (!chunkImports.ok)
1008
+ console.error('[vesk] chunk import merge aborted for', chunkName + ':', chunkImports.reason);
1009
+ const head = chunkImports.render();
1010
+ const code = (head ? head + '\n\n' : '') + chunkCode.join('\n\n');
1011
+ chunkEntries.push({ name: chunkName, code, node, importsTable: chunkImports, imports: chunkHasImports(head.length, !chunkImports.ok) });
1012
+ }
963
1013
  }
964
1014
  walkSplit(node.children || [], [..._chain, node]);
965
1015
  }
@@ -977,7 +1027,7 @@ export async function generateClientBundle(routeTree, appDir, componentMap, opti
977
1027
  console.error('[vesk] chunk import merge aborted for shared.js:', sharedImports.reason);
978
1028
  const head = sharedImports.render();
979
1029
  const code = (head ? head + '\n\n' : '') + sharedCode.join('\n\n');
980
- chunkEntries.push({ name: 'shared.js', code, node: null, importsTable: sharedImports, imports: chunkHasImports(head.length, !sharedImports.ok) });
1030
+ chunkEntries.push({ name: SHARED_CHUNK_NAME, code, node: null, importsTable: sharedImports, imports: chunkHasImports(head.length, !sharedImports.ok) });
981
1031
  }
982
1032
  const chunkIIFE = (body) => `(()=>{\nconst __components = globalThis.__components || (globalThis.__components = {});\nconst __hydrators = globalThis.__hydrators || (globalThis.__hydrators = {});\n${body}\n})();\n`;
983
1033
  /**
@@ -1115,9 +1165,15 @@ export async function generateClientBundle(routeTree, appDir, componentMap, opti
1115
1165
  },
1116
1166
  }
1117
1167
  : null;
1118
- for (const entry of chunkEntries) {
1168
+ // Each chunk is bundled through its own esbuild pass. Those passes are
1169
+ // independent, so they run CONCURRENTLY: one esbuild round-trip per chunk
1170
+ // was the single largest slice of `vesk dev` startup (37 chunks on a
1171
+ // 37-route app, strictly serial, with every core but one idle). Results are
1172
+ // written back in the original order so chunk load order — which the
1173
+ // preload/annotation passes below depend on — is unchanged.
1174
+ const buildChunkEntry = async (entry) => {
1119
1175
  if (!entry.code.trim())
1120
- continue;
1176
+ return null;
1121
1177
  let finalCode;
1122
1178
  if (entry.imports) {
1123
1179
  // Bundle the chunk through esbuild so every remaining import (npm
@@ -1200,11 +1256,27 @@ export async function generateClientBundle(routeTree, appDir, componentMap, opti
1200
1256
  // via the __components / __hydrators registries, matching the mono path).
1201
1257
  finalCode = chunkIIFE(demoteExports(entry.code));
1202
1258
  }
1203
- chunks.push({ name: entry.name, code: finalCode });
1259
+ return { name: entry.name, code: finalCode };
1260
+ };
1261
+ // Dev may defer route chunk BODIES (see ClientBundleOptions.skipRouteChunks).
1262
+ // The shared chunk is still built — route chunks import from it — and
1263
+ // `main` is assembled separately below, so the entry bundle is unaffected.
1264
+ // Chunk URLs are published for every route regardless; see annotate().
1265
+ const effectiveChunkEntries = options?.skipRouteChunks
1266
+ ? chunkEntries.filter((e) => e.name === SHARED_CHUNK_NAME)
1267
+ : chunkEntries;
1268
+ // Concurrency is capped below the core count: esbuild's own service is
1269
+ // already multi-process, so oversubscribing every chunk at once trades
1270
+ // throughput for memory on the constrained machines this runs on.
1271
+ const CHUNK_CONCURRENCY = Math.max(1, Math.min(6, (availableParallelism?.() ?? 4) - 1));
1272
+ const built = await mapWithConcurrency(effectiveChunkEntries, CHUNK_CONCURRENCY, buildChunkEntry);
1273
+ for (const c of built) {
1274
+ if (c !== null)
1275
+ chunks.push(c);
1204
1276
  }
1205
1277
  function annotate(nodes) {
1206
1278
  for (const node of nodes) {
1207
- const chunkName = `page-${buildChunkName(node)}.js`;
1279
+ const chunkName = `page-${buildChunkName(appDir, node)}.js`;
1208
1280
  // Production chunk names are content-hashed, and the ROUTER asks for
1209
1281
  // chunks by the URL baked here — so the hash has to be applied to this
1210
1282
  // reference, not just to the file on disk. Getting it wrong is silent
@@ -1216,6 +1288,17 @@ export async function generateClientBundle(routeTree, appDir, componentMap, opti
1216
1288
  const fileName = options?.hmr ? chunkName : hashedName(chunkName, emitted.code);
1217
1289
  node.chunk = `/_vesk/static/${fileName}`;
1218
1290
  }
1291
+ else if (options?.skipRouteChunks) {
1292
+ // The body is deferred, but the URL must still be published now.
1293
+ // The route tree — chunk URLs included — is baked into the ENTRY
1294
+ // bundle and the client router fetches `node.chunk` with no server
1295
+ // round-trip in between, so leaving it undefined means the chunk is
1296
+ // never requested and the page hydrates with nothing registered.
1297
+ // Dev chunk URLs are unhashed, so they depend only on the route and
1298
+ // are identical whether or not the body has been built — which also
1299
+ // keeps the entry bundle's cache key stable across lazy builds.
1300
+ node.chunk = `/_vesk/static/${chunkName}`;
1301
+ }
1219
1302
  annotate(node.children || []);
1220
1303
  }
1221
1304
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vesk/adapter",
3
- "version": "0.2.61",
3
+ "version": "0.2.63",
4
4
  "type": "module",
5
5
  "description": "Vesk adapter — builds deployable .vesk/ output for Deno and Node serverless",
6
6
  "main": "./dist/index.js",
@@ -23,9 +23,9 @@
23
23
  "sharp": "^0.35.3"
24
24
  },
25
25
  "dependencies": {
26
- "@vesk/compiler": "^0.2.61",
27
- "@vesk/runtime": "^0.2.61",
28
- "@vesk/types": "^0.2.61"
26
+ "@vesk/compiler": "^0.2.63",
27
+ "@vesk/runtime": "^0.2.63",
28
+ "@vesk/types": "^0.2.63"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@types/ws": "^8.18.1",