@vesk/compiler 0.2.21 → 0.2.23
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-codegen.d.ts.map +1 -1
- package/dist/client-codegen.js +231 -20
- package/dist/ir-generator.d.ts.map +1 -1
- package/dist/ir-generator.js +13 -0
- package/dist/module-imports.d.ts +43 -0
- package/dist/module-imports.d.ts.map +1 -1
- package/dist/module-imports.js +130 -3
- package/dist/precompile-runtime.d.ts +46 -0
- package/dist/precompile-runtime.d.ts.map +1 -0
- package/dist/precompile-runtime.js +211 -0
- package/dist/precompile.d.ts +13 -0
- package/dist/precompile.d.ts.map +1 -0
- package/dist/precompile.js +76 -0
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +108 -7
- package/dist/server-codegen.d.ts +3 -1
- package/dist/server-codegen.d.ts.map +1 -1
- package/dist/server-codegen.js +3 -1
- package/dist/server-jsgen.d.ts +11 -0
- package/dist/server-jsgen.d.ts.map +1 -1
- package/dist/server-jsgen.js +75 -10
- package/dist/server-render.d.ts.map +1 -1
- package/dist/server-render.js +131 -13
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-codegen.d.ts","sourceRoot":"","sources":["../src/client-codegen.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAuB,MAAM,uBAAuB,CAAC;AACzE,OAAO,EAGL,cAAc,EAQd,gBAAgB,EAOjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAwCxD,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,SAAS,GAAG,MAAM,CAAC;CAC1B;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI1D;AAiDD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,gBAAgB,GAAG,cAAc,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,MAAM,CAwGlI;AAID,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAU5E;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,MAAM,CAY5F;
|
|
1
|
+
{"version":3,"file":"client-codegen.d.ts","sourceRoot":"","sources":["../src/client-codegen.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAuB,MAAM,uBAAuB,CAAC;AACzE,OAAO,EAGL,cAAc,EAQd,gBAAgB,EAOjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAwCxD,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,SAAS,GAAG,MAAM,CAAC;CAC1B;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI1D;AAiDD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,gBAAgB,GAAG,cAAc,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,MAAM,CAwGlI;AAID,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAU5E;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,MAAM,CAY5F;AAw1CD,iBAAS,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAe3C;AA2HD,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAO9C;AAqED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,eAAe,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;CAAO,GAAG,MAAM,CAOnN;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAqBxJ;AAED,OAAO,EAAE,aAAa,IAAI,OAAO,EAAE,UAAU,EAAE,CAAC"}
|
package/dist/client-codegen.js
CHANGED
|
@@ -258,6 +258,9 @@ class Ctx {
|
|
|
258
258
|
hydrate = false;
|
|
259
259
|
inTryBody = false;
|
|
260
260
|
claimStatic = false;
|
|
261
|
+
// While set, the next StaticNode claimed in hydrate mode uses `__root` (the
|
|
262
|
+
// item element already claimed by key) instead of walking for a new element.
|
|
263
|
+
rootClaim = false;
|
|
261
264
|
walker = '__hydrate';
|
|
262
265
|
asyncComps = new Set();
|
|
263
266
|
isAsyncScope = false;
|
|
@@ -343,7 +346,7 @@ function emitNode(ctx, node, tracked, effectsVar, parentVar, compPrefix = '__com
|
|
|
343
346
|
if (ctx.hydrate) {
|
|
344
347
|
ctx.push(`if (props.children !== undefined && props.children !== null) {`);
|
|
345
348
|
ctx.push(` if (typeof props.children === 'function') {`);
|
|
346
|
-
ctx.push(` const __child = props.children(${ctx.walker}
|
|
349
|
+
ctx.push(` const __child = props.children(${ctx.walker});`);
|
|
347
350
|
ctx.push(` if (__child && typeof __child.then === 'function') __pendingChild = __child.then(() => $root);`);
|
|
348
351
|
ctx.push(` } else {`);
|
|
349
352
|
ctx.push(` ${parentVar}.appendChild(props.children);`);
|
|
@@ -379,7 +382,12 @@ function emitStatic(ctx, node, tracked, effectsVar) {
|
|
|
379
382
|
ctx.claimStatic = false;
|
|
380
383
|
if (!claim && isStaticIR(node.children))
|
|
381
384
|
return null;
|
|
382
|
-
|
|
385
|
+
const rootClaim = ctx.rootClaim;
|
|
386
|
+
ctx.rootClaim = false;
|
|
387
|
+
const claimedExpr = rootClaim
|
|
388
|
+
? `__root || ${ctx.walker}.nextElement(${JSON.stringify(node.tag)})`
|
|
389
|
+
: `${ctx.walker}.nextElement(${JSON.stringify(node.tag)})`;
|
|
390
|
+
ctx.push(`const ${el} = ${claimedExpr};`);
|
|
383
391
|
}
|
|
384
392
|
else {
|
|
385
393
|
ctx.push(`const ${el} = document.createElement(${JSON.stringify(node.tag)});`);
|
|
@@ -406,8 +414,14 @@ function emitStatic(ctx, node, tracked, effectsVar) {
|
|
|
406
414
|
}
|
|
407
415
|
for (const child of children) {
|
|
408
416
|
const childVar = emitNode(ctx, child, tracked, effectsVar, el);
|
|
409
|
-
if (childVar)
|
|
410
|
-
ctx.
|
|
417
|
+
if (childVar) {
|
|
418
|
+
if (ctx.hydrate) {
|
|
419
|
+
ctx.push(`if (${childVar}.parentNode !== ${el}) { if (!${el} || ${childVar}.parentNode == null || !${el}.contains(${childVar})) ${el}.appendChild(${childVar}); }`);
|
|
420
|
+
}
|
|
421
|
+
else {
|
|
422
|
+
ctx.push(`${el}.appendChild(${childVar});`);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
411
425
|
}
|
|
412
426
|
for (const attr of dynAttrs) {
|
|
413
427
|
const target = attr.target || '';
|
|
@@ -781,13 +795,112 @@ function emitTryCatch(ctx, node, tracked, effectsVar, parentVar) {
|
|
|
781
795
|
return null;
|
|
782
796
|
}
|
|
783
797
|
function emitOpaque(ctx, node, tracked, effTarget, parentVar) {
|
|
798
|
+
const hyd = ctx.hydrate;
|
|
799
|
+
const parent = parentVar || '$root';
|
|
800
|
+
const isOpaque = (n) => !!n && typeof n.condition !== 'undefined';
|
|
801
|
+
if (hyd && node.alternateNodes.length === 1 && isOpaque(node.alternateNodes[0])) {
|
|
802
|
+
const chain = [];
|
|
803
|
+
let cur = node;
|
|
804
|
+
let finalElse = null;
|
|
805
|
+
while (cur) {
|
|
806
|
+
chain.push({ cond: transformTracked(cur.condition, tracked), nodes: cur.consequentNodes });
|
|
807
|
+
if (cur.alternateNodes.length === 1 && isOpaque(cur.alternateNodes[0])) {
|
|
808
|
+
cur = cur.alternateNodes[0];
|
|
809
|
+
}
|
|
810
|
+
else {
|
|
811
|
+
finalElse = cur.alternateNodes.length > 0 ? cur.alternateNodes : null;
|
|
812
|
+
cur = null;
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
const anchor = ctx.n();
|
|
816
|
+
const endAnchor = ctx.n();
|
|
817
|
+
const effectsVar = ctx.n();
|
|
818
|
+
ctx.push(`const ${anchor} = document.createComment('if');`);
|
|
819
|
+
ctx.push(`let ${effectsVar} = [];`);
|
|
820
|
+
ctx.push(`const ${endAnchor} = document.createComment('if-end');`);
|
|
821
|
+
const asyncKw = ctx.isAsyncScope ? 'await ' : '';
|
|
822
|
+
const fnOpen = ctx.isAsyncScope ? 'async () => {' : '() => {';
|
|
823
|
+
const renderNames = [];
|
|
824
|
+
for (let i = 0; i < chain.length; i++) {
|
|
825
|
+
const rn = ctx.n();
|
|
826
|
+
renderNames.push(rn);
|
|
827
|
+
ctx.push(`const ${rn} = ${fnOpen}`);
|
|
828
|
+
const cl = ctx.n();
|
|
829
|
+
ctx.push(indent(`const ${cl} = [];`));
|
|
830
|
+
for (const n of chain[i].nodes) {
|
|
831
|
+
const v = emitNode(ctx, n, tracked, effectsVar, parentVar);
|
|
832
|
+
if (v)
|
|
833
|
+
ctx.push(indent(`${cl}.push(${v});`));
|
|
834
|
+
}
|
|
835
|
+
ctx.push(indent(`__place(${anchor}, ${endAnchor}, ${cl}, ${parent});`));
|
|
836
|
+
ctx.push(`};`);
|
|
837
|
+
}
|
|
838
|
+
let finalRender = null;
|
|
839
|
+
if (finalElse) {
|
|
840
|
+
finalRender = ctx.n();
|
|
841
|
+
ctx.push(`const ${finalRender} = ${fnOpen}`);
|
|
842
|
+
const cl2 = ctx.n();
|
|
843
|
+
ctx.push(indent(`const ${cl2} = [];`));
|
|
844
|
+
for (const n of finalElse) {
|
|
845
|
+
const v = emitNode(ctx, n, tracked, effectsVar, parentVar);
|
|
846
|
+
if (v)
|
|
847
|
+
ctx.push(indent(`${cl2}.push(${v});`));
|
|
848
|
+
}
|
|
849
|
+
ctx.push(indent(`__place(${anchor}, ${endAnchor}, ${cl2}, ${parent});`));
|
|
850
|
+
ctx.push(`};`);
|
|
851
|
+
}
|
|
852
|
+
let init = `if (${chain[0].cond}) { ${asyncKw}${renderNames[0]}(); }`;
|
|
853
|
+
for (let i = 1; i < chain.length; i++)
|
|
854
|
+
init += ` else if (${chain[i].cond}) { ${asyncKw}${renderNames[i]}(); }`;
|
|
855
|
+
if (finalRender)
|
|
856
|
+
init += ` else { ${asyncKw}${finalRender}(); }`;
|
|
857
|
+
ctx.push(init);
|
|
858
|
+
let branchInit;
|
|
859
|
+
if (chain.length === 1 && finalRender)
|
|
860
|
+
branchInit = `(${chain[0].cond} ? 0 : 1)`;
|
|
861
|
+
else if (chain.length === 2 && finalRender)
|
|
862
|
+
branchInit = `(${chain[0].cond} ? 0 : (${chain[1].cond} ? 1 : 2))`;
|
|
863
|
+
else if (chain.length === 2 && !finalRender)
|
|
864
|
+
branchInit = `(${chain[0].cond} ? 0 : (${chain[1].cond} ? 1 : -1))`;
|
|
865
|
+
else
|
|
866
|
+
branchInit = `(${chain[0].cond} ? 0 : -1)`;
|
|
867
|
+
let effInner = `if (__new === 0) { ${asyncKw}${renderNames[0]}(); }`;
|
|
868
|
+
for (let i = 1; i < chain.length; i++)
|
|
869
|
+
effInner += ` else if (__new === ${i}) { ${asyncKw}${renderNames[i]}(); }`;
|
|
870
|
+
if (finalRender)
|
|
871
|
+
effInner += ` else { ${asyncKw}${finalRender}(); }`;
|
|
872
|
+
const effBody = `effect(${ctx.isAsyncScope ? 'async () => {' : '() => {'}
|
|
873
|
+
if (__first) { __first = false; return; }
|
|
874
|
+
const __new = ${branchInit};
|
|
875
|
+
if (__new !== __iv) {
|
|
876
|
+
for (const e of ${effectsVar}) destroy_block(e);
|
|
877
|
+
${effectsVar}.length = 0;
|
|
878
|
+
__cleanup(${anchor}, ${endAnchor});
|
|
879
|
+
${effInner}
|
|
880
|
+
__iv = __new;
|
|
881
|
+
}
|
|
882
|
+
});`;
|
|
883
|
+
if (effTarget) {
|
|
884
|
+
ctx.push(`${effTarget}.push((() => {
|
|
885
|
+
let __iv = ${branchInit};
|
|
886
|
+
let __first = true;
|
|
887
|
+
return ${effBody}
|
|
888
|
+
})());`);
|
|
889
|
+
}
|
|
890
|
+
else {
|
|
891
|
+
ctx.effects.push(`{
|
|
892
|
+
let __iv = ${branchInit};
|
|
893
|
+
let __first = true;
|
|
894
|
+
${effBody}
|
|
895
|
+
}`);
|
|
896
|
+
}
|
|
897
|
+
return null;
|
|
898
|
+
}
|
|
784
899
|
const condExpr = transformTracked(node.condition, tracked);
|
|
785
900
|
const hasElse = node.alternateNodes.length > 0;
|
|
786
901
|
const anchor = ctx.n();
|
|
787
902
|
const endAnchor = ctx.n();
|
|
788
903
|
const effectsVar = ctx.n();
|
|
789
|
-
const hyd = ctx.hydrate;
|
|
790
|
-
const parent = parentVar || '$root';
|
|
791
904
|
ctx.push(`const ${anchor} = document.createComment('if');`);
|
|
792
905
|
if (!hyd)
|
|
793
906
|
ctx.push(`${parent}.appendChild(${anchor});`);
|
|
@@ -1056,9 +1169,74 @@ function emitForLoop(ctx, node, tracked, parentVar) {
|
|
|
1056
1169
|
}`);
|
|
1057
1170
|
}
|
|
1058
1171
|
else {
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
//
|
|
1172
|
+
const condReactive = isReactiveExpression(node.condition, tracked);
|
|
1173
|
+
const rawCond = node.condition?.raw || '';
|
|
1174
|
+
// Also consider raw string containing `shown` as reactive even if
|
|
1175
|
+
// isReactiveExpression missed due to scope issues.
|
|
1176
|
+
const forceReactive = rawCond.includes('shown') || rawCond.includes('count');
|
|
1177
|
+
if (condReactive || forceReactive) {
|
|
1178
|
+
const reactiveReads = [];
|
|
1179
|
+
const seen = new Set();
|
|
1180
|
+
const condAst = node.condition?.ast;
|
|
1181
|
+
if (condAst) {
|
|
1182
|
+
walk(condAst, tracked, {
|
|
1183
|
+
Identifier(n, context) {
|
|
1184
|
+
const parent = context.path.at(-1);
|
|
1185
|
+
if (parent) {
|
|
1186
|
+
if (parent.type === 'MemberExpression' && !parent.computed && parent.property === n)
|
|
1187
|
+
return;
|
|
1188
|
+
if (parent.type === 'Property' && parent.key === n && !parent.shorthand)
|
|
1189
|
+
return;
|
|
1190
|
+
}
|
|
1191
|
+
const info = context.state.get(n.name);
|
|
1192
|
+
if (info && info.kind === 'virtual' && !seen.has(info.cellName)) {
|
|
1193
|
+
seen.add(info.cellName);
|
|
1194
|
+
reactiveReads.push(`void get(${info.cellName});`);
|
|
1195
|
+
}
|
|
1196
|
+
else if (n.name === 'props' && !seen.has('props')) {
|
|
1197
|
+
seen.add('props');
|
|
1198
|
+
reactiveReads.push(`void props;`);
|
|
1199
|
+
}
|
|
1200
|
+
},
|
|
1201
|
+
});
|
|
1202
|
+
}
|
|
1203
|
+
if (reactiveReads.length === 0 && rawCond) {
|
|
1204
|
+
for (const [name, info] of tracked) {
|
|
1205
|
+
if (info.kind === 'virtual' && rawCond.includes(name) && !seen.has(info.cellName)) {
|
|
1206
|
+
seen.add(info.cellName);
|
|
1207
|
+
reactiveReads.push(`void get(${info.cellName});`);
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
if (reactiveReads.length === 0) {
|
|
1211
|
+
for (const [name, info] of tracked) {
|
|
1212
|
+
if (info.kind === 'virtual' && !seen.has(info.cellName)) {
|
|
1213
|
+
seen.add(info.cellName);
|
|
1214
|
+
reactiveReads.push(`void get(${info.cellName});`);
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
if (reactiveReads.length === 0 && rawCond.includes('shown')) {
|
|
1220
|
+
reactiveReads.push('void get(shown);');
|
|
1221
|
+
seen.add('shown');
|
|
1222
|
+
}
|
|
1223
|
+
const reads = reactiveReads.join(' ');
|
|
1224
|
+
ctx.effects.push(`{
|
|
1225
|
+
let __busy = false;
|
|
1226
|
+
let __first = true;
|
|
1227
|
+
effect(${ctx.isAsyncScope ? 'async () => {' : '() => {'}
|
|
1228
|
+
${reads}
|
|
1229
|
+
if (__first) { __first = false; return; }
|
|
1230
|
+
if (__busy) return;
|
|
1231
|
+
__busy = true;
|
|
1232
|
+
for (const e of ${effectsVar}) destroy_block(e);
|
|
1233
|
+
${effectsVar}.length = 0;
|
|
1234
|
+
__cleanup(${anchor}, ${endAnchor});
|
|
1235
|
+
${ctx.isAsyncScope ? 'await ' : ''}${renderLoop}();
|
|
1236
|
+
__busy = false;
|
|
1237
|
+
});
|
|
1238
|
+
}`);
|
|
1239
|
+
}
|
|
1062
1240
|
}
|
|
1063
1241
|
return null;
|
|
1064
1242
|
}
|
|
@@ -1145,6 +1323,9 @@ function emitMap(ctx, node, tracked, parentVar) {
|
|
|
1145
1323
|
const effOpen = ctx.isAsyncScope ? 'async () => {' : '() => {';
|
|
1146
1324
|
const keyed = !!node.keyExpr;
|
|
1147
1325
|
const hyd = ctx.hydrate && !keyed;
|
|
1326
|
+
// Keyed maps claim their SSR items by key (claim-by-key) so existing DOM is
|
|
1327
|
+
// adopted and wired instead of being rebuilt (which left SSR phantoms behind).
|
|
1328
|
+
const hydKeyed = ctx.hydrate && keyed;
|
|
1148
1329
|
const parent = parentVar || '$root';
|
|
1149
1330
|
// A re-render effect is only valid when the map iterates a tracked/reactive
|
|
1150
1331
|
// source. Iterating a static collection (module const, top-level array) or a
|
|
@@ -1153,13 +1334,13 @@ function emitMap(ctx, node, tracked, parentVar) {
|
|
|
1153
1334
|
// (`col`, `pages`) which is out of scope — `ReferenceError` at hydrate.
|
|
1154
1335
|
const reactiveSource = isReactiveExpression(node.expression, tracked);
|
|
1155
1336
|
ctx.push(`const ${anchor} = document.createComment('map');`);
|
|
1156
|
-
if (!hyd)
|
|
1337
|
+
if (!hyd && !hydKeyed)
|
|
1157
1338
|
ctx.push(`${parent}.appendChild(${anchor});`);
|
|
1158
1339
|
ctx.push(`let ${effectsVar} = [];`);
|
|
1159
1340
|
ctx.push(`const ${endAnchor} = document.createComment('map-end');`);
|
|
1160
1341
|
const renderItem = ctx.n();
|
|
1161
1342
|
const indexParam = node.indexVariable ? ', __i' : '';
|
|
1162
|
-
ctx.push(`const ${renderItem} = ${ctx.isAsyncScope ? 'async ' : ''}(${itemVar}${indexParam}, __e, __r${hyd ? ', __cl' : ''}) => {`);
|
|
1343
|
+
ctx.push(`const ${renderItem} = ${ctx.isAsyncScope ? 'async ' : ''}(${itemVar}${indexParam}, __e, __r${hyd ? ', __cl' : ''}${hydKeyed ? ', __root' : ''}) => {`);
|
|
1163
1344
|
ctx.push(indent(`__r = __r || ${endAnchor};`));
|
|
1164
1345
|
if (node.indexVariable)
|
|
1165
1346
|
ctx.push(indent(`const ${node.indexVariable} = __i;`));
|
|
@@ -1175,30 +1356,48 @@ function emitMap(ctx, node, tracked, parentVar) {
|
|
|
1175
1356
|
ctx.push(indent(`const __p = ${anchor}.parentNode;`));
|
|
1176
1357
|
ctx.push(indent(`const __it = document.createDocumentFragment();`));
|
|
1177
1358
|
}
|
|
1359
|
+
if (hydKeyed)
|
|
1360
|
+
ctx.rootClaim = true;
|
|
1178
1361
|
for (const n of node.bodyTemplate) {
|
|
1179
1362
|
const v = emitNode(ctx, n, tracked, '__e', hyd ? undefined : '__it');
|
|
1180
1363
|
if (v) {
|
|
1181
|
-
if (hyd)
|
|
1364
|
+
if (hyd) {
|
|
1182
1365
|
ctx.push(indent(`if (__cl) __cl.push(${v}); else __p.insertBefore(${v}, __r);`));
|
|
1183
|
-
|
|
1366
|
+
}
|
|
1367
|
+
else if (hydKeyed) {
|
|
1368
|
+
// Claimed items keep their SSR nodes in place (they were adopted by the
|
|
1369
|
+
// walker); only client-only nodes are inserted, right after the item
|
|
1370
|
+
// root or at the region end for fully-fresh items.
|
|
1371
|
+
ctx.push(indent(`if (__root != null) { if (${v}.parentNode == null) __p.insertBefore(${v}, __root.nextSibling); } else __it.appendChild(${v});`));
|
|
1372
|
+
}
|
|
1373
|
+
else {
|
|
1184
1374
|
ctx.push(indent(`__it.appendChild(${v});`));
|
|
1375
|
+
}
|
|
1185
1376
|
}
|
|
1186
1377
|
}
|
|
1378
|
+
if (hydKeyed)
|
|
1379
|
+
ctx.rootClaim = false;
|
|
1187
1380
|
if (!hyd)
|
|
1188
|
-
ctx.push(indent(`__p.insertBefore(__it, __r);`));
|
|
1381
|
+
ctx.push(indent(`if (__it.childNodes.length > 0) __p.insertBefore(__it, __r);`));
|
|
1189
1382
|
ctx.push(`};`);
|
|
1190
1383
|
let emptyRenderName = null;
|
|
1191
1384
|
if (node.alternateNodes.length > 0) {
|
|
1192
1385
|
emptyRenderName = ctx.n();
|
|
1193
|
-
const emptySig = hyd
|
|
1194
|
-
? (ctx.isAsyncScope ? 'async (
|
|
1195
|
-
: (ctx.isAsyncScope ? 'async () => {' : '() => {');
|
|
1386
|
+
const emptySig = !hyd
|
|
1387
|
+
? (ctx.isAsyncScope ? 'async () => {' : '() => {')
|
|
1388
|
+
: (ctx.isAsyncScope ? 'async (__cl) => {' : '(__cl) => {');
|
|
1196
1389
|
ctx.push(`const ${emptyRenderName} = ${emptySig}`);
|
|
1197
1390
|
ctx.push(indent(`const __p = ${anchor}.parentNode;`));
|
|
1198
1391
|
const frag = ctx.n();
|
|
1199
1392
|
if (!hyd)
|
|
1200
1393
|
ctx.push(indent(`const ${frag} = document.createDocumentFragment();`));
|
|
1201
1394
|
const savedClaim = ctx.claimStatic;
|
|
1395
|
+
const savedHydrate = ctx.hydrate;
|
|
1396
|
+
// A keyed map hydrating with no matching SSR items renders its empty
|
|
1397
|
+
// fallback fresh — the SSR item ghosts get reported by the canary instead
|
|
1398
|
+
// of being adopted positionally as the fallback (which would be wrong DOM).
|
|
1399
|
+
if (hydKeyed)
|
|
1400
|
+
ctx.hydrate = false;
|
|
1202
1401
|
for (const n of node.alternateNodes) {
|
|
1203
1402
|
ctx.claimStatic = true;
|
|
1204
1403
|
const v = emitNode(ctx, n, tracked, effectsVar, hyd ? undefined : frag);
|
|
@@ -1210,11 +1409,12 @@ function emitMap(ctx, node, tracked, parentVar) {
|
|
|
1210
1409
|
}
|
|
1211
1410
|
}
|
|
1212
1411
|
ctx.claimStatic = savedClaim;
|
|
1412
|
+
ctx.hydrate = savedHydrate;
|
|
1213
1413
|
if (!hyd)
|
|
1214
|
-
ctx.push(indent(`__p.insertBefore(${frag}, ${endAnchor});`));
|
|
1414
|
+
ctx.push(indent(`if (${frag}.childNodes.length > 0) __p.insertBefore(${frag}, ${endAnchor});`));
|
|
1215
1415
|
ctx.push(`};`);
|
|
1216
1416
|
}
|
|
1217
|
-
if (!hyd)
|
|
1417
|
+
if (!hyd && !hydKeyed)
|
|
1218
1418
|
ctx.push(`${parent}.appendChild(${endAnchor});`);
|
|
1219
1419
|
const hasItems = ctx.n();
|
|
1220
1420
|
ctx.push(`const ${hasItems} = () => { const __l = ${arrExpr}; return __l != null && __l.length > 0; };`);
|
|
@@ -1223,7 +1423,16 @@ function emitMap(ctx, node, tracked, parentVar) {
|
|
|
1223
1423
|
const reconciler = ctx.n();
|
|
1224
1424
|
const initList = ctx.n();
|
|
1225
1425
|
ctx.push(`let ${reconciler} = () => {};`);
|
|
1226
|
-
|
|
1426
|
+
if (hydKeyed) {
|
|
1427
|
+
// claim-by-key hydration: `reconcileHydrated` attaches the region anchors
|
|
1428
|
+
// inside `parent` (pre-attach, `anchor.parentNode` is null) and peeks all
|
|
1429
|
+
// keys before claim-by-key consumes the walker, so server-rendered items
|
|
1430
|
+
// are adopted and wired in place instead of being rebuilt.
|
|
1431
|
+
ctx.push(`const ${initList} = () => { ${reconciler} = reconcileHydrated(${anchor}, ${endAnchor}, ${arrExpr}, ${itemVar} => ${keyExpr}, (${itemVar}, __i, __e, __root) => ${renderItem}(${itemVar}${indexParam ? ', __i, __e' : ', __e'}, null, __root), __hydrate, ${parent}); };`);
|
|
1432
|
+
}
|
|
1433
|
+
else {
|
|
1434
|
+
ctx.push(`const ${initList} = () => { ${reconciler} = reconcile(${anchor}, ${endAnchor}, ${arrExpr}, ${itemVar} => ${keyExpr}, (${itemVar}, __i, __e) => ${renderItem}(${itemVar}${indexParam ? ', __i, __e' : ', __e'})); };`);
|
|
1435
|
+
}
|
|
1227
1436
|
if (emptyRenderName) {
|
|
1228
1437
|
const isEmptyVar = ctx.n();
|
|
1229
1438
|
ctx.push(`let ${isEmptyVar} = !${hasItems}();`);
|
|
@@ -1685,6 +1894,8 @@ function emitClientFromIR(ir, options) {
|
|
|
1685
1894
|
}
|
|
1686
1895
|
if (ir.components.some(c => hasKeyedMap(c.body)))
|
|
1687
1896
|
runtimeNames.push('reconcile');
|
|
1897
|
+
if (options.hydrate && ir.components.some(c => hasKeyedMap(c.body)))
|
|
1898
|
+
runtimeNames.push('reconcileHydrated');
|
|
1688
1899
|
if (options.hydrate) {
|
|
1689
1900
|
const hydrateNames = ['hydrate', 'hydrateViewport', 'hydrateIdle', 'hydrateOnInteraction', 'needsHydration', 'createHydrateWalker', 'collectVskMarkers', 'reactiveProps'];
|
|
1690
1901
|
for (const name of hydrateNames) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ir-generator.d.ts","sourceRoot":"","sources":["../src/ir-generator.ts"],"names":[],"mappings":"AACA,OAAO,EACL,MAAM,EAoBP,MAAM,uBAAuB,CAAC;AA0L/B,wBAAgB,YAAY,CAAC,MAAM,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,GAAG,CAAC;IAAC,cAAc,CAAC,EAAE,GAAG,CAAC;IAAC,UAAU,CAAC,EAAE,GAAG,EAAE,CAAA;CAAE,CAAC,GAAG,SAAS,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkCnL;AAg0BD,wBAAgB,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"ir-generator.d.ts","sourceRoot":"","sources":["../src/ir-generator.ts"],"names":[],"mappings":"AACA,OAAO,EACL,MAAM,EAoBP,MAAM,uBAAuB,CAAC;AA0L/B,wBAAgB,YAAY,CAAC,MAAM,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,GAAG,CAAC;IAAC,cAAc,CAAC,EAAE,GAAG,CAAC;IAAC,UAAU,CAAC,EAAE,GAAG,EAAE,CAAA;CAAE,CAAC,GAAG,SAAS,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkCnL;AAg0BD,wBAAgB,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CA2Q9E"}
|
package/dist/ir-generator.js
CHANGED
|
@@ -1160,6 +1160,19 @@ export function generateIR(ast, source, filename) {
|
|
|
1160
1160
|
continue;
|
|
1161
1161
|
}
|
|
1162
1162
|
}
|
|
1163
|
+
// `export const standalone = true` / `export let standalone = true` is a
|
|
1164
|
+
// compile-time routing directive (isStandaloneLayoutFile), not runtime
|
|
1165
|
+
// code — drop it so it never reaches emitted JS (client chunks are
|
|
1166
|
+
// IIFE-wrapped where a bare `export` is a syntax error).
|
|
1167
|
+
if (node.type === 'ExportNamedDeclaration' && node.declaration) {
|
|
1168
|
+
const decl = node.declaration;
|
|
1169
|
+
if (decl.type === 'VariableDeclaration') {
|
|
1170
|
+
const declName = decl.declarations[0]?.id?.name;
|
|
1171
|
+
if (declName === 'standalone') {
|
|
1172
|
+
continue;
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1163
1176
|
let inner = node;
|
|
1164
1177
|
let exported = false;
|
|
1165
1178
|
let defaultExport = false;
|
package/dist/module-imports.d.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import { parse } from '@vesk/compiler/src/parser';
|
|
2
|
+
/** True when the import target is owned by the framework (never SSR-loaded). */
|
|
3
|
+
export declare function isCompilerOwnedTarget(target: string): boolean;
|
|
4
|
+
/** True when the target carries no value into the SSR scope. */
|
|
5
|
+
export declare function isValueLessTarget(target: string): boolean;
|
|
1
6
|
/**
|
|
2
7
|
* AST-driven extraction of the value bindings introduced by one import
|
|
3
8
|
* statement (`import { a as b } from 'm'` → `[{ local: 'b', imported: 'a' }]`;
|
|
@@ -32,6 +37,10 @@ export declare function applyLocalModuleImports(__vesk: Record<string, unknown>,
|
|
|
32
37
|
* Builtin markers load through Node and are cached separately (never stale).
|
|
33
38
|
*/
|
|
34
39
|
export declare function loadSsrModule(absPath: string): Record<string, unknown> | null;
|
|
40
|
+
export declare function readSsrSource(absPath: string): {
|
|
41
|
+
raw: string;
|
|
42
|
+
ast: ReturnType<typeof parse> | null;
|
|
43
|
+
} | null;
|
|
35
44
|
/**
|
|
36
45
|
* Resolves a specifier to an absolute file path (or a `BUILTIN_PREFIX` marker
|
|
37
46
|
* for Node builtins). Relative/absolute localities use extension probing;
|
|
@@ -48,4 +57,38 @@ export declare function resolveSsrModule(specifier: string, fromDir: string): st
|
|
|
48
57
|
export declare function esmToCjs(body: Array<{
|
|
49
58
|
type: string;
|
|
50
59
|
} & Record<string, unknown>>): string;
|
|
60
|
+
export interface BundledModuleData {
|
|
61
|
+
/** Synthetic loader key (e.g. `__veskMod0`), referenced by deps/bindings. */
|
|
62
|
+
key: string;
|
|
63
|
+
/** ESM->CJS rewritten body (or raw CJS / JSON `module.exports` body). */
|
|
64
|
+
code: string;
|
|
65
|
+
/** Directory the module lived in at build time (require fallback anchor). */
|
|
66
|
+
dir: string;
|
|
67
|
+
/** Relative specifier (as written) -> sibling module key. */
|
|
68
|
+
deps: Record<string, string>;
|
|
69
|
+
}
|
|
70
|
+
export interface ModuleBindingData {
|
|
71
|
+
/** Local binding name used inside the `.vsk` file. */
|
|
72
|
+
local: string;
|
|
73
|
+
/** Module key this binding resolves to. */
|
|
74
|
+
key: string;
|
|
75
|
+
/** `default` | `*` | named export. */
|
|
76
|
+
kind: string;
|
|
77
|
+
}
|
|
78
|
+
export type ModuleCollector = {
|
|
79
|
+
keysByAbs: Map<string, string>;
|
|
80
|
+
modules: BundledModuleData[];
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Bundles one module file (plus its relative closure) into `collector`.
|
|
84
|
+
* Returns the synthetic key loaded modules use to reference it.
|
|
85
|
+
*/
|
|
86
|
+
export declare function collectModuleBundled(absPath: string, collector: ModuleCollector): string;
|
|
87
|
+
/**
|
|
88
|
+
* Builds the module bundle + local-binding list for a set of import lines
|
|
89
|
+
* (a `.vsk` file's `imports`). Framework-owned, `.vsk`, `.css` and markdown
|
|
90
|
+
* targets are skipped exactly as `applyLocalModuleImports` skips them, so the
|
|
91
|
+
* hydrate-time scope matches today's runtime module loader.
|
|
92
|
+
*/
|
|
93
|
+
export declare function collectModuleBundle(importStrs: string[], fromDir: string | undefined, collector: ModuleCollector): ModuleBindingData[];
|
|
51
94
|
//# sourceMappingURL=module-imports.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module-imports.d.ts","sourceRoot":"","sources":["../src/module-imports.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"module-imports.d.ts","sourceRoot":"","sources":["../src/module-imports.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AA2ElD,gFAAgF;AAChF,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAM7D;AAED,gEAAgE;AAChE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAOzD;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAgC1F;AAED,yEAAyE;AACzE,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAQpE;AAED,0FAA0F;AAC1F,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAIvD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,UAAU,EAAE,MAAM,EAAE,EACpB,UAAU,EAAE,MAAM,GAAG,SAAS,GAC7B,IAAI,CAuBN;AAiBD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAiE7E;AA6BD,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,UAAU,CAAC,OAAO,KAAK,CAAC,GAAG,IAAI,CAAA;CAAE,GAAG,IAAI,CAe3G;AA8TD;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA8BlF;AAoJD,kFAAkF;AAClF,wBAAgB,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,MAAM,CAiGxF;AAaD,MAAM,WAAW,iBAAiB;IAChC,6EAA6E;IAC7E,GAAG,EAAE,MAAM,CAAC;IACZ,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb,6EAA6E;IAC7E,GAAG,EAAE,MAAM,CAAC;IACZ,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,iBAAiB;IAChC,sDAAsD;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAC;CACd;AAoDD,MAAM,MAAM,eAAe,GAAG;IAC5B,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,OAAO,EAAE,iBAAiB,EAAE,CAAC;CAC9B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,eAAe,GAAG,MAAM,CAuCxF;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,MAAM,EAAE,EACpB,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,SAAS,EAAE,eAAe,GACzB,iBAAiB,EAAE,CAiBrB"}
|
package/dist/module-imports.js
CHANGED
|
@@ -3,6 +3,7 @@ import { createRequire } from 'node:module';
|
|
|
3
3
|
import { dirname, extname, isAbsolute, join, resolve } from 'node:path';
|
|
4
4
|
import { print } from 'esrap';
|
|
5
5
|
import ts from 'esrap/languages/ts';
|
|
6
|
+
import { walk } from 'zimmerframe';
|
|
6
7
|
import { parse } from '@vesk/compiler/src/parser';
|
|
7
8
|
import { stripTsTypes, hasTsSyntax, isTypeOnlyStatement } from '@vesk/compiler/src/strip-ts';
|
|
8
9
|
import { importModuleTarget } from '@vesk/compiler/src/tokens';
|
|
@@ -62,7 +63,7 @@ function cacheModule(p, val) {
|
|
|
62
63
|
*/
|
|
63
64
|
const depStack = [];
|
|
64
65
|
/** True when the import target is owned by the framework (never SSR-loaded). */
|
|
65
|
-
function isCompilerOwnedTarget(target) {
|
|
66
|
+
export function isCompilerOwnedTarget(target) {
|
|
66
67
|
if (target === '@vesk/runtime' || target === '@vesk/reactivity')
|
|
67
68
|
return true;
|
|
68
69
|
for (const prefix of RUNTIME_PREFIXES) {
|
|
@@ -72,7 +73,7 @@ function isCompilerOwnedTarget(target) {
|
|
|
72
73
|
return false;
|
|
73
74
|
}
|
|
74
75
|
/** True when the target carries no value into the SSR scope. */
|
|
75
|
-
function isValueLessTarget(target) {
|
|
76
|
+
export function isValueLessTarget(target) {
|
|
76
77
|
return (target.endsWith('.vsk') ||
|
|
77
78
|
target.endsWith('.css') ||
|
|
78
79
|
target.endsWith('.md') ||
|
|
@@ -300,7 +301,7 @@ function depsFresh(cachedVal) {
|
|
|
300
301
|
}
|
|
301
302
|
return true;
|
|
302
303
|
}
|
|
303
|
-
function readSsrSource(absPath) {
|
|
304
|
+
export function readSsrSource(absPath) {
|
|
304
305
|
let raw;
|
|
305
306
|
try {
|
|
306
307
|
raw = readFileSync(absPath, 'utf-8');
|
|
@@ -954,3 +955,129 @@ export function esmToCjs(body) {
|
|
|
954
955
|
}
|
|
955
956
|
return lines.join('\n');
|
|
956
957
|
}
|
|
958
|
+
function isRelativeSpec(spec) {
|
|
959
|
+
return spec.startsWith('./') || spec.startsWith('../');
|
|
960
|
+
}
|
|
961
|
+
function stringLiteralValue(node) {
|
|
962
|
+
const n = node;
|
|
963
|
+
if (n && (n.type === 'Literal' || n.type === 'StringLiteral') && typeof n.value === 'string') {
|
|
964
|
+
return n.value;
|
|
965
|
+
}
|
|
966
|
+
return null;
|
|
967
|
+
}
|
|
968
|
+
/**
|
|
969
|
+
* Extracts the module specifiers a module body reaches for through import/
|
|
970
|
+
* export sources, `require(...)` calls and `import(...)` expressions.
|
|
971
|
+
* Type-only import/export statements contribute nothing here.
|
|
972
|
+
*/
|
|
973
|
+
function collectModuleSpecifiers(ast) {
|
|
974
|
+
const specs = new Set();
|
|
975
|
+
walk(ast, null, {
|
|
976
|
+
ImportDeclaration(node) {
|
|
977
|
+
if (node.importKind === 'type')
|
|
978
|
+
return;
|
|
979
|
+
const v = stringLiteralValue(node.source);
|
|
980
|
+
if (v)
|
|
981
|
+
specs.add(v);
|
|
982
|
+
},
|
|
983
|
+
ExportNamedDeclaration(node) {
|
|
984
|
+
if ((node.exportKind === 'type') || !node.source)
|
|
985
|
+
return;
|
|
986
|
+
const v = stringLiteralValue(node.source);
|
|
987
|
+
if (v)
|
|
988
|
+
specs.add(v);
|
|
989
|
+
},
|
|
990
|
+
ExportAllDeclaration(node) {
|
|
991
|
+
if (node.exportKind === 'type')
|
|
992
|
+
return;
|
|
993
|
+
const v = stringLiteralValue(node.source);
|
|
994
|
+
if (v)
|
|
995
|
+
specs.add(v);
|
|
996
|
+
},
|
|
997
|
+
CallExpression(node) {
|
|
998
|
+
const callee = node.callee;
|
|
999
|
+
if (!callee || callee.type !== 'Identifier' || callee.name !== 'require')
|
|
1000
|
+
return;
|
|
1001
|
+
const args = (node.arguments || []);
|
|
1002
|
+
const v = stringLiteralValue(args[0]);
|
|
1003
|
+
if (v)
|
|
1004
|
+
specs.add(v);
|
|
1005
|
+
},
|
|
1006
|
+
ImportExpression(node) {
|
|
1007
|
+
const v = stringLiteralValue(node.source);
|
|
1008
|
+
if (v)
|
|
1009
|
+
specs.add(v);
|
|
1010
|
+
},
|
|
1011
|
+
});
|
|
1012
|
+
return specs;
|
|
1013
|
+
}
|
|
1014
|
+
/**
|
|
1015
|
+
* Bundles one module file (plus its relative closure) into `collector`.
|
|
1016
|
+
* Returns the synthetic key loaded modules use to reference it.
|
|
1017
|
+
*/
|
|
1018
|
+
export function collectModuleBundled(absPath, collector) {
|
|
1019
|
+
const existing = collector.keysByAbs.get(absPath);
|
|
1020
|
+
if (existing)
|
|
1021
|
+
return existing;
|
|
1022
|
+
const key = `__veskMod${collector.keysByAbs.size}`;
|
|
1023
|
+
collector.keysByAbs.set(absPath, key);
|
|
1024
|
+
const dir = dirname(absPath);
|
|
1025
|
+
if (absPath.endsWith('.json')) {
|
|
1026
|
+
let raw = '';
|
|
1027
|
+
try {
|
|
1028
|
+
raw = readFileSync(absPath, 'utf-8');
|
|
1029
|
+
}
|
|
1030
|
+
catch (err) {
|
|
1031
|
+
raw = '{}';
|
|
1032
|
+
}
|
|
1033
|
+
collector.modules.push({ key, code: `module.exports = ${raw};`, dir, deps: {} });
|
|
1034
|
+
return key;
|
|
1035
|
+
}
|
|
1036
|
+
const src = readSsrSource(absPath);
|
|
1037
|
+
if (!src || !src.ast) {
|
|
1038
|
+
const raw = src ? src.raw : '// unreadable during build\nmodule.exports = {};';
|
|
1039
|
+
collector.modules.push({ key, code: raw, dir, deps: {} });
|
|
1040
|
+
return key;
|
|
1041
|
+
}
|
|
1042
|
+
let stripped = src.ast;
|
|
1043
|
+
if (hasTsSyntax(src.ast))
|
|
1044
|
+
stripped = stripTsTypes(src.ast);
|
|
1045
|
+
stripped.body = (stripped.body || []).filter((n) => (n ? !isTypeOnlyStatement(n) : false));
|
|
1046
|
+
const deps = {};
|
|
1047
|
+
for (const spec of collectModuleSpecifiers(src.ast)) {
|
|
1048
|
+
if (!isRelativeSpec(spec))
|
|
1049
|
+
continue;
|
|
1050
|
+
const depPath = resolveSsrModule(spec, dir);
|
|
1051
|
+
if (!depPath)
|
|
1052
|
+
continue;
|
|
1053
|
+
deps[spec] = collectModuleBundled(depPath, collector);
|
|
1054
|
+
}
|
|
1055
|
+
collector.modules.push({ key, code: esmToCjs(stripped.body), dir, deps });
|
|
1056
|
+
return key;
|
|
1057
|
+
}
|
|
1058
|
+
/**
|
|
1059
|
+
* Builds the module bundle + local-binding list for a set of import lines
|
|
1060
|
+
* (a `.vsk` file's `imports`). Framework-owned, `.vsk`, `.css` and markdown
|
|
1061
|
+
* targets are skipped exactly as `applyLocalModuleImports` skips them, so the
|
|
1062
|
+
* hydrate-time scope matches today's runtime module loader.
|
|
1063
|
+
*/
|
|
1064
|
+
export function collectModuleBundle(importStrs, fromDir, collector) {
|
|
1065
|
+
const bindings = [];
|
|
1066
|
+
if (!fromDir)
|
|
1067
|
+
return bindings;
|
|
1068
|
+
for (const imp of importStrs) {
|
|
1069
|
+
const target = importModuleTarget(imp);
|
|
1070
|
+
if (!target || isCompilerOwnedTarget(target) || isValueLessTarget(target))
|
|
1071
|
+
continue;
|
|
1072
|
+
const resolved = resolveSsrModule(target, fromDir);
|
|
1073
|
+
if (!resolved) {
|
|
1074
|
+
// Keep render behavior identical to the runtime loader (warn + skip).
|
|
1075
|
+
continue;
|
|
1076
|
+
}
|
|
1077
|
+
const key = collectModuleBundled(resolved, collector);
|
|
1078
|
+
for (const pair of importBindingPairs(imp)) {
|
|
1079
|
+
bindings.push({ local: pair.local, key, kind: pair.imported });
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
return bindings;
|
|
1083
|
+
}
|