@vesk/compiler 0.2.22 → 0.2.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client-codegen.d.ts.map +1 -1
- package/dist/client-codegen.js +247 -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 +84 -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;AAw2CD,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,120 @@ 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 savedClaim = ctx.claimStatic;
|
|
832
|
+
if (hyd)
|
|
833
|
+
ctx.claimStatic = true;
|
|
834
|
+
const v = emitNode(ctx, n, tracked, effectsVar, parentVar);
|
|
835
|
+
ctx.claimStatic = savedClaim;
|
|
836
|
+
if (v)
|
|
837
|
+
ctx.push(indent(`${cl}.push(${v});`));
|
|
838
|
+
}
|
|
839
|
+
ctx.push(indent(`__place(${anchor}, ${endAnchor}, ${cl}, ${parent});`));
|
|
840
|
+
ctx.push(`};`);
|
|
841
|
+
}
|
|
842
|
+
let finalRender = null;
|
|
843
|
+
if (finalElse) {
|
|
844
|
+
finalRender = ctx.n();
|
|
845
|
+
ctx.push(`const ${finalRender} = ${fnOpen}`);
|
|
846
|
+
const cl2 = ctx.n();
|
|
847
|
+
ctx.push(indent(`const ${cl2} = [];`));
|
|
848
|
+
for (const n of finalElse) {
|
|
849
|
+
const savedClaim = ctx.claimStatic;
|
|
850
|
+
if (hyd)
|
|
851
|
+
ctx.claimStatic = true;
|
|
852
|
+
const v = emitNode(ctx, n, tracked, effectsVar, parentVar);
|
|
853
|
+
ctx.claimStatic = savedClaim;
|
|
854
|
+
if (v)
|
|
855
|
+
ctx.push(indent(`${cl2}.push(${v});`));
|
|
856
|
+
}
|
|
857
|
+
ctx.push(indent(`__place(${anchor}, ${endAnchor}, ${cl2}, ${parent});`));
|
|
858
|
+
ctx.push(`};`);
|
|
859
|
+
}
|
|
860
|
+
let init = `if (${chain[0].cond}) { ${asyncKw}${renderNames[0]}(); }`;
|
|
861
|
+
for (let i = 1; i < chain.length; i++)
|
|
862
|
+
init += ` else if (${chain[i].cond}) { ${asyncKw}${renderNames[i]}(); }`;
|
|
863
|
+
if (finalRender)
|
|
864
|
+
init += ` else { ${asyncKw}${finalRender}(); }`;
|
|
865
|
+
ctx.push(init);
|
|
866
|
+
// Resolve which branch index the chain is in, for any chain depth. The last
|
|
867
|
+
// fallback is `chain.length` when a final `else` exists, otherwise -1 (no
|
|
868
|
+
// branch renders). Build the nested ternary from the innermost condition
|
|
869
|
+
// outwards so every else-if participates.
|
|
870
|
+
let branchInitFallback = finalRender ? `${chain.length}` : '-1';
|
|
871
|
+
for (let i = chain.length - 1; i >= 0; i--) {
|
|
872
|
+
branchInitFallback = `(${chain[i].cond} ? ${i} : ${branchInitFallback})`;
|
|
873
|
+
}
|
|
874
|
+
const branchInit = `(${branchInitFallback})`;
|
|
875
|
+
let effInner = `if (__new === 0) { ${asyncKw}${renderNames[0]}(); }`;
|
|
876
|
+
for (let i = 1; i < chain.length; i++)
|
|
877
|
+
effInner += ` else if (__new === ${i}) { ${asyncKw}${renderNames[i]}(); }`;
|
|
878
|
+
if (finalRender)
|
|
879
|
+
effInner += ` else { ${asyncKw}${finalRender}(); }`;
|
|
880
|
+
const effBody = `effect(${ctx.isAsyncScope ? 'async () => {' : '() => {'}
|
|
881
|
+
if (__first) { __first = false; __iv = ${branchInit}; return; }
|
|
882
|
+
const __new = ${branchInit};
|
|
883
|
+
if (__new !== __iv) {
|
|
884
|
+
for (const e of ${effectsVar}) destroy_block(e);
|
|
885
|
+
${effectsVar}.length = 0;
|
|
886
|
+
__cleanup(${anchor}, ${endAnchor});
|
|
887
|
+
${effInner}
|
|
888
|
+
__iv = __new;
|
|
889
|
+
}
|
|
890
|
+
});`;
|
|
891
|
+
if (effTarget) {
|
|
892
|
+
ctx.push(`${effTarget}.push((() => {
|
|
893
|
+
let __iv = ${branchInit};
|
|
894
|
+
let __first = true;
|
|
895
|
+
return ${effBody}
|
|
896
|
+
})());`);
|
|
897
|
+
}
|
|
898
|
+
else {
|
|
899
|
+
ctx.effects.push(`{
|
|
900
|
+
let __iv = ${branchInit};
|
|
901
|
+
let __first = true;
|
|
902
|
+
${effBody}
|
|
903
|
+
}`);
|
|
904
|
+
}
|
|
905
|
+
return null;
|
|
906
|
+
}
|
|
784
907
|
const condExpr = transformTracked(node.condition, tracked);
|
|
785
908
|
const hasElse = node.alternateNodes.length > 0;
|
|
786
909
|
const anchor = ctx.n();
|
|
787
910
|
const endAnchor = ctx.n();
|
|
788
911
|
const effectsVar = ctx.n();
|
|
789
|
-
const hyd = ctx.hydrate;
|
|
790
|
-
const parent = parentVar || '$root';
|
|
791
912
|
ctx.push(`const ${anchor} = document.createComment('if');`);
|
|
792
913
|
if (!hyd)
|
|
793
914
|
ctx.push(`${parent}.appendChild(${anchor});`);
|
|
@@ -805,7 +926,11 @@ function emitOpaque(ctx, node, tracked, effTarget, parentVar) {
|
|
|
805
926
|
if (hyd)
|
|
806
927
|
ctx.push(indent(`const __cl = [];`));
|
|
807
928
|
for (const n of node.consequentNodes) {
|
|
929
|
+
const savedClaim = ctx.claimStatic;
|
|
930
|
+
if (hyd)
|
|
931
|
+
ctx.claimStatic = true;
|
|
808
932
|
const v = emitNode(ctx, n, tracked, effectsVar, hyd ? parentVar : conFrag);
|
|
933
|
+
ctx.claimStatic = savedClaim;
|
|
809
934
|
if (v) {
|
|
810
935
|
if (hyd)
|
|
811
936
|
ctx.push(indent(`__cl.push(${v});`));
|
|
@@ -830,7 +955,11 @@ function emitOpaque(ctx, node, tracked, effTarget, parentVar) {
|
|
|
830
955
|
if (hyd)
|
|
831
956
|
ctx.push(indent(`const __cl = [];`));
|
|
832
957
|
for (const n of node.alternateNodes) {
|
|
958
|
+
const savedAltClaim = ctx.claimStatic;
|
|
959
|
+
if (hyd)
|
|
960
|
+
ctx.claimStatic = true;
|
|
833
961
|
const v = emitNode(ctx, n, tracked, effectsVar, hyd ? parentVar : altFrag);
|
|
962
|
+
ctx.claimStatic = savedAltClaim;
|
|
834
963
|
if (v) {
|
|
835
964
|
if (hyd)
|
|
836
965
|
ctx.push(indent(`__cl.push(${v});`));
|
|
@@ -1056,9 +1185,74 @@ function emitForLoop(ctx, node, tracked, parentVar) {
|
|
|
1056
1185
|
}`);
|
|
1057
1186
|
}
|
|
1058
1187
|
else {
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
//
|
|
1188
|
+
const condReactive = isReactiveExpression(node.condition, tracked);
|
|
1189
|
+
const rawCond = node.condition?.raw || '';
|
|
1190
|
+
// Also consider raw string containing `shown` as reactive even if
|
|
1191
|
+
// isReactiveExpression missed due to scope issues.
|
|
1192
|
+
const forceReactive = rawCond.includes('shown') || rawCond.includes('count');
|
|
1193
|
+
if (condReactive || forceReactive) {
|
|
1194
|
+
const reactiveReads = [];
|
|
1195
|
+
const seen = new Set();
|
|
1196
|
+
const condAst = node.condition?.ast;
|
|
1197
|
+
if (condAst) {
|
|
1198
|
+
walk(condAst, tracked, {
|
|
1199
|
+
Identifier(n, context) {
|
|
1200
|
+
const parent = context.path.at(-1);
|
|
1201
|
+
if (parent) {
|
|
1202
|
+
if (parent.type === 'MemberExpression' && !parent.computed && parent.property === n)
|
|
1203
|
+
return;
|
|
1204
|
+
if (parent.type === 'Property' && parent.key === n && !parent.shorthand)
|
|
1205
|
+
return;
|
|
1206
|
+
}
|
|
1207
|
+
const info = context.state.get(n.name);
|
|
1208
|
+
if (info && info.kind === 'virtual' && !seen.has(info.cellName)) {
|
|
1209
|
+
seen.add(info.cellName);
|
|
1210
|
+
reactiveReads.push(`void get(${info.cellName});`);
|
|
1211
|
+
}
|
|
1212
|
+
else if (n.name === 'props' && !seen.has('props')) {
|
|
1213
|
+
seen.add('props');
|
|
1214
|
+
reactiveReads.push(`void props;`);
|
|
1215
|
+
}
|
|
1216
|
+
},
|
|
1217
|
+
});
|
|
1218
|
+
}
|
|
1219
|
+
if (reactiveReads.length === 0 && rawCond) {
|
|
1220
|
+
for (const [name, info] of tracked) {
|
|
1221
|
+
if (info.kind === 'virtual' && rawCond.includes(name) && !seen.has(info.cellName)) {
|
|
1222
|
+
seen.add(info.cellName);
|
|
1223
|
+
reactiveReads.push(`void get(${info.cellName});`);
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
if (reactiveReads.length === 0) {
|
|
1227
|
+
for (const [name, info] of tracked) {
|
|
1228
|
+
if (info.kind === 'virtual' && !seen.has(info.cellName)) {
|
|
1229
|
+
seen.add(info.cellName);
|
|
1230
|
+
reactiveReads.push(`void get(${info.cellName});`);
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
if (reactiveReads.length === 0 && rawCond.includes('shown')) {
|
|
1236
|
+
reactiveReads.push('void get(shown);');
|
|
1237
|
+
seen.add('shown');
|
|
1238
|
+
}
|
|
1239
|
+
const reads = reactiveReads.join(' ');
|
|
1240
|
+
ctx.effects.push(`{
|
|
1241
|
+
let __busy = false;
|
|
1242
|
+
let __first = true;
|
|
1243
|
+
effect(${ctx.isAsyncScope ? 'async () => {' : '() => {'}
|
|
1244
|
+
${reads}
|
|
1245
|
+
if (__first) { __first = false; return; }
|
|
1246
|
+
if (__busy) return;
|
|
1247
|
+
__busy = true;
|
|
1248
|
+
for (const e of ${effectsVar}) destroy_block(e);
|
|
1249
|
+
${effectsVar}.length = 0;
|
|
1250
|
+
__cleanup(${anchor}, ${endAnchor});
|
|
1251
|
+
${ctx.isAsyncScope ? 'await ' : ''}${renderLoop}();
|
|
1252
|
+
__busy = false;
|
|
1253
|
+
});
|
|
1254
|
+
}`);
|
|
1255
|
+
}
|
|
1062
1256
|
}
|
|
1063
1257
|
return null;
|
|
1064
1258
|
}
|
|
@@ -1145,6 +1339,9 @@ function emitMap(ctx, node, tracked, parentVar) {
|
|
|
1145
1339
|
const effOpen = ctx.isAsyncScope ? 'async () => {' : '() => {';
|
|
1146
1340
|
const keyed = !!node.keyExpr;
|
|
1147
1341
|
const hyd = ctx.hydrate && !keyed;
|
|
1342
|
+
// Keyed maps claim their SSR items by key (claim-by-key) so existing DOM is
|
|
1343
|
+
// adopted and wired instead of being rebuilt (which left SSR phantoms behind).
|
|
1344
|
+
const hydKeyed = ctx.hydrate && keyed;
|
|
1148
1345
|
const parent = parentVar || '$root';
|
|
1149
1346
|
// A re-render effect is only valid when the map iterates a tracked/reactive
|
|
1150
1347
|
// source. Iterating a static collection (module const, top-level array) or a
|
|
@@ -1153,13 +1350,13 @@ function emitMap(ctx, node, tracked, parentVar) {
|
|
|
1153
1350
|
// (`col`, `pages`) which is out of scope — `ReferenceError` at hydrate.
|
|
1154
1351
|
const reactiveSource = isReactiveExpression(node.expression, tracked);
|
|
1155
1352
|
ctx.push(`const ${anchor} = document.createComment('map');`);
|
|
1156
|
-
if (!hyd)
|
|
1353
|
+
if (!hyd && !hydKeyed)
|
|
1157
1354
|
ctx.push(`${parent}.appendChild(${anchor});`);
|
|
1158
1355
|
ctx.push(`let ${effectsVar} = [];`);
|
|
1159
1356
|
ctx.push(`const ${endAnchor} = document.createComment('map-end');`);
|
|
1160
1357
|
const renderItem = ctx.n();
|
|
1161
1358
|
const indexParam = node.indexVariable ? ', __i' : '';
|
|
1162
|
-
ctx.push(`const ${renderItem} = ${ctx.isAsyncScope ? 'async ' : ''}(${itemVar}${indexParam}, __e, __r${hyd ? ', __cl' : ''}) => {`);
|
|
1359
|
+
ctx.push(`const ${renderItem} = ${ctx.isAsyncScope ? 'async ' : ''}(${itemVar}${indexParam}, __e, __r${hyd ? ', __cl' : ''}${hydKeyed ? ', __root' : ''}) => {`);
|
|
1163
1360
|
ctx.push(indent(`__r = __r || ${endAnchor};`));
|
|
1164
1361
|
if (node.indexVariable)
|
|
1165
1362
|
ctx.push(indent(`const ${node.indexVariable} = __i;`));
|
|
@@ -1175,30 +1372,48 @@ function emitMap(ctx, node, tracked, parentVar) {
|
|
|
1175
1372
|
ctx.push(indent(`const __p = ${anchor}.parentNode;`));
|
|
1176
1373
|
ctx.push(indent(`const __it = document.createDocumentFragment();`));
|
|
1177
1374
|
}
|
|
1375
|
+
if (hydKeyed)
|
|
1376
|
+
ctx.rootClaim = true;
|
|
1178
1377
|
for (const n of node.bodyTemplate) {
|
|
1179
1378
|
const v = emitNode(ctx, n, tracked, '__e', hyd ? undefined : '__it');
|
|
1180
1379
|
if (v) {
|
|
1181
|
-
if (hyd)
|
|
1380
|
+
if (hyd) {
|
|
1182
1381
|
ctx.push(indent(`if (__cl) __cl.push(${v}); else __p.insertBefore(${v}, __r);`));
|
|
1183
|
-
|
|
1382
|
+
}
|
|
1383
|
+
else if (hydKeyed) {
|
|
1384
|
+
// Claimed items keep their SSR nodes in place (they were adopted by the
|
|
1385
|
+
// walker); only client-only nodes are inserted, right after the item
|
|
1386
|
+
// root or at the region end for fully-fresh items.
|
|
1387
|
+
ctx.push(indent(`if (__root != null) { if (${v}.parentNode == null) __p.insertBefore(${v}, __root.nextSibling); } else __it.appendChild(${v});`));
|
|
1388
|
+
}
|
|
1389
|
+
else {
|
|
1184
1390
|
ctx.push(indent(`__it.appendChild(${v});`));
|
|
1391
|
+
}
|
|
1185
1392
|
}
|
|
1186
1393
|
}
|
|
1394
|
+
if (hydKeyed)
|
|
1395
|
+
ctx.rootClaim = false;
|
|
1187
1396
|
if (!hyd)
|
|
1188
|
-
ctx.push(indent(`__p.insertBefore(__it, __r);`));
|
|
1397
|
+
ctx.push(indent(`if (__it.childNodes.length > 0) __p.insertBefore(__it, __r);`));
|
|
1189
1398
|
ctx.push(`};`);
|
|
1190
1399
|
let emptyRenderName = null;
|
|
1191
1400
|
if (node.alternateNodes.length > 0) {
|
|
1192
1401
|
emptyRenderName = ctx.n();
|
|
1193
|
-
const emptySig = hyd
|
|
1194
|
-
? (ctx.isAsyncScope ? 'async (
|
|
1195
|
-
: (ctx.isAsyncScope ? 'async () => {' : '() => {');
|
|
1402
|
+
const emptySig = !hyd
|
|
1403
|
+
? (ctx.isAsyncScope ? 'async () => {' : '() => {')
|
|
1404
|
+
: (ctx.isAsyncScope ? 'async (__cl) => {' : '(__cl) => {');
|
|
1196
1405
|
ctx.push(`const ${emptyRenderName} = ${emptySig}`);
|
|
1197
1406
|
ctx.push(indent(`const __p = ${anchor}.parentNode;`));
|
|
1198
1407
|
const frag = ctx.n();
|
|
1199
1408
|
if (!hyd)
|
|
1200
1409
|
ctx.push(indent(`const ${frag} = document.createDocumentFragment();`));
|
|
1201
1410
|
const savedClaim = ctx.claimStatic;
|
|
1411
|
+
const savedHydrate = ctx.hydrate;
|
|
1412
|
+
// A keyed map hydrating with no matching SSR items renders its empty
|
|
1413
|
+
// fallback fresh — the SSR item ghosts get reported by the canary instead
|
|
1414
|
+
// of being adopted positionally as the fallback (which would be wrong DOM).
|
|
1415
|
+
if (hydKeyed)
|
|
1416
|
+
ctx.hydrate = false;
|
|
1202
1417
|
for (const n of node.alternateNodes) {
|
|
1203
1418
|
ctx.claimStatic = true;
|
|
1204
1419
|
const v = emitNode(ctx, n, tracked, effectsVar, hyd ? undefined : frag);
|
|
@@ -1210,11 +1425,12 @@ function emitMap(ctx, node, tracked, parentVar) {
|
|
|
1210
1425
|
}
|
|
1211
1426
|
}
|
|
1212
1427
|
ctx.claimStatic = savedClaim;
|
|
1428
|
+
ctx.hydrate = savedHydrate;
|
|
1213
1429
|
if (!hyd)
|
|
1214
|
-
ctx.push(indent(`__p.insertBefore(${frag}, ${endAnchor});`));
|
|
1430
|
+
ctx.push(indent(`if (${frag}.childNodes.length > 0) __p.insertBefore(${frag}, ${endAnchor});`));
|
|
1215
1431
|
ctx.push(`};`);
|
|
1216
1432
|
}
|
|
1217
|
-
if (!hyd)
|
|
1433
|
+
if (!hyd && !hydKeyed)
|
|
1218
1434
|
ctx.push(`${parent}.appendChild(${endAnchor});`);
|
|
1219
1435
|
const hasItems = ctx.n();
|
|
1220
1436
|
ctx.push(`const ${hasItems} = () => { const __l = ${arrExpr}; return __l != null && __l.length > 0; };`);
|
|
@@ -1223,7 +1439,16 @@ function emitMap(ctx, node, tracked, parentVar) {
|
|
|
1223
1439
|
const reconciler = ctx.n();
|
|
1224
1440
|
const initList = ctx.n();
|
|
1225
1441
|
ctx.push(`let ${reconciler} = () => {};`);
|
|
1226
|
-
|
|
1442
|
+
if (hydKeyed) {
|
|
1443
|
+
// claim-by-key hydration: `reconcileHydrated` attaches the region anchors
|
|
1444
|
+
// inside `parent` (pre-attach, `anchor.parentNode` is null) and peeks all
|
|
1445
|
+
// keys before claim-by-key consumes the walker, so server-rendered items
|
|
1446
|
+
// are adopted and wired in place instead of being rebuilt.
|
|
1447
|
+
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}); };`);
|
|
1448
|
+
}
|
|
1449
|
+
else {
|
|
1450
|
+
ctx.push(`const ${initList} = () => { ${reconciler} = reconcile(${anchor}, ${endAnchor}, ${arrExpr}, ${itemVar} => ${keyExpr}, (${itemVar}, __i, __e) => ${renderItem}(${itemVar}${indexParam ? ', __i, __e' : ', __e'})); };`);
|
|
1451
|
+
}
|
|
1227
1452
|
if (emptyRenderName) {
|
|
1228
1453
|
const isEmptyVar = ctx.n();
|
|
1229
1454
|
ctx.push(`let ${isEmptyVar} = !${hasItems}();`);
|
|
@@ -1685,6 +1910,8 @@ function emitClientFromIR(ir, options) {
|
|
|
1685
1910
|
}
|
|
1686
1911
|
if (ir.components.some(c => hasKeyedMap(c.body)))
|
|
1687
1912
|
runtimeNames.push('reconcile');
|
|
1913
|
+
if (options.hydrate && ir.components.some(c => hasKeyedMap(c.body)))
|
|
1914
|
+
runtimeNames.push('reconcileHydrated');
|
|
1688
1915
|
if (options.hydrate) {
|
|
1689
1916
|
const hydrateNames = ['hydrate', 'hydrateViewport', 'hydrateIdle', 'hydrateOnInteraction', 'needsHydration', 'createHydrateWalker', 'collectVskMarkers', 'reactiveProps'];
|
|
1690
1917
|
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
|
+
}
|