Files

154 lines
5.8 KiB
TypeScript
Raw Permalink Normal View History

2026-08-27 21:09:14 +00:00
import { describe } from "bun:test";
import { itBundled } from "./expectBundled";
describe("bundler", () => {
describe("compile with splitting", () => {
itBundled("compile/splitting/RelativePathsAcrossChunks", {
compile: true,
splitting: true,
backend: "cli",
files: {
"/src/app/entry.ts": /* js */ `
console.log('app entry');
import('../components/header').then(m => m.render());
`,
"/src/components/header.ts": /* js */ `
export async function render() {
console.log('header rendering');
const nav = await import('./nav/menu');
nav.show();
}
`,
"/src/components/nav/menu.ts": /* js */ `
export async function show() {
console.log('menu showing');
const items = await import('./items');
console.log('items:', items.list);
}
`,
"/src/components/nav/items.ts": /* js */ `
export const list = ['home', 'about', 'contact'].join(',');
`,
},
entryPoints: ["/src/app/entry.ts"],
outdir: "/build",
run: {
stdout: "app entry\nheader rendering\nmenu showing\nitems: home,about,contact",
},
});
for (const minify of [false, true]) {
itBundled(`compile/splitting/ImportMetaInSplitChunk${minify ? "+minify" : ""}`, {
compile: true,
splitting: true,
bytecode: true,
format: "esm",
...(minify ? { minifySyntax: true, minifyIdentifiers: true, minifyWhitespace: true } : {}),
files: {
"/entry.ts": /* js */ `
const mod = await import("./worker.ts");
mod.run();
`,
"/worker.ts": /* js */ `
export function run() {
console.log(typeof import.meta.url === "string" ? "ok" : "fail");
console.log(typeof import.meta.dir === "string" ? "ok" : "fail");
}
`,
},
run: {
stdout: "ok\nok",
},
});
}
// The shared chunk contains a require()d (so __esm-wrapped) module with an
// unused import of a node builtin. Builtins are side-effect free, so that
// import is tree-shaken out of the printed chunk, but the module record
// built for --bytecode still listed it, under the import's original local
// name because the dead symbol was never renamed. When a live export of the
// chunk had the same name, its export entry turned into a re-export of the
// builtin, and the other chunk got fs/promises.rm instead of the local rm().
//
// The unused import binds every single-character name as well, so the
// collision also happens with whatever name the minifier gives `rm`.
//
// Only the bytecode builds have a record to get wrong, and only the
// splitting builds export `rm` across chunks; the other combinations pin
// the configurations that already worked.
const deadImportNames = [
"rm",
...Array.from("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$", c => `rm as ${c}`),
];
for (const splitting of [false, true]) {
for (const bytecode of [false, true]) {
for (const minify of [false, true]) {
const suffix = (splitting ? "+splitting" : "") + (bytecode ? "+bytecode" : "") + (minify ? "+minify" : "");
itBundled(`compile/DeadExternalImportInWrappedModule${suffix}`, {
compile: true,
splitting,
bytecode,
format: "esm",
...(minify ? { minifySyntax: true, minifyIdentifiers: true, minifyWhitespace: true } : {}),
files: {
"/entry.js": /* js */ `
import { rm } from "./shared.js";
console.log("entry:", rm());
await import("./page.js");
`,
"/page.js": /* js */ `
import { rm } from "./shared.js";
console.log("page:", rm());
`,
"/shared.js": /* js */ `
const { value } = require("./wrapped.js");
export function rm() {
return "local rm " + value;
}
`,
// A .js file on purpose: in TypeScript an unused import is dropped by
// the parser and never reaches the linker.
"/wrapped.js": /* js */ `
import { ${deadImportNames.join(", ")} } from "fs/promises";
export const value = 42;
`,
},
run: {
stdout: "entry: local rm 42\npage: local rm 42",
},
});
}
}
}
// A split chunk gets its own bytecode + module record. Re-exports of
// externals in it are printed as `export * from`, or as imports plus the
// chunk's `export { ... }` tail; the record has to describe all of them in
// addition to the cross-chunk imports, or reading `fs` off the namespace
// throws a TDZ ReferenceError.
for (const minify of [false, true]) {
itBundled(`compile/splitting/ReExportExternalFromSplitChunk${minify ? "+minify" : ""}`, {
compile: true,
splitting: true,
bytecode: true,
format: "esm",
...(minify ? { minifySyntax: true, minifyIdentifiers: true, minifyWhitespace: true } : {}),
files: {
"/entry.ts": /* js */ `
const mod = await import("./reexports.ts");
console.log(typeof mod.fs.readFileSync, typeof mod.join, typeof mod.rfs);
`,
"/reexports.ts": /* js */ `
export * from "node:path";
export * as fs from "node:fs";
export { readFileSync as rfs } from "node:fs";
`,
},
run: {
stdout: "function function function",
},
});
}
});
});