@scelar/nodepod 1.0.3 → 1.0.5
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/__sw__.js +642 -642
- package/dist/{child_process-hmVqFcF7.cjs → child_process-B9qsOKHs.cjs} +7434 -7434
- package/dist/child_process-B9qsOKHs.cjs.map +1 -0
- package/dist/{child_process-D6oDN2MX.js → child_process-PY34i_6n.js} +8233 -8233
- package/dist/child_process-PY34i_6n.js.map +1 -0
- package/dist/{index-BO1i013L.cjs → index-CyhVjVJU.cjs} +38383 -37240
- package/dist/index-CyhVjVJU.cjs.map +1 -0
- package/dist/index-D8Hn2kWU.js +36455 -0
- package/dist/index-D8Hn2kWU.js.map +1 -0
- package/dist/index.cjs +67 -65
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +88 -86
- package/dist/index.mjs +61 -59
- package/dist/memory-handler.d.ts +57 -0
- package/dist/memory-volume.d.ts +157 -147
- package/dist/packages/installer.d.ts +44 -41
- package/dist/persistence/idb-cache.d.ts +7 -0
- package/dist/polyfills/wasi.d.ts +45 -4
- package/dist/script-engine.d.ts +84 -81
- package/dist/sdk/nodepod-process.d.ts +29 -28
- package/dist/sdk/nodepod.d.ts +59 -39
- package/dist/sdk/types.d.ts +64 -53
- package/dist/threading/process-manager.d.ts +1 -1
- package/dist/threading/worker-protocol.d.ts +1 -1
- package/package.json +1 -1
- package/src/index.ts +194 -192
- package/src/memory-handler.ts +168 -0
- package/src/memory-volume.ts +78 -8
- package/src/packages/installer.ts +49 -1
- package/src/packages/version-resolver.ts +421 -411
- package/src/persistence/idb-cache.ts +107 -0
- package/src/polyfills/child_process.ts +2288 -2288
- package/src/polyfills/events.ts +6 -2
- package/src/polyfills/fs.ts +2888 -2888
- package/src/polyfills/http.ts +1450 -1449
- package/src/polyfills/process.ts +27 -1
- package/src/polyfills/stream.ts +1621 -1620
- package/src/polyfills/wasi.ts +1306 -44
- package/src/polyfills/zlib.ts +881 -881
- package/src/request-proxy.ts +716 -716
- package/src/script-engine.ts +444 -118
- package/src/sdk/nodepod-process.ts +94 -86
- package/src/sdk/nodepod.ts +571 -509
- package/src/sdk/types.ts +82 -70
- package/src/syntax-transforms.ts +2 -2
- package/src/threading/offload-worker.ts +383 -383
- package/src/threading/offload.ts +271 -271
- package/src/threading/process-manager.ts +967 -956
- package/src/threading/process-worker-entry.ts +858 -854
- package/src/threading/worker-protocol.ts +358 -358
- package/dist/child_process-D6oDN2MX.js.map +0 -1
- package/dist/child_process-hmVqFcF7.cjs.map +0 -1
- package/dist/index-Ale2oba_.js +0 -35412
- package/dist/index-Ale2oba_.js.map +0 -1
- package/dist/index-BO1i013L.cjs.map +0 -1
package/src/script-engine.ts
CHANGED
|
@@ -10,6 +10,7 @@ import type {
|
|
|
10
10
|
} from "./engine-types";
|
|
11
11
|
import type { PackageManifest } from "./types/manifest";
|
|
12
12
|
import { quickDigest } from "./helpers/digest";
|
|
13
|
+
import { LRUCache as _LRUCache } from "./memory-handler";
|
|
13
14
|
import { bytesToBase64, bytesToHex } from "./helpers/byte-encoding";
|
|
14
15
|
import { buildFileSystemBridge, FsBridge } from "./polyfills/fs";
|
|
15
16
|
import * as pathPolyfill from "./polyfills/path";
|
|
@@ -121,7 +122,11 @@ import {
|
|
|
121
122
|
hasTopLevelAwait,
|
|
122
123
|
stripTopLevelAwait,
|
|
123
124
|
} from "./syntax-transforms";
|
|
124
|
-
import {
|
|
125
|
+
import {
|
|
126
|
+
getCachedModule,
|
|
127
|
+
precompileWasm,
|
|
128
|
+
compileWasmInWorker,
|
|
129
|
+
} from "./helpers/wasm-cache";
|
|
125
130
|
import * as acorn from "acorn";
|
|
126
131
|
|
|
127
132
|
// ── TypeScript type stripper ──
|
|
@@ -224,11 +229,8 @@ function stripTypeScript(source: string): string {
|
|
|
224
229
|
|
|
225
230
|
function isTypeScriptFile(filename: string): boolean {
|
|
226
231
|
const clean = filename.split("?")[0];
|
|
227
|
-
if (
|
|
228
|
-
|
|
229
|
-
clean.endsWith(".tsx") ||
|
|
230
|
-
clean.endsWith(".mts")
|
|
231
|
-
) return true;
|
|
232
|
+
if (clean.endsWith(".ts") || clean.endsWith(".tsx") || clean.endsWith(".mts"))
|
|
233
|
+
return true;
|
|
232
234
|
// Vite SFC query params like ?type=script&lang.ts
|
|
233
235
|
if (filename.includes("lang.ts") || filename.includes("lang=ts")) return true;
|
|
234
236
|
return false;
|
|
@@ -245,9 +247,11 @@ function isCSSFile(filename: string): boolean {
|
|
|
245
247
|
clean.endsWith(".styl") ||
|
|
246
248
|
clean.endsWith(".stylus") ||
|
|
247
249
|
clean.endsWith(".postcss")
|
|
248
|
-
)
|
|
250
|
+
)
|
|
251
|
+
return true;
|
|
249
252
|
if (filename.includes("type=style")) return true;
|
|
250
|
-
if (/lang[.=](?:css|scss|sass|less|styl|stylus|postcss)/.test(filename))
|
|
253
|
+
if (/lang[.=](?:css|scss|sass|less|styl|stylus|postcss)/.test(filename))
|
|
254
|
+
return true;
|
|
251
255
|
return false;
|
|
252
256
|
}
|
|
253
257
|
|
|
@@ -255,7 +259,9 @@ function isCSSFile(filename: string): boolean {
|
|
|
255
259
|
function looksLikeTypeScript(source: string): boolean {
|
|
256
260
|
return (
|
|
257
261
|
/\b(?:interface|type)\s+\w+/.test(source) ||
|
|
258
|
-
/:\s*(?:string|number|boolean|void|any|never|unknown|Record|Array|Promise)\b/.test(
|
|
262
|
+
/:\s*(?:string|number|boolean|void|any|never|unknown|Record|Array|Promise)\b/.test(
|
|
263
|
+
source,
|
|
264
|
+
) ||
|
|
259
265
|
/(?:as\s+(?:string|number|boolean|any|const)\b)/.test(source)
|
|
260
266
|
);
|
|
261
267
|
}
|
|
@@ -299,7 +305,12 @@ function convertModuleSyntax(source: string, filePath: string): string {
|
|
|
299
305
|
try {
|
|
300
306
|
return convertViaAst(source, filePath);
|
|
301
307
|
} catch (astErr) {
|
|
302
|
-
_nativeConsole.warn(
|
|
308
|
+
_nativeConsole.warn(
|
|
309
|
+
"[convertModuleSyntax] AST parse failed for",
|
|
310
|
+
filePath,
|
|
311
|
+
"falling back to regex:",
|
|
312
|
+
astErr instanceof Error ? astErr.message : String(astErr),
|
|
313
|
+
);
|
|
303
314
|
return convertViaRegex(source, filePath);
|
|
304
315
|
}
|
|
305
316
|
}
|
|
@@ -337,7 +348,7 @@ function convertViaAst(source: string, filePath: string): string {
|
|
|
337
348
|
|
|
338
349
|
// apply all patches in one pass
|
|
339
350
|
let output = source;
|
|
340
|
-
patches.sort((a, b) => b[0] - a[0]);
|
|
351
|
+
patches.sort((a, b) => b[0] - a[0] || b[1] - a[1]);
|
|
341
352
|
for (const [s, e, r] of patches)
|
|
342
353
|
output = output.slice(0, s) + r + output.slice(e);
|
|
343
354
|
|
|
@@ -356,10 +367,7 @@ function convertViaAst(source: string, filePath: string): string {
|
|
|
356
367
|
// Demote `const/let require =` to plain assignment to avoid TDZ with esmToCjs-generated require() calls
|
|
357
368
|
function demoteLexicalRequire(code: string): string {
|
|
358
369
|
if (!/\b(?:const|let)\s+require\s*=/.test(code)) return code;
|
|
359
|
-
return code.replace(
|
|
360
|
-
/\b(const|let)\s+(require)\s*=/g,
|
|
361
|
-
"require =",
|
|
362
|
-
);
|
|
370
|
+
return code.replace(/\b(const|let)\s+(require)\s*=/g, "require =");
|
|
363
371
|
}
|
|
364
372
|
|
|
365
373
|
// Builds the IIFE wrapper that sandboxes user code with shimmed globals
|
|
@@ -632,7 +640,9 @@ function createSyncPromise(): typeof Promise {
|
|
|
632
640
|
res(onRejected(innerErr) as TResult2),
|
|
633
641
|
) as any;
|
|
634
642
|
}
|
|
635
|
-
return new SyncPromise<TResult2>((_, rej) =>
|
|
643
|
+
return new SyncPromise<TResult2>((_, rej) =>
|
|
644
|
+
rej(innerErr),
|
|
645
|
+
) as any;
|
|
636
646
|
}
|
|
637
647
|
return NativePromise.resolve(result).then(null, onRejected) as any;
|
|
638
648
|
}
|
|
@@ -670,8 +680,7 @@ function createSyncPromise(): typeof Promise {
|
|
|
670
680
|
|
|
671
681
|
// instanceof must work for native Promises too since we inject SyncPromise as `Promise`
|
|
672
682
|
Object.defineProperty(SyncPromise, Symbol.hasInstance, {
|
|
673
|
-
value: (instance: any) =>
|
|
674
|
-
instance instanceof NativePromise,
|
|
683
|
+
value: (instance: any) => instance instanceof NativePromise,
|
|
675
684
|
configurable: true,
|
|
676
685
|
});
|
|
677
686
|
|
|
@@ -704,11 +713,13 @@ function createSyncPromise(): typeof Promise {
|
|
|
704
713
|
allSync = false;
|
|
705
714
|
break;
|
|
706
715
|
}
|
|
707
|
-
} else if (
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
716
|
+
} else if (v && typeof v === "object" && typeof v.then === "function") {
|
|
717
|
+
let probed = false,
|
|
718
|
+
pVal: any;
|
|
719
|
+
v.then((x: any) => {
|
|
720
|
+
pVal = x;
|
|
721
|
+
probed = true;
|
|
722
|
+
});
|
|
712
723
|
if (probed) {
|
|
713
724
|
results[i] = pVal;
|
|
714
725
|
} else {
|
|
@@ -742,9 +753,7 @@ function createSyncPromise(): typeof Promise {
|
|
|
742
753
|
allSync = false;
|
|
743
754
|
break;
|
|
744
755
|
}
|
|
745
|
-
} else if (
|
|
746
|
-
v && typeof v === "object" && typeof v.then === "function"
|
|
747
|
-
) {
|
|
756
|
+
} else if (v && typeof v === "object" && typeof v.then === "function") {
|
|
748
757
|
allSync = false;
|
|
749
758
|
break;
|
|
750
759
|
} else {
|
|
@@ -786,9 +795,7 @@ function createSyncPromise(): typeof Promise {
|
|
|
786
795
|
if (v instanceof SyncPromise && (v as any)._syncResolved) {
|
|
787
796
|
return new SyncPromise((res: any) => res((v as any)._syncValue));
|
|
788
797
|
}
|
|
789
|
-
if (
|
|
790
|
-
!(v && typeof v === "object" && typeof v.then === "function")
|
|
791
|
-
) {
|
|
798
|
+
if (!(v && typeof v === "object" && typeof v.then === "function")) {
|
|
792
799
|
return new SyncPromise((res: any) => res(v));
|
|
793
800
|
}
|
|
794
801
|
}
|
|
@@ -830,12 +837,16 @@ function makeDynamicLoader(
|
|
|
830
837
|
) {
|
|
831
838
|
return new SyncThenable(loaded);
|
|
832
839
|
}
|
|
833
|
-
const spread =
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
840
|
+
const spread =
|
|
841
|
+
loaded && (typeof loaded === "object" || typeof loaded === "function")
|
|
842
|
+
? Object.getOwnPropertyNames(loaded as object).reduce(
|
|
843
|
+
(acc, key) => {
|
|
844
|
+
acc[key] = (loaded as any)[key];
|
|
845
|
+
return acc;
|
|
846
|
+
},
|
|
847
|
+
{} as Record<string, unknown>,
|
|
848
|
+
)
|
|
849
|
+
: {};
|
|
839
850
|
return new SyncThenable({
|
|
840
851
|
default: loaded,
|
|
841
852
|
...spread,
|
|
@@ -866,6 +877,7 @@ export interface EngineOptions {
|
|
|
866
877
|
workerData: unknown;
|
|
867
878
|
threadId: number;
|
|
868
879
|
};
|
|
880
|
+
handler?: import('./memory-handler').MemoryHandler;
|
|
869
881
|
}
|
|
870
882
|
|
|
871
883
|
export interface ResolverFn {
|
|
@@ -939,8 +951,8 @@ const CORE_MODULES: Record<string, unknown> = {
|
|
|
939
951
|
sea: seaPolyfill,
|
|
940
952
|
sqlite: sqlitePolyfill,
|
|
941
953
|
quic: quicPolyfill,
|
|
942
|
-
lightningcss: lightningcssPolyfill,
|
|
943
|
-
"@tailwindcss/oxide": tailwindOxidePolyfill,
|
|
954
|
+
// lightningcss: lightningcssPolyfill,
|
|
955
|
+
// "@tailwindcss/oxide": tailwindOxidePolyfill,
|
|
944
956
|
sys: helpersPolyfill,
|
|
945
957
|
"util/types": helpersPolyfill.types,
|
|
946
958
|
"path/posix": pathPolyfill,
|
|
@@ -1109,10 +1121,17 @@ function buildResolver(
|
|
|
1109
1121
|
deAsyncImports = false,
|
|
1110
1122
|
): ResolverFn {
|
|
1111
1123
|
// Shared across all resolvers — avoids re-resolving the same paths/manifests per module
|
|
1124
|
+
// Use bounded LRU when a memory handler is available, else plain Map
|
|
1112
1125
|
const resolveCache: Map<string, string | null> =
|
|
1113
|
-
(cache as any).__resolveCache ??
|
|
1126
|
+
(cache as any).__resolveCache ??
|
|
1127
|
+
((cache as any).__resolveCache = opts.handler
|
|
1128
|
+
? new _LRUCache<string, string | null>(opts.handler.options.resolveCacheSize)
|
|
1129
|
+
: new Map());
|
|
1114
1130
|
const manifestCache: Map<string, PackageManifest | null> =
|
|
1115
|
-
(cache as any).__manifestCache ??
|
|
1131
|
+
(cache as any).__manifestCache ??
|
|
1132
|
+
((cache as any).__manifestCache = opts.handler
|
|
1133
|
+
? new _LRUCache<string, PackageManifest | null>(opts.handler.options.manifestCacheSize)
|
|
1134
|
+
: new Map());
|
|
1116
1135
|
// Shared across all resolvers — deduplicates same-version packages from nested node_modules
|
|
1117
1136
|
const _pkgIdentityMap: Record<string, string> =
|
|
1118
1137
|
(cache as any).__pkgIdentityMap ?? ((cache as any).__pkgIdentityMap = {});
|
|
@@ -1234,13 +1253,19 @@ function buildResolver(
|
|
|
1234
1253
|
sync: noop,
|
|
1235
1254
|
transform: async (filename: string, code: string, opts?: any) => {
|
|
1236
1255
|
code = applyDefineReplacements(code, opts?.define);
|
|
1237
|
-
if (
|
|
1256
|
+
if (
|
|
1257
|
+
!isCSSFile(filename) &&
|
|
1258
|
+
(isTypeScriptFile(filename) || looksLikeTypeScript(code))
|
|
1259
|
+
)
|
|
1238
1260
|
code = stripTypeScript(code);
|
|
1239
1261
|
return { code, map: null, errors: [], warnings: [] };
|
|
1240
1262
|
},
|
|
1241
1263
|
transformSync: (filename: string, code: string, opts?: any) => {
|
|
1242
1264
|
code = applyDefineReplacements(code, opts?.define);
|
|
1243
|
-
if (
|
|
1265
|
+
if (
|
|
1266
|
+
!isCSSFile(filename) &&
|
|
1267
|
+
(isTypeScriptFile(filename) || looksLikeTypeScript(code))
|
|
1268
|
+
)
|
|
1244
1269
|
code = stripTypeScript(code);
|
|
1245
1270
|
return { code, map: null, errors: [], warnings: [] };
|
|
1246
1271
|
},
|
|
@@ -1250,7 +1275,10 @@ function buildResolver(
|
|
|
1250
1275
|
opts?: any,
|
|
1251
1276
|
) => {
|
|
1252
1277
|
code = applyDefineReplacements(code, opts?.define);
|
|
1253
|
-
if (
|
|
1278
|
+
if (
|
|
1279
|
+
!isCSSFile(filename) &&
|
|
1280
|
+
(isTypeScriptFile(filename) || looksLikeTypeScript(code))
|
|
1281
|
+
)
|
|
1254
1282
|
code = stripTypeScript(code);
|
|
1255
1283
|
return {
|
|
1256
1284
|
code,
|
|
@@ -1267,7 +1295,10 @@ function buildResolver(
|
|
|
1267
1295
|
opts?: any,
|
|
1268
1296
|
) => {
|
|
1269
1297
|
code = applyDefineReplacements(code, opts?.define);
|
|
1270
|
-
if (
|
|
1298
|
+
if (
|
|
1299
|
+
!isCSSFile(filename) &&
|
|
1300
|
+
(isTypeScriptFile(filename) || looksLikeTypeScript(code))
|
|
1301
|
+
)
|
|
1271
1302
|
code = stripTypeScript(code);
|
|
1272
1303
|
return {
|
|
1273
1304
|
code,
|
|
@@ -1303,12 +1334,18 @@ function buildResolver(
|
|
|
1303
1334
|
warnings: [],
|
|
1304
1335
|
}),
|
|
1305
1336
|
moduleRunnerTransform: async (filename: string, code: string) => {
|
|
1306
|
-
if (
|
|
1337
|
+
if (
|
|
1338
|
+
!isCSSFile(filename) &&
|
|
1339
|
+
(isTypeScriptFile(filename) || looksLikeTypeScript(code))
|
|
1340
|
+
)
|
|
1307
1341
|
code = stripTypeScript(code);
|
|
1308
1342
|
return { code, map: null, deps: [], dynamicDeps: [], errors: [] };
|
|
1309
1343
|
},
|
|
1310
1344
|
moduleRunnerTransformSync: (filename: string, code: string) => {
|
|
1311
|
-
if (
|
|
1345
|
+
if (
|
|
1346
|
+
!isCSSFile(filename) &&
|
|
1347
|
+
(isTypeScriptFile(filename) || looksLikeTypeScript(code))
|
|
1348
|
+
)
|
|
1312
1349
|
code = stripTypeScript(code);
|
|
1313
1350
|
return { code, map: null, deps: [], dynamicDeps: [], errors: [] };
|
|
1314
1351
|
},
|
|
@@ -1404,7 +1441,9 @@ function buildResolver(
|
|
|
1404
1441
|
)
|
|
1405
1442
|
specs.push(node.source.value);
|
|
1406
1443
|
}
|
|
1407
|
-
} catch {
|
|
1444
|
+
} catch {
|
|
1445
|
+
/* fallback to regex */
|
|
1446
|
+
}
|
|
1408
1447
|
const dynRe = /\bimport\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
1409
1448
|
let m;
|
|
1410
1449
|
while ((m = dynRe.exec(code)) !== null) specs.push(m[1]);
|
|
@@ -1416,8 +1455,14 @@ function buildResolver(
|
|
|
1416
1455
|
try {
|
|
1417
1456
|
await p.buildStart(mockCtx, {});
|
|
1418
1457
|
} catch (hookErr) {
|
|
1419
|
-
const msg =
|
|
1420
|
-
|
|
1458
|
+
const msg =
|
|
1459
|
+
hookErr instanceof Error
|
|
1460
|
+
? hookErr.message
|
|
1461
|
+
: String(hookErr);
|
|
1462
|
+
_nativeConsole.warn(
|
|
1463
|
+
"[rolldown scan] buildStart hook error:",
|
|
1464
|
+
msg,
|
|
1465
|
+
);
|
|
1421
1466
|
}
|
|
1422
1467
|
}
|
|
1423
1468
|
}
|
|
@@ -1446,8 +1491,15 @@ function buildResolver(
|
|
|
1446
1491
|
if (r && typeof r === "object" && r.code)
|
|
1447
1492
|
return r.code;
|
|
1448
1493
|
} catch (loadErr) {
|
|
1449
|
-
const msg =
|
|
1450
|
-
|
|
1494
|
+
const msg =
|
|
1495
|
+
loadErr instanceof Error
|
|
1496
|
+
? loadErr.message
|
|
1497
|
+
: String(loadErr);
|
|
1498
|
+
_nativeConsole.warn(
|
|
1499
|
+
"[rolldown scan] load hook error:",
|
|
1500
|
+
filePath,
|
|
1501
|
+
msg,
|
|
1502
|
+
);
|
|
1451
1503
|
}
|
|
1452
1504
|
}
|
|
1453
1505
|
}
|
|
@@ -1487,8 +1539,15 @@ function buildResolver(
|
|
|
1487
1539
|
custom: undefined,
|
|
1488
1540
|
});
|
|
1489
1541
|
} catch (resolveErr) {
|
|
1490
|
-
const msg =
|
|
1491
|
-
|
|
1542
|
+
const msg =
|
|
1543
|
+
resolveErr instanceof Error
|
|
1544
|
+
? resolveErr.message
|
|
1545
|
+
: String(resolveErr);
|
|
1546
|
+
_nativeConsole.warn(
|
|
1547
|
+
"[rolldown scan] resolveId hook error:",
|
|
1548
|
+
spec,
|
|
1549
|
+
msg,
|
|
1550
|
+
);
|
|
1492
1551
|
}
|
|
1493
1552
|
}
|
|
1494
1553
|
}
|
|
@@ -1527,14 +1586,24 @@ function buildResolver(
|
|
|
1527
1586
|
try {
|
|
1528
1587
|
await p.buildEnd(mockCtx);
|
|
1529
1588
|
} catch (endErr) {
|
|
1530
|
-
const msg =
|
|
1531
|
-
|
|
1589
|
+
const msg =
|
|
1590
|
+
endErr instanceof Error
|
|
1591
|
+
? endErr.message
|
|
1592
|
+
: String(endErr);
|
|
1593
|
+
_nativeConsole.warn(
|
|
1594
|
+
"[rolldown scan] buildEnd hook error:",
|
|
1595
|
+
msg,
|
|
1596
|
+
);
|
|
1532
1597
|
}
|
|
1533
1598
|
}
|
|
1534
1599
|
}
|
|
1535
1600
|
} catch (scanErr) {
|
|
1536
|
-
const msg =
|
|
1537
|
-
|
|
1601
|
+
const msg =
|
|
1602
|
+
scanErr instanceof Error ? scanErr.message : String(scanErr);
|
|
1603
|
+
const detail =
|
|
1604
|
+
scanErr instanceof Error && scanErr.stack
|
|
1605
|
+
? `\n${scanErr.stack}`
|
|
1606
|
+
: "";
|
|
1538
1607
|
_nativeConsole.warn("[rolldown scan]", msg);
|
|
1539
1608
|
}
|
|
1540
1609
|
}
|
|
@@ -1603,11 +1672,14 @@ function buildResolver(
|
|
|
1603
1672
|
const parts = afterNm.split("/");
|
|
1604
1673
|
const scoped = parts[0].startsWith("@");
|
|
1605
1674
|
const pkgName = scoped ? parts.slice(0, 2).join("/") : parts[0];
|
|
1606
|
-
const pkgRoot =
|
|
1675
|
+
const pkgRoot =
|
|
1676
|
+
origPath.slice(0, nmIdx) + "/node_modules/" + pkgName;
|
|
1607
1677
|
const pkgJsonPath = pkgRoot + "/package.json";
|
|
1608
1678
|
try {
|
|
1609
1679
|
if (!vol.existsSync(pkgJsonPath)) return null;
|
|
1610
|
-
const manifest = JSON.parse(
|
|
1680
|
+
const manifest = JSON.parse(
|
|
1681
|
+
vol.readFileSync(pkgJsonPath, "utf8"),
|
|
1682
|
+
);
|
|
1611
1683
|
for (const conds of [
|
|
1612
1684
|
{ browser: true, import: true },
|
|
1613
1685
|
{ import: true },
|
|
@@ -1616,11 +1688,16 @@ function buildResolver(
|
|
|
1616
1688
|
const resolved = resolveExports(manifest, ".", conds);
|
|
1617
1689
|
if (resolved?.length) {
|
|
1618
1690
|
const full = pathPolyfill.join(pkgRoot, resolved[0]);
|
|
1619
|
-
if (vol.existsSync(full) && full !== origPath)
|
|
1691
|
+
if (vol.existsSync(full) && full !== origPath)
|
|
1692
|
+
return full;
|
|
1620
1693
|
}
|
|
1621
|
-
} catch {
|
|
1694
|
+
} catch {
|
|
1695
|
+
/* try next */
|
|
1696
|
+
}
|
|
1622
1697
|
}
|
|
1623
|
-
} catch {
|
|
1698
|
+
} catch {
|
|
1699
|
+
/* can't re-resolve */
|
|
1700
|
+
}
|
|
1624
1701
|
return null;
|
|
1625
1702
|
};
|
|
1626
1703
|
|
|
@@ -1646,7 +1723,10 @@ function buildResolver(
|
|
|
1646
1723
|
target: "esnext",
|
|
1647
1724
|
logLevel: "warning",
|
|
1648
1725
|
});
|
|
1649
|
-
return
|
|
1726
|
+
return (
|
|
1727
|
+
result.outputFiles?.[0]?.text ??
|
|
1728
|
+
vol.readFileSync(ep, "utf8")
|
|
1729
|
+
);
|
|
1650
1730
|
};
|
|
1651
1731
|
|
|
1652
1732
|
try {
|
|
@@ -1669,8 +1749,15 @@ function buildResolver(
|
|
|
1669
1749
|
}
|
|
1670
1750
|
}
|
|
1671
1751
|
} catch (buildErr) {
|
|
1672
|
-
const buildMsg =
|
|
1673
|
-
|
|
1752
|
+
const buildMsg =
|
|
1753
|
+
buildErr instanceof Error
|
|
1754
|
+
? buildErr.message
|
|
1755
|
+
: String(buildErr);
|
|
1756
|
+
_nativeConsole.warn(
|
|
1757
|
+
"[rolldown bundle] esbuild failed for",
|
|
1758
|
+
entryPath,
|
|
1759
|
+
buildMsg,
|
|
1760
|
+
);
|
|
1674
1761
|
try {
|
|
1675
1762
|
code = vol.readFileSync(entryPath, "utf8");
|
|
1676
1763
|
} catch {
|
|
@@ -1770,10 +1857,13 @@ function buildResolver(
|
|
|
1770
1857
|
if (resolved) {
|
|
1771
1858
|
return { id: resolved + querySuffix };
|
|
1772
1859
|
}
|
|
1773
|
-
} catch (_e) {
|
|
1860
|
+
} catch (_e) {
|
|
1861
|
+
/* not found */
|
|
1862
|
+
}
|
|
1774
1863
|
|
|
1775
1864
|
if (candidate.startsWith("/")) {
|
|
1776
|
-
if (vol.existsSync(candidate))
|
|
1865
|
+
if (vol.existsSync(candidate))
|
|
1866
|
+
return { id: candidate + querySuffix };
|
|
1777
1867
|
const cwd =
|
|
1778
1868
|
(typeof globalThis !== "undefined" &&
|
|
1779
1869
|
(globalThis as any).process?.cwd?.()) ||
|
|
@@ -1782,7 +1872,8 @@ function buildResolver(
|
|
|
1782
1872
|
const abs = cwd + candidate;
|
|
1783
1873
|
if (vol.existsSync(abs)) return { id: abs + querySuffix };
|
|
1784
1874
|
for (const ext of RESOLVE_EXTENSIONS) {
|
|
1785
|
-
if (vol.existsSync(abs + ext))
|
|
1875
|
+
if (vol.existsSync(abs + ext))
|
|
1876
|
+
return { id: abs + ext + querySuffix };
|
|
1786
1877
|
}
|
|
1787
1878
|
}
|
|
1788
1879
|
}
|
|
@@ -2079,7 +2170,9 @@ function buildResolver(
|
|
|
2079
2170
|
const cached = resolveCache.get(cacheKey);
|
|
2080
2171
|
if (cached !== undefined) {
|
|
2081
2172
|
if (cached === null) {
|
|
2082
|
-
const e = new Error(`Cannot find module '${id}'`) as Error & {
|
|
2173
|
+
const e = new Error(`Cannot find module '${id}'`) as Error & {
|
|
2174
|
+
code: string;
|
|
2175
|
+
};
|
|
2083
2176
|
e.code = "MODULE_NOT_FOUND";
|
|
2084
2177
|
throw e;
|
|
2085
2178
|
}
|
|
@@ -2124,7 +2217,9 @@ function buildResolver(
|
|
|
2124
2217
|
}
|
|
2125
2218
|
|
|
2126
2219
|
resolveCache.set(cacheKey, null);
|
|
2127
|
-
const e = new Error(
|
|
2220
|
+
const e = new Error(
|
|
2221
|
+
`Cannot find module '${id}' from '${fromDir}'`,
|
|
2222
|
+
) as Error & { code: string };
|
|
2128
2223
|
e.code = "MODULE_NOT_FOUND";
|
|
2129
2224
|
throw e;
|
|
2130
2225
|
}
|
|
@@ -2173,7 +2268,8 @@ function buildResolver(
|
|
|
2173
2268
|
for (let ai = 0; ai < execArgv.length; ai++) {
|
|
2174
2269
|
const arg = execArgv[ai];
|
|
2175
2270
|
if (arg === "--conditions" || arg === "-C") {
|
|
2176
|
-
if (ai + 1 < execArgv.length)
|
|
2271
|
+
if (ai + 1 < execArgv.length)
|
|
2272
|
+
extraConditions.push(execArgv[++ai]);
|
|
2177
2273
|
} else if (arg.startsWith("--conditions=")) {
|
|
2178
2274
|
extraConditions.push(arg.slice("--conditions=".length));
|
|
2179
2275
|
}
|
|
@@ -2181,9 +2277,8 @@ function buildResolver(
|
|
|
2181
2277
|
const nodeOpts = proc.env?.NODE_OPTIONS || "";
|
|
2182
2278
|
const condMatch = nodeOpts.matchAll(/(?:--conditions[= ]|-C )(\S+)/g);
|
|
2183
2279
|
for (const m of condMatch) extraConditions.push(m[1]);
|
|
2184
|
-
const condExtra =
|
|
2185
|
-
? { conditions: extraConditions }
|
|
2186
|
-
: {};
|
|
2280
|
+
const condExtra =
|
|
2281
|
+
extraConditions.length > 0 ? { conditions: extraConditions } : {};
|
|
2187
2282
|
|
|
2188
2283
|
const baseSets: Record<string, unknown>[] = preferEsm
|
|
2189
2284
|
? [
|
|
@@ -2275,12 +2370,17 @@ function buildResolver(
|
|
|
2275
2370
|
}
|
|
2276
2371
|
|
|
2277
2372
|
resolveCache.set(cacheKey, null);
|
|
2278
|
-
const e = new Error(
|
|
2373
|
+
const e = new Error(
|
|
2374
|
+
`Cannot find module '${id}' from '${fromDir}'`,
|
|
2375
|
+
) as Error & { code: string };
|
|
2279
2376
|
e.code = "MODULE_NOT_FOUND";
|
|
2280
2377
|
throw e;
|
|
2281
2378
|
};
|
|
2282
2379
|
|
|
2283
|
-
const loadModule = (
|
|
2380
|
+
const loadModule = (
|
|
2381
|
+
resolved: string,
|
|
2382
|
+
parentRecord?: ModuleRecord,
|
|
2383
|
+
): ModuleRecord => {
|
|
2284
2384
|
if (cache[resolved]) return cache[resolved];
|
|
2285
2385
|
|
|
2286
2386
|
// Package dedup: reuse first instance of name@version:path to prevent
|
|
@@ -2289,12 +2389,17 @@ function buildResolver(
|
|
|
2289
2389
|
if (nmIdx !== -1) {
|
|
2290
2390
|
const afterNm = resolved.slice(nmIdx + "/node_modules/".length);
|
|
2291
2391
|
const parts = afterNm.split("/");
|
|
2292
|
-
const pkgName = parts[0].startsWith("@")
|
|
2392
|
+
const pkgName = parts[0].startsWith("@")
|
|
2393
|
+
? parts[0] + "/" + parts[1]
|
|
2394
|
+
: parts[0];
|
|
2293
2395
|
const pkgDir = resolved.slice(0, nmIdx) + "/node_modules/" + pkgName;
|
|
2294
2396
|
try {
|
|
2295
|
-
const pkgJson = JSON.parse(
|
|
2397
|
+
const pkgJson = JSON.parse(
|
|
2398
|
+
vol.readFileSync(pkgDir + "/package.json", "utf8"),
|
|
2399
|
+
);
|
|
2296
2400
|
// Include file path so different subpath exports (svelte vs svelte/compiler) aren't deduped
|
|
2297
|
-
const identity =
|
|
2401
|
+
const identity =
|
|
2402
|
+
pkgName + "@" + (pkgJson.version || "0.0.0") + ":" + afterNm;
|
|
2298
2403
|
if (!_pkgIdentityMap[identity]) {
|
|
2299
2404
|
_pkgIdentityMap[identity] = resolved;
|
|
2300
2405
|
} else if (_pkgIdentityMap[identity] !== resolved) {
|
|
@@ -2305,7 +2410,9 @@ function buildResolver(
|
|
|
2305
2410
|
return cache[canonical];
|
|
2306
2411
|
}
|
|
2307
2412
|
}
|
|
2308
|
-
} catch {
|
|
2413
|
+
} catch {
|
|
2414
|
+
/* no package.json */
|
|
2415
|
+
}
|
|
2309
2416
|
}
|
|
2310
2417
|
|
|
2311
2418
|
const _loadDepth = ((globalThis as any).__loadModuleDepth ?? 0) + 1;
|
|
@@ -2334,11 +2441,15 @@ function buildResolver(
|
|
|
2334
2441
|
return record;
|
|
2335
2442
|
}
|
|
2336
2443
|
|
|
2337
|
-
// Native addons
|
|
2444
|
+
// Native .node addons cannot run in the browser — throw so that
|
|
2445
|
+
// callers (e.g. napi-rs packages) fall back to their WASM build.
|
|
2338
2446
|
if (resolved.endsWith(".node")) {
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2447
|
+
delete cache[resolved];
|
|
2448
|
+
const e = new Error(
|
|
2449
|
+
`Cannot load native addon '${resolved}' — native .node binaries are not supported in the browser`,
|
|
2450
|
+
) as Error & { code: string };
|
|
2451
|
+
e.code = "ERR_DLOPEN_FAILED";
|
|
2452
|
+
throw e;
|
|
2342
2453
|
}
|
|
2343
2454
|
|
|
2344
2455
|
const rawSource = vol.readFileSync(resolved, "utf8");
|
|
@@ -2366,12 +2477,19 @@ function buildResolver(
|
|
|
2366
2477
|
const cjsPatches: Array<[number, number, string]> = [];
|
|
2367
2478
|
const walkCjs = (node: any) => {
|
|
2368
2479
|
if (!node || typeof node !== "object") return;
|
|
2369
|
-
if (Array.isArray(node)) {
|
|
2480
|
+
if (Array.isArray(node)) {
|
|
2481
|
+
for (const c of node) walkCjs(c);
|
|
2482
|
+
return;
|
|
2483
|
+
}
|
|
2370
2484
|
if (typeof node.type !== "string") return;
|
|
2371
2485
|
if (node.type === "ImportExpression") {
|
|
2372
2486
|
cjsPatches.push([node.start, node.start + 6, "__asyncLoad"]);
|
|
2373
2487
|
}
|
|
2374
|
-
if (
|
|
2488
|
+
if (
|
|
2489
|
+
node.type === "MetaProperty" &&
|
|
2490
|
+
node.meta?.name === "import" &&
|
|
2491
|
+
node.property?.name === "meta"
|
|
2492
|
+
) {
|
|
2375
2493
|
cjsPatches.push([
|
|
2376
2494
|
node.start,
|
|
2377
2495
|
node.end,
|
|
@@ -2386,12 +2504,17 @@ function buildResolver(
|
|
|
2386
2504
|
};
|
|
2387
2505
|
walkCjs(cjsAst);
|
|
2388
2506
|
if (cjsPatches.length > 0) {
|
|
2389
|
-
cjsPatches.sort((a, b) => b[0] - a[0]);
|
|
2507
|
+
cjsPatches.sort((a, b) => b[0] - a[0] || b[1] - a[1]);
|
|
2390
2508
|
for (const [start, end, replacement] of cjsPatches) {
|
|
2391
|
-
processedCode =
|
|
2509
|
+
processedCode =
|
|
2510
|
+
processedCode.slice(0, start) +
|
|
2511
|
+
replacement +
|
|
2512
|
+
processedCode.slice(end);
|
|
2392
2513
|
}
|
|
2393
2514
|
}
|
|
2394
|
-
} catch {
|
|
2515
|
+
} catch {
|
|
2516
|
+
/* can't parse — leave untransformed */
|
|
2517
|
+
}
|
|
2395
2518
|
} else {
|
|
2396
2519
|
processedCode = convertModuleSyntax(processedCode, resolved);
|
|
2397
2520
|
}
|
|
@@ -2401,7 +2524,11 @@ function buildResolver(
|
|
|
2401
2524
|
const isCjs = resolved.endsWith(".cjs");
|
|
2402
2525
|
const moduleHasTLA = !isCjs && hasTopLevelAwait(processedCode);
|
|
2403
2526
|
const useFullDeAsync = deAsyncImports || moduleHasTLA;
|
|
2404
|
-
if (!isCjs)
|
|
2527
|
+
if (!isCjs)
|
|
2528
|
+
processedCode = stripTopLevelAwait(
|
|
2529
|
+
processedCode,
|
|
2530
|
+
deAsyncImports ? "full" : "topLevelOnly",
|
|
2531
|
+
);
|
|
2405
2532
|
|
|
2406
2533
|
const childResolver = buildResolver(
|
|
2407
2534
|
vol,
|
|
@@ -2432,7 +2559,9 @@ function buildResolver(
|
|
|
2432
2559
|
}
|
|
2433
2560
|
|
|
2434
2561
|
{
|
|
2435
|
-
const srcMap =
|
|
2562
|
+
const srcMap =
|
|
2563
|
+
(globalThis as any).__dbgSrcMap ||
|
|
2564
|
+
((globalThis as any).__dbgSrcMap = new Map());
|
|
2436
2565
|
srcMap.set(resolved, wrapper);
|
|
2437
2566
|
}
|
|
2438
2567
|
|
|
@@ -2521,7 +2650,7 @@ function buildResolver(
|
|
|
2521
2650
|
if (typeof id !== "string") {
|
|
2522
2651
|
// Match real Node.js error: TypeError with ERR_INVALID_ARG_TYPE code
|
|
2523
2652
|
const err: any = new TypeError(
|
|
2524
|
-
`The "id" argument must be of type string. Received ${id === null ? "null" : typeof id}
|
|
2653
|
+
`The "id" argument must be of type string. Received ${id === null ? "null" : typeof id}`,
|
|
2525
2654
|
);
|
|
2526
2655
|
err.code = "ERR_INVALID_ARG_TYPE";
|
|
2527
2656
|
throw err;
|
|
@@ -2535,7 +2664,11 @@ function buildResolver(
|
|
|
2535
2664
|
if (id === "worker_threads") {
|
|
2536
2665
|
if (opts.workerThreadsOverride) {
|
|
2537
2666
|
const base = CORE_MODULES["worker_threads"];
|
|
2538
|
-
const override = Object.assign(
|
|
2667
|
+
const override = Object.assign(
|
|
2668
|
+
Object.create(null),
|
|
2669
|
+
base,
|
|
2670
|
+
opts.workerThreadsOverride,
|
|
2671
|
+
);
|
|
2539
2672
|
override.default = override;
|
|
2540
2673
|
return override;
|
|
2541
2674
|
}
|
|
@@ -2558,7 +2691,16 @@ function buildResolver(
|
|
|
2558
2691
|
fromPath = fromPath.slice(1);
|
|
2559
2692
|
}
|
|
2560
2693
|
const childDir = pathPolyfill.dirname(fromPath);
|
|
2561
|
-
const child = buildResolver(
|
|
2694
|
+
const child = buildResolver(
|
|
2695
|
+
vol,
|
|
2696
|
+
fsBridge,
|
|
2697
|
+
proc,
|
|
2698
|
+
childDir,
|
|
2699
|
+
cache,
|
|
2700
|
+
opts,
|
|
2701
|
+
codeCache,
|
|
2702
|
+
deAsyncImports,
|
|
2703
|
+
);
|
|
2562
2704
|
child.cache = cache;
|
|
2563
2705
|
return child;
|
|
2564
2706
|
};
|
|
@@ -2572,9 +2714,7 @@ function buildResolver(
|
|
|
2572
2714
|
options?: any,
|
|
2573
2715
|
) => {
|
|
2574
2716
|
if (typeof request !== "string") {
|
|
2575
|
-
const err: any = new Error(
|
|
2576
|
-
`Cannot find module '${request}'`,
|
|
2577
|
-
);
|
|
2717
|
+
const err: any = new Error(`Cannot find module '${request}'`);
|
|
2578
2718
|
err.code = "MODULE_NOT_FOUND";
|
|
2579
2719
|
throw err;
|
|
2580
2720
|
}
|
|
@@ -2605,14 +2745,16 @@ function buildResolver(
|
|
|
2605
2745
|
try {
|
|
2606
2746
|
return resolveId(request, fromDir);
|
|
2607
2747
|
} catch {
|
|
2608
|
-
const err: any = new Error(
|
|
2609
|
-
`Cannot find module '${request}'`,
|
|
2610
|
-
);
|
|
2748
|
+
const err: any = new Error(`Cannot find module '${request}'`);
|
|
2611
2749
|
err.code = "MODULE_NOT_FOUND";
|
|
2612
2750
|
throw err;
|
|
2613
2751
|
}
|
|
2614
2752
|
};
|
|
2615
|
-
PerEngineModule._load = (
|
|
2753
|
+
PerEngineModule._load = (
|
|
2754
|
+
request: string,
|
|
2755
|
+
parent?: any,
|
|
2756
|
+
isMain?: boolean,
|
|
2757
|
+
) => {
|
|
2616
2758
|
try {
|
|
2617
2759
|
return resolver(request);
|
|
2618
2760
|
} catch {
|
|
@@ -2640,10 +2782,81 @@ function buildResolver(
|
|
|
2640
2782
|
}
|
|
2641
2783
|
if (CORE_MODULES[id]) return CORE_MODULES[id];
|
|
2642
2784
|
|
|
2643
|
-
|
|
2785
|
+
let resolved: string;
|
|
2786
|
+
try {
|
|
2787
|
+
resolved = resolveId(id, baseDir);
|
|
2788
|
+
} catch (resolveErr: any) {
|
|
2789
|
+
if (
|
|
2790
|
+
resolveErr?.code === "MODULE_NOT_FOUND" &&
|
|
2791
|
+
!id.startsWith("./") &&
|
|
2792
|
+
!id.startsWith("../")
|
|
2793
|
+
) {
|
|
2794
|
+
// --- Determine WASM alternative package name(s) to try ---
|
|
2795
|
+
const wasmAlts: string[] = [];
|
|
2796
|
+
|
|
2797
|
+
if (id.includes("wasm32-wasi")) {
|
|
2798
|
+
// Explicit wasm32-wasi package — auto-install as-is
|
|
2799
|
+
wasmAlts.push(id);
|
|
2800
|
+
} else {
|
|
2801
|
+
// Platform-specific native package pattern:
|
|
2802
|
+
// {name}-{platform}-{arch}[-{abi}]
|
|
2803
|
+
// e.g. lightningcss-linux-x64-gnu, @pkg/core-darwin-arm64
|
|
2804
|
+
const platformRe =
|
|
2805
|
+
/^(.+)-(darwin|linux|win32|freebsd|android|sunos)-(x64|x86|arm64|arm|ia32|s390x|ppc64|mips64el|riscv64)(-[a-z]+)?$/;
|
|
2806
|
+
const m = id.match(platformRe);
|
|
2807
|
+
if (m) {
|
|
2808
|
+
const baseName = m[1]; // e.g. "lightningcss" or "@scope/pkg"
|
|
2809
|
+
wasmAlts.push(baseName + "-wasm32-wasi");
|
|
2810
|
+
wasmAlts.push(baseName + "-wasm");
|
|
2811
|
+
}
|
|
2812
|
+
}
|
|
2813
|
+
|
|
2814
|
+
// Try resolving any of the WASM alternatives (already installed)
|
|
2815
|
+
for (const alt of wasmAlts) {
|
|
2816
|
+
resolveCache.delete(`${baseDir}|${alt}`);
|
|
2817
|
+
try {
|
|
2818
|
+
const altResolved = resolveId(alt, baseDir);
|
|
2819
|
+
const altRec = loadModule(altResolved, resolver._ownerRecord);
|
|
2820
|
+
return altRec.exports;
|
|
2821
|
+
} catch {
|
|
2822
|
+
// not installed yet
|
|
2823
|
+
}
|
|
2824
|
+
}
|
|
2825
|
+
|
|
2826
|
+
}
|
|
2827
|
+
throw resolveErr;
|
|
2828
|
+
}
|
|
2644
2829
|
if (CORE_MODULES[resolved]) return CORE_MODULES[resolved];
|
|
2645
2830
|
|
|
2646
|
-
|
|
2831
|
+
let rec: ModuleRecord;
|
|
2832
|
+
try {
|
|
2833
|
+
rec = loadModule(resolved, resolver._ownerRecord);
|
|
2834
|
+
} catch (loadErr: any) {
|
|
2835
|
+
// When a bare module fails to load (e.g. native binding not found inside
|
|
2836
|
+
// the module), try a WASM drop-in replacement: {name}-wasm or {name}-wasm32-wasi
|
|
2837
|
+
if (
|
|
2838
|
+
!id.startsWith("./") &&
|
|
2839
|
+
!id.startsWith("../") &&
|
|
2840
|
+
!id.startsWith("/") &&
|
|
2841
|
+
(loadErr?.code === "MODULE_NOT_FOUND" ||
|
|
2842
|
+
loadErr?.code === "ERR_DLOPEN_FAILED" ||
|
|
2843
|
+
(loadErr?.message &&
|
|
2844
|
+
/cannot\s+(find|load)\s+(module|native)/i.test(loadErr.message)))
|
|
2845
|
+
) {
|
|
2846
|
+
const wasmAlts = [id + "-wasm32-wasi", id + "-wasm"];
|
|
2847
|
+
for (const alt of wasmAlts) {
|
|
2848
|
+
try {
|
|
2849
|
+
resolveCache.delete(`${baseDir}|${alt}`);
|
|
2850
|
+
const altResolved = resolveId(alt, baseDir);
|
|
2851
|
+
const altRec = loadModule(altResolved, resolver._ownerRecord);
|
|
2852
|
+
return altRec.exports;
|
|
2853
|
+
} catch {
|
|
2854
|
+
// not available
|
|
2855
|
+
}
|
|
2856
|
+
}
|
|
2857
|
+
}
|
|
2858
|
+
throw loadErr;
|
|
2859
|
+
}
|
|
2647
2860
|
// Proxy for async WASM — reads from rec.exports at access time so
|
|
2648
2861
|
// reassigned module.exports is picked up after compilation finishes
|
|
2649
2862
|
if ((rec as any).__wasmReady) {
|
|
@@ -2707,9 +2920,15 @@ export class ScriptEngine {
|
|
|
2707
2920
|
private proc: ProcessObject;
|
|
2708
2921
|
private moduleRegistry: Record<string, ModuleRecord> = {};
|
|
2709
2922
|
private opts: EngineOptions;
|
|
2710
|
-
private transformCache: Map<string, string
|
|
2923
|
+
private transformCache: Map<string, string>;
|
|
2711
2924
|
|
|
2712
2925
|
constructor(vol: MemoryVolume, opts: EngineOptions = {}) {
|
|
2926
|
+
// Use handler's LRU transform cache if available, else a plain Map
|
|
2927
|
+
if (opts.handler) {
|
|
2928
|
+
this.transformCache = opts.handler.transformCache as unknown as Map<string, string>;
|
|
2929
|
+
} else {
|
|
2930
|
+
this.transformCache = new Map();
|
|
2931
|
+
}
|
|
2713
2932
|
this.vol = vol;
|
|
2714
2933
|
this.proc = buildProcessEnv({
|
|
2715
2934
|
cwd: opts.cwd || "/",
|
|
@@ -2735,6 +2954,62 @@ export class ScriptEngine {
|
|
|
2735
2954
|
|
|
2736
2955
|
(globalThis as any).__nodepodVolume = vol;
|
|
2737
2956
|
|
|
2957
|
+
// Intercept fetch() for file:// URLs — serve from VFS instead of network.
|
|
2958
|
+
// napi-rs wasm32-wasi packages use fetch(new URL('file.wasm', import.meta.url))
|
|
2959
|
+
// which browsers block. This patches fetch to read from the in-memory filesystem.
|
|
2960
|
+
if (!(globalThis.fetch as any).__nodepodPatched) {
|
|
2961
|
+
const origFetch = globalThis.fetch.bind(globalThis);
|
|
2962
|
+
const patchedFetch = (
|
|
2963
|
+
input: RequestInfo | URL,
|
|
2964
|
+
init?: RequestInit,
|
|
2965
|
+
): Promise<Response> => {
|
|
2966
|
+
let url: string | undefined;
|
|
2967
|
+
if (typeof input === "string") url = input;
|
|
2968
|
+
else if (input instanceof URL) url = input.href;
|
|
2969
|
+
else if (input instanceof Request) url = input.url;
|
|
2970
|
+
|
|
2971
|
+
if (url?.startsWith("file://")) {
|
|
2972
|
+
// Convert file:// URL to VFS path
|
|
2973
|
+
let vfsPath: string;
|
|
2974
|
+
try {
|
|
2975
|
+
vfsPath = decodeURIComponent(new URL(url).pathname);
|
|
2976
|
+
} catch {
|
|
2977
|
+
vfsPath = decodeURIComponent(url.slice(7));
|
|
2978
|
+
}
|
|
2979
|
+
const v = (globalThis as any).__nodepodVolume as MemoryVolume | undefined;
|
|
2980
|
+
if (v) {
|
|
2981
|
+
try {
|
|
2982
|
+
const data = v.readFileSync(vfsPath);
|
|
2983
|
+
const bytes =
|
|
2984
|
+
data instanceof Uint8Array
|
|
2985
|
+
? data
|
|
2986
|
+
: new TextEncoder().encode(String(data));
|
|
2987
|
+
const contentType = vfsPath.endsWith(".wasm")
|
|
2988
|
+
? "application/wasm"
|
|
2989
|
+
: "application/octet-stream";
|
|
2990
|
+
return Promise.resolve(
|
|
2991
|
+
new Response(bytes.buffer.slice(
|
|
2992
|
+
bytes.byteOffset,
|
|
2993
|
+
bytes.byteOffset + bytes.byteLength,
|
|
2994
|
+
) as ArrayBuffer, {
|
|
2995
|
+
status: 200,
|
|
2996
|
+
headers: { "Content-Type": contentType },
|
|
2997
|
+
}),
|
|
2998
|
+
);
|
|
2999
|
+
} catch {
|
|
3000
|
+
return Promise.resolve(
|
|
3001
|
+
new Response("Not found", { status: 404 }),
|
|
3002
|
+
);
|
|
3003
|
+
}
|
|
3004
|
+
}
|
|
3005
|
+
}
|
|
3006
|
+
return origFetch(input, init);
|
|
3007
|
+
};
|
|
3008
|
+
(globalThis as any).fetch = Object.assign(patchedFetch, {
|
|
3009
|
+
__nodepodPatched: true,
|
|
3010
|
+
});
|
|
3011
|
+
}
|
|
3012
|
+
|
|
2738
3013
|
if (typeof globalThis.setImmediate === "undefined") {
|
|
2739
3014
|
(globalThis as any).setImmediate = (
|
|
2740
3015
|
fn: (...a: unknown[]) => void,
|
|
@@ -2766,7 +3041,9 @@ export class ScriptEngine {
|
|
|
2766
3041
|
const cached2 = getCachedModule(bytes);
|
|
2767
3042
|
if (cached2) return cached2;
|
|
2768
3043
|
const compilePromise = compileWasmInWorker(
|
|
2769
|
-
bytes instanceof ArrayBuffer
|
|
3044
|
+
bytes instanceof ArrayBuffer
|
|
3045
|
+
? new Uint8Array(bytes)
|
|
3046
|
+
: (bytes as Uint8Array),
|
|
2770
3047
|
);
|
|
2771
3048
|
(globalThis as any).__wasmCompilePromise = compilePromise;
|
|
2772
3049
|
}
|
|
@@ -2793,11 +3070,23 @@ export class ScriptEngine {
|
|
|
2793
3070
|
const obj = {
|
|
2794
3071
|
_id: id,
|
|
2795
3072
|
_ref: true,
|
|
2796
|
-
ref() {
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
3073
|
+
ref() {
|
|
3074
|
+
obj._ref = true;
|
|
3075
|
+
return obj;
|
|
3076
|
+
},
|
|
3077
|
+
unref() {
|
|
3078
|
+
obj._ref = false;
|
|
3079
|
+
return obj;
|
|
3080
|
+
},
|
|
3081
|
+
hasRef() {
|
|
3082
|
+
return obj._ref;
|
|
3083
|
+
},
|
|
3084
|
+
refresh() {
|
|
3085
|
+
return obj;
|
|
3086
|
+
},
|
|
3087
|
+
[Symbol.toPrimitive]() {
|
|
3088
|
+
return id;
|
|
3089
|
+
},
|
|
2801
3090
|
};
|
|
2802
3091
|
return obj;
|
|
2803
3092
|
};
|
|
@@ -2806,11 +3095,23 @@ export class ScriptEngine {
|
|
|
2806
3095
|
const obj = {
|
|
2807
3096
|
_id: id,
|
|
2808
3097
|
_ref: true,
|
|
2809
|
-
ref() {
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
3098
|
+
ref() {
|
|
3099
|
+
obj._ref = true;
|
|
3100
|
+
return obj;
|
|
3101
|
+
},
|
|
3102
|
+
unref() {
|
|
3103
|
+
obj._ref = false;
|
|
3104
|
+
return obj;
|
|
3105
|
+
},
|
|
3106
|
+
hasRef() {
|
|
3107
|
+
return obj._ref;
|
|
3108
|
+
},
|
|
3109
|
+
refresh() {
|
|
3110
|
+
return obj;
|
|
3111
|
+
},
|
|
3112
|
+
[Symbol.toPrimitive]() {
|
|
3113
|
+
return id;
|
|
3114
|
+
},
|
|
2814
3115
|
};
|
|
2815
3116
|
return obj;
|
|
2816
3117
|
};
|
|
@@ -3051,6 +3352,7 @@ export class ScriptEngine {
|
|
|
3051
3352
|
code: string,
|
|
3052
3353
|
filename: string = "/index.js",
|
|
3053
3354
|
): { exports: unknown; module: ModuleRecord } {
|
|
3355
|
+
this._trimModuleCache();
|
|
3054
3356
|
const dir = pathPolyfill.dirname(filename);
|
|
3055
3357
|
// Only write when the content differs to avoid triggering file watchers
|
|
3056
3358
|
// (e.g. nodemon/chokidar) with a no-op write that causes restart loops.
|
|
@@ -3090,12 +3392,19 @@ export class ScriptEngine {
|
|
|
3090
3392
|
const cjsPatches: Array<[number, number, string]> = [];
|
|
3091
3393
|
const walkCjs = (node: any) => {
|
|
3092
3394
|
if (!node || typeof node !== "object") return;
|
|
3093
|
-
if (Array.isArray(node)) {
|
|
3395
|
+
if (Array.isArray(node)) {
|
|
3396
|
+
for (const c of node) walkCjs(c);
|
|
3397
|
+
return;
|
|
3398
|
+
}
|
|
3094
3399
|
if (typeof node.type !== "string") return;
|
|
3095
3400
|
if (node.type === "ImportExpression") {
|
|
3096
3401
|
cjsPatches.push([node.start, node.start + 6, "__asyncLoad"]);
|
|
3097
3402
|
}
|
|
3098
|
-
if (
|
|
3403
|
+
if (
|
|
3404
|
+
node.type === "MetaProperty" &&
|
|
3405
|
+
node.meta?.name === "import" &&
|
|
3406
|
+
node.property?.name === "meta"
|
|
3407
|
+
) {
|
|
3099
3408
|
cjsPatches.push([
|
|
3100
3409
|
node.start,
|
|
3101
3410
|
node.end,
|
|
@@ -3112,10 +3421,13 @@ export class ScriptEngine {
|
|
|
3112
3421
|
if (cjsPatches.length > 0) {
|
|
3113
3422
|
cjsPatches.sort((a, b) => b[0] - a[0]);
|
|
3114
3423
|
for (const [start, end, replacement] of cjsPatches) {
|
|
3115
|
-
processed =
|
|
3424
|
+
processed =
|
|
3425
|
+
processed.slice(0, start) + replacement + processed.slice(end);
|
|
3116
3426
|
}
|
|
3117
3427
|
}
|
|
3118
|
-
} catch {
|
|
3428
|
+
} catch {
|
|
3429
|
+
/* can't parse */
|
|
3430
|
+
}
|
|
3119
3431
|
} else {
|
|
3120
3432
|
processed = convertModuleSyntax(processed, filename);
|
|
3121
3433
|
}
|
|
@@ -3310,6 +3622,20 @@ export class ScriptEngine {
|
|
|
3310
3622
|
(this.moduleRegistry as any).__resolveCache?.clear();
|
|
3311
3623
|
(this.moduleRegistry as any).__manifestCache?.clear();
|
|
3312
3624
|
delete (this.moduleRegistry as any).__pkgIdentityMap;
|
|
3625
|
+
this.transformCache.clear();
|
|
3626
|
+
}
|
|
3627
|
+
|
|
3628
|
+
/** Evict one node_modules entry when module cache exceeds soft limit. */
|
|
3629
|
+
private _trimModuleCache(): void {
|
|
3630
|
+
const limit = this.opts.handler?.options.moduleSoftCacheSize ?? 512;
|
|
3631
|
+
const keys = Object.keys(this.moduleRegistry);
|
|
3632
|
+
if (keys.length < limit) return;
|
|
3633
|
+
for (const k of keys) {
|
|
3634
|
+
if (k.includes('/node_modules/')) {
|
|
3635
|
+
delete this.moduleRegistry[k];
|
|
3636
|
+
return; // One eviction per call — amortized O(1)
|
|
3637
|
+
}
|
|
3638
|
+
}
|
|
3313
3639
|
}
|
|
3314
3640
|
|
|
3315
3641
|
getVolume(): MemoryVolume {
|