@vesk/vesk-cli 0.2.58 → 0.2.59
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 +341 -15
- package/package.json +5 -5
package/dist/cli.js
CHANGED
|
@@ -3369,6 +3369,17 @@ ${String(this.root.outerHTML).slice(0, 800)}` : ""),
|
|
|
3369
3369
|
// callee's first claim and resets the deposit so later claims stay
|
|
3370
3370
|
// positional against the advancing cursor. Consumed synchronously on the
|
|
3371
3371
|
// same walker reference the call was made through.
|
|
3372
|
+
//
|
|
3373
|
+
// The deposit is ALSO consumed implicitly by the next claim made through this
|
|
3374
|
+
// walker when the caller passed no explicit skipK. A component written in plain
|
|
3375
|
+
// JS (lucide-vesk icons are the common case) never calls `takeSkipK`, so
|
|
3376
|
+
// before this the deposit was silently dropped: the icon's `nextElement("svg")`
|
|
3377
|
+
// claimed the slot still holding the STATIC residue in front of it
|
|
3378
|
+
// (`<button><span>Apply Now</span><svg/></button>`), the descriptor missed on
|
|
3379
|
+
// `<span>`, and the walker detached server-rendered content that no client
|
|
3380
|
+
// program had any intention of replacing. Implicit consumption keeps static
|
|
3381
|
+
// residue out of the way for plain-JS components exactly as it is for
|
|
3382
|
+
// compiled ones.
|
|
3372
3383
|
inheritOffset = 0;
|
|
3373
3384
|
injectSkipK(n) {
|
|
3374
3385
|
this.inheritOffset = n;
|
|
@@ -3382,7 +3393,11 @@ ${String(this.root.outerHTML).slice(0, 800)}` : ""),
|
|
|
3382
3393
|
if (globalThis.__vesk_hydrate_debug) {
|
|
3383
3394
|
console.error("[hyd-dbg] claimAt", tag, "skip=", skipK, "idx=", this.idx, "els=", this.els.length);
|
|
3384
3395
|
}
|
|
3385
|
-
let
|
|
3396
|
+
let offset2 = skipK || 0;
|
|
3397
|
+
const inherited = this.inheritOffset;
|
|
3398
|
+
this.inheritOffset = 0;
|
|
3399
|
+
if (!offset2) offset2 = inherited;
|
|
3400
|
+
let target = this.advancePastSkippable(this.idx + offset2);
|
|
3386
3401
|
if (target > this.els.length) target = this.idx;
|
|
3387
3402
|
while (target < this.els.length) {
|
|
3388
3403
|
const el = this.els[target];
|
|
@@ -21909,6 +21924,7 @@ function warnStaleConstBindings(comp, file) {
|
|
|
21909
21924
|
for (const d of st.declarations || []) {
|
|
21910
21925
|
if (d.id?.type !== "Identifier" || !d.init) continue;
|
|
21911
21926
|
if (reactive.has(d.id.name)) continue;
|
|
21927
|
+
if (d.init.type === "ArrowFunctionExpression" || d.init.type === "FunctionExpression") continue;
|
|
21912
21928
|
if (d.init.type === "Identifier" && reactive.has(d.init.name)) continue;
|
|
21913
21929
|
const seen = /* @__PURE__ */ new Set();
|
|
21914
21930
|
collectIdentifiers(d.init, seen);
|
|
@@ -30704,6 +30720,9 @@ function isReactiveExpression(node, tracked2) {
|
|
|
30704
30720
|
if (!ast) return false;
|
|
30705
30721
|
let reactive = false;
|
|
30706
30722
|
walk4(ast, tracked2, {
|
|
30723
|
+
CallExpression() {
|
|
30724
|
+
reactive = true;
|
|
30725
|
+
},
|
|
30707
30726
|
Identifier(n, context) {
|
|
30708
30727
|
if (reactive) return;
|
|
30709
30728
|
const parent = context.path.at(-1);
|
|
@@ -30831,7 +30850,7 @@ function emitComponentCall(ctx2, node, tracked2, effectsVar, parentVar, compPref
|
|
|
30831
30850
|
ctx2.push(`return $f; })();`);
|
|
30832
30851
|
propsEntries.push(`children: ${frag}`);
|
|
30833
30852
|
}
|
|
30834
|
-
if (ctx2.markerless && promptExpr
|
|
30853
|
+
if (ctx2.markerless && promptExpr) {
|
|
30835
30854
|
ctx2.push(`${walkerArg}.injectSkipK(${promptExpr});`);
|
|
30836
30855
|
}
|
|
30837
30856
|
ctx2.push(`let ${v} = undefined;`);
|
|
@@ -49528,6 +49547,34 @@ function demoteExports(code) {
|
|
|
49528
49547
|
function chunkHasImports(headLen, mergeAborted) {
|
|
49529
49548
|
return headLen > 0 || mergeAborted;
|
|
49530
49549
|
}
|
|
49550
|
+
function runtimeImportsOf(filePath) {
|
|
49551
|
+
let text;
|
|
49552
|
+
try {
|
|
49553
|
+
text = readFileSync11(filePath, "utf8");
|
|
49554
|
+
} catch {
|
|
49555
|
+
return [];
|
|
49556
|
+
}
|
|
49557
|
+
const names = [];
|
|
49558
|
+
const pattern2 = /import\s+(type\s+)?\{([^}]*)\}\s*from\s*['"]@vesk\/runtime[^'"]*['"]/g;
|
|
49559
|
+
for (const match of text.matchAll(pattern2)) {
|
|
49560
|
+
if (match[1]) continue;
|
|
49561
|
+
for (const part of match[2].split(",")) {
|
|
49562
|
+
const cleaned = part.trim().replace(/^type\s+/, "");
|
|
49563
|
+
if (!cleaned) continue;
|
|
49564
|
+
const name = cleaned.split(/\s+as\s+/)[0].trim();
|
|
49565
|
+
if (name) names.push(name);
|
|
49566
|
+
}
|
|
49567
|
+
}
|
|
49568
|
+
return names;
|
|
49569
|
+
}
|
|
49570
|
+
function sharedRuntimeResolver(shimPath) {
|
|
49571
|
+
return {
|
|
49572
|
+
name: "vesk-shared-runtime",
|
|
49573
|
+
setup(build4) {
|
|
49574
|
+
build4.onResolve({ filter: /^@vesk\/runtime(\/.*)?$/ }, () => ({ path: shimPath }));
|
|
49575
|
+
}
|
|
49576
|
+
};
|
|
49577
|
+
}
|
|
49531
49578
|
var ChunkImports = class {
|
|
49532
49579
|
bySource = /* @__PURE__ */ new Map();
|
|
49533
49580
|
aborted = false;
|
|
@@ -49625,6 +49672,20 @@ var ChunkImports = class {
|
|
|
49625
49672
|
get reason() {
|
|
49626
49673
|
return this.abortReason;
|
|
49627
49674
|
}
|
|
49675
|
+
/** Every import source this chunk's merged block pulls in (absolute paths). */
|
|
49676
|
+
sources() {
|
|
49677
|
+
return this.aborted ? [] : [...this.bySource.keys()];
|
|
49678
|
+
}
|
|
49679
|
+
/**
|
|
49680
|
+
* The named bindings this chunk imports from `source`, so a shared-module
|
|
49681
|
+
* shim can re-export exactly what consumers use (re-exporting `*` from the
|
|
49682
|
+
* real module would drag it back into the chunk being built).
|
|
49683
|
+
*/
|
|
49684
|
+
bindingsFor(source) {
|
|
49685
|
+
const group = this.bySource.get(source);
|
|
49686
|
+
if (!group) return { named: [], hasDefault: false };
|
|
49687
|
+
return { named: [...group.named.keys()].sort(), hasDefault: !!group.default };
|
|
49688
|
+
}
|
|
49628
49689
|
/** Renders the deduped import block (empty string when there are no imports). */
|
|
49629
49690
|
render() {
|
|
49630
49691
|
if (this.aborted || this.bySource.size === 0) return "";
|
|
@@ -49760,6 +49821,7 @@ async function generateClientBundle(routeTree, appDir, componentMap, options) {
|
|
|
49760
49821
|
let cachedFileHits = 0;
|
|
49761
49822
|
let compiledFiles = 0;
|
|
49762
49823
|
let mainFromCache = false;
|
|
49824
|
+
let sharedModuleBundle = "";
|
|
49763
49825
|
function mustReuseWithoutStat(filePath) {
|
|
49764
49826
|
return !!only && !only.has(filePath);
|
|
49765
49827
|
}
|
|
@@ -49945,7 +50007,7 @@ async function generateClientBundle(routeTree, appDir, componentMap, options) {
|
|
|
49945
50007
|
if (!chunkImports.ok) console.error("[vesk] chunk import merge aborted for", chunkName + ":", chunkImports.reason);
|
|
49946
50008
|
const head = chunkImports.render();
|
|
49947
50009
|
const code = (head ? head + "\n\n" : "") + chunkCode.join("\n\n");
|
|
49948
|
-
chunkEntries.push({ name: chunkName, code, node, imports: chunkHasImports(head.length, !chunkImports.ok) });
|
|
50010
|
+
chunkEntries.push({ name: chunkName, code, node, importsTable: chunkImports, imports: chunkHasImports(head.length, !chunkImports.ok) });
|
|
49949
50011
|
}
|
|
49950
50012
|
walkSplit2(node.children || [], [..._chain, node]);
|
|
49951
50013
|
}
|
|
@@ -49974,7 +50036,7 @@ async function generateClientBundle(routeTree, appDir, componentMap, options) {
|
|
|
49974
50036
|
if (!sharedImports.ok) console.error("[vesk] chunk import merge aborted for shared.js:", sharedImports.reason);
|
|
49975
50037
|
const head = sharedImports.render();
|
|
49976
50038
|
const code = (head ? head + "\n\n" : "") + sharedCode.join("\n\n");
|
|
49977
|
-
chunkEntries.push({ name: "shared.js", code, node: null, imports: chunkHasImports(head.length, !sharedImports.ok) });
|
|
50039
|
+
chunkEntries.push({ name: "shared.js", code, node: null, importsTable: sharedImports, imports: chunkHasImports(head.length, !sharedImports.ok) });
|
|
49978
50040
|
}
|
|
49979
50041
|
const chunkIIFE = (body) => `(()=>{
|
|
49980
50042
|
const __components = globalThis.__components || (globalThis.__components = {});
|
|
@@ -49982,6 +50044,98 @@ const __hydrators = globalThis.__hydrators || (globalThis.__hydrators = {});
|
|
|
49982
50044
|
${body}
|
|
49983
50045
|
})();
|
|
49984
50046
|
`;
|
|
50047
|
+
const sharedUsage = /* @__PURE__ */ new Map();
|
|
50048
|
+
for (const entry of chunkEntries) {
|
|
50049
|
+
for (const source of new Set(entry.importsTable.sources())) {
|
|
50050
|
+
sharedUsage.set(source, (sharedUsage.get(source) ?? 0) + 1);
|
|
50051
|
+
}
|
|
50052
|
+
}
|
|
50053
|
+
const isAppLocal = (source) => !source.includes("node_modules") && source.startsWith(resolve10(appDir, ".."));
|
|
50054
|
+
const sharedSources = [...sharedUsage.entries()].filter(([source, uses]) => uses > 1 && isAppLocal(source)).map(([source]) => source);
|
|
50055
|
+
if (process.env.VESK_DEBUG_SHARED) {
|
|
50056
|
+
console.error("[shared] candidates:", [...sharedUsage.entries()].map(([s, n]) => `${n}x ${s}`).join("\n"));
|
|
50057
|
+
console.error("[shared] selected:", sharedSources.join(", "));
|
|
50058
|
+
}
|
|
50059
|
+
const chunkAlias = {};
|
|
50060
|
+
let sharedBundleCode = "";
|
|
50061
|
+
const sharedRuntimeNames = /* @__PURE__ */ new Set();
|
|
50062
|
+
if (sharedSources.length > 0) {
|
|
50063
|
+
const tmpBase = mkdtempSync(join7(resolve10(appDir, ".."), "tmp-vesk-shared-"));
|
|
50064
|
+
try {
|
|
50065
|
+
const sharedEntry = join7(tmpBase, "shared-entry.js");
|
|
50066
|
+
const lines = [];
|
|
50067
|
+
const members = [];
|
|
50068
|
+
sharedSources.forEach((source, i) => {
|
|
50069
|
+
lines.push(`import * as m${i} from ${JSON.stringify(source)};`);
|
|
50070
|
+
members.push(` ${JSON.stringify(source)}: m${i},`);
|
|
50071
|
+
});
|
|
50072
|
+
lines.push(`globalThis.__veskShared = { ${members.join("\n")} };`);
|
|
50073
|
+
writeFileSync4(sharedEntry, lines.join("\n"));
|
|
50074
|
+
const appTsconfig = findTsconfigPath(appDir);
|
|
50075
|
+
const runtimeShim = join7(tmpBase, "runtime-shim.js");
|
|
50076
|
+
const runtimeLines = [
|
|
50077
|
+
"// ONE runtime instance: the entry bundle publishes these on globalThis,",
|
|
50078
|
+
"// and route chunks import the same functions. A second bundled copy",
|
|
50079
|
+
"// would mean a second Cell class and a second currentEffect.",
|
|
50080
|
+
"const __r = (n) => (...args) => globalThis[n](...args);"
|
|
50081
|
+
];
|
|
50082
|
+
for (const source of sharedSources) {
|
|
50083
|
+
for (const name of runtimeImportsOf(source)) sharedRuntimeNames.add(name);
|
|
50084
|
+
}
|
|
50085
|
+
for (const name of [...sharedRuntimeNames].sort()) {
|
|
50086
|
+
runtimeLines.push(`export const ${name} = __r(${JSON.stringify(name)});`);
|
|
50087
|
+
}
|
|
50088
|
+
writeFileSync4(runtimeShim, runtimeLines.join("\n") + "\n");
|
|
50089
|
+
const result = await build({
|
|
50090
|
+
entryPoints: [sharedEntry],
|
|
50091
|
+
bundle: true,
|
|
50092
|
+
format: "iife",
|
|
50093
|
+
platform: "browser",
|
|
50094
|
+
write: false,
|
|
50095
|
+
logLevel: "silent",
|
|
50096
|
+
loader: { ".js": "tsx" },
|
|
50097
|
+
legalComments: "none",
|
|
50098
|
+
// `@vesk/runtime` MUST stay the entry bundle's instance. Bundling a
|
|
50099
|
+
// second copy in here gives the app a second `Cell` class and a
|
|
50100
|
+
// second `currentEffect` variable: a store cell written from a click
|
|
50101
|
+
// notifies subscribers registered against the OTHER copy, so nothing
|
|
50102
|
+
// the store drives ever updates — writes land, no error, no repaint.
|
|
50103
|
+
plugins: [sharedRuntimeResolver(runtimeShim)],
|
|
50104
|
+
...appTsconfig ? { tsconfig: appTsconfig } : {}
|
|
50105
|
+
});
|
|
50106
|
+
sharedBundleCode = result.outputFiles[0].text;
|
|
50107
|
+
sharedSources.forEach((source, i) => {
|
|
50108
|
+
const named = /* @__PURE__ */ new Set();
|
|
50109
|
+
let hasDefault = false;
|
|
50110
|
+
for (const entry of chunkEntries) {
|
|
50111
|
+
const bindings = entry.importsTable.bindingsFor(source);
|
|
50112
|
+
bindings.named.forEach((n) => named.add(n));
|
|
50113
|
+
hasDefault = hasDefault || bindings.hasDefault;
|
|
50114
|
+
}
|
|
50115
|
+
const shim = join7(tmpBase, `shim-${i}.js`);
|
|
50116
|
+
const shimLines = [`const m = globalThis.__veskShared[${JSON.stringify(source)}];`];
|
|
50117
|
+
if (hasDefault) shimLines.push(`export default m;`);
|
|
50118
|
+
for (const name of [...named].sort()) {
|
|
50119
|
+
shimLines.push(`export const ${name} = m[${JSON.stringify(name)}];`);
|
|
50120
|
+
}
|
|
50121
|
+
writeFileSync4(shim, shimLines.join("\n") + "\n");
|
|
50122
|
+
chunkAlias[source] = shim;
|
|
50123
|
+
});
|
|
50124
|
+
} catch (e) {
|
|
50125
|
+
console.error("[vesk] shared-module pass failed; falling back to per-chunk inlining:", e.message);
|
|
50126
|
+
sharedBundleCode = "";
|
|
50127
|
+
for (const key of Object.keys(chunkAlias)) delete chunkAlias[key];
|
|
50128
|
+
}
|
|
50129
|
+
}
|
|
50130
|
+
const sharedRedirectPlugin = Object.keys(chunkAlias).length > 0 ? {
|
|
50131
|
+
name: "vesk-shared-modules",
|
|
50132
|
+
setup(build4) {
|
|
50133
|
+
build4.onResolve({ filter: /.*/ }, (args2) => {
|
|
50134
|
+
const mapped = chunkAlias[args2.path];
|
|
50135
|
+
return mapped ? { path: mapped } : null;
|
|
50136
|
+
});
|
|
50137
|
+
}
|
|
50138
|
+
} : null;
|
|
49985
50139
|
for (const entry of chunkEntries) {
|
|
49986
50140
|
if (!entry.code.trim()) continue;
|
|
49987
50141
|
let finalCode;
|
|
@@ -50010,6 +50164,13 @@ ${entry.code}
|
|
|
50010
50164
|
// for a dependency stays in its own package; shipping every
|
|
50011
50165
|
// module's header inside our own chunk adds nothing.
|
|
50012
50166
|
legalComments: "none",
|
|
50167
|
+
// Shared app modules are NOT inlined here: the resolver below
|
|
50168
|
+
// redirects them to a generated shim reading
|
|
50169
|
+
// `globalThis.__veskShared`, so the single copy in
|
|
50170
|
+
// shared-modules.js serves every route chunk. (esbuild's `alias`
|
|
50171
|
+
// option only accepts bare package names, so this is a resolver
|
|
50172
|
+
// rather than a map.)
|
|
50173
|
+
...sharedRedirectPlugin ? { plugins: [sharedRedirectPlugin] } : {},
|
|
50013
50174
|
...appTsconfig ? { tsconfig: appTsconfig } : {}
|
|
50014
50175
|
});
|
|
50015
50176
|
finalCode = result.outputFiles[0].text;
|
|
@@ -50037,13 +50198,15 @@ ${entry.code}
|
|
|
50037
50198
|
chunks.push({ name: entry.name, code: finalCode });
|
|
50038
50199
|
}
|
|
50039
50200
|
annotate2(routeTree);
|
|
50040
|
-
|
|
50201
|
+
sharedModuleBundle = sharedBundleCode;
|
|
50202
|
+
for (const name of sharedRuntimeNames) runtimeImportNames.add(name);
|
|
50203
|
+
const mainKey = JSON.stringify(routeTree) + "|" + [...runtimeImportNames].sort().join(",") + `|${!!options?.hmr}|${!!options?.importRuntime}|${options?.routeDataCache ?? ""}|${sharedModuleBundle.length}`;
|
|
50041
50204
|
let main;
|
|
50042
50205
|
if (cache2?.mainBundle && cache2.mainBundle.key === mainKey) {
|
|
50043
50206
|
mainFromCache = true;
|
|
50044
50207
|
main = cache2.mainBundle.code;
|
|
50045
50208
|
} else {
|
|
50046
|
-
main = await buildMainBundle(routeTree, runtimeDir, true, {}, !!options?.hmr, !!options?.importRuntime, runtimeImportNames, options?.routeDataCache);
|
|
50209
|
+
main = await buildMainBundle(routeTree, runtimeDir, true, {}, !!options?.hmr, !!options?.importRuntime, runtimeImportNames, options?.routeDataCache, sharedModuleBundle);
|
|
50047
50210
|
if (cache2) cache2.mainBundle = { key: mainKey, code: main };
|
|
50048
50211
|
}
|
|
50049
50212
|
const transformedChunks = [];
|
|
@@ -50244,7 +50407,7 @@ export { ${unique.join(", ")} };
|
|
|
50244
50407
|
function appendHmrGlobals(code) {
|
|
50245
50408
|
return code + "globalThis.__vesk_hmr_eval = (code, n) => {\n if (!n || n !== globalThis.__vesk_hmr_nonce) throw new Error('vesk hmr: invalid nonce');\n return eval(code);\n};\n";
|
|
50246
50409
|
}
|
|
50247
|
-
async function buildMainBundle(routeTree, runtimeDir, codeSplit, mono, hmr, importRuntime, runtimeImportNames, routeDataCache) {
|
|
50410
|
+
async function buildMainBundle(routeTree, runtimeDir, codeSplit, mono, hmr, importRuntime, runtimeImportNames, routeDataCache, sharedModuleBundle = "") {
|
|
50248
50411
|
const baseRuntimeImports = ["createFileRouter", "get", "set", "effect", "track", "destroy_block", "getActiveComponent", "setActiveComponent", "NavLink", "Link", "reactiveProps", "matchRoute", "ensureChunk", "toDomNode", "rerenderNode"];
|
|
50249
50412
|
const allRuntimeImports = runtimeImportNames && runtimeImportNames.size > 0 ? [.../* @__PURE__ */ new Set([...baseRuntimeImports, ...runtimeImportNames])] : baseRuntimeImports;
|
|
50250
50413
|
const runtimeGlobals = [
|
|
@@ -50313,7 +50476,11 @@ if (__pendChunks.length > 0 && typeof ensureChunk === 'function') {
|
|
|
50313
50476
|
`).join("") + "globalThis.__runtime_comps = __runtime_comps;\nglobalThis.__cleanup = __cleanup;\nglobalThis.__place = __place;\n\n";
|
|
50314
50477
|
const extraGlobals = [...runtimeImportNames || []].filter((n) => n && n !== "default").map((n) => `globalThis.${n} = ${n};
|
|
50315
50478
|
`).join("");
|
|
50316
|
-
const code2 = preamble + "const __components = globalThis.__components || (globalThis.__components = {});\nconst __hydrators = globalThis.__hydrators || (globalThis.__hydrators = {});\nconst __runtime_comps = __components;\n\n" + runtimeGlobals2 + extraGlobals +
|
|
50479
|
+
const code2 = preamble + "const __components = globalThis.__components || (globalThis.__components = {});\nconst __hydrators = globalThis.__hydrators || (globalThis.__hydrators = {});\nconst __runtime_comps = __components;\n\n" + runtimeGlobals2 + extraGlobals + // Shared app modules run HERE: after the runtime bindings are published,
|
|
50480
|
+
// before anything can request a route chunk. Earlier (at the top of the
|
|
50481
|
+
// bundle) `globalThis.track` was still undefined, so every module-scope
|
|
50482
|
+
// cell in a store was created against a missing runtime.
|
|
50483
|
+
(sharedModuleBundle ? sharedModuleBundle + "\n" : "") + cleanupFn + placeFn + "globalThis.__components = __components;\n" + resolveNamesFn + updateComponentsFn + "const __routeTree = " + routeTreeJson + ";\n__resolveNames(__routeTree);\n" + pendCode + startRouterCode;
|
|
50317
50484
|
return hmr ? appendHmrGlobals(code2) : code2;
|
|
50318
50485
|
}
|
|
50319
50486
|
const componentLines = mono?.componentLines || [];
|
|
@@ -52568,6 +52735,9 @@ function isReactiveExpression2(node, tracked2) {
|
|
|
52568
52735
|
return false;
|
|
52569
52736
|
let reactive = false;
|
|
52570
52737
|
walk7(ast, tracked2, {
|
|
52738
|
+
CallExpression() {
|
|
52739
|
+
reactive = true;
|
|
52740
|
+
},
|
|
52571
52741
|
Identifier(n, context) {
|
|
52572
52742
|
if (reactive)
|
|
52573
52743
|
return;
|
|
@@ -52713,7 +52883,7 @@ function emitComponentCall2(ctx2, node, tracked2, effectsVar, parentVar, compPre
|
|
|
52713
52883
|
ctx2.push(`return $f; })();`);
|
|
52714
52884
|
propsEntries.push(`children: ${frag}`);
|
|
52715
52885
|
}
|
|
52716
|
-
if (ctx2.markerless && promptExpr
|
|
52886
|
+
if (ctx2.markerless && promptExpr) {
|
|
52717
52887
|
ctx2.push(`${walkerArg}.injectSkipK(${promptExpr});`);
|
|
52718
52888
|
}
|
|
52719
52889
|
ctx2.push(`let ${v} = undefined;`);
|
|
@@ -55489,6 +55659,37 @@ function demoteExports2(code) {
|
|
|
55489
55659
|
function chunkHasImports2(headLen, mergeAborted) {
|
|
55490
55660
|
return headLen > 0 || mergeAborted;
|
|
55491
55661
|
}
|
|
55662
|
+
function runtimeImportsOf2(filePath) {
|
|
55663
|
+
let text;
|
|
55664
|
+
try {
|
|
55665
|
+
text = readFileSync24(filePath, "utf8");
|
|
55666
|
+
} catch {
|
|
55667
|
+
return [];
|
|
55668
|
+
}
|
|
55669
|
+
const names = [];
|
|
55670
|
+
const pattern2 = /import\s+(type\s+)?\{([^}]*)\}\s*from\s*['"]@vesk\/runtime[^'"]*['"]/g;
|
|
55671
|
+
for (const match of text.matchAll(pattern2)) {
|
|
55672
|
+
if (match[1])
|
|
55673
|
+
continue;
|
|
55674
|
+
for (const part of match[2].split(",")) {
|
|
55675
|
+
const cleaned = part.trim().replace(/^type\s+/, "");
|
|
55676
|
+
if (!cleaned)
|
|
55677
|
+
continue;
|
|
55678
|
+
const name = cleaned.split(/\s+as\s+/)[0].trim();
|
|
55679
|
+
if (name)
|
|
55680
|
+
names.push(name);
|
|
55681
|
+
}
|
|
55682
|
+
}
|
|
55683
|
+
return names;
|
|
55684
|
+
}
|
|
55685
|
+
function sharedRuntimeResolver2(shimPath) {
|
|
55686
|
+
return {
|
|
55687
|
+
name: "vesk-shared-runtime",
|
|
55688
|
+
setup(build4) {
|
|
55689
|
+
build4.onResolve({ filter: /^@vesk\/runtime(\/.*)?$/ }, () => ({ path: shimPath }));
|
|
55690
|
+
}
|
|
55691
|
+
};
|
|
55692
|
+
}
|
|
55492
55693
|
var ChunkImports2 = class {
|
|
55493
55694
|
bySource = /* @__PURE__ */ new Map();
|
|
55494
55695
|
aborted = false;
|
|
@@ -55596,6 +55797,21 @@ var ChunkImports2 = class {
|
|
|
55596
55797
|
get reason() {
|
|
55597
55798
|
return this.abortReason;
|
|
55598
55799
|
}
|
|
55800
|
+
/** Every import source this chunk's merged block pulls in (absolute paths). */
|
|
55801
|
+
sources() {
|
|
55802
|
+
return this.aborted ? [] : [...this.bySource.keys()];
|
|
55803
|
+
}
|
|
55804
|
+
/**
|
|
55805
|
+
* The named bindings this chunk imports from `source`, so a shared-module
|
|
55806
|
+
* shim can re-export exactly what consumers use (re-exporting `*` from the
|
|
55807
|
+
* real module would drag it back into the chunk being built).
|
|
55808
|
+
*/
|
|
55809
|
+
bindingsFor(source) {
|
|
55810
|
+
const group = this.bySource.get(source);
|
|
55811
|
+
if (!group)
|
|
55812
|
+
return { named: [], hasDefault: false };
|
|
55813
|
+
return { named: [...group.named.keys()].sort(), hasDefault: !!group.default };
|
|
55814
|
+
}
|
|
55599
55815
|
/** Renders the deduped import block (empty string when there are no imports). */
|
|
55600
55816
|
render() {
|
|
55601
55817
|
if (this.aborted || this.bySource.size === 0)
|
|
@@ -55750,6 +55966,7 @@ async function generateClientBundle2(routeTree, appDir, componentMap, options) {
|
|
|
55750
55966
|
let cachedFileHits = 0;
|
|
55751
55967
|
let compiledFiles = 0;
|
|
55752
55968
|
let mainFromCache = false;
|
|
55969
|
+
let sharedModuleBundle = "";
|
|
55753
55970
|
function mustReuseWithoutStat(filePath) {
|
|
55754
55971
|
return !!only && !only.has(filePath);
|
|
55755
55972
|
}
|
|
@@ -55948,7 +56165,7 @@ async function generateClientBundle2(routeTree, appDir, componentMap, options) {
|
|
|
55948
56165
|
console.error("[vesk] chunk import merge aborted for", chunkName + ":", chunkImports.reason);
|
|
55949
56166
|
const head = chunkImports.render();
|
|
55950
56167
|
const code = (head ? head + "\n\n" : "") + chunkCode.join("\n\n");
|
|
55951
|
-
chunkEntries.push({ name: chunkName, code, node, imports: chunkHasImports2(head.length, !chunkImports.ok) });
|
|
56168
|
+
chunkEntries.push({ name: chunkName, code, node, importsTable: chunkImports, imports: chunkHasImports2(head.length, !chunkImports.ok) });
|
|
55952
56169
|
}
|
|
55953
56170
|
walkSplit2(node.children || [], [..._chain, node]);
|
|
55954
56171
|
}
|
|
@@ -55978,7 +56195,7 @@ async function generateClientBundle2(routeTree, appDir, componentMap, options) {
|
|
|
55978
56195
|
console.error("[vesk] chunk import merge aborted for shared.js:", sharedImports.reason);
|
|
55979
56196
|
const head = sharedImports.render();
|
|
55980
56197
|
const code = (head ? head + "\n\n" : "") + sharedCode.join("\n\n");
|
|
55981
|
-
chunkEntries.push({ name: "shared.js", code, node: null, imports: chunkHasImports2(head.length, !sharedImports.ok) });
|
|
56198
|
+
chunkEntries.push({ name: "shared.js", code, node: null, importsTable: sharedImports, imports: chunkHasImports2(head.length, !sharedImports.ok) });
|
|
55982
56199
|
}
|
|
55983
56200
|
const chunkIIFE = (body) => `(()=>{
|
|
55984
56201
|
const __components = globalThis.__components || (globalThis.__components = {});
|
|
@@ -55986,6 +56203,101 @@ const __hydrators = globalThis.__hydrators || (globalThis.__hydrators = {});
|
|
|
55986
56203
|
${body}
|
|
55987
56204
|
})();
|
|
55988
56205
|
`;
|
|
56206
|
+
const sharedUsage = /* @__PURE__ */ new Map();
|
|
56207
|
+
for (const entry of chunkEntries) {
|
|
56208
|
+
for (const source of new Set(entry.importsTable.sources())) {
|
|
56209
|
+
sharedUsage.set(source, (sharedUsage.get(source) ?? 0) + 1);
|
|
56210
|
+
}
|
|
56211
|
+
}
|
|
56212
|
+
const isAppLocal = (source) => !source.includes("node_modules") && source.startsWith(resolve24(appDir, ".."));
|
|
56213
|
+
const sharedSources = [...sharedUsage.entries()].filter(([source, uses]) => uses > 1 && isAppLocal(source)).map(([source]) => source);
|
|
56214
|
+
if (process.env.VESK_DEBUG_SHARED) {
|
|
56215
|
+
console.error("[shared] candidates:", [...sharedUsage.entries()].map(([s, n]) => `${n}x ${s}`).join("\n"));
|
|
56216
|
+
console.error("[shared] selected:", sharedSources.join(", "));
|
|
56217
|
+
}
|
|
56218
|
+
const chunkAlias = {};
|
|
56219
|
+
let sharedBundleCode = "";
|
|
56220
|
+
const sharedRuntimeNames = /* @__PURE__ */ new Set();
|
|
56221
|
+
if (sharedSources.length > 0) {
|
|
56222
|
+
const tmpBase = mkdtempSync2(join20(resolve24(appDir, ".."), "tmp-vesk-shared-"));
|
|
56223
|
+
try {
|
|
56224
|
+
const sharedEntry = join20(tmpBase, "shared-entry.js");
|
|
56225
|
+
const lines = [];
|
|
56226
|
+
const members = [];
|
|
56227
|
+
sharedSources.forEach((source, i) => {
|
|
56228
|
+
lines.push(`import * as m${i} from ${JSON.stringify(source)};`);
|
|
56229
|
+
members.push(` ${JSON.stringify(source)}: m${i},`);
|
|
56230
|
+
});
|
|
56231
|
+
lines.push(`globalThis.__veskShared = { ${members.join("\n")} };`);
|
|
56232
|
+
writeFileSync13(sharedEntry, lines.join("\n"));
|
|
56233
|
+
const appTsconfig = findTsconfigPath(appDir);
|
|
56234
|
+
const runtimeShim = join20(tmpBase, "runtime-shim.js");
|
|
56235
|
+
const runtimeLines = [
|
|
56236
|
+
"// ONE runtime instance: the entry bundle publishes these on globalThis,",
|
|
56237
|
+
"// and route chunks import the same functions. A second bundled copy",
|
|
56238
|
+
"// would mean a second Cell class and a second currentEffect.",
|
|
56239
|
+
"const __r = (n) => (...args) => globalThis[n](...args);"
|
|
56240
|
+
];
|
|
56241
|
+
for (const source of sharedSources) {
|
|
56242
|
+
for (const name of runtimeImportsOf2(source))
|
|
56243
|
+
sharedRuntimeNames.add(name);
|
|
56244
|
+
}
|
|
56245
|
+
for (const name of [...sharedRuntimeNames].sort()) {
|
|
56246
|
+
runtimeLines.push(`export const ${name} = __r(${JSON.stringify(name)});`);
|
|
56247
|
+
}
|
|
56248
|
+
writeFileSync13(runtimeShim, runtimeLines.join("\n") + "\n");
|
|
56249
|
+
const result = await build3({
|
|
56250
|
+
entryPoints: [sharedEntry],
|
|
56251
|
+
bundle: true,
|
|
56252
|
+
format: "iife",
|
|
56253
|
+
platform: "browser",
|
|
56254
|
+
write: false,
|
|
56255
|
+
logLevel: "silent",
|
|
56256
|
+
loader: { ".js": "tsx" },
|
|
56257
|
+
legalComments: "none",
|
|
56258
|
+
// `@vesk/runtime` MUST stay the entry bundle's instance. Bundling a
|
|
56259
|
+
// second copy in here gives the app a second `Cell` class and a
|
|
56260
|
+
// second `currentEffect` variable: a store cell written from a click
|
|
56261
|
+
// notifies subscribers registered against the OTHER copy, so nothing
|
|
56262
|
+
// the store drives ever updates — writes land, no error, no repaint.
|
|
56263
|
+
plugins: [sharedRuntimeResolver2(runtimeShim)],
|
|
56264
|
+
...appTsconfig ? { tsconfig: appTsconfig } : {}
|
|
56265
|
+
});
|
|
56266
|
+
sharedBundleCode = result.outputFiles[0].text;
|
|
56267
|
+
sharedSources.forEach((source, i) => {
|
|
56268
|
+
const named = /* @__PURE__ */ new Set();
|
|
56269
|
+
let hasDefault = false;
|
|
56270
|
+
for (const entry of chunkEntries) {
|
|
56271
|
+
const bindings = entry.importsTable.bindingsFor(source);
|
|
56272
|
+
bindings.named.forEach((n) => named.add(n));
|
|
56273
|
+
hasDefault = hasDefault || bindings.hasDefault;
|
|
56274
|
+
}
|
|
56275
|
+
const shim = join20(tmpBase, `shim-${i}.js`);
|
|
56276
|
+
const shimLines = [`const m = globalThis.__veskShared[${JSON.stringify(source)}];`];
|
|
56277
|
+
if (hasDefault)
|
|
56278
|
+
shimLines.push(`export default m;`);
|
|
56279
|
+
for (const name of [...named].sort()) {
|
|
56280
|
+
shimLines.push(`export const ${name} = m[${JSON.stringify(name)}];`);
|
|
56281
|
+
}
|
|
56282
|
+
writeFileSync13(shim, shimLines.join("\n") + "\n");
|
|
56283
|
+
chunkAlias[source] = shim;
|
|
56284
|
+
});
|
|
56285
|
+
} catch (e) {
|
|
56286
|
+
console.error("[vesk] shared-module pass failed; falling back to per-chunk inlining:", e.message);
|
|
56287
|
+
sharedBundleCode = "";
|
|
56288
|
+
for (const key of Object.keys(chunkAlias))
|
|
56289
|
+
delete chunkAlias[key];
|
|
56290
|
+
}
|
|
56291
|
+
}
|
|
56292
|
+
const sharedRedirectPlugin = Object.keys(chunkAlias).length > 0 ? {
|
|
56293
|
+
name: "vesk-shared-modules",
|
|
56294
|
+
setup(build4) {
|
|
56295
|
+
build4.onResolve({ filter: /.*/ }, (args2) => {
|
|
56296
|
+
const mapped = chunkAlias[args2.path];
|
|
56297
|
+
return mapped ? { path: mapped } : null;
|
|
56298
|
+
});
|
|
56299
|
+
}
|
|
56300
|
+
} : null;
|
|
55989
56301
|
for (const entry of chunkEntries) {
|
|
55990
56302
|
if (!entry.code.trim())
|
|
55991
56303
|
continue;
|
|
@@ -56015,6 +56327,13 @@ ${entry.code}
|
|
|
56015
56327
|
// for a dependency stays in its own package; shipping every
|
|
56016
56328
|
// module's header inside our own chunk adds nothing.
|
|
56017
56329
|
legalComments: "none",
|
|
56330
|
+
// Shared app modules are NOT inlined here: the resolver below
|
|
56331
|
+
// redirects them to a generated shim reading
|
|
56332
|
+
// `globalThis.__veskShared`, so the single copy in
|
|
56333
|
+
// shared-modules.js serves every route chunk. (esbuild's `alias`
|
|
56334
|
+
// option only accepts bare package names, so this is a resolver
|
|
56335
|
+
// rather than a map.)
|
|
56336
|
+
...sharedRedirectPlugin ? { plugins: [sharedRedirectPlugin] } : {},
|
|
56018
56337
|
...appTsconfig ? { tsconfig: appTsconfig } : {}
|
|
56019
56338
|
});
|
|
56020
56339
|
finalCode = result.outputFiles[0].text;
|
|
@@ -56042,13 +56361,16 @@ ${entry.code}
|
|
|
56042
56361
|
chunks.push({ name: entry.name, code: finalCode });
|
|
56043
56362
|
}
|
|
56044
56363
|
annotate2(routeTree);
|
|
56045
|
-
|
|
56364
|
+
sharedModuleBundle = sharedBundleCode;
|
|
56365
|
+
for (const name of sharedRuntimeNames)
|
|
56366
|
+
runtimeImportNames.add(name);
|
|
56367
|
+
const mainKey = JSON.stringify(routeTree) + "|" + [...runtimeImportNames].sort().join(",") + `|${!!options?.hmr}|${!!options?.importRuntime}|${options?.routeDataCache ?? ""}|${sharedModuleBundle.length}`;
|
|
56046
56368
|
let main;
|
|
56047
56369
|
if (cache2?.mainBundle && cache2.mainBundle.key === mainKey) {
|
|
56048
56370
|
mainFromCache = true;
|
|
56049
56371
|
main = cache2.mainBundle.code;
|
|
56050
56372
|
} else {
|
|
56051
|
-
main = await buildMainBundle2(routeTree, runtimeDir, true, {}, !!options?.hmr, !!options?.importRuntime, runtimeImportNames, options?.routeDataCache);
|
|
56373
|
+
main = await buildMainBundle2(routeTree, runtimeDir, true, {}, !!options?.hmr, !!options?.importRuntime, runtimeImportNames, options?.routeDataCache, sharedModuleBundle);
|
|
56052
56374
|
if (cache2)
|
|
56053
56375
|
cache2.mainBundle = { key: mainKey, code: main };
|
|
56054
56376
|
}
|
|
@@ -56265,7 +56587,7 @@ export { ${unique.join(", ")} };
|
|
|
56265
56587
|
function appendHmrGlobals2(code) {
|
|
56266
56588
|
return code + "globalThis.__vesk_hmr_eval = (code, n) => {\n if (!n || n !== globalThis.__vesk_hmr_nonce) throw new Error('vesk hmr: invalid nonce');\n return eval(code);\n};\n";
|
|
56267
56589
|
}
|
|
56268
|
-
async function buildMainBundle2(routeTree, runtimeDir, codeSplit, mono, hmr, importRuntime, runtimeImportNames, routeDataCache) {
|
|
56590
|
+
async function buildMainBundle2(routeTree, runtimeDir, codeSplit, mono, hmr, importRuntime, runtimeImportNames, routeDataCache, sharedModuleBundle = "") {
|
|
56269
56591
|
const baseRuntimeImports = ["createFileRouter", "get", "set", "effect", "track", "destroy_block", "getActiveComponent", "setActiveComponent", "NavLink", "Link", "reactiveProps", "matchRoute", "ensureChunk", "toDomNode", "rerenderNode"];
|
|
56270
56592
|
const allRuntimeImports = runtimeImportNames && runtimeImportNames.size > 0 ? [.../* @__PURE__ */ new Set([...baseRuntimeImports, ...runtimeImportNames])] : baseRuntimeImports;
|
|
56271
56593
|
const runtimeGlobals = [
|
|
@@ -56334,7 +56656,11 @@ if (__pendChunks.length > 0 && typeof ensureChunk === 'function') {
|
|
|
56334
56656
|
`).join("") + "globalThis.__runtime_comps = __runtime_comps;\nglobalThis.__cleanup = __cleanup;\nglobalThis.__place = __place;\n\n";
|
|
56335
56657
|
const extraGlobals = [...runtimeImportNames || []].filter((n) => n && n !== "default").map((n) => `globalThis.${n} = ${n};
|
|
56336
56658
|
`).join("");
|
|
56337
|
-
const code2 = preamble + "const __components = globalThis.__components || (globalThis.__components = {});\nconst __hydrators = globalThis.__hydrators || (globalThis.__hydrators = {});\nconst __runtime_comps = __components;\n\n" + runtimeGlobals2 + extraGlobals +
|
|
56659
|
+
const code2 = preamble + "const __components = globalThis.__components || (globalThis.__components = {});\nconst __hydrators = globalThis.__hydrators || (globalThis.__hydrators = {});\nconst __runtime_comps = __components;\n\n" + runtimeGlobals2 + extraGlobals + // Shared app modules run HERE: after the runtime bindings are published,
|
|
56660
|
+
// before anything can request a route chunk. Earlier (at the top of the
|
|
56661
|
+
// bundle) `globalThis.track` was still undefined, so every module-scope
|
|
56662
|
+
// cell in a store was created against a missing runtime.
|
|
56663
|
+
(sharedModuleBundle ? sharedModuleBundle + "\n" : "") + cleanupFn + placeFn + "globalThis.__components = __components;\n" + resolveNamesFn + updateComponentsFn + "const __routeTree = " + routeTreeJson + ";\n__resolveNames(__routeTree);\n" + pendCode + startRouterCode;
|
|
56338
56664
|
return hmr ? appendHmrGlobals2(code2) : code2;
|
|
56339
56665
|
}
|
|
56340
56666
|
const componentLines = mono?.componentLines || [];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vesk/vesk-cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.59",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Vesk — compiler-first framework for the post-VDOM web. vesk dev, vesk build.",
|
|
6
6
|
"bin": {
|
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
},
|
|
9
9
|
"main": "./dist/cli.js",
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@vesk/adapter": "^0.2.
|
|
12
|
-
"@vesk/compiler": "^0.2.
|
|
13
|
-
"@vesk/plugin-tailwind": "^0.2.
|
|
14
|
-
"@vesk/runtime": "^0.2.
|
|
11
|
+
"@vesk/adapter": "^0.2.59",
|
|
12
|
+
"@vesk/compiler": "^0.2.59",
|
|
13
|
+
"@vesk/plugin-tailwind": "^0.2.59",
|
|
14
|
+
"@vesk/runtime": "^0.2.59",
|
|
15
15
|
"esrap": "^2.3.0",
|
|
16
16
|
"typescript": "^5.8.0",
|
|
17
17
|
"ws": "^8.18.0",
|