esbuild build API bundling virtual files in memory (write:false): working versions (tested 2026-10-15)
Bundle TypeScript from an in-memory file map with an esbuild resolve/load plugin and write:false, use define, tree shaking, minify and external source maps, evaluate the bundle, and assert structured build errors.
passed5 passed · 0 failed2026-10-15 20:08 UTC- Status
- passed
- Last passed
- 2026-10-15 20:08 UTC
- Tests
- 5 / 5
- Language
- TypeScript
- Runtime
- node v22.23.3
pinned versions3
esbuild@0.28.2@types/node@26.6.5tsx@4.23.15
run it
npm install --no-audit --no-fund --ignore-scripts=false npm test
test environment
node v22.23.3 linux 6.17.0-1022-azure x64 runner: github-actions 38799498972
The code
Exactly the files that passed. Your agent can pull them with get_recipe("esbuild-in-memory-bundle") (install), or see them on GitHub.
package.json
{
"name": "esbuild-in-memory-bundle",
"private": true,
"type": "module",
"scripts": {
"test": "node --import tsx --test test/*.test.ts"
},
"dependencies": {
"esbuild": "0.28.2"
},
"devDependencies": {
"@types/node": "26.6.5",
"tsx": "4.23.15"
}
}
src/bundle.ts
import * as esbuild from "esbuild";
/** Virtual-file plugin: resolves bare imports from an in-memory map, so nothing touches disk. */
function virtualFs(files: Record<string, string>): esbuild.Plugin {
return {
name: "virtual-fs",
setup(build) {
build.onResolve({ filter: /.*/ }, (args) => {
const key = args.path.replace(/^\.\//, "");
if (key in files) return { path: key, namespace: "virtual" };
if (args.path === "env:build") return { path: "env", namespace: "env" };
return undefined;
});
build.onLoad({ filter: /.*/, namespace: "virtual" }, (args) => ({ contents: files[args.path], loader: args.path.endsWith(".ts") ? "ts" : "js" }));
build.onLoad({ filter: /.*/, namespace: "env" }, () => ({ contents: JSON.stringify({ builtAt: "fixed" }), loader: "json" }));
},
};
}
export async function bundle(entry: string, files: Record<string, string>, opts: Partial<esbuild.BuildOptions> = {}) {
const result = await esbuild.build({
entryPoints: [entry],
bundle: true,
write: false,
outfile: "out.js",
format: "esm",
platform: "neutral",
metafile: true,
logLevel: "silent",
plugins: [virtualFs(files)],
...opts,
});
const out = result.outputFiles.find((f) => f.path.endsWith("out.js"))!;
return { code: out.text, inputs: Object.keys(result.metafile!.inputs).sort(), warnings: result.warnings.length, files: result.outputFiles.map((f) => f.path.split("/").pop()) };
}
/** Run an ESM bundle string and return its exports. */
export async function evaluate(code: string) {
return import("data:text/javascript;base64," + Buffer.from(code).toString("base64"));
}
export const transformTs = (src: string) => esbuild.transform(src, { loader: "ts", format: "esm", target: "es2020" });
test/bundle.test.ts
import { test } from "node:test";
import assert from "node:assert/strict";
import { bundle, evaluate, transformTs } from "../src/bundle.ts";
const files = {
"main.ts": 'import { add } from "./math.ts";\nimport env from "env:build";\nimport { unused } from "./math.ts";\nexport const total: number = add(2, 3);\nexport const meta = env.builtAt;\nexport const DEBUG = process.env.NODE_ENV !== "production";\n',
"math.ts": "export const add = (a: number, b: number): number => a + b;\nexport const unused = () => 'dead code';\n",
};
test("bundles virtual TS files in memory and runs them", async () => {
const { code, inputs } = await bundle("main.ts", files, { define: { "process.env.NODE_ENV": '"production"' } });
assert.deepEqual(inputs, ["env:env", "virtual:main.ts", "virtual:math.ts"]);
const mod = await evaluate(code);
assert.equal(mod.total, 5);
assert.equal(mod.meta, "fixed");
assert.equal(mod.DEBUG, false);
});
test("tree shaking drops unused exports", async () => {
const { code } = await bundle("main.ts", files, { define: { "process.env.NODE_ENV": '"production"' } });
assert.doesNotMatch(code, /dead code/);
});
test("minify plus external source map produces two outputs", async () => {
const { code, files: outs } = await bundle("main.ts", files, { minify: true, sourcemap: "external", define: { "process.env.NODE_ENV": '"production"' } });
assert.deepEqual(outs.sort(), ["out.js", "out.js.map"]);
assert.ok(code.length < 200, `minified length ${code.length}`);
assert.equal((await evaluate(code)).total, 5);
});
test("build errors are reported with location", async () => {
await assert.rejects(bundle("main.ts", { "main.ts": "export const x = ;" }), (e: { errors: { text: string; location: { line: number } }[] }) => {
assert.equal(e.errors[0].location.line, 1);
assert.match(e.errors[0].text, /Unexpected/);
return true;
});
});
test("transform strips types only", async () => {
const { code } = await transformTs("export const f = (x: number): string => `${x}` as string;\n");
// esbuild hoists exports into a trailing export list
assert.equal(code, "const f = (x) => `${x}`;\nexport {\n f\n};\n");
});
Connect to ProvenPin
Add the free MCP server so your agent can pull this recipe and others like it. Same setup as the docs.
terminal
claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp
~/.cursor/mcp.json
{ "mcpServers": { "provenpin": { "url": "https://mcp.provenpin.com/mcp" } } }.vscode/mcp.json
{ "servers": { "provenpin": { "type": "http", "url": "https://mcp.provenpin.com/mcp" } } }~/.codeium/windsurf/mcp_config.json
{ "mcpServers": { "provenpin": { "serverUrl": "https://mcp.provenpin.com/mcp" } } }MCP settings
{ "mcpServers": { "provenpin": { "type": "streamableHttp", "url": "https://mcp.provenpin.com/mcp" } } }Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.