@scelar/nodepod 1.0.2 → 1.0.4
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/__tests__/bench/integration.bench.d.ts +1 -0
- package/dist/__tests__/bench/memory-volume.bench.d.ts +1 -0
- package/dist/__tests__/bench/polyfills.bench.d.ts +1 -0
- package/dist/__tests__/bench/script-engine.bench.d.ts +1 -0
- package/dist/__tests__/bench/shell.bench.d.ts +1 -0
- package/dist/__tests__/bench/syntax-transforms.bench.d.ts +1 -0
- package/dist/__tests__/bench/version-resolver.bench.d.ts +1 -0
- package/dist/__tests__/buffer.test.d.ts +1 -0
- package/dist/__tests__/byte-encoding.test.d.ts +1 -0
- package/dist/__tests__/digest.test.d.ts +1 -0
- package/dist/__tests__/events.test.d.ts +1 -0
- package/dist/__tests__/memory-volume.test.d.ts +1 -0
- package/dist/__tests__/path.test.d.ts +1 -0
- package/dist/__tests__/process.test.d.ts +1 -0
- package/dist/__tests__/script-engine.test.d.ts +1 -0
- package/dist/__tests__/shell-builtins.test.d.ts +1 -0
- package/dist/__tests__/shell-interpreter.test.d.ts +1 -0
- package/dist/__tests__/shell-parser.test.d.ts +1 -0
- package/dist/__tests__/stream.test.d.ts +1 -0
- package/dist/__tests__/syntax-transforms.test.d.ts +1 -0
- package/dist/__tests__/version-resolver.test.d.ts +1 -0
- package/dist/{child_process-Dopvyd-E.js → child_process-53fMkug_.js} +4 -4
- package/dist/child_process-53fMkug_.js.map +1 -0
- package/dist/{child_process-B38qoN6R.cjs → child_process-lxSKECHq.cjs} +5 -5
- package/dist/child_process-lxSKECHq.cjs.map +1 -0
- package/dist/{index--Qr8LVpQ.js → index-B8lyh_ti.js} +1316 -559
- package/dist/index-B8lyh_ti.js.map +1 -0
- package/dist/{index-cnitc68U.cjs → index-C-TQIrdG.cjs} +1422 -612
- package/dist/index-C-TQIrdG.cjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/memory-volume.d.ts +1 -1
- package/dist/polyfills/wasi.d.ts +45 -4
- package/dist/script-engine.d.ts +2 -0
- package/dist/sdk/nodepod.d.ts +4 -3
- package/dist/sdk/types.d.ts +6 -0
- package/dist/syntax-transforms.d.ts +1 -0
- package/dist/threading/process-manager.d.ts +1 -1
- package/dist/threading/worker-protocol.d.ts +1 -1
- package/package.json +5 -3
- package/src/__tests__/bench/integration.bench.ts +117 -0
- package/src/__tests__/bench/memory-volume.bench.ts +115 -0
- package/src/__tests__/bench/polyfills.bench.ts +147 -0
- package/src/__tests__/bench/script-engine.bench.ts +104 -0
- package/src/__tests__/bench/shell.bench.ts +101 -0
- package/src/__tests__/bench/syntax-transforms.bench.ts +82 -0
- package/src/__tests__/bench/version-resolver.bench.ts +95 -0
- package/src/__tests__/buffer.test.ts +273 -0
- package/src/__tests__/byte-encoding.test.ts +98 -0
- package/src/__tests__/digest.test.ts +44 -0
- package/src/__tests__/events.test.ts +245 -0
- package/src/__tests__/memory-volume.test.ts +443 -0
- package/src/__tests__/path.test.ts +181 -0
- package/src/__tests__/process.test.ts +129 -0
- package/src/__tests__/script-engine.test.ts +229 -0
- package/src/__tests__/shell-builtins.test.ts +357 -0
- package/src/__tests__/shell-interpreter.test.ts +157 -0
- package/src/__tests__/shell-parser.test.ts +204 -0
- package/src/__tests__/stream.test.ts +142 -0
- package/src/__tests__/syntax-transforms.test.ts +158 -0
- package/src/__tests__/version-resolver.test.ts +184 -0
- package/src/constants/cdn-urls.ts +18 -18
- package/src/helpers/byte-encoding.ts +51 -39
- package/src/index.ts +192 -192
- package/src/memory-volume.ts +968 -941
- package/src/module-transformer.ts +368 -368
- package/src/packages/installer.ts +396 -396
- package/src/packages/version-resolver.ts +12 -2
- package/src/polyfills/buffer.ts +633 -628
- package/src/polyfills/child_process.ts +2288 -2288
- package/src/polyfills/esbuild.ts +854 -854
- package/src/polyfills/events.ts +282 -276
- package/src/polyfills/fs.ts +2888 -2888
- package/src/polyfills/http.ts +1450 -1449
- package/src/polyfills/process.ts +721 -690
- package/src/polyfills/readline.ts +692 -692
- package/src/polyfills/stream.ts +1620 -1620
- package/src/polyfills/tty.ts +71 -71
- package/src/polyfills/wasi.ts +1284 -22
- package/src/request-proxy.ts +716 -716
- package/src/script-engine.ts +465 -146
- package/src/sdk/nodepod.ts +525 -509
- package/src/sdk/types.ts +7 -0
- package/src/syntax-transforms.ts +543 -561
- package/src/threading/offload-worker.ts +383 -383
- package/src/threading/offload.ts +271 -271
- package/src/threading/process-manager.ts +956 -956
- package/src/threading/process-worker-entry.ts +858 -854
- package/src/threading/worker-protocol.ts +1 -1
- package/dist/child_process-B38qoN6R.cjs.map +0 -1
- package/dist/child_process-Dopvyd-E.js.map +0 -1
- package/dist/index--Qr8LVpQ.js.map +0 -1
- package/dist/index-cnitc68U.cjs.map +0 -1
package/src/script-engine.ts
CHANGED
|
@@ -117,10 +117,15 @@ import {
|
|
|
117
117
|
} from "resolve.exports";
|
|
118
118
|
import {
|
|
119
119
|
esmToCjs,
|
|
120
|
-
|
|
120
|
+
collectEsmCjsPatches,
|
|
121
121
|
hasTopLevelAwait,
|
|
122
|
+
stripTopLevelAwait,
|
|
122
123
|
} from "./syntax-transforms";
|
|
123
|
-
import {
|
|
124
|
+
import {
|
|
125
|
+
getCachedModule,
|
|
126
|
+
precompileWasm,
|
|
127
|
+
compileWasmInWorker,
|
|
128
|
+
} from "./helpers/wasm-cache";
|
|
124
129
|
import * as acorn from "acorn";
|
|
125
130
|
|
|
126
131
|
// ── TypeScript type stripper ──
|
|
@@ -223,11 +228,8 @@ function stripTypeScript(source: string): string {
|
|
|
223
228
|
|
|
224
229
|
function isTypeScriptFile(filename: string): boolean {
|
|
225
230
|
const clean = filename.split("?")[0];
|
|
226
|
-
if (
|
|
227
|
-
|
|
228
|
-
clean.endsWith(".tsx") ||
|
|
229
|
-
clean.endsWith(".mts")
|
|
230
|
-
) return true;
|
|
231
|
+
if (clean.endsWith(".ts") || clean.endsWith(".tsx") || clean.endsWith(".mts"))
|
|
232
|
+
return true;
|
|
231
233
|
// Vite SFC query params like ?type=script&lang.ts
|
|
232
234
|
if (filename.includes("lang.ts") || filename.includes("lang=ts")) return true;
|
|
233
235
|
return false;
|
|
@@ -244,9 +246,11 @@ function isCSSFile(filename: string): boolean {
|
|
|
244
246
|
clean.endsWith(".styl") ||
|
|
245
247
|
clean.endsWith(".stylus") ||
|
|
246
248
|
clean.endsWith(".postcss")
|
|
247
|
-
)
|
|
249
|
+
)
|
|
250
|
+
return true;
|
|
248
251
|
if (filename.includes("type=style")) return true;
|
|
249
|
-
if (/lang[.=](?:css|scss|sass|less|styl|stylus|postcss)/.test(filename))
|
|
252
|
+
if (/lang[.=](?:css|scss|sass|less|styl|stylus|postcss)/.test(filename))
|
|
253
|
+
return true;
|
|
250
254
|
return false;
|
|
251
255
|
}
|
|
252
256
|
|
|
@@ -254,7 +258,9 @@ function isCSSFile(filename: string): boolean {
|
|
|
254
258
|
function looksLikeTypeScript(source: string): boolean {
|
|
255
259
|
return (
|
|
256
260
|
/\b(?:interface|type)\s+\w+/.test(source) ||
|
|
257
|
-
/:\s*(?:string|number|boolean|void|any|never|unknown|Record|Array|Promise)\b/.test(
|
|
261
|
+
/:\s*(?:string|number|boolean|void|any|never|unknown|Record|Array|Promise)\b/.test(
|
|
262
|
+
source,
|
|
263
|
+
) ||
|
|
258
264
|
/(?:as\s+(?:string|number|boolean|any|const)\b)/.test(source)
|
|
259
265
|
);
|
|
260
266
|
}
|
|
@@ -263,7 +269,7 @@ function looksLikeTypeScript(source: string): boolean {
|
|
|
263
269
|
function traverseAst(node: any, visitor: (n: any) => void): void {
|
|
264
270
|
if (!node || typeof node !== "object") return;
|
|
265
271
|
if (typeof node.type === "string") visitor(node);
|
|
266
|
-
for (const key
|
|
272
|
+
for (const key in node) {
|
|
267
273
|
if (
|
|
268
274
|
key === "type" ||
|
|
269
275
|
key === "start" ||
|
|
@@ -275,7 +281,8 @@ function traverseAst(node: any, visitor: (n: any) => void): void {
|
|
|
275
281
|
const val = node[key];
|
|
276
282
|
if (val && typeof val === "object") {
|
|
277
283
|
if (Array.isArray(val)) {
|
|
278
|
-
for (
|
|
284
|
+
for (let i = 0; i < val.length; i++) {
|
|
285
|
+
const item = val[i];
|
|
279
286
|
if (item && typeof item === "object" && typeof item.type === "string")
|
|
280
287
|
traverseAst(item, visitor);
|
|
281
288
|
}
|
|
@@ -297,7 +304,12 @@ function convertModuleSyntax(source: string, filePath: string): string {
|
|
|
297
304
|
try {
|
|
298
305
|
return convertViaAst(source, filePath);
|
|
299
306
|
} catch (astErr) {
|
|
300
|
-
_nativeConsole.warn(
|
|
307
|
+
_nativeConsole.warn(
|
|
308
|
+
"[convertModuleSyntax] AST parse failed for",
|
|
309
|
+
filePath,
|
|
310
|
+
"falling back to regex:",
|
|
311
|
+
astErr instanceof Error ? astErr.message : String(astErr),
|
|
312
|
+
);
|
|
301
313
|
return convertViaRegex(source, filePath);
|
|
302
314
|
}
|
|
303
315
|
}
|
|
@@ -309,6 +321,7 @@ function convertViaAst(source: string, filePath: string): string {
|
|
|
309
321
|
}) as any;
|
|
310
322
|
const patches: Array<[number, number, string]> = [];
|
|
311
323
|
|
|
324
|
+
// collect import.meta and import() patches
|
|
312
325
|
traverseAst(ast, (node: any) => {
|
|
313
326
|
if (
|
|
314
327
|
node.type === "MetaProperty" &&
|
|
@@ -327,18 +340,21 @@ function convertViaAst(source: string, filePath: string): string {
|
|
|
327
340
|
);
|
|
328
341
|
const hasExportDecl = ast.body.some((n: any) => n.type?.startsWith("Export"));
|
|
329
342
|
|
|
343
|
+
// collect ESM→CJS patches from the same AST (no second parse)
|
|
344
|
+
if (hasImportDecl || hasExportDecl) {
|
|
345
|
+
collectEsmCjsPatches(ast, source, patches);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// apply all patches in one pass
|
|
330
349
|
let output = source;
|
|
331
|
-
patches.sort((a, b) => b[0] - a[0]);
|
|
350
|
+
patches.sort((a, b) => b[0] - a[0] || b[1] - a[1]);
|
|
332
351
|
for (const [s, e, r] of patches)
|
|
333
352
|
output = output.slice(0, s) + r + output.slice(e);
|
|
334
353
|
|
|
335
|
-
if (
|
|
336
|
-
output =
|
|
337
|
-
|
|
338
|
-
output
|
|
339
|
-
'Object.defineProperty(exports, "__esModule", { value: true });\n' +
|
|
340
|
-
output;
|
|
341
|
-
}
|
|
354
|
+
if (hasExportDecl) {
|
|
355
|
+
output =
|
|
356
|
+
'Object.defineProperty(exports, "__esModule", { value: true });\n' +
|
|
357
|
+
output;
|
|
342
358
|
}
|
|
343
359
|
|
|
344
360
|
// .mjs files with `const require = createRequire(...)` hit TDZ after esmToCjs
|
|
@@ -350,10 +366,7 @@ function convertViaAst(source: string, filePath: string): string {
|
|
|
350
366
|
// Demote `const/let require =` to plain assignment to avoid TDZ with esmToCjs-generated require() calls
|
|
351
367
|
function demoteLexicalRequire(code: string): string {
|
|
352
368
|
if (!/\b(?:const|let)\s+require\s*=/.test(code)) return code;
|
|
353
|
-
return code.replace(
|
|
354
|
-
/\b(const|let)\s+(require)\s*=/g,
|
|
355
|
-
"require =",
|
|
356
|
-
);
|
|
369
|
+
return code.replace(/\b(const|let)\s+(require)\s*=/g, "require =");
|
|
357
370
|
}
|
|
358
371
|
|
|
359
372
|
// Builds the IIFE wrapper that sandboxes user code with shimmed globals
|
|
@@ -626,7 +639,9 @@ function createSyncPromise(): typeof Promise {
|
|
|
626
639
|
res(onRejected(innerErr) as TResult2),
|
|
627
640
|
) as any;
|
|
628
641
|
}
|
|
629
|
-
return new SyncPromise<TResult2>((_, rej) =>
|
|
642
|
+
return new SyncPromise<TResult2>((_, rej) =>
|
|
643
|
+
rej(innerErr),
|
|
644
|
+
) as any;
|
|
630
645
|
}
|
|
631
646
|
return NativePromise.resolve(result).then(null, onRejected) as any;
|
|
632
647
|
}
|
|
@@ -664,8 +679,7 @@ function createSyncPromise(): typeof Promise {
|
|
|
664
679
|
|
|
665
680
|
// instanceof must work for native Promises too since we inject SyncPromise as `Promise`
|
|
666
681
|
Object.defineProperty(SyncPromise, Symbol.hasInstance, {
|
|
667
|
-
value: (instance: any) =>
|
|
668
|
-
instance instanceof NativePromise,
|
|
682
|
+
value: (instance: any) => instance instanceof NativePromise,
|
|
669
683
|
configurable: true,
|
|
670
684
|
});
|
|
671
685
|
|
|
@@ -698,11 +712,13 @@ function createSyncPromise(): typeof Promise {
|
|
|
698
712
|
allSync = false;
|
|
699
713
|
break;
|
|
700
714
|
}
|
|
701
|
-
} else if (
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
715
|
+
} else if (v && typeof v === "object" && typeof v.then === "function") {
|
|
716
|
+
let probed = false,
|
|
717
|
+
pVal: any;
|
|
718
|
+
v.then((x: any) => {
|
|
719
|
+
pVal = x;
|
|
720
|
+
probed = true;
|
|
721
|
+
});
|
|
706
722
|
if (probed) {
|
|
707
723
|
results[i] = pVal;
|
|
708
724
|
} else {
|
|
@@ -736,9 +752,7 @@ function createSyncPromise(): typeof Promise {
|
|
|
736
752
|
allSync = false;
|
|
737
753
|
break;
|
|
738
754
|
}
|
|
739
|
-
} else if (
|
|
740
|
-
v && typeof v === "object" && typeof v.then === "function"
|
|
741
|
-
) {
|
|
755
|
+
} else if (v && typeof v === "object" && typeof v.then === "function") {
|
|
742
756
|
allSync = false;
|
|
743
757
|
break;
|
|
744
758
|
} else {
|
|
@@ -780,9 +794,7 @@ function createSyncPromise(): typeof Promise {
|
|
|
780
794
|
if (v instanceof SyncPromise && (v as any)._syncResolved) {
|
|
781
795
|
return new SyncPromise((res: any) => res((v as any)._syncValue));
|
|
782
796
|
}
|
|
783
|
-
if (
|
|
784
|
-
!(v && typeof v === "object" && typeof v.then === "function")
|
|
785
|
-
) {
|
|
797
|
+
if (!(v && typeof v === "object" && typeof v.then === "function")) {
|
|
786
798
|
return new SyncPromise((res: any) => res(v));
|
|
787
799
|
}
|
|
788
800
|
}
|
|
@@ -824,12 +836,16 @@ function makeDynamicLoader(
|
|
|
824
836
|
) {
|
|
825
837
|
return new SyncThenable(loaded);
|
|
826
838
|
}
|
|
827
|
-
const spread =
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
839
|
+
const spread =
|
|
840
|
+
loaded && (typeof loaded === "object" || typeof loaded === "function")
|
|
841
|
+
? Object.getOwnPropertyNames(loaded as object).reduce(
|
|
842
|
+
(acc, key) => {
|
|
843
|
+
acc[key] = (loaded as any)[key];
|
|
844
|
+
return acc;
|
|
845
|
+
},
|
|
846
|
+
{} as Record<string, unknown>,
|
|
847
|
+
)
|
|
848
|
+
: {};
|
|
833
849
|
return new SyncThenable({
|
|
834
850
|
default: loaded,
|
|
835
851
|
...spread,
|
|
@@ -845,6 +861,7 @@ export interface ModuleRecord {
|
|
|
845
861
|
loaded: boolean;
|
|
846
862
|
children: ModuleRecord[];
|
|
847
863
|
paths: string[];
|
|
864
|
+
parent: ModuleRecord | null;
|
|
848
865
|
}
|
|
849
866
|
|
|
850
867
|
export interface EngineOptions {
|
|
@@ -867,6 +884,7 @@ export interface ResolverFn {
|
|
|
867
884
|
cache: Record<string, ModuleRecord>;
|
|
868
885
|
extensions: Record<string, unknown>;
|
|
869
886
|
main: ModuleRecord | null;
|
|
887
|
+
_ownerRecord?: ModuleRecord;
|
|
870
888
|
}
|
|
871
889
|
|
|
872
890
|
// Mutable copy so packages can monkey-patch frozen polyfill namespaces
|
|
@@ -931,8 +949,8 @@ const CORE_MODULES: Record<string, unknown> = {
|
|
|
931
949
|
sea: seaPolyfill,
|
|
932
950
|
sqlite: sqlitePolyfill,
|
|
933
951
|
quic: quicPolyfill,
|
|
934
|
-
lightningcss: lightningcssPolyfill,
|
|
935
|
-
"@tailwindcss/oxide": tailwindOxidePolyfill,
|
|
952
|
+
// lightningcss: lightningcssPolyfill,
|
|
953
|
+
// "@tailwindcss/oxide": tailwindOxidePolyfill,
|
|
936
954
|
sys: helpersPolyfill,
|
|
937
955
|
"util/types": helpersPolyfill.types,
|
|
938
956
|
"path/posix": pathPolyfill,
|
|
@@ -1100,8 +1118,13 @@ function buildResolver(
|
|
|
1100
1118
|
codeCache?: Map<string, string>,
|
|
1101
1119
|
deAsyncImports = false,
|
|
1102
1120
|
): ResolverFn {
|
|
1103
|
-
|
|
1104
|
-
const
|
|
1121
|
+
// Shared across all resolvers — avoids re-resolving the same paths/manifests per module
|
|
1122
|
+
const resolveCache: Map<string, string | null> =
|
|
1123
|
+
(cache as any).__resolveCache ??
|
|
1124
|
+
((cache as any).__resolveCache = new Map());
|
|
1125
|
+
const manifestCache: Map<string, PackageManifest | null> =
|
|
1126
|
+
(cache as any).__manifestCache ??
|
|
1127
|
+
((cache as any).__manifestCache = new Map());
|
|
1105
1128
|
// Shared across all resolvers — deduplicates same-version packages from nested node_modules
|
|
1106
1129
|
const _pkgIdentityMap: Record<string, string> =
|
|
1107
1130
|
(cache as any).__pkgIdentityMap ?? ((cache as any).__pkgIdentityMap = {});
|
|
@@ -1223,13 +1246,19 @@ function buildResolver(
|
|
|
1223
1246
|
sync: noop,
|
|
1224
1247
|
transform: async (filename: string, code: string, opts?: any) => {
|
|
1225
1248
|
code = applyDefineReplacements(code, opts?.define);
|
|
1226
|
-
if (
|
|
1249
|
+
if (
|
|
1250
|
+
!isCSSFile(filename) &&
|
|
1251
|
+
(isTypeScriptFile(filename) || looksLikeTypeScript(code))
|
|
1252
|
+
)
|
|
1227
1253
|
code = stripTypeScript(code);
|
|
1228
1254
|
return { code, map: null, errors: [], warnings: [] };
|
|
1229
1255
|
},
|
|
1230
1256
|
transformSync: (filename: string, code: string, opts?: any) => {
|
|
1231
1257
|
code = applyDefineReplacements(code, opts?.define);
|
|
1232
|
-
if (
|
|
1258
|
+
if (
|
|
1259
|
+
!isCSSFile(filename) &&
|
|
1260
|
+
(isTypeScriptFile(filename) || looksLikeTypeScript(code))
|
|
1261
|
+
)
|
|
1233
1262
|
code = stripTypeScript(code);
|
|
1234
1263
|
return { code, map: null, errors: [], warnings: [] };
|
|
1235
1264
|
},
|
|
@@ -1239,7 +1268,10 @@ function buildResolver(
|
|
|
1239
1268
|
opts?: any,
|
|
1240
1269
|
) => {
|
|
1241
1270
|
code = applyDefineReplacements(code, opts?.define);
|
|
1242
|
-
if (
|
|
1271
|
+
if (
|
|
1272
|
+
!isCSSFile(filename) &&
|
|
1273
|
+
(isTypeScriptFile(filename) || looksLikeTypeScript(code))
|
|
1274
|
+
)
|
|
1243
1275
|
code = stripTypeScript(code);
|
|
1244
1276
|
return {
|
|
1245
1277
|
code,
|
|
@@ -1256,7 +1288,10 @@ function buildResolver(
|
|
|
1256
1288
|
opts?: any,
|
|
1257
1289
|
) => {
|
|
1258
1290
|
code = applyDefineReplacements(code, opts?.define);
|
|
1259
|
-
if (
|
|
1291
|
+
if (
|
|
1292
|
+
!isCSSFile(filename) &&
|
|
1293
|
+
(isTypeScriptFile(filename) || looksLikeTypeScript(code))
|
|
1294
|
+
)
|
|
1260
1295
|
code = stripTypeScript(code);
|
|
1261
1296
|
return {
|
|
1262
1297
|
code,
|
|
@@ -1292,12 +1327,18 @@ function buildResolver(
|
|
|
1292
1327
|
warnings: [],
|
|
1293
1328
|
}),
|
|
1294
1329
|
moduleRunnerTransform: async (filename: string, code: string) => {
|
|
1295
|
-
if (
|
|
1330
|
+
if (
|
|
1331
|
+
!isCSSFile(filename) &&
|
|
1332
|
+
(isTypeScriptFile(filename) || looksLikeTypeScript(code))
|
|
1333
|
+
)
|
|
1296
1334
|
code = stripTypeScript(code);
|
|
1297
1335
|
return { code, map: null, deps: [], dynamicDeps: [], errors: [] };
|
|
1298
1336
|
},
|
|
1299
1337
|
moduleRunnerTransformSync: (filename: string, code: string) => {
|
|
1300
|
-
if (
|
|
1338
|
+
if (
|
|
1339
|
+
!isCSSFile(filename) &&
|
|
1340
|
+
(isTypeScriptFile(filename) || looksLikeTypeScript(code))
|
|
1341
|
+
)
|
|
1301
1342
|
code = stripTypeScript(code);
|
|
1302
1343
|
return { code, map: null, deps: [], dynamicDeps: [], errors: [] };
|
|
1303
1344
|
},
|
|
@@ -1393,7 +1434,9 @@ function buildResolver(
|
|
|
1393
1434
|
)
|
|
1394
1435
|
specs.push(node.source.value);
|
|
1395
1436
|
}
|
|
1396
|
-
} catch {
|
|
1437
|
+
} catch {
|
|
1438
|
+
/* fallback to regex */
|
|
1439
|
+
}
|
|
1397
1440
|
const dynRe = /\bimport\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
1398
1441
|
let m;
|
|
1399
1442
|
while ((m = dynRe.exec(code)) !== null) specs.push(m[1]);
|
|
@@ -1405,8 +1448,14 @@ function buildResolver(
|
|
|
1405
1448
|
try {
|
|
1406
1449
|
await p.buildStart(mockCtx, {});
|
|
1407
1450
|
} catch (hookErr) {
|
|
1408
|
-
const msg =
|
|
1409
|
-
|
|
1451
|
+
const msg =
|
|
1452
|
+
hookErr instanceof Error
|
|
1453
|
+
? hookErr.message
|
|
1454
|
+
: String(hookErr);
|
|
1455
|
+
_nativeConsole.warn(
|
|
1456
|
+
"[rolldown scan] buildStart hook error:",
|
|
1457
|
+
msg,
|
|
1458
|
+
);
|
|
1410
1459
|
}
|
|
1411
1460
|
}
|
|
1412
1461
|
}
|
|
@@ -1435,8 +1484,15 @@ function buildResolver(
|
|
|
1435
1484
|
if (r && typeof r === "object" && r.code)
|
|
1436
1485
|
return r.code;
|
|
1437
1486
|
} catch (loadErr) {
|
|
1438
|
-
const msg =
|
|
1439
|
-
|
|
1487
|
+
const msg =
|
|
1488
|
+
loadErr instanceof Error
|
|
1489
|
+
? loadErr.message
|
|
1490
|
+
: String(loadErr);
|
|
1491
|
+
_nativeConsole.warn(
|
|
1492
|
+
"[rolldown scan] load hook error:",
|
|
1493
|
+
filePath,
|
|
1494
|
+
msg,
|
|
1495
|
+
);
|
|
1440
1496
|
}
|
|
1441
1497
|
}
|
|
1442
1498
|
}
|
|
@@ -1476,8 +1532,15 @@ function buildResolver(
|
|
|
1476
1532
|
custom: undefined,
|
|
1477
1533
|
});
|
|
1478
1534
|
} catch (resolveErr) {
|
|
1479
|
-
const msg =
|
|
1480
|
-
|
|
1535
|
+
const msg =
|
|
1536
|
+
resolveErr instanceof Error
|
|
1537
|
+
? resolveErr.message
|
|
1538
|
+
: String(resolveErr);
|
|
1539
|
+
_nativeConsole.warn(
|
|
1540
|
+
"[rolldown scan] resolveId hook error:",
|
|
1541
|
+
spec,
|
|
1542
|
+
msg,
|
|
1543
|
+
);
|
|
1481
1544
|
}
|
|
1482
1545
|
}
|
|
1483
1546
|
}
|
|
@@ -1516,14 +1579,24 @@ function buildResolver(
|
|
|
1516
1579
|
try {
|
|
1517
1580
|
await p.buildEnd(mockCtx);
|
|
1518
1581
|
} catch (endErr) {
|
|
1519
|
-
const msg =
|
|
1520
|
-
|
|
1582
|
+
const msg =
|
|
1583
|
+
endErr instanceof Error
|
|
1584
|
+
? endErr.message
|
|
1585
|
+
: String(endErr);
|
|
1586
|
+
_nativeConsole.warn(
|
|
1587
|
+
"[rolldown scan] buildEnd hook error:",
|
|
1588
|
+
msg,
|
|
1589
|
+
);
|
|
1521
1590
|
}
|
|
1522
1591
|
}
|
|
1523
1592
|
}
|
|
1524
1593
|
} catch (scanErr) {
|
|
1525
|
-
const msg =
|
|
1526
|
-
|
|
1594
|
+
const msg =
|
|
1595
|
+
scanErr instanceof Error ? scanErr.message : String(scanErr);
|
|
1596
|
+
const detail =
|
|
1597
|
+
scanErr instanceof Error && scanErr.stack
|
|
1598
|
+
? `\n${scanErr.stack}`
|
|
1599
|
+
: "";
|
|
1527
1600
|
_nativeConsole.warn("[rolldown scan]", msg);
|
|
1528
1601
|
}
|
|
1529
1602
|
}
|
|
@@ -1592,11 +1665,14 @@ function buildResolver(
|
|
|
1592
1665
|
const parts = afterNm.split("/");
|
|
1593
1666
|
const scoped = parts[0].startsWith("@");
|
|
1594
1667
|
const pkgName = scoped ? parts.slice(0, 2).join("/") : parts[0];
|
|
1595
|
-
const pkgRoot =
|
|
1668
|
+
const pkgRoot =
|
|
1669
|
+
origPath.slice(0, nmIdx) + "/node_modules/" + pkgName;
|
|
1596
1670
|
const pkgJsonPath = pkgRoot + "/package.json";
|
|
1597
1671
|
try {
|
|
1598
1672
|
if (!vol.existsSync(pkgJsonPath)) return null;
|
|
1599
|
-
const manifest = JSON.parse(
|
|
1673
|
+
const manifest = JSON.parse(
|
|
1674
|
+
vol.readFileSync(pkgJsonPath, "utf8"),
|
|
1675
|
+
);
|
|
1600
1676
|
for (const conds of [
|
|
1601
1677
|
{ browser: true, import: true },
|
|
1602
1678
|
{ import: true },
|
|
@@ -1605,11 +1681,16 @@ function buildResolver(
|
|
|
1605
1681
|
const resolved = resolveExports(manifest, ".", conds);
|
|
1606
1682
|
if (resolved?.length) {
|
|
1607
1683
|
const full = pathPolyfill.join(pkgRoot, resolved[0]);
|
|
1608
|
-
if (vol.existsSync(full) && full !== origPath)
|
|
1684
|
+
if (vol.existsSync(full) && full !== origPath)
|
|
1685
|
+
return full;
|
|
1609
1686
|
}
|
|
1610
|
-
} catch {
|
|
1687
|
+
} catch {
|
|
1688
|
+
/* try next */
|
|
1689
|
+
}
|
|
1611
1690
|
}
|
|
1612
|
-
} catch {
|
|
1691
|
+
} catch {
|
|
1692
|
+
/* can't re-resolve */
|
|
1693
|
+
}
|
|
1613
1694
|
return null;
|
|
1614
1695
|
};
|
|
1615
1696
|
|
|
@@ -1635,7 +1716,10 @@ function buildResolver(
|
|
|
1635
1716
|
target: "esnext",
|
|
1636
1717
|
logLevel: "warning",
|
|
1637
1718
|
});
|
|
1638
|
-
return
|
|
1719
|
+
return (
|
|
1720
|
+
result.outputFiles?.[0]?.text ??
|
|
1721
|
+
vol.readFileSync(ep, "utf8")
|
|
1722
|
+
);
|
|
1639
1723
|
};
|
|
1640
1724
|
|
|
1641
1725
|
try {
|
|
@@ -1658,8 +1742,15 @@ function buildResolver(
|
|
|
1658
1742
|
}
|
|
1659
1743
|
}
|
|
1660
1744
|
} catch (buildErr) {
|
|
1661
|
-
const buildMsg =
|
|
1662
|
-
|
|
1745
|
+
const buildMsg =
|
|
1746
|
+
buildErr instanceof Error
|
|
1747
|
+
? buildErr.message
|
|
1748
|
+
: String(buildErr);
|
|
1749
|
+
_nativeConsole.warn(
|
|
1750
|
+
"[rolldown bundle] esbuild failed for",
|
|
1751
|
+
entryPath,
|
|
1752
|
+
buildMsg,
|
|
1753
|
+
);
|
|
1663
1754
|
try {
|
|
1664
1755
|
code = vol.readFileSync(entryPath, "utf8");
|
|
1665
1756
|
} catch {
|
|
@@ -1759,10 +1850,13 @@ function buildResolver(
|
|
|
1759
1850
|
if (resolved) {
|
|
1760
1851
|
return { id: resolved + querySuffix };
|
|
1761
1852
|
}
|
|
1762
|
-
} catch (_e) {
|
|
1853
|
+
} catch (_e) {
|
|
1854
|
+
/* not found */
|
|
1855
|
+
}
|
|
1763
1856
|
|
|
1764
1857
|
if (candidate.startsWith("/")) {
|
|
1765
|
-
if (vol.existsSync(candidate))
|
|
1858
|
+
if (vol.existsSync(candidate))
|
|
1859
|
+
return { id: candidate + querySuffix };
|
|
1766
1860
|
const cwd =
|
|
1767
1861
|
(typeof globalThis !== "undefined" &&
|
|
1768
1862
|
(globalThis as any).process?.cwd?.()) ||
|
|
@@ -1771,7 +1865,8 @@ function buildResolver(
|
|
|
1771
1865
|
const abs = cwd + candidate;
|
|
1772
1866
|
if (vol.existsSync(abs)) return { id: abs + querySuffix };
|
|
1773
1867
|
for (const ext of RESOLVE_EXTENSIONS) {
|
|
1774
|
-
if (vol.existsSync(abs + ext))
|
|
1868
|
+
if (vol.existsSync(abs + ext))
|
|
1869
|
+
return { id: abs + ext + querySuffix };
|
|
1775
1870
|
}
|
|
1776
1871
|
}
|
|
1777
1872
|
}
|
|
@@ -2068,7 +2163,9 @@ function buildResolver(
|
|
|
2068
2163
|
const cached = resolveCache.get(cacheKey);
|
|
2069
2164
|
if (cached !== undefined) {
|
|
2070
2165
|
if (cached === null) {
|
|
2071
|
-
const e = new Error(`Cannot find module '${id}'`) as Error & {
|
|
2166
|
+
const e = new Error(`Cannot find module '${id}'`) as Error & {
|
|
2167
|
+
code: string;
|
|
2168
|
+
};
|
|
2072
2169
|
e.code = "MODULE_NOT_FOUND";
|
|
2073
2170
|
throw e;
|
|
2074
2171
|
}
|
|
@@ -2113,7 +2210,9 @@ function buildResolver(
|
|
|
2113
2210
|
}
|
|
2114
2211
|
|
|
2115
2212
|
resolveCache.set(cacheKey, null);
|
|
2116
|
-
const e = new Error(
|
|
2213
|
+
const e = new Error(
|
|
2214
|
+
`Cannot find module '${id}' from '${fromDir}'`,
|
|
2215
|
+
) as Error & { code: string };
|
|
2117
2216
|
e.code = "MODULE_NOT_FOUND";
|
|
2118
2217
|
throw e;
|
|
2119
2218
|
}
|
|
@@ -2162,7 +2261,8 @@ function buildResolver(
|
|
|
2162
2261
|
for (let ai = 0; ai < execArgv.length; ai++) {
|
|
2163
2262
|
const arg = execArgv[ai];
|
|
2164
2263
|
if (arg === "--conditions" || arg === "-C") {
|
|
2165
|
-
if (ai + 1 < execArgv.length)
|
|
2264
|
+
if (ai + 1 < execArgv.length)
|
|
2265
|
+
extraConditions.push(execArgv[++ai]);
|
|
2166
2266
|
} else if (arg.startsWith("--conditions=")) {
|
|
2167
2267
|
extraConditions.push(arg.slice("--conditions=".length));
|
|
2168
2268
|
}
|
|
@@ -2170,9 +2270,8 @@ function buildResolver(
|
|
|
2170
2270
|
const nodeOpts = proc.env?.NODE_OPTIONS || "";
|
|
2171
2271
|
const condMatch = nodeOpts.matchAll(/(?:--conditions[= ]|-C )(\S+)/g);
|
|
2172
2272
|
for (const m of condMatch) extraConditions.push(m[1]);
|
|
2173
|
-
const condExtra =
|
|
2174
|
-
? { conditions: extraConditions }
|
|
2175
|
-
: {};
|
|
2273
|
+
const condExtra =
|
|
2274
|
+
extraConditions.length > 0 ? { conditions: extraConditions } : {};
|
|
2176
2275
|
|
|
2177
2276
|
const baseSets: Record<string, unknown>[] = preferEsm
|
|
2178
2277
|
? [
|
|
@@ -2264,12 +2363,17 @@ function buildResolver(
|
|
|
2264
2363
|
}
|
|
2265
2364
|
|
|
2266
2365
|
resolveCache.set(cacheKey, null);
|
|
2267
|
-
const e = new Error(
|
|
2366
|
+
const e = new Error(
|
|
2367
|
+
`Cannot find module '${id}' from '${fromDir}'`,
|
|
2368
|
+
) as Error & { code: string };
|
|
2268
2369
|
e.code = "MODULE_NOT_FOUND";
|
|
2269
2370
|
throw e;
|
|
2270
2371
|
};
|
|
2271
2372
|
|
|
2272
|
-
const loadModule = (
|
|
2373
|
+
const loadModule = (
|
|
2374
|
+
resolved: string,
|
|
2375
|
+
parentRecord?: ModuleRecord,
|
|
2376
|
+
): ModuleRecord => {
|
|
2273
2377
|
if (cache[resolved]) return cache[resolved];
|
|
2274
2378
|
|
|
2275
2379
|
// Package dedup: reuse first instance of name@version:path to prevent
|
|
@@ -2278,12 +2382,17 @@ function buildResolver(
|
|
|
2278
2382
|
if (nmIdx !== -1) {
|
|
2279
2383
|
const afterNm = resolved.slice(nmIdx + "/node_modules/".length);
|
|
2280
2384
|
const parts = afterNm.split("/");
|
|
2281
|
-
const pkgName = parts[0].startsWith("@")
|
|
2385
|
+
const pkgName = parts[0].startsWith("@")
|
|
2386
|
+
? parts[0] + "/" + parts[1]
|
|
2387
|
+
: parts[0];
|
|
2282
2388
|
const pkgDir = resolved.slice(0, nmIdx) + "/node_modules/" + pkgName;
|
|
2283
2389
|
try {
|
|
2284
|
-
const pkgJson = JSON.parse(
|
|
2390
|
+
const pkgJson = JSON.parse(
|
|
2391
|
+
vol.readFileSync(pkgDir + "/package.json", "utf8"),
|
|
2392
|
+
);
|
|
2285
2393
|
// Include file path so different subpath exports (svelte vs svelte/compiler) aren't deduped
|
|
2286
|
-
const identity =
|
|
2394
|
+
const identity =
|
|
2395
|
+
pkgName + "@" + (pkgJson.version || "0.0.0") + ":" + afterNm;
|
|
2287
2396
|
if (!_pkgIdentityMap[identity]) {
|
|
2288
2397
|
_pkgIdentityMap[identity] = resolved;
|
|
2289
2398
|
} else if (_pkgIdentityMap[identity] !== resolved) {
|
|
@@ -2294,7 +2403,9 @@ function buildResolver(
|
|
|
2294
2403
|
return cache[canonical];
|
|
2295
2404
|
}
|
|
2296
2405
|
}
|
|
2297
|
-
} catch {
|
|
2406
|
+
} catch {
|
|
2407
|
+
/* no package.json */
|
|
2408
|
+
}
|
|
2298
2409
|
}
|
|
2299
2410
|
|
|
2300
2411
|
const _loadDepth = ((globalThis as any).__loadModuleDepth ?? 0) + 1;
|
|
@@ -2307,7 +2418,9 @@ function buildResolver(
|
|
|
2307
2418
|
loaded: false,
|
|
2308
2419
|
children: [],
|
|
2309
2420
|
paths: [],
|
|
2421
|
+
parent: parentRecord ?? null,
|
|
2310
2422
|
};
|
|
2423
|
+
if (parentRecord) parentRecord.children.push(record);
|
|
2311
2424
|
|
|
2312
2425
|
cache[resolved] = record;
|
|
2313
2426
|
|
|
@@ -2321,11 +2434,15 @@ function buildResolver(
|
|
|
2321
2434
|
return record;
|
|
2322
2435
|
}
|
|
2323
2436
|
|
|
2324
|
-
// Native addons
|
|
2437
|
+
// Native .node addons cannot run in the browser — throw so that
|
|
2438
|
+
// callers (e.g. napi-rs packages) fall back to their WASM build.
|
|
2325
2439
|
if (resolved.endsWith(".node")) {
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2440
|
+
delete cache[resolved];
|
|
2441
|
+
const e = new Error(
|
|
2442
|
+
`Cannot load native addon '${resolved}' — native .node binaries are not supported in the browser`,
|
|
2443
|
+
) as Error & { code: string };
|
|
2444
|
+
e.code = "ERR_DLOPEN_FAILED";
|
|
2445
|
+
throw e;
|
|
2329
2446
|
}
|
|
2330
2447
|
|
|
2331
2448
|
const rawSource = vol.readFileSync(resolved, "utf8");
|
|
@@ -2353,12 +2470,19 @@ function buildResolver(
|
|
|
2353
2470
|
const cjsPatches: Array<[number, number, string]> = [];
|
|
2354
2471
|
const walkCjs = (node: any) => {
|
|
2355
2472
|
if (!node || typeof node !== "object") return;
|
|
2356
|
-
if (Array.isArray(node)) {
|
|
2473
|
+
if (Array.isArray(node)) {
|
|
2474
|
+
for (const c of node) walkCjs(c);
|
|
2475
|
+
return;
|
|
2476
|
+
}
|
|
2357
2477
|
if (typeof node.type !== "string") return;
|
|
2358
2478
|
if (node.type === "ImportExpression") {
|
|
2359
2479
|
cjsPatches.push([node.start, node.start + 6, "__asyncLoad"]);
|
|
2360
2480
|
}
|
|
2361
|
-
if (
|
|
2481
|
+
if (
|
|
2482
|
+
node.type === "MetaProperty" &&
|
|
2483
|
+
node.meta?.name === "import" &&
|
|
2484
|
+
node.property?.name === "meta"
|
|
2485
|
+
) {
|
|
2362
2486
|
cjsPatches.push([
|
|
2363
2487
|
node.start,
|
|
2364
2488
|
node.end,
|
|
@@ -2373,22 +2497,31 @@ function buildResolver(
|
|
|
2373
2497
|
};
|
|
2374
2498
|
walkCjs(cjsAst);
|
|
2375
2499
|
if (cjsPatches.length > 0) {
|
|
2376
|
-
cjsPatches.sort((a, b) => b[0] - a[0]);
|
|
2500
|
+
cjsPatches.sort((a, b) => b[0] - a[0] || b[1] - a[1]);
|
|
2377
2501
|
for (const [start, end, replacement] of cjsPatches) {
|
|
2378
|
-
processedCode =
|
|
2502
|
+
processedCode =
|
|
2503
|
+
processedCode.slice(0, start) +
|
|
2504
|
+
replacement +
|
|
2505
|
+
processedCode.slice(end);
|
|
2379
2506
|
}
|
|
2380
2507
|
}
|
|
2381
|
-
} catch {
|
|
2508
|
+
} catch {
|
|
2509
|
+
/* can't parse — leave untransformed */
|
|
2510
|
+
}
|
|
2382
2511
|
} else {
|
|
2383
2512
|
processedCode = convertModuleSyntax(processedCode, resolved);
|
|
2384
2513
|
}
|
|
2385
2514
|
codeCache?.set(codeCacheKey, processedCode);
|
|
2386
2515
|
}
|
|
2387
2516
|
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
const moduleHasTLA = resolved.endsWith(".cjs") ? false : hasTopLevelAwait(processedCode);
|
|
2517
|
+
const isCjs = resolved.endsWith(".cjs");
|
|
2518
|
+
const moduleHasTLA = !isCjs && hasTopLevelAwait(processedCode);
|
|
2391
2519
|
const useFullDeAsync = deAsyncImports || moduleHasTLA;
|
|
2520
|
+
if (!isCjs)
|
|
2521
|
+
processedCode = stripTopLevelAwait(
|
|
2522
|
+
processedCode,
|
|
2523
|
+
deAsyncImports ? "full" : "topLevelOnly",
|
|
2524
|
+
);
|
|
2392
2525
|
|
|
2393
2526
|
const childResolver = buildResolver(
|
|
2394
2527
|
vol,
|
|
@@ -2401,18 +2534,12 @@ function buildResolver(
|
|
|
2401
2534
|
useFullDeAsync,
|
|
2402
2535
|
);
|
|
2403
2536
|
childResolver.cache = cache;
|
|
2537
|
+
childResolver._ownerRecord = record;
|
|
2404
2538
|
|
|
2405
2539
|
const wrappedConsole = wrapConsole(opts.onConsole);
|
|
2406
2540
|
|
|
2407
2541
|
try {
|
|
2408
2542
|
const metaUrl = "file://" + resolved;
|
|
2409
|
-
// CJS files: skip — would corrupt await inside async functions
|
|
2410
|
-
if (!resolved.endsWith(".cjs")) {
|
|
2411
|
-
processedCode = stripTopLevelAwait(
|
|
2412
|
-
processedCode,
|
|
2413
|
-
useFullDeAsync ? "full" : "topLevelOnly",
|
|
2414
|
-
);
|
|
2415
|
-
}
|
|
2416
2543
|
const wrapper = buildModuleWrapper(processedCode);
|
|
2417
2544
|
|
|
2418
2545
|
let fn;
|
|
@@ -2425,7 +2552,9 @@ function buildResolver(
|
|
|
2425
2552
|
}
|
|
2426
2553
|
|
|
2427
2554
|
{
|
|
2428
|
-
const srcMap =
|
|
2555
|
+
const srcMap =
|
|
2556
|
+
(globalThis as any).__dbgSrcMap ||
|
|
2557
|
+
((globalThis as any).__dbgSrcMap = new Map());
|
|
2429
2558
|
srcMap.set(resolved, wrapper);
|
|
2430
2559
|
}
|
|
2431
2560
|
|
|
@@ -2514,7 +2643,7 @@ function buildResolver(
|
|
|
2514
2643
|
if (typeof id !== "string") {
|
|
2515
2644
|
// Match real Node.js error: TypeError with ERR_INVALID_ARG_TYPE code
|
|
2516
2645
|
const err: any = new TypeError(
|
|
2517
|
-
`The "id" argument must be of type string. Received ${id === null ? "null" : typeof id}
|
|
2646
|
+
`The "id" argument must be of type string. Received ${id === null ? "null" : typeof id}`,
|
|
2518
2647
|
);
|
|
2519
2648
|
err.code = "ERR_INVALID_ARG_TYPE";
|
|
2520
2649
|
throw err;
|
|
@@ -2528,7 +2657,11 @@ function buildResolver(
|
|
|
2528
2657
|
if (id === "worker_threads") {
|
|
2529
2658
|
if (opts.workerThreadsOverride) {
|
|
2530
2659
|
const base = CORE_MODULES["worker_threads"];
|
|
2531
|
-
const override = Object.assign(
|
|
2660
|
+
const override = Object.assign(
|
|
2661
|
+
Object.create(null),
|
|
2662
|
+
base,
|
|
2663
|
+
opts.workerThreadsOverride,
|
|
2664
|
+
);
|
|
2532
2665
|
override.default = override;
|
|
2533
2666
|
return override;
|
|
2534
2667
|
}
|
|
@@ -2551,7 +2684,16 @@ function buildResolver(
|
|
|
2551
2684
|
fromPath = fromPath.slice(1);
|
|
2552
2685
|
}
|
|
2553
2686
|
const childDir = pathPolyfill.dirname(fromPath);
|
|
2554
|
-
const child = buildResolver(
|
|
2687
|
+
const child = buildResolver(
|
|
2688
|
+
vol,
|
|
2689
|
+
fsBridge,
|
|
2690
|
+
proc,
|
|
2691
|
+
childDir,
|
|
2692
|
+
cache,
|
|
2693
|
+
opts,
|
|
2694
|
+
codeCache,
|
|
2695
|
+
deAsyncImports,
|
|
2696
|
+
);
|
|
2555
2697
|
child.cache = cache;
|
|
2556
2698
|
return child;
|
|
2557
2699
|
};
|
|
@@ -2565,9 +2707,7 @@ function buildResolver(
|
|
|
2565
2707
|
options?: any,
|
|
2566
2708
|
) => {
|
|
2567
2709
|
if (typeof request !== "string") {
|
|
2568
|
-
const err: any = new Error(
|
|
2569
|
-
`Cannot find module '${request}'`,
|
|
2570
|
-
);
|
|
2710
|
+
const err: any = new Error(`Cannot find module '${request}'`);
|
|
2571
2711
|
err.code = "MODULE_NOT_FOUND";
|
|
2572
2712
|
throw err;
|
|
2573
2713
|
}
|
|
@@ -2598,14 +2738,16 @@ function buildResolver(
|
|
|
2598
2738
|
try {
|
|
2599
2739
|
return resolveId(request, fromDir);
|
|
2600
2740
|
} catch {
|
|
2601
|
-
const err: any = new Error(
|
|
2602
|
-
`Cannot find module '${request}'`,
|
|
2603
|
-
);
|
|
2741
|
+
const err: any = new Error(`Cannot find module '${request}'`);
|
|
2604
2742
|
err.code = "MODULE_NOT_FOUND";
|
|
2605
2743
|
throw err;
|
|
2606
2744
|
}
|
|
2607
2745
|
};
|
|
2608
|
-
PerEngineModule._load = (
|
|
2746
|
+
PerEngineModule._load = (
|
|
2747
|
+
request: string,
|
|
2748
|
+
parent?: any,
|
|
2749
|
+
isMain?: boolean,
|
|
2750
|
+
) => {
|
|
2609
2751
|
try {
|
|
2610
2752
|
return resolver(request);
|
|
2611
2753
|
} catch {
|
|
@@ -2633,10 +2775,81 @@ function buildResolver(
|
|
|
2633
2775
|
}
|
|
2634
2776
|
if (CORE_MODULES[id]) return CORE_MODULES[id];
|
|
2635
2777
|
|
|
2636
|
-
|
|
2778
|
+
let resolved: string;
|
|
2779
|
+
try {
|
|
2780
|
+
resolved = resolveId(id, baseDir);
|
|
2781
|
+
} catch (resolveErr: any) {
|
|
2782
|
+
if (
|
|
2783
|
+
resolveErr?.code === "MODULE_NOT_FOUND" &&
|
|
2784
|
+
!id.startsWith("./") &&
|
|
2785
|
+
!id.startsWith("../")
|
|
2786
|
+
) {
|
|
2787
|
+
// --- Determine WASM alternative package name(s) to try ---
|
|
2788
|
+
const wasmAlts: string[] = [];
|
|
2789
|
+
|
|
2790
|
+
if (id.includes("wasm32-wasi")) {
|
|
2791
|
+
// Explicit wasm32-wasi package — auto-install as-is
|
|
2792
|
+
wasmAlts.push(id);
|
|
2793
|
+
} else {
|
|
2794
|
+
// Platform-specific native package pattern:
|
|
2795
|
+
// {name}-{platform}-{arch}[-{abi}]
|
|
2796
|
+
// e.g. lightningcss-linux-x64-gnu, @pkg/core-darwin-arm64
|
|
2797
|
+
const platformRe =
|
|
2798
|
+
/^(.+)-(darwin|linux|win32|freebsd|android|sunos)-(x64|x86|arm64|arm|ia32|s390x|ppc64|mips64el|riscv64)(-[a-z]+)?$/;
|
|
2799
|
+
const m = id.match(platformRe);
|
|
2800
|
+
if (m) {
|
|
2801
|
+
const baseName = m[1]; // e.g. "lightningcss" or "@scope/pkg"
|
|
2802
|
+
wasmAlts.push(baseName + "-wasm32-wasi");
|
|
2803
|
+
wasmAlts.push(baseName + "-wasm");
|
|
2804
|
+
}
|
|
2805
|
+
}
|
|
2806
|
+
|
|
2807
|
+
// Try resolving any of the WASM alternatives (already installed)
|
|
2808
|
+
for (const alt of wasmAlts) {
|
|
2809
|
+
resolveCache.delete(`${baseDir}|${alt}`);
|
|
2810
|
+
try {
|
|
2811
|
+
const altResolved = resolveId(alt, baseDir);
|
|
2812
|
+
const altRec = loadModule(altResolved, resolver._ownerRecord);
|
|
2813
|
+
return altRec.exports;
|
|
2814
|
+
} catch {
|
|
2815
|
+
// not installed yet
|
|
2816
|
+
}
|
|
2817
|
+
}
|
|
2818
|
+
|
|
2819
|
+
}
|
|
2820
|
+
throw resolveErr;
|
|
2821
|
+
}
|
|
2637
2822
|
if (CORE_MODULES[resolved]) return CORE_MODULES[resolved];
|
|
2638
2823
|
|
|
2639
|
-
|
|
2824
|
+
let rec: ModuleRecord;
|
|
2825
|
+
try {
|
|
2826
|
+
rec = loadModule(resolved, resolver._ownerRecord);
|
|
2827
|
+
} catch (loadErr: any) {
|
|
2828
|
+
// When a bare module fails to load (e.g. native binding not found inside
|
|
2829
|
+
// the module), try a WASM drop-in replacement: {name}-wasm or {name}-wasm32-wasi
|
|
2830
|
+
if (
|
|
2831
|
+
!id.startsWith("./") &&
|
|
2832
|
+
!id.startsWith("../") &&
|
|
2833
|
+
!id.startsWith("/") &&
|
|
2834
|
+
(loadErr?.code === "MODULE_NOT_FOUND" ||
|
|
2835
|
+
loadErr?.code === "ERR_DLOPEN_FAILED" ||
|
|
2836
|
+
(loadErr?.message &&
|
|
2837
|
+
/cannot\s+(find|load)\s+(module|native)/i.test(loadErr.message)))
|
|
2838
|
+
) {
|
|
2839
|
+
const wasmAlts = [id + "-wasm32-wasi", id + "-wasm"];
|
|
2840
|
+
for (const alt of wasmAlts) {
|
|
2841
|
+
try {
|
|
2842
|
+
resolveCache.delete(`${baseDir}|${alt}`);
|
|
2843
|
+
const altResolved = resolveId(alt, baseDir);
|
|
2844
|
+
const altRec = loadModule(altResolved, resolver._ownerRecord);
|
|
2845
|
+
return altRec.exports;
|
|
2846
|
+
} catch {
|
|
2847
|
+
// not available
|
|
2848
|
+
}
|
|
2849
|
+
}
|
|
2850
|
+
}
|
|
2851
|
+
throw loadErr;
|
|
2852
|
+
}
|
|
2640
2853
|
// Proxy for async WASM — reads from rec.exports at access time so
|
|
2641
2854
|
// reassigned module.exports is picked up after compilation finishes
|
|
2642
2855
|
if ((rec as any).__wasmReady) {
|
|
@@ -2728,6 +2941,62 @@ export class ScriptEngine {
|
|
|
2728
2941
|
|
|
2729
2942
|
(globalThis as any).__nodepodVolume = vol;
|
|
2730
2943
|
|
|
2944
|
+
// Intercept fetch() for file:// URLs — serve from VFS instead of network.
|
|
2945
|
+
// napi-rs wasm32-wasi packages use fetch(new URL('file.wasm', import.meta.url))
|
|
2946
|
+
// which browsers block. This patches fetch to read from the in-memory filesystem.
|
|
2947
|
+
if (!(globalThis.fetch as any).__nodepodPatched) {
|
|
2948
|
+
const origFetch = globalThis.fetch.bind(globalThis);
|
|
2949
|
+
const patchedFetch = (
|
|
2950
|
+
input: RequestInfo | URL,
|
|
2951
|
+
init?: RequestInit,
|
|
2952
|
+
): Promise<Response> => {
|
|
2953
|
+
let url: string | undefined;
|
|
2954
|
+
if (typeof input === "string") url = input;
|
|
2955
|
+
else if (input instanceof URL) url = input.href;
|
|
2956
|
+
else if (input instanceof Request) url = input.url;
|
|
2957
|
+
|
|
2958
|
+
if (url?.startsWith("file://")) {
|
|
2959
|
+
// Convert file:// URL to VFS path
|
|
2960
|
+
let vfsPath: string;
|
|
2961
|
+
try {
|
|
2962
|
+
vfsPath = decodeURIComponent(new URL(url).pathname);
|
|
2963
|
+
} catch {
|
|
2964
|
+
vfsPath = decodeURIComponent(url.slice(7));
|
|
2965
|
+
}
|
|
2966
|
+
const v = (globalThis as any).__nodepodVolume as MemoryVolume | undefined;
|
|
2967
|
+
if (v) {
|
|
2968
|
+
try {
|
|
2969
|
+
const data = v.readFileSync(vfsPath);
|
|
2970
|
+
const bytes =
|
|
2971
|
+
data instanceof Uint8Array
|
|
2972
|
+
? data
|
|
2973
|
+
: new TextEncoder().encode(String(data));
|
|
2974
|
+
const contentType = vfsPath.endsWith(".wasm")
|
|
2975
|
+
? "application/wasm"
|
|
2976
|
+
: "application/octet-stream";
|
|
2977
|
+
return Promise.resolve(
|
|
2978
|
+
new Response(bytes.buffer.slice(
|
|
2979
|
+
bytes.byteOffset,
|
|
2980
|
+
bytes.byteOffset + bytes.byteLength,
|
|
2981
|
+
) as ArrayBuffer, {
|
|
2982
|
+
status: 200,
|
|
2983
|
+
headers: { "Content-Type": contentType },
|
|
2984
|
+
}),
|
|
2985
|
+
);
|
|
2986
|
+
} catch {
|
|
2987
|
+
return Promise.resolve(
|
|
2988
|
+
new Response("Not found", { status: 404 }),
|
|
2989
|
+
);
|
|
2990
|
+
}
|
|
2991
|
+
}
|
|
2992
|
+
}
|
|
2993
|
+
return origFetch(input, init);
|
|
2994
|
+
};
|
|
2995
|
+
(globalThis as any).fetch = Object.assign(patchedFetch, {
|
|
2996
|
+
__nodepodPatched: true,
|
|
2997
|
+
});
|
|
2998
|
+
}
|
|
2999
|
+
|
|
2731
3000
|
if (typeof globalThis.setImmediate === "undefined") {
|
|
2732
3001
|
(globalThis as any).setImmediate = (
|
|
2733
3002
|
fn: (...a: unknown[]) => void,
|
|
@@ -2759,7 +3028,9 @@ export class ScriptEngine {
|
|
|
2759
3028
|
const cached2 = getCachedModule(bytes);
|
|
2760
3029
|
if (cached2) return cached2;
|
|
2761
3030
|
const compilePromise = compileWasmInWorker(
|
|
2762
|
-
bytes instanceof ArrayBuffer
|
|
3031
|
+
bytes instanceof ArrayBuffer
|
|
3032
|
+
? new Uint8Array(bytes)
|
|
3033
|
+
: (bytes as Uint8Array),
|
|
2763
3034
|
);
|
|
2764
3035
|
(globalThis as any).__wasmCompilePromise = compilePromise;
|
|
2765
3036
|
}
|
|
@@ -2786,11 +3057,23 @@ export class ScriptEngine {
|
|
|
2786
3057
|
const obj = {
|
|
2787
3058
|
_id: id,
|
|
2788
3059
|
_ref: true,
|
|
2789
|
-
ref() {
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
3060
|
+
ref() {
|
|
3061
|
+
obj._ref = true;
|
|
3062
|
+
return obj;
|
|
3063
|
+
},
|
|
3064
|
+
unref() {
|
|
3065
|
+
obj._ref = false;
|
|
3066
|
+
return obj;
|
|
3067
|
+
},
|
|
3068
|
+
hasRef() {
|
|
3069
|
+
return obj._ref;
|
|
3070
|
+
},
|
|
3071
|
+
refresh() {
|
|
3072
|
+
return obj;
|
|
3073
|
+
},
|
|
3074
|
+
[Symbol.toPrimitive]() {
|
|
3075
|
+
return id;
|
|
3076
|
+
},
|
|
2794
3077
|
};
|
|
2795
3078
|
return obj;
|
|
2796
3079
|
};
|
|
@@ -2799,11 +3082,23 @@ export class ScriptEngine {
|
|
|
2799
3082
|
const obj = {
|
|
2800
3083
|
_id: id,
|
|
2801
3084
|
_ref: true,
|
|
2802
|
-
ref() {
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
3085
|
+
ref() {
|
|
3086
|
+
obj._ref = true;
|
|
3087
|
+
return obj;
|
|
3088
|
+
},
|
|
3089
|
+
unref() {
|
|
3090
|
+
obj._ref = false;
|
|
3091
|
+
return obj;
|
|
3092
|
+
},
|
|
3093
|
+
hasRef() {
|
|
3094
|
+
return obj._ref;
|
|
3095
|
+
},
|
|
3096
|
+
refresh() {
|
|
3097
|
+
return obj;
|
|
3098
|
+
},
|
|
3099
|
+
[Symbol.toPrimitive]() {
|
|
3100
|
+
return id;
|
|
3101
|
+
},
|
|
2807
3102
|
};
|
|
2808
3103
|
return obj;
|
|
2809
3104
|
};
|
|
@@ -3045,7 +3340,14 @@ export class ScriptEngine {
|
|
|
3045
3340
|
filename: string = "/index.js",
|
|
3046
3341
|
): { exports: unknown; module: ModuleRecord } {
|
|
3047
3342
|
const dir = pathPolyfill.dirname(filename);
|
|
3048
|
-
|
|
3343
|
+
// Only write when the content differs to avoid triggering file watchers
|
|
3344
|
+
// (e.g. nodemon/chokidar) with a no-op write that causes restart loops.
|
|
3345
|
+
try {
|
|
3346
|
+
const existing = this.vol.readFileSync(filename, "utf8");
|
|
3347
|
+
if (existing !== code) this.vol.writeFileSync(filename, code);
|
|
3348
|
+
} catch {
|
|
3349
|
+
this.vol.writeFileSync(filename, code);
|
|
3350
|
+
}
|
|
3049
3351
|
|
|
3050
3352
|
const mod: ModuleRecord = {
|
|
3051
3353
|
id: filename,
|
|
@@ -3054,6 +3356,7 @@ export class ScriptEngine {
|
|
|
3054
3356
|
loaded: false,
|
|
3055
3357
|
children: [],
|
|
3056
3358
|
paths: [],
|
|
3359
|
+
parent: null,
|
|
3057
3360
|
};
|
|
3058
3361
|
this.moduleRegistry[filename] = mod;
|
|
3059
3362
|
|
|
@@ -3075,12 +3378,19 @@ export class ScriptEngine {
|
|
|
3075
3378
|
const cjsPatches: Array<[number, number, string]> = [];
|
|
3076
3379
|
const walkCjs = (node: any) => {
|
|
3077
3380
|
if (!node || typeof node !== "object") return;
|
|
3078
|
-
if (Array.isArray(node)) {
|
|
3381
|
+
if (Array.isArray(node)) {
|
|
3382
|
+
for (const c of node) walkCjs(c);
|
|
3383
|
+
return;
|
|
3384
|
+
}
|
|
3079
3385
|
if (typeof node.type !== "string") return;
|
|
3080
3386
|
if (node.type === "ImportExpression") {
|
|
3081
3387
|
cjsPatches.push([node.start, node.start + 6, "__asyncLoad"]);
|
|
3082
3388
|
}
|
|
3083
|
-
if (
|
|
3389
|
+
if (
|
|
3390
|
+
node.type === "MetaProperty" &&
|
|
3391
|
+
node.meta?.name === "import" &&
|
|
3392
|
+
node.property?.name === "meta"
|
|
3393
|
+
) {
|
|
3084
3394
|
cjsPatches.push([
|
|
3085
3395
|
node.start,
|
|
3086
3396
|
node.end,
|
|
@@ -3097,15 +3407,21 @@ export class ScriptEngine {
|
|
|
3097
3407
|
if (cjsPatches.length > 0) {
|
|
3098
3408
|
cjsPatches.sort((a, b) => b[0] - a[0]);
|
|
3099
3409
|
for (const [start, end, replacement] of cjsPatches) {
|
|
3100
|
-
processed =
|
|
3410
|
+
processed =
|
|
3411
|
+
processed.slice(0, start) + replacement + processed.slice(end);
|
|
3101
3412
|
}
|
|
3102
3413
|
}
|
|
3103
|
-
} catch {
|
|
3414
|
+
} catch {
|
|
3415
|
+
/* can't parse */
|
|
3416
|
+
}
|
|
3104
3417
|
} else {
|
|
3105
3418
|
processed = convertModuleSyntax(processed, filename);
|
|
3106
3419
|
}
|
|
3107
3420
|
|
|
3108
|
-
const
|
|
3421
|
+
const isCjs = filename.endsWith(".cjs");
|
|
3422
|
+
const fileHasTLA = !isCjs && hasTopLevelAwait(processed);
|
|
3423
|
+
if (!isCjs) processed = stripTopLevelAwait(processed);
|
|
3424
|
+
|
|
3109
3425
|
const resolver = buildResolver(
|
|
3110
3426
|
this.vol,
|
|
3111
3427
|
this.fsBridge,
|
|
@@ -3116,15 +3432,10 @@ export class ScriptEngine {
|
|
|
3116
3432
|
this.transformCache,
|
|
3117
3433
|
fileHasTLA,
|
|
3118
3434
|
);
|
|
3435
|
+
resolver._ownerRecord = mod;
|
|
3119
3436
|
|
|
3120
3437
|
try {
|
|
3121
3438
|
const metaUrl = "file://" + filename;
|
|
3122
|
-
if (!filename.endsWith(".cjs")) {
|
|
3123
|
-
processed = stripTopLevelAwait(
|
|
3124
|
-
processed,
|
|
3125
|
-
fileHasTLA ? "full" : "topLevelOnly",
|
|
3126
|
-
);
|
|
3127
|
-
}
|
|
3128
3439
|
const wrapper = buildModuleWrapper(processed);
|
|
3129
3440
|
|
|
3130
3441
|
const asyncLoader = makeDynamicLoader(resolver);
|
|
@@ -3180,7 +3491,8 @@ export class ScriptEngine {
|
|
|
3180
3491
|
): Promise<{ exports: unknown; module: ModuleRecord }> {
|
|
3181
3492
|
const source = this.vol.readFileSync(filename, "utf8");
|
|
3182
3493
|
const dir = pathPolyfill.dirname(filename);
|
|
3183
|
-
|
|
3494
|
+
// No need to write — source was just read from the same volume.
|
|
3495
|
+
// Writing it back triggers file watchers (nodemon restart loops).
|
|
3184
3496
|
|
|
3185
3497
|
const mod: ModuleRecord = {
|
|
3186
3498
|
id: filename,
|
|
@@ -3189,6 +3501,7 @@ export class ScriptEngine {
|
|
|
3189
3501
|
loaded: false,
|
|
3190
3502
|
children: [],
|
|
3191
3503
|
paths: [],
|
|
3504
|
+
parent: null,
|
|
3192
3505
|
};
|
|
3193
3506
|
this.moduleRegistry[filename] = mod;
|
|
3194
3507
|
|
|
@@ -3214,6 +3527,7 @@ export class ScriptEngine {
|
|
|
3214
3527
|
processed = convertModuleSyntax(processed, filename);
|
|
3215
3528
|
}
|
|
3216
3529
|
const tla = hasTopLevelAwait(processed);
|
|
3530
|
+
const tlaStripped = stripTopLevelAwait(processed);
|
|
3217
3531
|
|
|
3218
3532
|
// Don't propagate deAsyncImports from entry — it uses native await (async IIFE),
|
|
3219
3533
|
// so deps don't need de-async. loadModule handles individual TLA modules.
|
|
@@ -3227,10 +3541,11 @@ export class ScriptEngine {
|
|
|
3227
3541
|
this.transformCache,
|
|
3228
3542
|
false,
|
|
3229
3543
|
);
|
|
3544
|
+
resolver._ownerRecord = mod;
|
|
3230
3545
|
|
|
3231
3546
|
if (!tla) {
|
|
3232
3547
|
try {
|
|
3233
|
-
processed =
|
|
3548
|
+
processed = tlaStripped;
|
|
3234
3549
|
const wrapper = buildModuleWrapper(processed);
|
|
3235
3550
|
const asyncLoader = makeDynamicLoader(resolver);
|
|
3236
3551
|
const fn = (0, eval)(wrapper);
|
|
@@ -3289,6 +3604,10 @@ export class ScriptEngine {
|
|
|
3289
3604
|
clearCache(): void {
|
|
3290
3605
|
for (const k of Object.keys(this.moduleRegistry))
|
|
3291
3606
|
delete this.moduleRegistry[k];
|
|
3607
|
+
// Also clear shared resolver/manifest caches
|
|
3608
|
+
(this.moduleRegistry as any).__resolveCache?.clear();
|
|
3609
|
+
(this.moduleRegistry as any).__manifestCache?.clear();
|
|
3610
|
+
delete (this.moduleRegistry as any).__pkgIdentityMap;
|
|
3292
3611
|
}
|
|
3293
3612
|
|
|
3294
3613
|
getVolume(): MemoryVolume {
|