@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.
- package/dist/client-bundle.d.ts +9 -0
- package/dist/client-bundle.d.ts.map +1 -1
- package/dist/client-bundle.js +104 -21
- package/package.json +4 -4
package/dist/client-bundle.d.ts
CHANGED
|
@@ -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;
|
|
1
|
+
{"version":3,"file":"client-bundle.d.ts","sourceRoot":"","sources":["../src/client-bundle.ts"],"names":[],"mappings":"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"}
|
package/dist/client-bundle.js
CHANGED
|
@@ -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
|
-
//
|
|
955
|
-
//
|
|
956
|
-
//
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
27
|
-
"@vesk/runtime": "^0.2.
|
|
28
|
-
"@vesk/types": "^0.2.
|
|
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",
|