@statewalker/webrun-bundler 0.1.0 → 0.1.1
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/README.md +13 -1
- package/dist/index.d.mts +1 -24
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +66 -7
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/bundle.test.ts +71 -0
- package/src/bundle.ts +55 -9
- package/src/input-maps.ts +11 -0
- package/src/types.ts +1 -1
package/README.md
CHANGED
|
@@ -85,7 +85,7 @@ const { code, map } = await transpile(source, { esbuild, path: "~/src/f.ts", low
|
|
|
85
85
|
| `lowerAwait` | `false` | lower `async`/`await`, async generators and `for await` to generators |
|
|
86
86
|
| `minify`, `define` | | as in esbuild |
|
|
87
87
|
| `outfile` | `bundle.js` | the name the map link uses (`<outfile>.map`) |
|
|
88
|
-
| `sourcemap` | `external` | `inline` also puts the map in `code` |
|
|
88
|
+
| `sourcemap` | `external` | `inline` also puts the map in `code`; `false` builds no map (`map` is empty, `code` has no link) and does not read the inputs' maps |
|
|
89
89
|
| `esbuildOptions` | | other esbuild options, applied last (the plugin and source maps stay) |
|
|
90
90
|
|
|
91
91
|
## Examples
|
|
@@ -146,6 +146,18 @@ tree, rewrites its sources to ids of that tree (`../src/index.ts` → `npm:pkg@1
|
|
|
146
146
|
fills a missing `sourcesContent` from the package's files, and inlines it. A map that is missing
|
|
147
147
|
or broken is dropped: the file then maps to itself.
|
|
148
148
|
|
|
149
|
+
With `sourcemap: false` none of this happens: the `sourceMappingURL` comment is removed and the map
|
|
150
|
+
is not read. An inlined map carries its sources' text and can outweigh the code: for EmDash's
|
|
151
|
+
server bundle (cellb.dev's in-browser builder) esbuild's input goes from 58.9 MB to 27.0 MB.
|
|
152
|
+
|
|
153
|
+
### Module types follow Node
|
|
154
|
+
|
|
155
|
+
esbuild reads a `package.json` `"type"` only for files on its own file system. For the files this
|
|
156
|
+
plugin loads, a `.js` file in a `"type": "module"` scope gets an id ending in `?type=module.mjs`,
|
|
157
|
+
so esbuild treats it as ESM the way Node does: a default import of a CommonJS module is its
|
|
158
|
+
`module.exports`, even when it sets `__esModule`. tslib 2.3's `modules/index.js` depends on it.
|
|
159
|
+
The suffix is dropped from the ids in the source map.
|
|
160
|
+
|
|
149
161
|
### pnpm layouts
|
|
150
162
|
|
|
151
163
|
In a pnpm install, `node_modules/x` is a symlink into `node_modules/.pnpm`, and `x`'s own
|
package/dist/index.d.mts
CHANGED
|
@@ -106,7 +106,7 @@ interface BundleOptions {
|
|
|
106
106
|
/** Name of the output file: the map is linked as `<outfile>.map` (default `bundle.js`). */
|
|
107
107
|
outfile?: string;
|
|
108
108
|
/** `external` (default): `code` links `<outfile>.map`, which `map` holds; `inline`: `code` carries it too. */
|
|
109
|
-
sourcemap?: "external" | "inline";
|
|
109
|
+
sourcemap?: "external" | "inline" | false;
|
|
110
110
|
/** Other esbuild options, applied last (the bundler's plugin and source maps stay). */
|
|
111
111
|
esbuildOptions?: Partial<BuildOptions>;
|
|
112
112
|
}
|
|
@@ -146,15 +146,6 @@ interface TranspileResult {
|
|
|
146
146
|
//#endregion
|
|
147
147
|
//#region src/bundle.d.ts
|
|
148
148
|
export declare const loaderFor: (path: string) => Loader;
|
|
149
|
-
/**
|
|
150
|
-
* Bundles `entry` of a project into one module with esbuild (esbuild-wasm in browsers).
|
|
151
|
-
* Every file is read through FilesApi (the project's, or a package's from `packages`):
|
|
152
|
-
* esbuild resolves and loads nothing itself. esbuild transpiles TypeScript and JSX,
|
|
153
|
-
* converts CommonJS, lowers `await` when asked, and bundles, all in one pass, and its
|
|
154
|
-
* source map goes back through each step to the files it read; where a package ships
|
|
155
|
-
* its own map (TypeScript compiled to `.js`), to the package's original source. The
|
|
156
|
-
* map's sources are file ids: `~/src/app.ts`, `npm:pkg@1.2.3/src/index.ts`.
|
|
157
|
-
*/
|
|
158
149
|
export declare function bundle(opts: BundleOptions): Promise<BundleResult>;
|
|
159
150
|
/**
|
|
160
151
|
* Transpiles one file (TypeScript, JSX, modern syntax down to `target`; `await` lowered
|
|
@@ -164,20 +155,6 @@ export declare function bundle(opts: BundleOptions): Promise<BundleResult>;
|
|
|
164
155
|
export declare function transpile(code: string, opts: TranspileOptions): Promise<TranspileResult>;
|
|
165
156
|
//#endregion
|
|
166
157
|
//#region src/input-maps.d.ts
|
|
167
|
-
/**
|
|
168
|
-
* A file's own source map, made usable by esbuild, which reads only maps inlined in
|
|
169
|
-
* the file it loads (it cannot follow a linked `.map` through a FilesApi):
|
|
170
|
-
*
|
|
171
|
-
* - a linked map (`//# sourceMappingURL=index.js.map`) is read from the same tree and
|
|
172
|
-
* inlined; an inline `data:` map is kept;
|
|
173
|
-
* - its sources become ids of the same tree (`npm:pkg@1.0.0/src/index.ts`), so the
|
|
174
|
-
* bundle's map names the package's original files, not the published JavaScript;
|
|
175
|
-
* - missing `sourcesContent` is filled from the tree when the original file ships
|
|
176
|
-
* with the package.
|
|
177
|
-
*
|
|
178
|
-
* esbuild then composes it with its own: a bundled line traces to the original source.
|
|
179
|
-
* A map that is missing or unreadable is dropped (the file maps to itself).
|
|
180
|
-
*/
|
|
181
158
|
export declare function inlineInputMap(mount: Mount, path: string, code: string): Promise<string>;
|
|
182
159
|
//#endregion
|
|
183
160
|
//#region src/packages.d.ts
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/bundle.ts","../src/input-maps.ts","../src/packages.ts","../src/resolve.ts"],"mappings":";;;;;;;;;;UASiB;EACf,cAAc;EACd,kBAAkB;;;UAIH;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA,eAAe;EACf,mBAAmB;EACnB,uBAAuB;EACvB,kBAAkB;GACjB;;;;;;;;UASc;;EAEf;EACA,OAAO;;EAEP;;EAEA,WAAW;;;UAII;EACf,OAAO;;EAEP;;;;;;;UAQe;;EAEf,IAAI,cAAc,UAAU,WAAW,QAAQ;;;KAIrC,2BAA2B;UAEtB;;EAEf,SAAS;;EAET,OAAO;;EAEP;;EAEA;;EAEA,WAAW;;EAEX,WAAW;;;;;;;EAOX,UAAU,2BAA2B;;;;;EAKrC;;;;;EAKA;;EAEA;;EAEA;;EAEA;;;;;;EAMA;EACA;EACA,SAAS;;EAET;;EAEA;;EAEA,iBAAiB,QAAQ;;;UAIV;EACf;EACA;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;;EAEA,KAAK;EACL,UAAU;EACV,UAAU;;UAGK;EACf,SAAS;;EAET;EACA;EACA;EACA;EACA;EACA,SAAS;EACT;;UAGe;EACf;EACA,KAAK;EACL,UAAU;;;;qBChHC,YAAS,iBAAmB
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/bundle.ts","../src/input-maps.ts","../src/packages.ts","../src/resolve.ts"],"mappings":";;;;;;;;;;UASiB;EACf,cAAc;EACd,kBAAkB;;;UAIH;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA,eAAe;EACf,mBAAmB;EACnB,uBAAuB;EACvB,kBAAkB;GACjB;;;;;;;;UASc;;EAEf;EACA,OAAO;;EAEP;;EAEA,WAAW;;;UAII;EACf,OAAO;;EAEP;;;;;;;UAQe;;EAEf,IAAI,cAAc,UAAU,WAAW,QAAQ;;;KAIrC,2BAA2B;UAEtB;;EAEf,SAAS;;EAET,OAAO;;EAEP;;EAEA;;EAEA,WAAW;;EAEX,WAAW;;;;;;;EAOX,UAAU,2BAA2B;;;;;EAKrC;;;;;EAKA;;EAEA;;EAEA;;EAEA;;;;;;EAMA;EACA;EACA,SAAS;;EAET;;EAEA;;EAEA,iBAAiB,QAAQ;;;UAIV;EACf;EACA;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;;EAEA,KAAK;EACL,UAAU;EACV,UAAU;;UAGK;EACf,SAAS;;EAET;EACA;EACA;EACA;EACA;EACA,SAAS;EACT;;UAGe;EACf;EACA,KAAK;EACL,UAAU;;;;qBChHC,YAAS,iBAAmB;wBAmDnB,OAAO,MAAM,gBAAgB,QAAQ;;;;;;wBAqLrC,UAAU,cAAc,MAAM,mBAAmB,QAAQ;;;wBCtOzD,eAAe,OAAO,OAAO,cAAc,eAAe;;;;;;;;;;;;;wBCzBhE,uBAAuB;;;;;;;wBA0DvB,YAAY;EAAQ,SAAS;IAAgB;;wBAkC7C,iBAAiB,QAAQ,iBAAiB;;;UCtGzC;EACf,OAAO;EACP;;KAoBG;EAAe;EAAsB;EAAkB;;;;;;;wBAoDtC,iBACpB,cACA,UAAU,UACV,UAAU,cACV,GAAG,aACF,QAAQ"}
|
package/dist/index.mjs
CHANGED
|
@@ -77,6 +77,16 @@ const fromBase64 = (b64) => new TextDecoder().decode(Uint8Array.from(atob(b64),
|
|
|
77
77
|
* esbuild then composes it with its own: a bundled line traces to the original source.
|
|
78
78
|
* A map that is missing or unreadable is dropped (the file maps to itself).
|
|
79
79
|
*/
|
|
80
|
+
/**
|
|
81
|
+
* `code` without its trailing `sourceMappingURL` comment (and without reading the map): for
|
|
82
|
+
* bundles built with no source map, where an inlined input map would only add to what esbuild
|
|
83
|
+
* parses and holds (a package's maps, with their sources' text, can outweigh its code).
|
|
84
|
+
*/
|
|
85
|
+
function withoutInputMap(code) {
|
|
86
|
+
const end = code.trimEnd();
|
|
87
|
+
const nl = end.lastIndexOf("\n");
|
|
88
|
+
return MAP_COMMENT.test(end.slice(nl + 1)) ? end.slice(0, Math.max(0, nl)) : code;
|
|
89
|
+
}
|
|
80
90
|
async function inlineInputMap(mount, path, code) {
|
|
81
91
|
const lines = code.trimEnd().split("\n");
|
|
82
92
|
const last = lines[lines.length - 1] ?? "";
|
|
@@ -375,7 +385,7 @@ const LOADERS = {
|
|
|
375
385
|
const loaderFor = (path) => LOADERS[/\.([a-z0-9]+)$/i.exec(path)?.[1]?.toLowerCase() ?? ""] ?? "js";
|
|
376
386
|
const isExternal = (spec, patterns) => /^(https?:|data:)/.test(spec) || patterns.some((p) => typeof p === "string" ? p.endsWith("*") ? spec.startsWith(p.slice(0, -1)) : spec === p : p.test(spec));
|
|
377
387
|
/** A source name of esbuild's map → the file id it stands for. */
|
|
378
|
-
const sourceId = (s) => s.replace(/^(\.\.\/)*/, "").replace(new RegExp(`^${VNS}:`), "virtual:").replace(new RegExp(`^${NS}:`), "");
|
|
388
|
+
const sourceId = (s) => s.replace(/^(\.\.\/)*/, "").replace(new RegExp(`^${VNS}:`), "virtual:").replace(new RegExp(`^${NS}:`), "").replace("?type=module.mjs", "");
|
|
379
389
|
const toBase64 = (text) => {
|
|
380
390
|
const bytes = new TextEncoder().encode(text);
|
|
381
391
|
let bin = "";
|
|
@@ -395,6 +405,8 @@ function linkMap(code, map, how, name) {
|
|
|
395
405
|
* its own map (TypeScript compiled to `.js`), to the package's original source. The
|
|
396
406
|
* map's sources are file ids: `~/src/app.ts`, `npm:pkg@1.2.3/src/index.ts`.
|
|
397
407
|
*/
|
|
408
|
+
/** Marks the id of a `.js` file in a `"type": "module"` package scope (see `moduleTypeOf`). */
|
|
409
|
+
const ESM_SUFFIX = "?type=module.mjs";
|
|
398
410
|
async function bundle(opts) {
|
|
399
411
|
const root = opts.root ?? "/";
|
|
400
412
|
const project = {
|
|
@@ -412,7 +424,34 @@ async function bundle(opts) {
|
|
|
412
424
|
const supplied = opts.modules;
|
|
413
425
|
const virtualSource = (spec) => typeof supplied === "function" ? supplied(spec) : supplied?.[spec];
|
|
414
426
|
/** The mount and path of a file id; the longest prefix wins (`npm:@a/b@1.0.0/…`). */
|
|
427
|
+
/**
|
|
428
|
+
* The module type of a `.js` file, as Node.js decides it: the `type` of the nearest
|
|
429
|
+
* `package.json` (tslib ships `modules/package.json` with `"type": "module"`). esbuild reads
|
|
430
|
+
* that only for files on its own file system; for ours, a file in a `"type": "module"` scope
|
|
431
|
+
* gets an id ending in ESM_SUFFIX (`.mjs`), so that esbuild gives its imports of CommonJS
|
|
432
|
+
* modules Node's interop: the default import is `module.exports`, even with `__esModule`.
|
|
433
|
+
* Vite gets the same from esbuild by pre-bundling dependencies from disk.
|
|
434
|
+
*/
|
|
435
|
+
const scopeTypes = /* @__PURE__ */ new Map();
|
|
436
|
+
const moduleTypeOf = async (mount, path) => {
|
|
437
|
+
const root = mount.root.replace(/\/$/, "");
|
|
438
|
+
for (let dir = dirOf(path); dir.length >= root.length; dir = dirOf(dir)) {
|
|
439
|
+
const key = `${mount.prefix}:${dir}`;
|
|
440
|
+
if (scopeTypes.has(key)) return scopeTypes.get(key);
|
|
441
|
+
const pj = `${dir === "/" ? "" : dir}/package.json`;
|
|
442
|
+
if (await isFile(mount, pj)) {
|
|
443
|
+
let type;
|
|
444
|
+
try {
|
|
445
|
+
type = JSON.parse(await readText(mount.files, pj)).type;
|
|
446
|
+
} catch {}
|
|
447
|
+
scopeTypes.set(key, type);
|
|
448
|
+
return type;
|
|
449
|
+
}
|
|
450
|
+
if (dir === root || dir === "/" || !dir) break;
|
|
451
|
+
}
|
|
452
|
+
};
|
|
415
453
|
const locate = (id) => {
|
|
454
|
+
if (id.endsWith(ESM_SUFFIX)) id = id.slice(0, -16);
|
|
416
455
|
let best;
|
|
417
456
|
for (const m of mounts.values()) if (id.startsWith(`${m.prefix}/`) && (!best || m.prefix.length > best.prefix.length)) best = m;
|
|
418
457
|
const path = best && pathOf(best, id);
|
|
@@ -462,8 +501,9 @@ async function bundle(opts) {
|
|
|
462
501
|
}
|
|
463
502
|
if (!r) return failed();
|
|
464
503
|
mounts.set(r.mount.prefix, r.mount);
|
|
504
|
+
const esm = /\.js$/.test(r.path) && await moduleTypeOf(r.mount, r.path) === "module";
|
|
465
505
|
return {
|
|
466
|
-
path: idOf(r.mount, r.path),
|
|
506
|
+
path: idOf(r.mount, r.path) + (esm ? ESM_SUFFIX : ""),
|
|
467
507
|
namespace: NS
|
|
468
508
|
};
|
|
469
509
|
});
|
|
@@ -495,8 +535,16 @@ async function bundle(opts) {
|
|
|
495
535
|
};
|
|
496
536
|
}
|
|
497
537
|
const text = await readText(mount.files, path);
|
|
538
|
+
if (!(loader === "js" || loader === "ts" || loader === "jsx" || loader === "tsx")) return {
|
|
539
|
+
contents: text,
|
|
540
|
+
loader
|
|
541
|
+
};
|
|
542
|
+
if (opts.sourcemap === false) return {
|
|
543
|
+
contents: withoutInputMap(text),
|
|
544
|
+
loader
|
|
545
|
+
};
|
|
498
546
|
return {
|
|
499
|
-
contents:
|
|
547
|
+
contents: await inlineInputMap(mount, path, text),
|
|
500
548
|
loader
|
|
501
549
|
};
|
|
502
550
|
});
|
|
@@ -519,14 +567,25 @@ async function bundle(opts) {
|
|
|
519
567
|
...opts.lowerAwait ? { supported: LOWER_AWAIT } : {},
|
|
520
568
|
...rest,
|
|
521
569
|
...opts.inject?.length ? { inject: opts.inject.map((s) => INJECT + s) } : {},
|
|
522
|
-
sourcemap: "external",
|
|
523
|
-
sourcesContent:
|
|
570
|
+
sourcemap: opts.sourcemap === false ? false : "external",
|
|
571
|
+
sourcesContent: opts.sourcemap !== false,
|
|
524
572
|
plugins: [...extraPlugins, plugin]
|
|
525
573
|
});
|
|
526
574
|
const out = result.outputFiles ?? [];
|
|
527
575
|
const jsFile = out.find((f) => !f.path.endsWith(".map"));
|
|
528
576
|
const mapFile = out.find((f) => f.path.endsWith(".map"));
|
|
529
|
-
if (!jsFile
|
|
577
|
+
if (!jsFile) throw new Error("webrun-bundler: esbuild produced no output");
|
|
578
|
+
if (!mapFile) return {
|
|
579
|
+
code: jsFile.text,
|
|
580
|
+
map: {
|
|
581
|
+
version: 3,
|
|
582
|
+
sources: [],
|
|
583
|
+
names: [],
|
|
584
|
+
mappings: ""
|
|
585
|
+
},
|
|
586
|
+
metafile: result.metafile,
|
|
587
|
+
warnings: result.warnings
|
|
588
|
+
};
|
|
530
589
|
const raw = JSON.parse(mapFile.text);
|
|
531
590
|
const map = {
|
|
532
591
|
...raw,
|
|
@@ -535,7 +594,7 @@ async function bundle(opts) {
|
|
|
535
594
|
};
|
|
536
595
|
delete map.sourceRoot;
|
|
537
596
|
return {
|
|
538
|
-
code: linkMap(jsFile.text, map, opts.sourcemap
|
|
597
|
+
code: linkMap(jsFile.text, map, opts.sourcemap || "external", outfile),
|
|
539
598
|
map,
|
|
540
599
|
metafile: result.metafile,
|
|
541
600
|
warnings: result.warnings
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["toBase64","resolvePackageExports","resolveImports"],"sources":["../src/paths.ts","../src/input-maps.ts","../src/packages.ts","../src/resolve.ts","../src/bundle.ts"],"sourcesContent":["import { normalizePath, tryReadText } from \"@statewalker/webrun-files\";\nimport type { Mount, PackageManifest } from \"./types.js\";\n\n/** `path` joined to `dir`, with `.` and `..` resolved; `undefined` when it leaves `root`. */\nexport function joinWithin(root: string, dir: string, path: string): string | undefined {\n const parts = (path.startsWith(\"/\") ? path : `${dir}/${path}`).split(\"/\");\n const out: string[] = [];\n for (const p of parts) {\n if (!p || p === \".\") continue;\n if (p === \"..\") {\n if (!out.length) return undefined;\n out.pop();\n } else out.push(p);\n }\n const joined = `/${out.join(\"/\")}`;\n const r = normalizePath(root);\n return r === \"/\" || joined === r || joined.startsWith(`${r}/`) ? joined : undefined;\n}\n\nexport const dirOf = (path: string) => path.slice(0, path.lastIndexOf(\"/\")) || \"/\";\n\n/** The id of a mount's file: `<prefix>/<path below root>`. */\nexport function idOf(mount: Mount, path: string): string {\n const r = normalizePath(mount.root);\n const rel = r === \"/\" ? path : path.slice(r.length);\n return `${mount.prefix}${rel || \"/\"}`;\n}\n\n/** A mount's file from its id; `undefined` when the id is not the mount's. */\nexport function pathOf(mount: Mount, id: string): string | undefined {\n if (!id.startsWith(`${mount.prefix}/`)) return undefined;\n const r = normalizePath(mount.root);\n const rel = id.slice(mount.prefix.length);\n return r === \"/\" ? rel : `${r}${rel}`;\n}\n\nexport async function isFile(mount: Mount, path: string): Promise<boolean> {\n const s = await mount.files.stats(path);\n return s?.kind === \"file\";\n}\n\nexport async function readManifest(\n files: Mount[\"files\"],\n dir: string,\n): Promise<PackageManifest | undefined> {\n const text = await tryReadText(files, `${dir === \"/\" ? \"\" : dir}/package.json`);\n if (text === undefined) return undefined;\n try {\n return JSON.parse(text) as PackageManifest;\n } catch {\n return undefined;\n }\n}\n\n/** `react` → `{ name: \"react\" }`; `@a/b/c.js` → `{ name: \"@a/b\", subpath: \"c.js\" }`. */\nexport function parsePackageSpecifier(spec: string): { name: string; subpath?: string } {\n const parts = spec.split(\"/\");\n const n = spec.startsWith(\"@\") ? 2 : 1;\n const name = parts.slice(0, n).join(\"/\");\n const subpath = parts.slice(n).join(\"/\");\n return subpath ? { name, subpath } : { name };\n}\n","import { tryReadText } from \"@statewalker/webrun-files\";\nimport { dirOf, idOf, joinWithin } from \"./paths.js\";\nimport type { Mount, SourceMap } from \"./types.js\";\n\n// The last `//# sourceMappingURL=…` (or `//@`) comment of a JS file.\nconst MAP_COMMENT = /\\/\\/[#@]\\s*sourceMappingURL=(\\S+)\\s*$/;\n\nconst toBase64 = (text: string) => {\n const bytes = new TextEncoder().encode(text);\n let bin = \"\";\n for (let i = 0; i < bytes.length; i += 0x8000)\n bin += String.fromCharCode(...bytes.subarray(i, i + 0x8000));\n return btoa(bin);\n};\nconst fromBase64 = (b64: string) =>\n new TextDecoder().decode(Uint8Array.from(atob(b64), (c) => c.charCodeAt(0)));\n\n/**\n * A file's own source map, made usable by esbuild, which reads only maps inlined in\n * the file it loads (it cannot follow a linked `.map` through a FilesApi):\n *\n * - a linked map (`//# sourceMappingURL=index.js.map`) is read from the same tree and\n * inlined; an inline `data:` map is kept;\n * - its sources become ids of the same tree (`npm:pkg@1.0.0/src/index.ts`), so the\n * bundle's map names the package's original files, not the published JavaScript;\n * - missing `sourcesContent` is filled from the tree when the original file ships\n * with the package.\n *\n * esbuild then composes it with its own: a bundled line traces to the original source.\n * A map that is missing or unreadable is dropped (the file maps to itself).\n */\nexport async function inlineInputMap(mount: Mount, path: string, code: string): Promise<string> {\n const lines = code.trimEnd().split(\"\\n\");\n const last = lines[lines.length - 1] ?? \"\";\n const match = MAP_COMMENT.exec(last);\n if (!match) return code;\n const url = match[1] as string;\n const body = lines.slice(0, -1).join(\"\\n\");\n let text: string | undefined;\n let mapDir = dirOf(path);\n if (url.startsWith(\"data:\")) {\n const comma = url.indexOf(\",\");\n const meta = url.slice(5, comma);\n const payload = url.slice(comma + 1);\n try {\n text = meta.endsWith(\";base64\") ? fromBase64(payload) : decodeURIComponent(payload);\n } catch {\n text = undefined;\n }\n } else if (!/^[a-z][a-z0-9+.-]*:/i.test(url)) {\n const mapPath = joinWithin(mount.root, dirOf(path), decodeURIComponent(url));\n if (mapPath) {\n text = await tryReadText(mount.files, mapPath);\n mapDir = dirOf(mapPath);\n }\n }\n let map: SourceMap;\n try {\n map = JSON.parse(text ?? \"\") as SourceMap;\n } catch {\n return body; // no usable map: the file is its own source\n }\n const sourceDir = map.sourceRoot\n ? (joinWithin(\"/\", mapDir, map.sourceRoot.replace(/\\/$/, \"\")) ?? mapDir)\n : mapDir;\n const contents: (string | null)[] = map.sourcesContent ? [...map.sourcesContent] : [];\n const sources: string[] = [];\n for (let i = 0; i < map.sources.length; i++) {\n const src = map.sources[i] as string;\n const local = /^[a-z][a-z0-9+.-]*:/i.test(src)\n ? undefined\n : joinWithin(mount.root, sourceDir, src);\n sources.push(local ? idOf(mount, local) : src);\n if (contents[i] == null && local) contents[i] = (await tryReadText(mount.files, local)) ?? null;\n }\n const fixed: SourceMap = { ...map, sources, sourcesContent: contents };\n delete fixed.sourceRoot;\n return `${body}\\n//# sourceMappingURL=data:application/json;base64,${toBase64(JSON.stringify(fixed))}\\n`;\n}\n","import type { Source } from \"@statewalker/webrun-modules\";\nimport { dirOf, readManifest } from \"./paths.js\";\nimport type { Importer, Mount, PackageStore } from \"./types.js\";\n\nconst mountPrefix = (name: string, version: string | undefined) =>\n `npm:${name}@${version ?? \"0.0.0\"}`;\n\n/**\n * Packages from `node_modules` folders, found as Node finds them: in the importing\n * file's directory and each parent, inside the importer's own FilesApi. A package\n * installed in the project (or in another package's `node_modules`) is read where it is.\n *\n * pnpm layouts: a package's own dependencies sit next to its real directory in\n * `node_modules/.pnpm`, which Node reaches through the symlink's real path and a FilesApi\n * cannot see. When the walk finds nothing, each ancestor's `node_modules/.pnpm/node_modules`\n * (pnpm's hoisted links to every installed package) is tried too.\n */\nexport function nodeModulesPackages(): PackageStore {\n const mounts = new Map<string, Mount>();\n const at = async (files: Mount[\"files\"], root: string, name: string) => {\n const known = mounts.get(root);\n if (known && known.files === files) return known;\n const manifest = await readManifest(files, root);\n if (!manifest) return undefined;\n const mount: Mount = { prefix: mountPrefix(name, manifest.version), files, root, manifest };\n mounts.set(root, mount);\n return mount;\n };\n const ancestors = (path: string) => {\n const dirs: string[] = [];\n for (let dir = dirOf(path); ; dir = dirOf(dir)) {\n dirs.push(dir === \"/\" ? \"\" : dir);\n if (dir === \"/\") return dirs;\n }\n };\n return {\n async get(name, importer) {\n const files = importer.mount.files;\n const dirs = ancestors(importer.path);\n for (const dir of dirs) {\n const m = await at(files, `${dir}/node_modules/${name}`, name);\n if (m) return m;\n }\n for (const dir of dirs) {\n const m = await at(files, `${dir}/node_modules/.pnpm/node_modules/${name}`, name);\n if (m) return m;\n }\n return undefined;\n },\n };\n}\n\nconst DEPENDENCY_FIELDS = [\n \"dependencies\",\n \"peerDependencies\",\n \"optionalDependencies\",\n \"devDependencies\",\n] as const;\n\n/** The version range `importer`'s `package.json` gives `name`, if any. */\nfunction rangeFor(name: string, importer: Importer): string | undefined {\n const m = importer.mount.manifest;\n for (const field of DEPENDENCY_FIELDS) {\n const range = m?.[field]?.[name];\n if (range) return range;\n }\n return undefined;\n}\n\n/**\n * Packages fetched on demand (default: the npm registry, through webrun-modules'\n * `npmRegistrySource`) and kept in memory: each one is its own FilesApi tree. The\n * version is the range the importer's `package.json` declares (the project's for the\n * project's files), else the latest; one range loads once.\n */\nexport function npmPackages(opts: { source?: Source } = {}): PackageStore {\n // Loaded only when used: a bundle of the bundler that brings its own source stays small.\n let registry: Promise<Source> | undefined;\n const source: Source = opts.source ?? {\n matches: (ref) => \"pkg\" in ref,\n load: async (ref) => {\n registry ??= import(\"@statewalker/webrun-modules\").then((m) => m.npmRegistrySource());\n return (await registry).load(ref);\n },\n };\n const byRange = new Map<string, Promise<Mount>>();\n const byVersion = new Map<string, Mount>();\n return {\n get(name, importer) {\n const range = rangeFor(name, importer);\n const key = `${name}@${range ?? \"latest\"}`;\n let mount = byRange.get(key);\n if (!mount) {\n mount = source.load({ pkg: name, version: range }).then((p) => {\n const prefix = mountPrefix(p.name, p.version);\n const seen = byVersion.get(prefix);\n if (seen) return seen; // two ranges, one version: one copy of the package\n const m: Mount = { prefix, files: p.files, root: \"/\", manifest: p.manifest };\n byVersion.set(prefix, m);\n return m;\n });\n byRange.set(key, mount);\n }\n return mount;\n },\n };\n}\n\n/** The first store that has the package wins (`node_modules` first, then the registry). */\nexport function chainPackages(...stores: PackageStore[]): PackageStore {\n return {\n async get(name, importer) {\n let failure: unknown;\n for (const s of stores) {\n try {\n const m = await s.get(name, importer);\n if (m) return m;\n } catch (e) {\n failure ??= e; // the next store may still have it\n }\n }\n if (failure) throw failure;\n return undefined;\n },\n };\n}\n","import { imports as resolveImports, exports as resolvePackageExports } from \"resolve.exports\";\nimport { dirOf, isFile, joinWithin, parsePackageSpecifier } from \"./paths.js\";\nimport type { Importer, Mount, PackageManifest, PackageStore } from \"./types.js\";\n\n/** Extensions tried, in order, for a path written without one (or with `.js` for a `.ts` file). */\nconst EXTENSIONS = [\".ts\", \".tsx\", \".mts\", \".cts\", \".js\", \".jsx\", \".mjs\", \".cjs\", \".json\"];\n\nexport interface Resolved {\n mount: Mount;\n path: string;\n}\n\n/** `path` as written, else with an extension, else its `index` file. */\nasync function resolveFile(mount: Mount, path: string): Promise<string | undefined> {\n if (await isFile(mount, path)) return path;\n // TypeScript sources import `./x.js` for `./x.ts`.\n const js = /\\.(m|c)?jsx?$/.exec(path);\n if (js) {\n const base = path.slice(0, -js[0].length);\n for (const ext of [`.${js[1] ?? \"\"}ts`, \".tsx\"])\n if (await isFile(mount, base + ext)) return base + ext;\n }\n for (const ext of EXTENSIONS) if (await isFile(mount, path + ext)) return path + ext;\n const dir = path.endsWith(\"/\") ? path.slice(0, -1) : path;\n for (const ext of EXTENSIONS)\n if (await isFile(mount, `${dir}/index${ext}`)) return `${dir}/index${ext}`;\n return undefined;\n}\n\ntype Conditions = { conditions: string[]; require: boolean; browser: boolean };\n\nfunction exportsTarget(\n manifest: PackageManifest,\n entry: string,\n c: Conditions,\n): string | undefined {\n try {\n const out = resolvePackageExports(manifest, entry, {\n conditions: c.conditions,\n require: c.require,\n browser: c.browser,\n }) as string[] | undefined;\n return out?.[0];\n } catch {\n return undefined;\n }\n}\n\n/** A package's file for `subpath`: `exports` first, then `module`/`main` (and `browser` when it is a string). */\nasync function resolvePackageEntry(\n mount: Mount,\n subpath: string | undefined,\n c: Conditions,\n): Promise<string | undefined> {\n const manifest = mount.manifest ?? {};\n const entry = subpath ? `./${subpath}` : \".\";\n if (manifest.exports !== undefined) {\n const target = exportsTarget(manifest, entry, c);\n if (!target) return undefined; // not exported: Node refuses it as well\n return joinWithin(mount.root, mount.root, target);\n }\n if (subpath) return resolveFile(mount, joinWithin(mount.root, mount.root, subpath) ?? \"\");\n const fields = [\n ...(c.browser && typeof manifest.browser === \"string\" ? [manifest.browser] : []),\n ...(c.require ? [] : [manifest.module]),\n manifest.main,\n \"index.js\",\n ].filter((f): f is string => typeof f === \"string\");\n for (const f of fields) {\n const p = joinWithin(mount.root, mount.root, f);\n const file = p && (await resolveFile(mount, p));\n if (file) return file;\n }\n return undefined;\n}\n\n/**\n * Resolves `spec` as written in `importer`: a path of the same tree (`./x`, `../y.js`,\n * `/z`), a `#imports` alias of the importer's package, or a package found by `packages`\n * (with its `exports`, `module` and `main`).\n */\nexport async function resolveSpecifier(\n spec: string,\n importer: Importer,\n packages: PackageStore,\n c: Conditions,\n): Promise<Resolved | undefined> {\n const { mount } = importer;\n if (spec.startsWith(\"./\") || spec.startsWith(\"../\") || spec.startsWith(\"/\") || spec === \".\") {\n const base = spec.startsWith(\"/\") ? mount.root : dirOf(importer.path);\n const target = joinWithin(mount.root, base, spec.startsWith(\"/\") ? spec.slice(1) : spec);\n const path = target && (await resolveFile(mount, target));\n return path ? { mount, path } : undefined;\n }\n if (spec.startsWith(\"#\")) {\n try {\n const out = resolveImports(mount.manifest ?? {}, spec, {\n conditions: c.conditions,\n require: c.require,\n browser: c.browser,\n }) as string[] | undefined;\n const target = out?.[0];\n if (!target) return undefined;\n if (!target.startsWith(\".\")) return resolveSpecifier(target, importer, packages, c);\n const path = joinWithin(mount.root, mount.root, target);\n return path && (await isFile(mount, path)) ? { mount, path } : undefined;\n } catch {\n return undefined;\n }\n }\n const { name, subpath } = parsePackageSpecifier(spec);\n const pkg = await packages.get(name, importer);\n if (!pkg) return undefined;\n const path = await resolvePackageEntry(pkg, subpath, c);\n return path && (await isFile(pkg, path)) ? { mount: pkg, path } : undefined;\n}\n","import { readText } from \"@statewalker/webrun-files\";\nimport type { Loader, Plugin } from \"esbuild-wasm\";\nimport { inlineInputMap } from \"./input-maps.js\";\nimport { nodeModulesPackages } from \"./packages.js\";\nimport { idOf, joinWithin, pathOf, readManifest } from \"./paths.js\";\nimport { resolveSpecifier } from \"./resolve.js\";\nimport type {\n BundleOptions,\n BundleResult,\n ExternalPattern,\n Mount,\n SourceMap,\n TranspileOptions,\n TranspileResult,\n} from \"./types.js\";\n\n/** esbuild's namespace for the files the bundler serves; its source-map names drop it. */\nconst NS = \"webrun\";\n/** esbuild's namespace for the host's modules (`modules`): `virtual:<specifier>` in maps. */\nconst VNS = \"webrun-virtual\";\n/** Marks an `inject` entry, so that it resolves like an import, not like the entry point. */\nconst INJECT = \"webrun-inject:\";\n\n/** esbuild `supported` flags that lower `await` to generators. */\nconst LOWER_AWAIT = { \"async-await\": false, \"async-generator\": false, \"for-await\": false };\n\nconst LOADERS: Record<string, Loader> = {\n ts: \"ts\",\n mts: \"ts\",\n cts: \"ts\",\n tsx: \"tsx\",\n jsx: \"jsx\",\n js: \"js\",\n mjs: \"js\",\n cjs: \"js\",\n json: \"json\",\n css: \"css\",\n txt: \"text\",\n wasm: \"binary\",\n};\nexport const loaderFor = (path: string): Loader =>\n LOADERS[/\\.([a-z0-9]+)$/i.exec(path)?.[1]?.toLowerCase() ?? \"\"] ?? \"js\";\n\nconst isExternal = (spec: string, patterns: ExternalPattern[]) =>\n /^(https?:|data:)/.test(spec) ||\n patterns.some((p) =>\n typeof p === \"string\"\n ? p.endsWith(\"*\")\n ? spec.startsWith(p.slice(0, -1))\n : spec === p\n : p.test(spec),\n );\n\n/** A source name of esbuild's map → the file id it stands for. */\nconst sourceId = (s: string) =>\n s\n .replace(/^(\\.\\.\\/)*/, \"\")\n .replace(new RegExp(`^${VNS}:`), \"virtual:\")\n .replace(new RegExp(`^${NS}:`), \"\");\n\nconst toBase64 = (text: string) => {\n const bytes = new TextEncoder().encode(text);\n let bin = \"\";\n for (let i = 0; i < bytes.length; i += 0x8000)\n bin += String.fromCharCode(...bytes.subarray(i, i + 0x8000));\n return btoa(bin);\n};\n\n/** `code` with its trailing map link replaced: by `map` inlined, or by a link to `name`. */\nfunction linkMap(code: string, map: SourceMap, how: \"external\" | \"inline\", name: string) {\n const body = code.replace(/\\n?\\/\\/# sourceMappingURL=\\S+\\s*$/, \"\");\n const url =\n how === \"inline\"\n ? `data:application/json;base64,${toBase64(JSON.stringify(map))}`\n : `${name.split(\"/\").pop()}.map`;\n return `${body}\\n//# sourceMappingURL=${url}\\n`;\n}\n\n/**\n * Bundles `entry` of a project into one module with esbuild (esbuild-wasm in browsers).\n * Every file is read through FilesApi (the project's, or a package's from `packages`):\n * esbuild resolves and loads nothing itself. esbuild transpiles TypeScript and JSX,\n * converts CommonJS, lowers `await` when asked, and bundles, all in one pass, and its\n * source map goes back through each step to the files it read; where a package ships\n * its own map (TypeScript compiled to `.js`), to the package's original source. The\n * map's sources are file ids: `~/src/app.ts`, `npm:pkg@1.2.3/src/index.ts`.\n */\nexport async function bundle(opts: BundleOptions): Promise<BundleResult> {\n const root = opts.root ?? \"/\";\n const project: Mount = {\n prefix: \"~\",\n files: opts.files,\n root,\n manifest: await readManifest(opts.files, root),\n };\n const packages = opts.packages ?? nodeModulesPackages();\n const external = opts.external ?? [];\n const browser = (opts.platform ?? \"browser\") === \"browser\";\n const conditions = opts.conditions ?? [\"browser\"];\n const outfile = opts.outfile ?? \"bundle.js\";\n const mounts = new Map<string, Mount>([[project.prefix, project]]);\n const supplied = opts.modules;\n const virtualSource = (spec: string) =>\n typeof supplied === \"function\" ? supplied(spec) : supplied?.[spec];\n\n /** The mount and path of a file id; the longest prefix wins (`npm:@a/b@1.0.0/…`). */\n const locate = (id: string) => {\n let best: Mount | undefined;\n for (const m of mounts.values())\n if (id.startsWith(`${m.prefix}/`) && (!best || m.prefix.length > best.prefix.length))\n best = m;\n const path = best && pathOf(best, id);\n if (!best || !path) throw new Error(`webrun-bundler: no file ${id}`);\n return { mount: best, path };\n };\n\n const plugin: Plugin = {\n name: \"webrun-files\",\n setup(b) {\n b.onResolve({ filter: /.*/ }, async (args) => {\n const injected = args.path.startsWith(INJECT);\n const spec = injected ? args.path.slice(INJECT.length) : args.path;\n if (args.kind === \"entry-point\" && !injected) {\n const path = joinWithin(root, root, args.path.replace(/^\\/+/, \"\"));\n if (!path) return { errors: [{ text: `entry ${args.path} is outside the project` }] };\n return { path: idOf(project, path), namespace: NS };\n }\n if (virtualSource(spec) !== undefined) return { path: spec, namespace: VNS };\n if (isExternal(spec, external)) return { path: spec, external: true };\n // The host's modules and `inject` entries import from the project's root.\n const importer =\n injected || args.namespace === VNS\n ? { mount: project, path: `${root === \"/\" ? \"\" : root}/` }\n : locate(args.importer);\n const require = args.kind === \"require-call\" || args.kind === \"require-resolve\";\n const failed = (why?: string) => ({\n errors: [\n {\n text: `Could not resolve \"${spec}\" (imported by ${args.importer || \"inject\"})${why ? `: ${why}` : \"\"}`,\n },\n ],\n });\n let r: Awaited<ReturnType<typeof resolveSpecifier>>;\n try {\n r = await resolveSpecifier(spec, importer, packages, {\n conditions,\n require,\n browser,\n });\n } catch (e) {\n return failed((e as Error)?.message ?? String(e));\n }\n if (!r) return failed();\n mounts.set(r.mount.prefix, r.mount);\n return { path: idOf(r.mount, r.path), namespace: NS };\n });\n b.onLoad({ filter: /.*/, namespace: VNS }, (args) => ({\n contents: virtualSource(args.path) ?? \"\",\n loader: \"js\",\n }));\n b.onLoad({ filter: /.*/, namespace: NS }, async (args) => {\n const { mount, path } = locate(args.path);\n const loader = loaderFor(path);\n if (loader === \"binary\") {\n const chunks: Uint8Array[] = [];\n for await (const c of mount.files.read(path)) chunks.push(c);\n const bytes = new Uint8Array(chunks.reduce((n, c) => n + c.length, 0));\n let at = 0;\n for (const c of chunks) {\n bytes.set(c, at);\n at += c.length;\n }\n return { contents: bytes, loader };\n }\n const text = await readText(mount.files, path);\n const js = loader === \"js\" || loader === \"ts\" || loader === \"jsx\" || loader === \"tsx\";\n return { contents: js ? await inlineInputMap(mount, path, text) : text, loader };\n });\n },\n };\n\n const { plugins: extraPlugins = [], ...rest } = opts.esbuildOptions ?? {};\n const result = await opts.esbuild.build({\n entryPoints: [opts.entry],\n bundle: true,\n write: false,\n format: opts.format ?? \"esm\",\n platform: opts.platform ?? \"browser\",\n target: opts.target ?? \"es2022\",\n outfile,\n absWorkingDir: \"/\",\n metafile: true,\n logLevel: \"silent\",\n minify: opts.minify,\n define: opts.define,\n ...(opts.lowerAwait ? { supported: LOWER_AWAIT } : {}),\n ...rest,\n ...(opts.inject?.length ? { inject: opts.inject.map((s) => INJECT + s) } : {}),\n sourcemap: \"external\",\n sourcesContent: true,\n plugins: [...extraPlugins, plugin],\n });\n const out = result.outputFiles ?? [];\n const jsFile = out.find((f) => !f.path.endsWith(\".map\"));\n const mapFile = out.find((f) => f.path.endsWith(\".map\"));\n if (!jsFile || !mapFile) throw new Error(\"webrun-bundler: esbuild produced no output\");\n const raw = JSON.parse(mapFile.text) as SourceMap;\n const map: SourceMap = {\n ...raw,\n file: outfile.split(\"/\").pop(),\n sources: raw.sources.map(sourceId),\n };\n delete map.sourceRoot;\n return {\n code: linkMap(jsFile.text, map, opts.sourcemap ?? \"external\", outfile),\n map,\n metafile: result.metafile as BundleResult[\"metafile\"],\n warnings: result.warnings,\n };\n}\n\n/**\n * Transpiles one file (TypeScript, JSX, modern syntax down to `target`; `await` lowered\n * when asked) with a source map back to it. A map the code carries (`sourceMappingURL`,\n * inline) is composed in, so the result still traces to the original.\n */\nexport async function transpile(code: string, opts: TranspileOptions): Promise<TranspileResult> {\n const r = await opts.esbuild.transform(code, {\n loader: loaderFor(opts.path),\n sourcefile: opts.path,\n sourcemap: \"external\",\n sourcesContent: true,\n format: opts.format,\n target: opts.target ?? \"es2022\",\n minify: opts.minify,\n define: opts.define,\n ...(opts.lowerAwait ? { supported: LOWER_AWAIT } : {}),\n });\n const map = JSON.parse(r.map) as SourceMap;\n return {\n code: linkMap(r.code, map, opts.sourcemap ?? \"external\", opts.path.replace(/\\.[^./]+$/, \".js\")),\n map,\n warnings: r.warnings,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["toBase64","resolvePackageExports","resolveImports"],"sources":["../src/paths.ts","../src/input-maps.ts","../src/packages.ts","../src/resolve.ts","../src/bundle.ts"],"sourcesContent":["import { normalizePath, tryReadText } from \"@statewalker/webrun-files\";\nimport type { Mount, PackageManifest } from \"./types.js\";\n\n/** `path` joined to `dir`, with `.` and `..` resolved; `undefined` when it leaves `root`. */\nexport function joinWithin(root: string, dir: string, path: string): string | undefined {\n const parts = (path.startsWith(\"/\") ? path : `${dir}/${path}`).split(\"/\");\n const out: string[] = [];\n for (const p of parts) {\n if (!p || p === \".\") continue;\n if (p === \"..\") {\n if (!out.length) return undefined;\n out.pop();\n } else out.push(p);\n }\n const joined = `/${out.join(\"/\")}`;\n const r = normalizePath(root);\n return r === \"/\" || joined === r || joined.startsWith(`${r}/`) ? joined : undefined;\n}\n\nexport const dirOf = (path: string) => path.slice(0, path.lastIndexOf(\"/\")) || \"/\";\n\n/** The id of a mount's file: `<prefix>/<path below root>`. */\nexport function idOf(mount: Mount, path: string): string {\n const r = normalizePath(mount.root);\n const rel = r === \"/\" ? path : path.slice(r.length);\n return `${mount.prefix}${rel || \"/\"}`;\n}\n\n/** A mount's file from its id; `undefined` when the id is not the mount's. */\nexport function pathOf(mount: Mount, id: string): string | undefined {\n if (!id.startsWith(`${mount.prefix}/`)) return undefined;\n const r = normalizePath(mount.root);\n const rel = id.slice(mount.prefix.length);\n return r === \"/\" ? rel : `${r}${rel}`;\n}\n\nexport async function isFile(mount: Mount, path: string): Promise<boolean> {\n const s = await mount.files.stats(path);\n return s?.kind === \"file\";\n}\n\nexport async function readManifest(\n files: Mount[\"files\"],\n dir: string,\n): Promise<PackageManifest | undefined> {\n const text = await tryReadText(files, `${dir === \"/\" ? \"\" : dir}/package.json`);\n if (text === undefined) return undefined;\n try {\n return JSON.parse(text) as PackageManifest;\n } catch {\n return undefined;\n }\n}\n\n/** `react` → `{ name: \"react\" }`; `@a/b/c.js` → `{ name: \"@a/b\", subpath: \"c.js\" }`. */\nexport function parsePackageSpecifier(spec: string): { name: string; subpath?: string } {\n const parts = spec.split(\"/\");\n const n = spec.startsWith(\"@\") ? 2 : 1;\n const name = parts.slice(0, n).join(\"/\");\n const subpath = parts.slice(n).join(\"/\");\n return subpath ? { name, subpath } : { name };\n}\n","import { tryReadText } from \"@statewalker/webrun-files\";\nimport { dirOf, idOf, joinWithin } from \"./paths.js\";\nimport type { Mount, SourceMap } from \"./types.js\";\n\n// The last `//# sourceMappingURL=…` (or `//@`) comment of a JS file.\nconst MAP_COMMENT = /\\/\\/[#@]\\s*sourceMappingURL=(\\S+)\\s*$/;\n\nconst toBase64 = (text: string) => {\n const bytes = new TextEncoder().encode(text);\n let bin = \"\";\n for (let i = 0; i < bytes.length; i += 0x8000)\n bin += String.fromCharCode(...bytes.subarray(i, i + 0x8000));\n return btoa(bin);\n};\nconst fromBase64 = (b64: string) =>\n new TextDecoder().decode(Uint8Array.from(atob(b64), (c) => c.charCodeAt(0)));\n\n/**\n * A file's own source map, made usable by esbuild, which reads only maps inlined in\n * the file it loads (it cannot follow a linked `.map` through a FilesApi):\n *\n * - a linked map (`//# sourceMappingURL=index.js.map`) is read from the same tree and\n * inlined; an inline `data:` map is kept;\n * - its sources become ids of the same tree (`npm:pkg@1.0.0/src/index.ts`), so the\n * bundle's map names the package's original files, not the published JavaScript;\n * - missing `sourcesContent` is filled from the tree when the original file ships\n * with the package.\n *\n * esbuild then composes it with its own: a bundled line traces to the original source.\n * A map that is missing or unreadable is dropped (the file maps to itself).\n */\n/**\n * `code` without its trailing `sourceMappingURL` comment (and without reading the map): for\n * bundles built with no source map, where an inlined input map would only add to what esbuild\n * parses and holds (a package's maps, with their sources' text, can outweigh its code).\n */\nexport function withoutInputMap(code: string): string {\n const end = code.trimEnd();\n const nl = end.lastIndexOf(\"\\n\");\n return MAP_COMMENT.test(end.slice(nl + 1)) ? end.slice(0, Math.max(0, nl)) : code;\n}\n\nexport async function inlineInputMap(mount: Mount, path: string, code: string): Promise<string> {\n const lines = code.trimEnd().split(\"\\n\");\n const last = lines[lines.length - 1] ?? \"\";\n const match = MAP_COMMENT.exec(last);\n if (!match) return code;\n const url = match[1] as string;\n const body = lines.slice(0, -1).join(\"\\n\");\n let text: string | undefined;\n let mapDir = dirOf(path);\n if (url.startsWith(\"data:\")) {\n const comma = url.indexOf(\",\");\n const meta = url.slice(5, comma);\n const payload = url.slice(comma + 1);\n try {\n text = meta.endsWith(\";base64\") ? fromBase64(payload) : decodeURIComponent(payload);\n } catch {\n text = undefined;\n }\n } else if (!/^[a-z][a-z0-9+.-]*:/i.test(url)) {\n const mapPath = joinWithin(mount.root, dirOf(path), decodeURIComponent(url));\n if (mapPath) {\n text = await tryReadText(mount.files, mapPath);\n mapDir = dirOf(mapPath);\n }\n }\n let map: SourceMap;\n try {\n map = JSON.parse(text ?? \"\") as SourceMap;\n } catch {\n return body; // no usable map: the file is its own source\n }\n const sourceDir = map.sourceRoot\n ? (joinWithin(\"/\", mapDir, map.sourceRoot.replace(/\\/$/, \"\")) ?? mapDir)\n : mapDir;\n const contents: (string | null)[] = map.sourcesContent ? [...map.sourcesContent] : [];\n const sources: string[] = [];\n for (let i = 0; i < map.sources.length; i++) {\n const src = map.sources[i] as string;\n const local = /^[a-z][a-z0-9+.-]*:/i.test(src)\n ? undefined\n : joinWithin(mount.root, sourceDir, src);\n sources.push(local ? idOf(mount, local) : src);\n if (contents[i] == null && local) contents[i] = (await tryReadText(mount.files, local)) ?? null;\n }\n const fixed: SourceMap = { ...map, sources, sourcesContent: contents };\n delete fixed.sourceRoot;\n return `${body}\\n//# sourceMappingURL=data:application/json;base64,${toBase64(JSON.stringify(fixed))}\\n`;\n}\n","import type { Source } from \"@statewalker/webrun-modules\";\nimport { dirOf, readManifest } from \"./paths.js\";\nimport type { Importer, Mount, PackageStore } from \"./types.js\";\n\nconst mountPrefix = (name: string, version: string | undefined) =>\n `npm:${name}@${version ?? \"0.0.0\"}`;\n\n/**\n * Packages from `node_modules` folders, found as Node finds them: in the importing\n * file's directory and each parent, inside the importer's own FilesApi. A package\n * installed in the project (or in another package's `node_modules`) is read where it is.\n *\n * pnpm layouts: a package's own dependencies sit next to its real directory in\n * `node_modules/.pnpm`, which Node reaches through the symlink's real path and a FilesApi\n * cannot see. When the walk finds nothing, each ancestor's `node_modules/.pnpm/node_modules`\n * (pnpm's hoisted links to every installed package) is tried too.\n */\nexport function nodeModulesPackages(): PackageStore {\n const mounts = new Map<string, Mount>();\n const at = async (files: Mount[\"files\"], root: string, name: string) => {\n const known = mounts.get(root);\n if (known && known.files === files) return known;\n const manifest = await readManifest(files, root);\n if (!manifest) return undefined;\n const mount: Mount = { prefix: mountPrefix(name, manifest.version), files, root, manifest };\n mounts.set(root, mount);\n return mount;\n };\n const ancestors = (path: string) => {\n const dirs: string[] = [];\n for (let dir = dirOf(path); ; dir = dirOf(dir)) {\n dirs.push(dir === \"/\" ? \"\" : dir);\n if (dir === \"/\") return dirs;\n }\n };\n return {\n async get(name, importer) {\n const files = importer.mount.files;\n const dirs = ancestors(importer.path);\n for (const dir of dirs) {\n const m = await at(files, `${dir}/node_modules/${name}`, name);\n if (m) return m;\n }\n for (const dir of dirs) {\n const m = await at(files, `${dir}/node_modules/.pnpm/node_modules/${name}`, name);\n if (m) return m;\n }\n return undefined;\n },\n };\n}\n\nconst DEPENDENCY_FIELDS = [\n \"dependencies\",\n \"peerDependencies\",\n \"optionalDependencies\",\n \"devDependencies\",\n] as const;\n\n/** The version range `importer`'s `package.json` gives `name`, if any. */\nfunction rangeFor(name: string, importer: Importer): string | undefined {\n const m = importer.mount.manifest;\n for (const field of DEPENDENCY_FIELDS) {\n const range = m?.[field]?.[name];\n if (range) return range;\n }\n return undefined;\n}\n\n/**\n * Packages fetched on demand (default: the npm registry, through webrun-modules'\n * `npmRegistrySource`) and kept in memory: each one is its own FilesApi tree. The\n * version is the range the importer's `package.json` declares (the project's for the\n * project's files), else the latest; one range loads once.\n */\nexport function npmPackages(opts: { source?: Source } = {}): PackageStore {\n // Loaded only when used: a bundle of the bundler that brings its own source stays small.\n let registry: Promise<Source> | undefined;\n const source: Source = opts.source ?? {\n matches: (ref) => \"pkg\" in ref,\n load: async (ref) => {\n registry ??= import(\"@statewalker/webrun-modules\").then((m) => m.npmRegistrySource());\n return (await registry).load(ref);\n },\n };\n const byRange = new Map<string, Promise<Mount>>();\n const byVersion = new Map<string, Mount>();\n return {\n get(name, importer) {\n const range = rangeFor(name, importer);\n const key = `${name}@${range ?? \"latest\"}`;\n let mount = byRange.get(key);\n if (!mount) {\n mount = source.load({ pkg: name, version: range }).then((p) => {\n const prefix = mountPrefix(p.name, p.version);\n const seen = byVersion.get(prefix);\n if (seen) return seen; // two ranges, one version: one copy of the package\n const m: Mount = { prefix, files: p.files, root: \"/\", manifest: p.manifest };\n byVersion.set(prefix, m);\n return m;\n });\n byRange.set(key, mount);\n }\n return mount;\n },\n };\n}\n\n/** The first store that has the package wins (`node_modules` first, then the registry). */\nexport function chainPackages(...stores: PackageStore[]): PackageStore {\n return {\n async get(name, importer) {\n let failure: unknown;\n for (const s of stores) {\n try {\n const m = await s.get(name, importer);\n if (m) return m;\n } catch (e) {\n failure ??= e; // the next store may still have it\n }\n }\n if (failure) throw failure;\n return undefined;\n },\n };\n}\n","import { imports as resolveImports, exports as resolvePackageExports } from \"resolve.exports\";\nimport { dirOf, isFile, joinWithin, parsePackageSpecifier } from \"./paths.js\";\nimport type { Importer, Mount, PackageManifest, PackageStore } from \"./types.js\";\n\n/** Extensions tried, in order, for a path written without one (or with `.js` for a `.ts` file). */\nconst EXTENSIONS = [\".ts\", \".tsx\", \".mts\", \".cts\", \".js\", \".jsx\", \".mjs\", \".cjs\", \".json\"];\n\nexport interface Resolved {\n mount: Mount;\n path: string;\n}\n\n/** `path` as written, else with an extension, else its `index` file. */\nasync function resolveFile(mount: Mount, path: string): Promise<string | undefined> {\n if (await isFile(mount, path)) return path;\n // TypeScript sources import `./x.js` for `./x.ts`.\n const js = /\\.(m|c)?jsx?$/.exec(path);\n if (js) {\n const base = path.slice(0, -js[0].length);\n for (const ext of [`.${js[1] ?? \"\"}ts`, \".tsx\"])\n if (await isFile(mount, base + ext)) return base + ext;\n }\n for (const ext of EXTENSIONS) if (await isFile(mount, path + ext)) return path + ext;\n const dir = path.endsWith(\"/\") ? path.slice(0, -1) : path;\n for (const ext of EXTENSIONS)\n if (await isFile(mount, `${dir}/index${ext}`)) return `${dir}/index${ext}`;\n return undefined;\n}\n\ntype Conditions = { conditions: string[]; require: boolean; browser: boolean };\n\nfunction exportsTarget(\n manifest: PackageManifest,\n entry: string,\n c: Conditions,\n): string | undefined {\n try {\n const out = resolvePackageExports(manifest, entry, {\n conditions: c.conditions,\n require: c.require,\n browser: c.browser,\n }) as string[] | undefined;\n return out?.[0];\n } catch {\n return undefined;\n }\n}\n\n/** A package's file for `subpath`: `exports` first, then `module`/`main` (and `browser` when it is a string). */\nasync function resolvePackageEntry(\n mount: Mount,\n subpath: string | undefined,\n c: Conditions,\n): Promise<string | undefined> {\n const manifest = mount.manifest ?? {};\n const entry = subpath ? `./${subpath}` : \".\";\n if (manifest.exports !== undefined) {\n const target = exportsTarget(manifest, entry, c);\n if (!target) return undefined; // not exported: Node refuses it as well\n return joinWithin(mount.root, mount.root, target);\n }\n if (subpath) return resolveFile(mount, joinWithin(mount.root, mount.root, subpath) ?? \"\");\n const fields = [\n ...(c.browser && typeof manifest.browser === \"string\" ? [manifest.browser] : []),\n ...(c.require ? [] : [manifest.module]),\n manifest.main,\n \"index.js\",\n ].filter((f): f is string => typeof f === \"string\");\n for (const f of fields) {\n const p = joinWithin(mount.root, mount.root, f);\n const file = p && (await resolveFile(mount, p));\n if (file) return file;\n }\n return undefined;\n}\n\n/**\n * Resolves `spec` as written in `importer`: a path of the same tree (`./x`, `../y.js`,\n * `/z`), a `#imports` alias of the importer's package, or a package found by `packages`\n * (with its `exports`, `module` and `main`).\n */\nexport async function resolveSpecifier(\n spec: string,\n importer: Importer,\n packages: PackageStore,\n c: Conditions,\n): Promise<Resolved | undefined> {\n const { mount } = importer;\n if (spec.startsWith(\"./\") || spec.startsWith(\"../\") || spec.startsWith(\"/\") || spec === \".\") {\n const base = spec.startsWith(\"/\") ? mount.root : dirOf(importer.path);\n const target = joinWithin(mount.root, base, spec.startsWith(\"/\") ? spec.slice(1) : spec);\n const path = target && (await resolveFile(mount, target));\n return path ? { mount, path } : undefined;\n }\n if (spec.startsWith(\"#\")) {\n try {\n const out = resolveImports(mount.manifest ?? {}, spec, {\n conditions: c.conditions,\n require: c.require,\n browser: c.browser,\n }) as string[] | undefined;\n const target = out?.[0];\n if (!target) return undefined;\n if (!target.startsWith(\".\")) return resolveSpecifier(target, importer, packages, c);\n const path = joinWithin(mount.root, mount.root, target);\n return path && (await isFile(mount, path)) ? { mount, path } : undefined;\n } catch {\n return undefined;\n }\n }\n const { name, subpath } = parsePackageSpecifier(spec);\n const pkg = await packages.get(name, importer);\n if (!pkg) return undefined;\n const path = await resolvePackageEntry(pkg, subpath, c);\n return path && (await isFile(pkg, path)) ? { mount: pkg, path } : undefined;\n}\n","import { readText } from \"@statewalker/webrun-files\";\nimport type { Loader, Plugin } from \"esbuild-wasm\";\nimport { inlineInputMap, withoutInputMap } from \"./input-maps.js\";\nimport { nodeModulesPackages } from \"./packages.js\";\nimport { dirOf, idOf, isFile, joinWithin, pathOf, readManifest } from \"./paths.js\";\nimport { resolveSpecifier } from \"./resolve.js\";\nimport type {\n BundleOptions,\n BundleResult,\n ExternalPattern,\n Mount,\n SourceMap,\n TranspileOptions,\n TranspileResult,\n} from \"./types.js\";\n\n/** esbuild's namespace for the files the bundler serves; its source-map names drop it. */\nconst NS = \"webrun\";\n/** esbuild's namespace for the host's modules (`modules`): `virtual:<specifier>` in maps. */\nconst VNS = \"webrun-virtual\";\n/** Marks an `inject` entry, so that it resolves like an import, not like the entry point. */\nconst INJECT = \"webrun-inject:\";\n\n/** esbuild `supported` flags that lower `await` to generators. */\nconst LOWER_AWAIT = { \"async-await\": false, \"async-generator\": false, \"for-await\": false };\n\nconst LOADERS: Record<string, Loader> = {\n ts: \"ts\",\n mts: \"ts\",\n cts: \"ts\",\n tsx: \"tsx\",\n jsx: \"jsx\",\n js: \"js\",\n mjs: \"js\",\n cjs: \"js\",\n json: \"json\",\n css: \"css\",\n txt: \"text\",\n wasm: \"binary\",\n};\nexport const loaderFor = (path: string): Loader =>\n LOADERS[/\\.([a-z0-9]+)$/i.exec(path)?.[1]?.toLowerCase() ?? \"\"] ?? \"js\";\n\nconst isExternal = (spec: string, patterns: ExternalPattern[]) =>\n /^(https?:|data:)/.test(spec) ||\n patterns.some((p) =>\n typeof p === \"string\"\n ? p.endsWith(\"*\")\n ? spec.startsWith(p.slice(0, -1))\n : spec === p\n : p.test(spec),\n );\n\n/** A source name of esbuild's map → the file id it stands for. */\nconst sourceId = (s: string) =>\n s\n .replace(/^(\\.\\.\\/)*/, \"\")\n .replace(new RegExp(`^${VNS}:`), \"virtual:\")\n .replace(new RegExp(`^${NS}:`), \"\")\n .replace(\"?type=module.mjs\", \"\"); // ESM_SUFFIX: the file's id, as in the map's other sources\n\nconst toBase64 = (text: string) => {\n const bytes = new TextEncoder().encode(text);\n let bin = \"\";\n for (let i = 0; i < bytes.length; i += 0x8000)\n bin += String.fromCharCode(...bytes.subarray(i, i + 0x8000));\n return btoa(bin);\n};\n\n/** `code` with its trailing map link replaced: by `map` inlined, or by a link to `name`. */\nfunction linkMap(code: string, map: SourceMap, how: \"external\" | \"inline\", name: string) {\n const body = code.replace(/\\n?\\/\\/# sourceMappingURL=\\S+\\s*$/, \"\");\n const url =\n how === \"inline\"\n ? `data:application/json;base64,${toBase64(JSON.stringify(map))}`\n : `${name.split(\"/\").pop()}.map`;\n return `${body}\\n//# sourceMappingURL=${url}\\n`;\n}\n\n/**\n * Bundles `entry` of a project into one module with esbuild (esbuild-wasm in browsers).\n * Every file is read through FilesApi (the project's, or a package's from `packages`):\n * esbuild resolves and loads nothing itself. esbuild transpiles TypeScript and JSX,\n * converts CommonJS, lowers `await` when asked, and bundles, all in one pass, and its\n * source map goes back through each step to the files it read; where a package ships\n * its own map (TypeScript compiled to `.js`), to the package's original source. The\n * map's sources are file ids: `~/src/app.ts`, `npm:pkg@1.2.3/src/index.ts`.\n */\n/** Marks the id of a `.js` file in a `\"type\": \"module\"` package scope (see `moduleTypeOf`). */\nconst ESM_SUFFIX = \"?type=module.mjs\";\n\nexport async function bundle(opts: BundleOptions): Promise<BundleResult> {\n const root = opts.root ?? \"/\";\n const project: Mount = {\n prefix: \"~\",\n files: opts.files,\n root,\n manifest: await readManifest(opts.files, root),\n };\n const packages = opts.packages ?? nodeModulesPackages();\n const external = opts.external ?? [];\n const browser = (opts.platform ?? \"browser\") === \"browser\";\n const conditions = opts.conditions ?? [\"browser\"];\n const outfile = opts.outfile ?? \"bundle.js\";\n const mounts = new Map<string, Mount>([[project.prefix, project]]);\n const supplied = opts.modules;\n const virtualSource = (spec: string) =>\n typeof supplied === \"function\" ? supplied(spec) : supplied?.[spec];\n\n /** The mount and path of a file id; the longest prefix wins (`npm:@a/b@1.0.0/…`). */\n /**\n * The module type of a `.js` file, as Node.js decides it: the `type` of the nearest\n * `package.json` (tslib ships `modules/package.json` with `\"type\": \"module\"`). esbuild reads\n * that only for files on its own file system; for ours, a file in a `\"type\": \"module\"` scope\n * gets an id ending in ESM_SUFFIX (`.mjs`), so that esbuild gives its imports of CommonJS\n * modules Node's interop: the default import is `module.exports`, even with `__esModule`.\n * Vite gets the same from esbuild by pre-bundling dependencies from disk.\n */\n const scopeTypes = new Map<string, string | undefined>();\n const moduleTypeOf = async (mount: Mount, path: string): Promise<string | undefined> => {\n const root = mount.root.replace(/\\/$/, \"\");\n for (let dir = dirOf(path); dir.length >= root.length; dir = dirOf(dir)) {\n const key = `${mount.prefix}:${dir}`;\n if (scopeTypes.has(key)) return scopeTypes.get(key);\n const pj = `${dir === \"/\" ? \"\" : dir}/package.json`;\n if (await isFile(mount, pj)) {\n let type: string | undefined;\n try {\n type = JSON.parse(await readText(mount.files, pj)).type;\n } catch {}\n scopeTypes.set(key, type);\n return type;\n }\n if (dir === root || dir === \"/\" || !dir) break;\n }\n return undefined;\n };\n\n const locate = (id: string) => {\n if (id.endsWith(ESM_SUFFIX)) id = id.slice(0, -ESM_SUFFIX.length);\n let best: Mount | undefined;\n for (const m of mounts.values())\n if (id.startsWith(`${m.prefix}/`) && (!best || m.prefix.length > best.prefix.length))\n best = m;\n const path = best && pathOf(best, id);\n if (!best || !path) throw new Error(`webrun-bundler: no file ${id}`);\n return { mount: best, path };\n };\n\n const plugin: Plugin = {\n name: \"webrun-files\",\n setup(b) {\n b.onResolve({ filter: /.*/ }, async (args) => {\n const injected = args.path.startsWith(INJECT);\n const spec = injected ? args.path.slice(INJECT.length) : args.path;\n if (args.kind === \"entry-point\" && !injected) {\n const path = joinWithin(root, root, args.path.replace(/^\\/+/, \"\"));\n if (!path) return { errors: [{ text: `entry ${args.path} is outside the project` }] };\n return { path: idOf(project, path), namespace: NS };\n }\n if (virtualSource(spec) !== undefined) return { path: spec, namespace: VNS };\n if (isExternal(spec, external)) return { path: spec, external: true };\n // The host's modules and `inject` entries import from the project's root.\n const importer =\n injected || args.namespace === VNS\n ? { mount: project, path: `${root === \"/\" ? \"\" : root}/` }\n : locate(args.importer);\n const require = args.kind === \"require-call\" || args.kind === \"require-resolve\";\n const failed = (why?: string) => ({\n errors: [\n {\n text: `Could not resolve \"${spec}\" (imported by ${args.importer || \"inject\"})${why ? `: ${why}` : \"\"}`,\n },\n ],\n });\n let r: Awaited<ReturnType<typeof resolveSpecifier>>;\n try {\n r = await resolveSpecifier(spec, importer, packages, {\n conditions,\n require,\n browser,\n });\n } catch (e) {\n return failed((e as Error)?.message ?? String(e));\n }\n if (!r) return failed();\n mounts.set(r.mount.prefix, r.mount);\n const esm = /\\.js$/.test(r.path) && (await moduleTypeOf(r.mount, r.path)) === \"module\";\n return { path: idOf(r.mount, r.path) + (esm ? ESM_SUFFIX : \"\"), namespace: NS };\n });\n b.onLoad({ filter: /.*/, namespace: VNS }, (args) => ({\n contents: virtualSource(args.path) ?? \"\",\n loader: \"js\",\n }));\n b.onLoad({ filter: /.*/, namespace: NS }, async (args) => {\n const { mount, path } = locate(args.path);\n const loader = loaderFor(path);\n if (loader === \"binary\") {\n const chunks: Uint8Array[] = [];\n for await (const c of mount.files.read(path)) chunks.push(c);\n const bytes = new Uint8Array(chunks.reduce((n, c) => n + c.length, 0));\n let at = 0;\n for (const c of chunks) {\n bytes.set(c, at);\n at += c.length;\n }\n return { contents: bytes, loader };\n }\n const text = await readText(mount.files, path);\n const js = loader === \"js\" || loader === \"ts\" || loader === \"jsx\" || loader === \"tsx\";\n // Without an output map, the inputs' own maps are not read: esbuild would only parse them.\n if (!js) return { contents: text, loader };\n if (opts.sourcemap === false) return { contents: withoutInputMap(text), loader };\n return { contents: await inlineInputMap(mount, path, text), loader };\n });\n },\n };\n\n const { plugins: extraPlugins = [], ...rest } = opts.esbuildOptions ?? {};\n const result = await opts.esbuild.build({\n entryPoints: [opts.entry],\n bundle: true,\n write: false,\n format: opts.format ?? \"esm\",\n platform: opts.platform ?? \"browser\",\n target: opts.target ?? \"es2022\",\n outfile,\n absWorkingDir: \"/\",\n metafile: true,\n logLevel: \"silent\",\n minify: opts.minify,\n define: opts.define,\n ...(opts.lowerAwait ? { supported: LOWER_AWAIT } : {}),\n ...rest,\n ...(opts.inject?.length ? { inject: opts.inject.map((s) => INJECT + s) } : {}),\n // `sourcemap: false`: no map at all (a large bundle's map, with every source's content,\n // can take more memory than the bundle).\n sourcemap: opts.sourcemap === false ? false : \"external\",\n sourcesContent: opts.sourcemap !== false,\n plugins: [...extraPlugins, plugin],\n });\n const out = result.outputFiles ?? [];\n const jsFile = out.find((f) => !f.path.endsWith(\".map\"));\n const mapFile = out.find((f) => f.path.endsWith(\".map\"));\n if (!jsFile) throw new Error(\"webrun-bundler: esbuild produced no output\");\n if (!mapFile)\n return {\n code: jsFile.text,\n map: { version: 3, sources: [], names: [], mappings: \"\" } as unknown as SourceMap,\n metafile: result.metafile as BundleResult[\"metafile\"],\n warnings: result.warnings,\n } as BundleResult;\n const raw = JSON.parse(mapFile.text) as SourceMap;\n const map: SourceMap = {\n ...raw,\n file: outfile.split(\"/\").pop(),\n sources: raw.sources.map(sourceId),\n };\n delete map.sourceRoot;\n return {\n code: linkMap(jsFile.text, map, opts.sourcemap || \"external\", outfile),\n map,\n metafile: result.metafile as BundleResult[\"metafile\"],\n warnings: result.warnings,\n };\n}\n\n/**\n * Transpiles one file (TypeScript, JSX, modern syntax down to `target`; `await` lowered\n * when asked) with a source map back to it. A map the code carries (`sourceMappingURL`,\n * inline) is composed in, so the result still traces to the original.\n */\nexport async function transpile(code: string, opts: TranspileOptions): Promise<TranspileResult> {\n const r = await opts.esbuild.transform(code, {\n loader: loaderFor(opts.path),\n sourcefile: opts.path,\n sourcemap: \"external\",\n sourcesContent: true,\n format: opts.format,\n target: opts.target ?? \"es2022\",\n minify: opts.minify,\n define: opts.define,\n ...(opts.lowerAwait ? { supported: LOWER_AWAIT } : {}),\n });\n const map = JSON.parse(r.map) as SourceMap;\n return {\n code: linkMap(r.code, map, opts.sourcemap ?? \"external\", opts.path.replace(/\\.[^./]+$/, \".js\")),\n map,\n warnings: r.warnings,\n };\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@statewalker/webrun-bundler",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Transpiler, resolver and bundler on esbuild-wasm that reads everything through a FilesApi (MemFilesApi, OPFS, a FilesApi over a port; never node:fs) and fetches npm packages on demand. Every transformation keeps a source map: each line of a bundle traces back to the user's file or to the npm package's own source.",
|
package/src/bundle.test.ts
CHANGED
|
@@ -168,6 +168,46 @@ describe("bundle", () => {
|
|
|
168
168
|
expect(r.map.sources).not.toContain("npm:esm-pkg@1.2.3/dist/browser.js");
|
|
169
169
|
});
|
|
170
170
|
|
|
171
|
+
it("sourcemap: false builds no map (the same code, no sourceMappingURL), warnings kept", async () => {
|
|
172
|
+
const files = await filesOf({
|
|
173
|
+
"/package.json": JSON.stringify({
|
|
174
|
+
dependencies: { "esm-pkg": "^1.0.0", "cjs-pkg": "^2.0.0" },
|
|
175
|
+
}),
|
|
176
|
+
"/src/app.ts": APP,
|
|
177
|
+
"/src/data.json": '{ "v": 42 }',
|
|
178
|
+
// esbuild warns about a comparison with -0.
|
|
179
|
+
"/src/warn.ts": "export const odd = (x: number) => x === -0;\n",
|
|
180
|
+
});
|
|
181
|
+
const { source } = fakeRegistry({ "esm-pkg": await esmPackage(), "cjs-pkg": CJS_PKG });
|
|
182
|
+
await files.write("/src/entry.ts", [
|
|
183
|
+
new TextEncoder().encode('export * from "./app.ts";\nexport * from "./warn.ts";\n'),
|
|
184
|
+
]);
|
|
185
|
+
const r = await bundle({
|
|
186
|
+
esbuild,
|
|
187
|
+
files,
|
|
188
|
+
entry: "/src/entry.ts",
|
|
189
|
+
packages: npmPackages({ source }),
|
|
190
|
+
sourcemap: false,
|
|
191
|
+
});
|
|
192
|
+
expect(await (await run(r.code)).main("bob")).toBe("hello bob! BOB! 42");
|
|
193
|
+
expect(r.code).not.toMatch(/sourceMappingURL/);
|
|
194
|
+
expect(r.map.mappings).toBe("");
|
|
195
|
+
expect(r.map.sources).toEqual([]);
|
|
196
|
+
expect(r.warnings?.map((w) => w.text).join(" ")).toMatch(/-0/);
|
|
197
|
+
// The package's own map is neither read nor inlined: esbuild gets its code alone.
|
|
198
|
+
const inputs = r.metafile?.inputs ?? {};
|
|
199
|
+
const pkgInput = Object.keys(inputs).find((k) => k.includes("esm-pkg@1.2.3/dist/browser.js"));
|
|
200
|
+
expect(pkgInput).toBeDefined();
|
|
201
|
+
const withMaps = await bundle({
|
|
202
|
+
esbuild,
|
|
203
|
+
files,
|
|
204
|
+
entry: "/src/entry.ts",
|
|
205
|
+
packages: npmPackages({ source }),
|
|
206
|
+
});
|
|
207
|
+
const mapped = withMaps.metafile?.inputs[pkgInput as string]?.bytes ?? 0;
|
|
208
|
+
expect(inputs[pkgInput as string]?.bytes ?? Infinity).toBeLessThan(mapped);
|
|
209
|
+
});
|
|
210
|
+
|
|
171
211
|
it("maps every line that comes from an input; only esbuild's own helpers have no source", async () => {
|
|
172
212
|
const files = await filesOf({
|
|
173
213
|
"/package.json": JSON.stringify({
|
|
@@ -246,6 +286,37 @@ describe("bundle", () => {
|
|
|
246
286
|
);
|
|
247
287
|
});
|
|
248
288
|
|
|
289
|
+
it('gives files in a "type": "module" scope Node\'s CommonJS interop (tslib\'s modules/)', async () => {
|
|
290
|
+
// tslib 2.3: exports "import" -> modules/index.js (modules/package.json: type module), which
|
|
291
|
+
// does `import tslib from "../tslib.js"` of a CommonJS file that sets __esModule. In Node
|
|
292
|
+
// (and Vite, which pre-bundles from disk) the default import is module.exports.
|
|
293
|
+
const files = await filesOf({
|
|
294
|
+
"/src/main.js": 'import { __extends } from "tslib";\nexport const out = typeof __extends;\n',
|
|
295
|
+
"/node_modules/tslib/package.json": JSON.stringify({
|
|
296
|
+
name: "tslib",
|
|
297
|
+
version: "2.3.0",
|
|
298
|
+
main: "tslib.js",
|
|
299
|
+
exports: {
|
|
300
|
+
".": { import: "./modules/index.js", module: "./tslib.es6.js", default: "./tslib.js" },
|
|
301
|
+
},
|
|
302
|
+
}),
|
|
303
|
+
"/node_modules/tslib/modules/package.json": JSON.stringify({ type: "module" }),
|
|
304
|
+
"/node_modules/tslib/modules/index.js":
|
|
305
|
+
'import tslib from "../tslib.js";\nconst { __extends } = tslib;\nexport { __extends };\n',
|
|
306
|
+
"/node_modules/tslib/tslib.js":
|
|
307
|
+
'Object.defineProperty(exports, "__esModule", { value: true });\nexports.__extends = function () {};\n',
|
|
308
|
+
"/node_modules/tslib/tslib.es6.js": "export function __extends() {}\n",
|
|
309
|
+
});
|
|
310
|
+
const r = await bundle({
|
|
311
|
+
esbuild,
|
|
312
|
+
files,
|
|
313
|
+
entry: "/src/main.js",
|
|
314
|
+
conditions: ["browser", "import"],
|
|
315
|
+
});
|
|
316
|
+
expect((await run(r.code)).out).toBe("function");
|
|
317
|
+
expect(r.map.sources).toContain("npm:tslib@2.3.0/modules/index.js");
|
|
318
|
+
});
|
|
319
|
+
|
|
249
320
|
it("keeps externals as imports, picks exports conditions, resolves .js to .ts and #imports", async () => {
|
|
250
321
|
const files = await filesOf({
|
|
251
322
|
"/package.json": JSON.stringify({ imports: { "#util": "./src/util.ts" } }),
|
package/src/bundle.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { readText } from "@statewalker/webrun-files";
|
|
2
2
|
import type { Loader, Plugin } from "esbuild-wasm";
|
|
3
|
-
import { inlineInputMap } from "./input-maps.js";
|
|
3
|
+
import { inlineInputMap, withoutInputMap } from "./input-maps.js";
|
|
4
4
|
import { nodeModulesPackages } from "./packages.js";
|
|
5
|
-
import { idOf, joinWithin, pathOf, readManifest } from "./paths.js";
|
|
5
|
+
import { dirOf, idOf, isFile, joinWithin, pathOf, readManifest } from "./paths.js";
|
|
6
6
|
import { resolveSpecifier } from "./resolve.js";
|
|
7
7
|
import type {
|
|
8
8
|
BundleOptions,
|
|
@@ -56,7 +56,8 @@ const sourceId = (s: string) =>
|
|
|
56
56
|
s
|
|
57
57
|
.replace(/^(\.\.\/)*/, "")
|
|
58
58
|
.replace(new RegExp(`^${VNS}:`), "virtual:")
|
|
59
|
-
.replace(new RegExp(`^${NS}:`), "")
|
|
59
|
+
.replace(new RegExp(`^${NS}:`), "")
|
|
60
|
+
.replace("?type=module.mjs", ""); // ESM_SUFFIX: the file's id, as in the map's other sources
|
|
60
61
|
|
|
61
62
|
const toBase64 = (text: string) => {
|
|
62
63
|
const bytes = new TextEncoder().encode(text);
|
|
@@ -85,6 +86,9 @@ function linkMap(code: string, map: SourceMap, how: "external" | "inline", name:
|
|
|
85
86
|
* its own map (TypeScript compiled to `.js`), to the package's original source. The
|
|
86
87
|
* map's sources are file ids: `~/src/app.ts`, `npm:pkg@1.2.3/src/index.ts`.
|
|
87
88
|
*/
|
|
89
|
+
/** Marks the id of a `.js` file in a `"type": "module"` package scope (see `moduleTypeOf`). */
|
|
90
|
+
const ESM_SUFFIX = "?type=module.mjs";
|
|
91
|
+
|
|
88
92
|
export async function bundle(opts: BundleOptions): Promise<BundleResult> {
|
|
89
93
|
const root = opts.root ?? "/";
|
|
90
94
|
const project: Mount = {
|
|
@@ -104,7 +108,36 @@ export async function bundle(opts: BundleOptions): Promise<BundleResult> {
|
|
|
104
108
|
typeof supplied === "function" ? supplied(spec) : supplied?.[spec];
|
|
105
109
|
|
|
106
110
|
/** The mount and path of a file id; the longest prefix wins (`npm:@a/b@1.0.0/…`). */
|
|
111
|
+
/**
|
|
112
|
+
* The module type of a `.js` file, as Node.js decides it: the `type` of the nearest
|
|
113
|
+
* `package.json` (tslib ships `modules/package.json` with `"type": "module"`). esbuild reads
|
|
114
|
+
* that only for files on its own file system; for ours, a file in a `"type": "module"` scope
|
|
115
|
+
* gets an id ending in ESM_SUFFIX (`.mjs`), so that esbuild gives its imports of CommonJS
|
|
116
|
+
* modules Node's interop: the default import is `module.exports`, even with `__esModule`.
|
|
117
|
+
* Vite gets the same from esbuild by pre-bundling dependencies from disk.
|
|
118
|
+
*/
|
|
119
|
+
const scopeTypes = new Map<string, string | undefined>();
|
|
120
|
+
const moduleTypeOf = async (mount: Mount, path: string): Promise<string | undefined> => {
|
|
121
|
+
const root = mount.root.replace(/\/$/, "");
|
|
122
|
+
for (let dir = dirOf(path); dir.length >= root.length; dir = dirOf(dir)) {
|
|
123
|
+
const key = `${mount.prefix}:${dir}`;
|
|
124
|
+
if (scopeTypes.has(key)) return scopeTypes.get(key);
|
|
125
|
+
const pj = `${dir === "/" ? "" : dir}/package.json`;
|
|
126
|
+
if (await isFile(mount, pj)) {
|
|
127
|
+
let type: string | undefined;
|
|
128
|
+
try {
|
|
129
|
+
type = JSON.parse(await readText(mount.files, pj)).type;
|
|
130
|
+
} catch {}
|
|
131
|
+
scopeTypes.set(key, type);
|
|
132
|
+
return type;
|
|
133
|
+
}
|
|
134
|
+
if (dir === root || dir === "/" || !dir) break;
|
|
135
|
+
}
|
|
136
|
+
return undefined;
|
|
137
|
+
};
|
|
138
|
+
|
|
107
139
|
const locate = (id: string) => {
|
|
140
|
+
if (id.endsWith(ESM_SUFFIX)) id = id.slice(0, -ESM_SUFFIX.length);
|
|
108
141
|
let best: Mount | undefined;
|
|
109
142
|
for (const m of mounts.values())
|
|
110
143
|
if (id.startsWith(`${m.prefix}/`) && (!best || m.prefix.length > best.prefix.length))
|
|
@@ -152,7 +185,8 @@ export async function bundle(opts: BundleOptions): Promise<BundleResult> {
|
|
|
152
185
|
}
|
|
153
186
|
if (!r) return failed();
|
|
154
187
|
mounts.set(r.mount.prefix, r.mount);
|
|
155
|
-
|
|
188
|
+
const esm = /\.js$/.test(r.path) && (await moduleTypeOf(r.mount, r.path)) === "module";
|
|
189
|
+
return { path: idOf(r.mount, r.path) + (esm ? ESM_SUFFIX : ""), namespace: NS };
|
|
156
190
|
});
|
|
157
191
|
b.onLoad({ filter: /.*/, namespace: VNS }, (args) => ({
|
|
158
192
|
contents: virtualSource(args.path) ?? "",
|
|
@@ -174,7 +208,10 @@ export async function bundle(opts: BundleOptions): Promise<BundleResult> {
|
|
|
174
208
|
}
|
|
175
209
|
const text = await readText(mount.files, path);
|
|
176
210
|
const js = loader === "js" || loader === "ts" || loader === "jsx" || loader === "tsx";
|
|
177
|
-
|
|
211
|
+
// Without an output map, the inputs' own maps are not read: esbuild would only parse them.
|
|
212
|
+
if (!js) return { contents: text, loader };
|
|
213
|
+
if (opts.sourcemap === false) return { contents: withoutInputMap(text), loader };
|
|
214
|
+
return { contents: await inlineInputMap(mount, path, text), loader };
|
|
178
215
|
});
|
|
179
216
|
},
|
|
180
217
|
};
|
|
@@ -196,14 +233,23 @@ export async function bundle(opts: BundleOptions): Promise<BundleResult> {
|
|
|
196
233
|
...(opts.lowerAwait ? { supported: LOWER_AWAIT } : {}),
|
|
197
234
|
...rest,
|
|
198
235
|
...(opts.inject?.length ? { inject: opts.inject.map((s) => INJECT + s) } : {}),
|
|
199
|
-
sourcemap:
|
|
200
|
-
|
|
236
|
+
// `sourcemap: false`: no map at all (a large bundle's map, with every source's content,
|
|
237
|
+
// can take more memory than the bundle).
|
|
238
|
+
sourcemap: opts.sourcemap === false ? false : "external",
|
|
239
|
+
sourcesContent: opts.sourcemap !== false,
|
|
201
240
|
plugins: [...extraPlugins, plugin],
|
|
202
241
|
});
|
|
203
242
|
const out = result.outputFiles ?? [];
|
|
204
243
|
const jsFile = out.find((f) => !f.path.endsWith(".map"));
|
|
205
244
|
const mapFile = out.find((f) => f.path.endsWith(".map"));
|
|
206
|
-
if (!jsFile
|
|
245
|
+
if (!jsFile) throw new Error("webrun-bundler: esbuild produced no output");
|
|
246
|
+
if (!mapFile)
|
|
247
|
+
return {
|
|
248
|
+
code: jsFile.text,
|
|
249
|
+
map: { version: 3, sources: [], names: [], mappings: "" } as unknown as SourceMap,
|
|
250
|
+
metafile: result.metafile as BundleResult["metafile"],
|
|
251
|
+
warnings: result.warnings,
|
|
252
|
+
} as BundleResult;
|
|
207
253
|
const raw = JSON.parse(mapFile.text) as SourceMap;
|
|
208
254
|
const map: SourceMap = {
|
|
209
255
|
...raw,
|
|
@@ -212,7 +258,7 @@ export async function bundle(opts: BundleOptions): Promise<BundleResult> {
|
|
|
212
258
|
};
|
|
213
259
|
delete map.sourceRoot;
|
|
214
260
|
return {
|
|
215
|
-
code: linkMap(jsFile.text, map, opts.sourcemap
|
|
261
|
+
code: linkMap(jsFile.text, map, opts.sourcemap || "external", outfile),
|
|
216
262
|
map,
|
|
217
263
|
metafile: result.metafile as BundleResult["metafile"],
|
|
218
264
|
warnings: result.warnings,
|
package/src/input-maps.ts
CHANGED
|
@@ -29,6 +29,17 @@ const fromBase64 = (b64: string) =>
|
|
|
29
29
|
* esbuild then composes it with its own: a bundled line traces to the original source.
|
|
30
30
|
* A map that is missing or unreadable is dropped (the file maps to itself).
|
|
31
31
|
*/
|
|
32
|
+
/**
|
|
33
|
+
* `code` without its trailing `sourceMappingURL` comment (and without reading the map): for
|
|
34
|
+
* bundles built with no source map, where an inlined input map would only add to what esbuild
|
|
35
|
+
* parses and holds (a package's maps, with their sources' text, can outweigh its code).
|
|
36
|
+
*/
|
|
37
|
+
export function withoutInputMap(code: string): string {
|
|
38
|
+
const end = code.trimEnd();
|
|
39
|
+
const nl = end.lastIndexOf("\n");
|
|
40
|
+
return MAP_COMMENT.test(end.slice(nl + 1)) ? end.slice(0, Math.max(0, nl)) : code;
|
|
41
|
+
}
|
|
42
|
+
|
|
32
43
|
export async function inlineInputMap(mount: Mount, path: string, code: string): Promise<string> {
|
|
33
44
|
const lines = code.trimEnd().split("\n");
|
|
34
45
|
const last = lines[lines.length - 1] ?? "";
|
package/src/types.ts
CHANGED
|
@@ -111,7 +111,7 @@ export interface BundleOptions {
|
|
|
111
111
|
/** Name of the output file: the map is linked as `<outfile>.map` (default `bundle.js`). */
|
|
112
112
|
outfile?: string;
|
|
113
113
|
/** `external` (default): `code` links `<outfile>.map`, which `map` holds; `inline`: `code` carries it too. */
|
|
114
|
-
sourcemap?: "external" | "inline";
|
|
114
|
+
sourcemap?: "external" | "inline" | false;
|
|
115
115
|
/** Other esbuild options, applied last (the bundler's plugin and source maps stay). */
|
|
116
116
|
esbuildOptions?: Partial<BuildOptions>;
|
|
117
117
|
}
|