initial commit

This commit is contained in:
i2p
2026-08-27 21:09:14 +00:00
commit a5b6d59437
12681 changed files with 3253832 additions and 0 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+3
View File
@@ -0,0 +1,3 @@
import fs from "fs";
import { fileURLToPath } from "url";
console.log(fs.existsSync(fileURLToPath(import.meta.url)), fs.existsSync(import.meta.path));
File diff suppressed because it is too large Load Diff
+330
View File
@@ -0,0 +1,330 @@
import { describe } from "bun:test";
import { itBundled } from "../expectBundled";
// Tests ported from:
// https://github.com/evanw/esbuild/blob/main/internal/bundler_tests/bundler_importstar_ts_test.go
// For debug, all files are written to $TEMP/bun-bundle-tests/ts
describe("bundler", () => {
itBundled("importstar_ts/Unused", {
files: {
"/entry.ts": /* ts */ `
import * as ns from './foo'
let foo = 234
console.log(foo)
`,
"/foo.ts": `export const foo = 123`,
},
run: { stdout: "234" },
});
itBundled("importstar_ts/Capture", {
files: {
"/entry.ts": /* ts */ `
import * as ns from './foo'
let foo = 234
console.log(JSON.stringify(ns), ns.foo, foo)
`,
"/foo.ts": `export const foo = 123`,
},
run: { stdout: '{"foo":123} 123 234' },
});
itBundled("importstar_ts/NoCapture", {
files: {
"/entry.ts": /* ts */ `
import * as ns from './foo'
let foo = 234
console.log(ns.foo, ns.foo, foo)
`,
"/foo.ts": `export const foo = 123`,
},
run: { stdout: "123 123 234" },
});
itBundled("importstar_ts/ExportImportStarUnused", {
files: {
"/entry.ts": /* ts */ `
import {ns} from './bar'
let foo = 234
console.log(foo)
`,
"/foo.ts": `export const foo = 123`,
"/bar.ts": /* ts */ `
import * as ns from './foo'
export {ns}
`,
},
run: { stdout: "234" },
});
itBundled("importstar_ts/ExportImportStarNoCapture", {
files: {
"/entry.ts": /* ts */ `
import {ns} from './bar'
let foo = 234
console.log(ns.foo, ns.foo, foo)
`,
"/foo.ts": `export const foo = 123`,
"/bar.ts": /* ts */ `
import * as ns from './foo'
export {ns}
`,
},
run: { stdout: "123 123 234" },
});
itBundled("importstar_ts/ExportImportStarCapture", {
files: {
"/entry.ts": /* ts */ `
import {ns} from './bar'
let foo = 234
console.log(JSON.stringify(ns), ns.foo, foo)
`,
"/foo.ts": `export const foo = 123`,
"/bar.ts": /* ts */ `
import * as ns from './foo'
export {ns}
`,
},
run: { stdout: '{"foo":123} 123 234' },
});
itBundled("importstar_ts/ExportStarAsUnused", {
files: {
"/entry.ts": /* ts */ `
import {ns} from './bar'
let foo = 234
console.log(foo)
`,
"/foo.ts": `export const foo = 123`,
"/bar.ts": `export * as ns from './foo'`,
},
});
itBundled("importstar_ts/ExportStarAsNoCapture", {
files: {
"/entry.ts": /* ts */ `
import {ns} from './bar'
let foo = 234
console.log(ns.foo, ns.foo, foo)
`,
"/foo.ts": `export const foo = 123`,
"/bar.ts": `export * as ns from './foo'`,
},
run: { stdout: "123 123 234" },
});
itBundled("importstar_ts/ExportStarAsCapture", {
files: {
"/entry.ts": /* ts */ `
import {ns} from './bar'
let foo = 234
console.log(JSON.stringify(ns), ns.foo, foo)
`,
"/foo.ts": `export const foo = 123`,
"/bar.ts": `export * as ns from './foo'`,
},
run: { stdout: '{"foo":123} 123 234' },
});
itBundled("importstar_ts/ExportStarUnused", {
files: {
"/entry.ts": /* ts */ `
import * as ns from './bar'
let foo = 234
console.log(foo)
`,
"/foo.ts": `export const foo = 123`,
"/bar.ts": `export * from './foo'`,
},
run: { stdout: "234" },
});
itBundled("importstar_ts/ExportStarNoCapture", {
files: {
"/entry.ts": /* ts */ `
import * as ns from './bar'
let foo = 234
console.log(ns.foo, ns.foo, foo)
`,
"/foo.ts": `export const foo = 123`,
"/bar.ts": `export * from './foo'`,
},
run: { stdout: "123 123 234" },
});
itBundled("importstar_ts/ExportStarCapture", {
files: {
"/entry.ts": /* ts */ `
import * as ns from './bar'
let foo = 234
console.log(JSON.stringify(ns), ns.foo, foo)
`,
"/foo.ts": `export const foo = 123`,
"/bar.ts": `export * from './foo'`,
},
run: { stdout: '{"foo":123} 123 234' },
});
itBundled("importstar_ts/CommonJSUnused", {
files: {
"/entry.ts": /* ts */ `
import * as ns from './foo'
let foo = 234
console.log(foo)
`,
"/foo.ts": `exports.foo = 123`,
},
run: { stdout: "234" },
});
itBundled("importstar_ts/CommonJSCapture", {
files: {
"/entry.ts": /* ts */ `
import * as ns from './foo'
let foo = 234
console.log(JSON.stringify(ns), ns.foo, foo)
`,
"/foo.ts": `exports.foo = 123`,
},
run: { stdout: '{"foo":123} 123 234' },
});
itBundled("importstar_ts/CommonJSNoCapture", {
files: {
"/entry.ts": /* ts */ `
import * as ns from './foo'
let foo = 234
console.log(ns.foo, ns.foo, foo)
`,
"/foo.ts": `exports.foo = 123`,
},
run: { stdout: "123 123 234" },
});
itBundled("importstar_ts/TSAndCommonJS", {
files: {
"/entry.js": /* js */ `
import * as ns from './foo'
const ns2 = require('./foo')
console.log(ns.foo, ns2.foo)
`,
"/foo.ts": `export const foo = 123`,
},
run: { stdout: "123 123" },
});
itBundled("importstar_ts/NoBundleUnused", {
files: {
"/entry.ts": /* ts */ `
import * as ns from './foo'
let foo = 234
console.log(foo)
`,
},
target: "bun",
bundling: false,
run: { stdout: "234" },
});
itBundled("importstar_ts/NoBundleCapture", {
files: {
"/entry.ts": /* ts */ `
import * as ns from './foo'
let foo = 234
console.log(JSON.stringify(ns), ns.foo, foo)
`,
},
target: "bun",
bundling: false,
runtimeFiles: {
"/foo.js": `
export const foo = 123
`,
},
run: { stdout: '{"foo":123} 123 234' },
});
itBundled("importstar_ts/NoBundleNoCapture", {
files: {
"/entry.ts": /* ts */ `
import * as ns from './foo'
let foo = 234
console.log(ns.foo, ns.foo, foo)
`,
},
target: "bun",
bundling: false,
runtimeFiles: {
"/foo.js": `
export const foo = 123
`,
},
run: { stdout: "123 123 234" },
});
itBundled("importstar_ts/MangleNoBundleUnused", {
files: {
"/entry.ts": /* ts */ `
import * as ns from './foo'
let foo = 234
console.log(foo)
`,
},
minifySyntax: true,
target: "bun",
bundling: false,
runtimeFiles: {
"/foo.js": `
export const foo = 123
`,
},
run: { stdout: "234" },
});
itBundled("importstar_ts/MangleNoBundleCapture", {
files: {
"/entry.ts": /* ts */ `
import * as ns from './foo'
let foo = 234
console.log(JSON.stringify(ns), ns.foo, foo)
`,
},
minifySyntax: true,
bundling: false,
runtimeFiles: {
"/foo.js": `
export const foo = 123
`,
},
run: { stdout: '{"foo":123} 123 234' },
});
itBundled("importstar_ts/MangleNoBundleNoCapture", {
files: {
"/entry.ts": /* ts */ `
import * as ns from './foo'
let foo = 234
console.log(ns.foo, ns.foo, foo)
`,
},
minifySyntax: true,
bundling: false,
runtimeFiles: {
"/foo.js": `
export const foo = 123
`,
},
run: { stdout: "123 123 234" },
});
itBundled("importstar_ts/ReExportTypeOnlyFileES6", {
files: {
"/entry.ts": /* ts */ `
import * as ns from './re-export'
console.log(ns.foo)
`,
"/re-export.ts": /* ts */ `
export * from './types1'
export * from './types2'
export * from './types3'
export * from './values'
`,
"/types1.ts": /* ts */ `
export interface Foo {}
export type Bar = number;
console.log('some code')
`,
"/types2.ts": /* ts */ `
import {Foo} from "./type"
export {Foo}
console.log('some code')
`,
"/types3.ts": /* ts */ `
export {Foo} from "./type"
console.log('some code');
`,
"/values.ts": `export let foo = 123`,
"/type.ts": `export type Foo = number`,
},
});
});
+902
View File
@@ -0,0 +1,902 @@
import { describe } from "bun:test";
import { itBundled } from "../expectBundled";
// Tests ported from:
// https://github.com/evanw/esbuild/blob/main/internal/bundler_tests/bundler_loader_test.go
// For debug, all files are written to $TEMP/bun-bundle-tests/loader
describe("bundler", () => {
itBundled("loader/JSONCommonJSAndES6", {
files: {
"/entry.js": /* js */ `
const x_json = require('./x.json')
import y_json from './y.json'
import {small, if as fi} from './z.json'
console.log(JSON.stringify(x_json), JSON.stringify(y_json), small, fi)
`,
"/x.json": `{"x": true}`,
"/y.json": `{"y1": true, "y2": false}`,
"/z.json": /* json */ `
{
"big": "this is a big long line of text that should be REMOVED",
"small": "some small text",
"if": "test keyword imports"
}
`,
},
dce: true,
run: {
stdout: '{"x":true} {"y1":true,"y2":false} some small text test keyword imports',
},
});
itBundled("loader/JSONSharedWithMultipleEntriesESBuildIssue413", {
todo: true,
files: {
"/a.js": /* js */ `
import data from './data.json'
import {test} from './data.json';
import * as NSData from './data.json';
console.log('a:', JSON.stringify(data), data.test, test === data.test, NSData.test === data.test, NSData.default === data, NSData.default.test === data.test, JSON.stringify(NSData))
`,
"/b.js": /* js */ `
import data from './data.json'
import {test} from './data.json';
import * as NSData from './data.json';
console.log('b:', JSON.stringify(data), data.test, test === data.test, NSData.test === data.test, NSData.default === data, NSData.default.test === data.test, JSON.stringify(NSData))
`,
"/data.json": `{"test": 123}`,
},
entryPoints: ["/a.js", "/b.js"],
format: "esm",
run: [
{
file: "/out/a.js",
stdout: 'a: {"test":123} 123 true true true true {"test":123}',
},
{
file: "/out/b.js",
stdout: 'b: {"test":123} 123 true true true true {"test":123}',
},
],
});
itBundled("loader/File", {
todo: process.platform === "win32", // TODO
files: {
"/entry.js": `
import path from 'path';
const file = require('./test.svg');
console.log(file);
const contents = await Bun.file(path.join(import.meta.dir, file)).text();
if(contents !== '<svg></svg>') throw new Error('Contents did not match');
`,
"/test.svg": `<svg></svg>`,
},
outdir: "/out",
loader: {
".svg": "file",
},
target: "bun",
run: {
stdout: /\.\/test-.*\.svg/,
},
});
itBundled("loader/FileMultipleNoCollision", {
todo: process.platform === "win32", // TODO
files: {
"/entry.js": /* js */ `
import path from 'path';
const file1 = require('./a/test.svg');
console.log(file1);
const contents = await Bun.file(path.join(import.meta.dir, file1)).text();
if(contents !== '<svg></svg>') throw new Error('Contents did not match');
const file2 = require('./b/test.svg');
console.log(file2);
const contents2 = await Bun.file(path.join(import.meta.dir, file2)).text();
if(contents2 !== '<svg></svg>') throw new Error('Contents did not match');
`,
"/a/test.svg": `<svg></svg>`,
"/b/test.svg": `<svg></svg>`,
},
loader: {
".svg": "file",
},
target: "bun",
outdir: "/out",
run: {
stdout: /\.\/test-.*\.svg\n\.\/test-.*\.svg/,
},
});
itBundled("loader/FileMultipleNoCollisionAssetNames", {
todo: process.platform === "win32", // TODO
files: {
"/entry.js": /* js */ `
import path from 'path';
const file1 = require('./a/test.svg');
console.log(file1);
const contents = await Bun.file(path.join(import.meta.dir, file1)).text();
if(contents !== '<svg></svg>') throw new Error('Contents did not match');
const file2 = require('./b/test.svg');
console.log(file2);
const contents2 = await Bun.file(path.join(import.meta.dir, file2)).text();
if(contents2 !== '<svg></svg>') throw new Error('Contents did not match');
`,
"/a/test.svg": `<svg></svg>`,
"/b/test.svg": `<svg></svg>`,
},
outdir: "/out",
assetNaming: "assets/[name]-[hash].[ext]",
loader: {
".svg": "file",
},
target: "bun",
run: {
stdout: /\.\/assets\/test-.*\.svg\n\.\/assets\/test-.*\.svg/,
},
});
itBundled("loader/JSXSyntaxInJSWithJSXLoader", {
files: {
"/entry.cjs": `console.log(<div/>)`,
},
loader: {
".cjs": "jsx",
},
bundling: false,
});
// itBundled("loader/JSXPreserveCapitalLetter", {
// // GENERATED
// files: {
// "/entry.jsx": /* jsx */ `
// import { mustStartWithUpperCaseLetter as Test } from './foo'
// console.log(<Test/>)
// `,
// "/foo.js": `export class mustStartWithUpperCaseLetter {}`,
// },
// });
// itBundled("loader/JSXPreserveCapitalLetterMinify", {
// files: {
// "/entry.jsx": /* jsx */ `
// import { mustStartWithUpperCaseLetter as XYYYY } from './foo'
// // This should be named "Y" due to frequency analysis
// console.log(<XYYYY YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY />)
// `,
// "/foo.js": `export class mustStartWithUpperCaseLetter {}`,
// },
// external: ["react"],
// minifyIdentifiers: true,
// });
// itBundled("loader/JSXPreserveCapitalLetterMinifyNested", {
// files: {
// "/entry.jsx": /* jsx */ `
// x = () => {
// class RENAME_ME {} // This should be named "Y" due to frequency analysis
// capture(RENAME_ME)
// return <RENAME_ME YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY />
// }
// `,
// },
// external: ["react"],
// minifyIdentifiers: true,
// });
itBundled("loader/RequireCustomExtensionString", {
files: {
"/entry.js": `console.log(require('./test.custom'))`,
"/test.custom": `#include <stdio.h>`,
},
loader: {
".custom": "text",
},
run: {
stdout: "#include <stdio.h>",
},
});
itBundled("loader/RequireCustomExtensionBase64", {
files: {
"/entry.js": `console.log(require('./test.custom'))`,
"/test.custom": `a\x00b\x80c\xFFd`,
},
loader: {
".custom": "base64",
},
run: {
stdout: "YQBiwoBjw79k",
},
});
itBundled("loader/RequireCustomExtensionDataURL", {
files: {
"/entry.js": `console.log(require('./test.custom'))`,
"/test.custom": `a\x00b\x80c\xFFd`,
},
loader: {
".custom": "dataurl",
},
run: {
stdout: "data:application/octet-stream,a\x00b\x80c\xFFd",
},
});
itBundled("loader/RequireCustomExtensionPreferLongest", {
files: {
"/entry.js": `console.log(require('./test.txt'), require('./test.base64.txt'))`,
"/test.txt": `test.txt`,
"/test.base64.txt": `test.base64.txt`,
},
loader: {
".txt": "text",
".base64.txt": "base64",
},
run: {
stdout: "test.txt dGVzdC5iYXNlNjQudHh0",
},
});
itBundled("loader/AutoDetectMimeTypeFromExtension", {
files: {
"/entry.js": `console.log(require('./test.svg'))`,
"/test.svg": `a\x00b\x80c\xFFd`,
},
loader: {
".svg": "dataurl",
},
run: {
stdout: "data:image/svg+xml,a\x00b\x80c\xFFd",
},
});
itBundled("loader/JSONInvalidIdentifierES6", {
todo: true,
files: {
"/entry.js": /* js */ `
import * as ns from './test.json'
import * as ns2 from './test2.json'
console.log(ns['invalid-identifier'], JSON.stringify(ns2))
`,
"/test.json": `{"invalid-identifier": true}`,
"/test2.json": `{"invalid-identifier": true}`,
},
run: {
stdout: 'true {"invalid-identifier":true}',
},
});
itBundled("loader/JSONMissingES6", {
files: {
"/entry.js": `import {missing} from './test.json'`,
"/test.json": `{"present": true}`,
},
bundleErrors: {
"/entry.js": [`No matching export in "test.json" for import "missing"`],
},
});
itBundled("loader/TextCommonJSAndES6", {
files: {
"/entry.js": /* js */ `
const x_txt = require('./x.txt')
import y_txt from './y.txt'
console.log(x_txt, y_txt)
`,
"/x.txt": `x`,
"/y.txt": `y`,
},
run: {
stdout: "x y",
},
});
itBundled("loader/Base64CommonJSAndES6", {
files: {
"/entry.js": /* js */ `
const x_b64 = require('./x.b64')
import y_b64 from './y.b64'
console.log(x_b64, y_b64)
`,
"/x.b64": `x`,
"/y.b64": `y`,
},
loader: {
".b64": "base64",
},
run: {
stdout: "eA== eQ==",
},
});
itBundled("loader/DataURLCommonJSAndES6", {
files: {
"/entry.js": /* js */ `
const x_url = require('./x.txt')
import y_url from './y.txt'
console.log(x_url, y_url)
`,
"/x.txt": `x`,
"/y.txt": `y`,
},
loader: {
".txt": "dataurl",
},
run: {
stdout: "data:text/plain;charset=utf-8,x data:text/plain;charset=utf-8,y",
},
});
itBundled("loader/FileCommonJSAndES6", {
files: {
"/entry.js": /* js */ `
const x_url = require('./x.txt')
import y_url from './y.txt'
console.log(x_url, y_url)
`,
"/x.txt": `x`,
"/y.txt": `y`,
},
});
itBundled("loader/FileRelativePathJS", {
files: {
"/src/entries/entry.js": /* js */ `
import x from '../images/image.png'
console.log(x)
`,
"/src/images/image.png": `x`,
},
root: "/src",
outdir: "/out",
outputPaths: ["/out/entries/entry.js"],
loader: {
".png": "file",
},
run: {
stdout: /^..\/image-.*\.png$/,
},
});
// itBundled("loader/FileRelativePathCSS", {
// // GENERATED
// files: {
// "/src/entries/entry.css": /* css */ `
// div {
// background: url(../images/image.png);
// }
// `,
// "/src/images/image.png": `x`,
// },
// outbase: "/src",
// });
return;
itBundled("loader/FileRelativePathAssetNamesJS", {
// GENERATED
files: {
"/src/entries/entry.js": /* js */ `
import x from '../images/image.png'
console.log(x)
`,
"/src/images/image.png": `x`,
},
root: "/src",
assetNaming: "[dir]/[name]-[hash]",
outdir: "/out",
outputPaths: ["/out/entries/entry.js"],
loader: {
".png": "file",
},
run: {
stdout: /^..\/images\/image-.*\.png$/,
},
});
itBundled("loader/FileExtPathAssetNamesJS", {
// GENERATED
files: {
"/src/entries/entry.js": /* js */ `
import x from '../images/image.png'
import y from '../uploads/file.txt'
console.log(x, y)
`,
"/src/images/image.png": `x`,
"/src/uploads/file.txt": `y`,
},
root: "/src",
assetNaming: "[ext]/[name]-[hash]",
});
itBundled("loader/FileRelativePathAssetNamesCSS", {
// GENERATED
files: {
"/src/entries/entry.css": /* css */ `
div {
background: url(../images/image.png);
}
`,
"/src/images/image.png": `x`,
},
root: "/src",
assetNaming: "[dir]/[name]-[hash]",
});
itBundled("loader/FilePublicPathJS", {
// GENERATED
files: {
"/src/entries/entry.js": /* js */ `
import x from '../images/image.png'
console.log(x)
`,
"/src/images/image.png": `x`,
},
root: "/src",
publicPath: "https://example.com",
});
itBundled("loader/FilePublicPathCSS", {
// GENERATED
files: {
"/src/entries/entry.css": /* css */ `
div {
background: url(../images/image.png);
}
`,
"/src/images/image.png": `x`,
},
root: "/src",
publicPath: "https://example.com",
});
itBundled("loader/FilePublicPathAssetNamesJS", {
// GENERATED
files: {
"/src/entries/entry.js": /* js */ `
import x from '../images/image.png'
console.log(x)
`,
"/src/images/image.png": `x`,
},
root: "/src",
publicPath: "https://example.com",
assetNaming: "[dir]/[name]-[hash]",
});
itBundled("loader/FilePublicPathAssetNamesCSS", {
// GENERATED
files: {
"/src/entries/entry.css": /* css */ `
div {
background: url(../images/image.png);
}
`,
"/src/images/image.png": `x`,
},
root: "/src",
publicPath: "https://example.com",
assetNaming: "[dir]/[name]-[hash]",
});
itBundled("loader/FileOneSourceTwoDifferentOutputPathsJS", {
// GENERATED
files: {
"/src/entries/entry.js": `import '../shared/common.js'`,
"/src/entries/other/entry.js": `import '../../shared/common.js'`,
"/src/shared/common.js": /* js */ `
import x from './common.png'
console.log(x)
`,
"/src/shared/common.png": `x`,
},
entryPoints: ["/src/entries/entry.js", "/src/entries/other/entry.js"],
root: "/src",
});
itBundled("loader/FileOneSourceTwoDifferentOutputPathsCSS", {
// GENERATED
files: {
"/src/entries/entry.css": `@import "../shared/common.css";`,
"/src/entries/other/entry.css": `@import "../../shared/common.css";`,
"/src/shared/common.css": /* css */ `
div {
background: url(common.png);
}
`,
"/src/shared/common.png": `x`,
},
entryPoints: ["/src/entries/entry.css", "/src/entries/other/entry.css"],
root: "/src",
});
itBundled("loader/JSONNoBundle", {
// GENERATED
files: {
"/test.json": `{"test": 123, "invalid-identifier": true}`,
},
bundling: false,
});
itBundled("loader/JSONNoBundleES6", {
// GENERATED
files: {
"/test.json": `{"test": 123, "invalid-identifier": true}`,
},
format: "esm",
unsupportedJSFeatures: "ArbitraryModuleNamespaceNames",
mode: "convertformat",
});
itBundled("loader/JSONNoBundleES6ArbitraryModuleNamespaceNames", {
// GENERATED
files: {
"/test.json": `{"test": 123, "invalid-identifier": true}`,
},
format: "esm",
mode: "convertformat",
});
itBundled("loader/JSONNoBundleCommonJS", {
// GENERATED
files: {
"/test.json": `{"test": 123, "invalid-identifier": true}`,
},
format: "cjs",
mode: "convertformat",
});
itBundled("loader/JSONNoBundleIIFE", {
// GENERATED
files: {
"/test.json": `{"test": 123, "invalid-identifier": true}`,
},
format: "iife",
mode: "convertformat",
});
itBundled("loader/FileWithQueryParameter", {
// GENERATED
files: {
"/entry.js": /* js */ `
// Each of these should have a separate identity (i.e. end up in the output file twice)
import foo from './file.txt?foo'
import bar from './file.txt?bar'
console.log(foo, bar)
`,
"/file.txt": `This is some text`,
},
});
itBundled("loader/FromExtensionWithQueryParameter", {
// GENERATED
files: {
"/entry.js": /* js */ `
import foo from './file.abc?query.xyz'
console.log(foo)
`,
"/file.abc": `This should not be base64 encoded`,
},
});
itBundled("loader/DataURLTextCSS", {
// GENERATED
files: {
"/entry.css": /* css */ `
@import "data:text/css,body{color:%72%65%64}";
@import "data:text/css;base64,Ym9keXtiYWNrZ3JvdW5kOmJsdWV9";
@import "data:text/css;charset=UTF-8,body{color:%72%65%64}";
@import "data:text/css;charset=UTF-8;base64,Ym9keXtiYWNrZ3JvdW5kOmJsdWV9";
`,
},
});
itBundled("loader/DataURLTextCSSCannotImport", {
// GENERATED
files: {
"/entry.css": `@import "data:text/css,@import './other.css';";`,
"/other.css": `div { should-not-be-imported: true }`,
},
/* TODO FIX expectedScanLog: `<data:text/css,@import './other.css';>: ERROR: Could not resolve "./other.css"
`, */
});
itBundled("loader/DataURLTextJavaScript", {
// GENERATED
files: {
"/entry.js": /* js */ `
import "data:text/javascript,console.log('%31%32%33')";
import "data:text/javascript;base64,Y29uc29sZS5sb2coMjM0KQ==";
import "data:text/javascript;charset=UTF-8,console.log(%31%32%33)";
import "data:text/javascript;charset=UTF-8;base64,Y29uc29sZS5sb2coMjM0KQ==";
`,
},
});
itBundled("loader/DataURLTextJavaScriptCannotImport", {
// GENERATED
files: {
"/entry.js": `import "data:text/javascript,import './other.js'"`,
"/other.js": `shouldNotBeImported = true`,
},
/* TODO FIX expectedScanLog: `<data:text/javascript,import './other.js'>: ERROR: Could not resolve "./other.js"
`, */
});
itBundled("loader/DataURLTextJavaScriptPlusCharacter", {
// GENERATED
files: {
"/entry.js": `import "data:text/javascript,console.log(1+2)";`,
},
});
itBundled("loader/DataURLApplicationJSON", {
// GENERATED
files: {
"/entry.js": /* js */ `
import a from 'data:application/json,"%31%32%33"';
import b from 'data:application/json;base64,eyJ3b3JrcyI6dHJ1ZX0=';
import c from 'data:application/json;charset=UTF-8,%31%32%33';
import d from 'data:application/json;charset=UTF-8;base64,eyJ3b3JrcyI6dHJ1ZX0=';
console.log([
a, b, c, d,
])
`,
},
});
itBundled("loader/DataURLUnknownMIME", {
// GENERATED
files: {
"/entry.js": /* js */ `
import a from 'data:some/thing;what,someData%31%32%33';
import b from 'data:other/thing;stuff;base64,c29tZURhdGEyMzQ=';
console.log(a, b)
`,
},
});
itBundled("loader/DataURLExtensionBasedMIME", {
// GENERATED
files: {
"/entry.foo": /* foo */ `
export { default as css } from "./example.css"
export { default as eot } from "./example.eot"
export { default as gif } from "./example.gif"
export { default as htm } from "./example.htm"
export { default as html } from "./example.html"
export { default as jpeg } from "./example.jpeg"
export { default as jpg } from "./example.jpg"
export { default as js } from "./example.js"
export { default as json } from "./example.json"
export { default as mjs } from "./example.mjs"
export { default as otf } from "./example.otf"
export { default as pdf } from "./example.pdf"
export { default as png } from "./example.png"
export { default as sfnt } from "./example.sfnt"
export { default as svg } from "./example.svg"
export { default as ttf } from "./example.ttf"
export { default as wasm } from "./example.wasm"
export { default as webp } from "./example.webp"
export { default as woff } from "./example.woff"
export { default as woff2 } from "./example.woff2"
export { default as xml } from "./example.xml"
`,
"/example.css": `css`,
"/example.eot": `eot`,
"/example.gif": `gif`,
"/example.htm": `htm`,
"/example.html": `html`,
"/example.jpeg": `jpeg`,
"/example.jpg": `jpg`,
"/example.js": `js`,
"/example.json": `json`,
"/example.mjs": `mjs`,
"/example.otf": `otf`,
"/example.pdf": `pdf`,
"/example.png": `png`,
"/example.sfnt": `sfnt`,
"/example.svg": `svg`,
"/example.ttf": `ttf`,
"/example.wasm": `wasm`,
"/example.webp": `webp`,
"/example.woff": `woff`,
"/example.woff2": `woff2`,
"/example.xml": `xml`,
},
});
itBundled("loader/DataURLBase64VsPercentEncoding", {
// GENERATED
files: {
"/entry.js": /* js */ `
import a from './shouldUsePercent_1.txt'
import b from './shouldUsePercent_2.txt'
import c from './shouldUseBase64_1.txt'
import d from './shouldUseBase64_2.txt'
console.log(
a,
b,
c,
d,
)
`,
"/shouldUsePercent_1.txt": `\n\n\n`,
"/shouldUsePercent_2.txt": `\n\n\n\n`,
"/shouldUseBase64_1.txt": `\n\n\n\n\n`,
"/shouldUseBase64_2.txt": `\n\n\n\n\n\n`,
},
});
itBundled("loader/DataURLBase64InvalidUTF8", {
// GENERATED
files: {
"/entry.js": /* js */ `
import a from './binary.txt'
console.log(a)
`,
"/binary.txt": `\xFF`,
},
});
itBundled("loader/DataURLEscapePercents", {
// GENERATED
files: {
"/entry.js": /* js */ `
import a from './percents.txt'
console.log(a)
`,
"/percents.txt": /* txt */ `
%, %3, %33, %333
%, %e, %ee, %eee
%, %E, %EE, %EEE
`,
},
});
itBundled("loader/CopyWithBundleFromJS", {
// GENERATED
files: {
"/Users/user/project/src/entry.js": /* js */ `
import x from "../assets/some.file"
console.log(x)
`,
"/Users/user/project/assets/some.file": `stuff`,
},
root: "/Users/user/project",
});
itBundled("loader/CopyWithBundleFromCSS", {
// GENERATED
files: {
"/Users/user/project/src/entry.css": /* css */ `
body {
background: url(../assets/some.file);
}
`,
"/Users/user/project/assets/some.file": `stuff`,
},
root: "/Users/user/project",
});
itBundled("loader/CopyWithBundleEntryPoint", {
// GENERATED
files: {
"/Users/user/project/src/entry.js": /* js */ `
import x from "../assets/some.file"
console.log(x)
`,
"/Users/user/project/src/entry.css": /* css */ `
body {
background: url(../assets/some.file);
}
`,
"/Users/user/project/assets/some.file": `stuff`,
},
entryPoints: [
"/Users/user/project/src/entry.js",
"/Users/user/project/src/entry.css",
"/Users/user/project/assets/some.file",
],
root: "/Users/user/project",
});
itBundled("loader/CopyWithTransform", {
// GENERATED
files: {
"/Users/user/project/src/entry.js": `console.log('entry')`,
"/Users/user/project/assets/some.file": `stuff`,
},
entryPoints: ["/Users/user/project/src/entry.js", "/Users/user/project/assets/some.file"],
root: "/Users/user/project",
mode: "passthrough",
});
itBundled("loader/CopyWithFormat", {
// GENERATED
files: {
"/Users/user/project/src/entry.js": `console.log('entry')`,
"/Users/user/project/assets/some.file": `stuff`,
},
entryPoints: ["/Users/user/project/src/entry.js", "/Users/user/project/assets/some.file"],
format: "iife",
root: "/Users/user/project",
mode: "convertformat",
});
itBundled("loader/JSXAutomaticNoNameCollision", {
// GENERATED
files: {
"/entry.jsx": /* jsx */ `
import { Link } from "@remix-run/react"
const x = <Link {...y} key={z} />
`,
},
format: "cjs",
mode: "convertformat",
});
itBundled("loader/AssertTypeJSONWrongLoader", {
// GENERATED
files: {
"/entry.js": `import foo from './foo.json' assert { type: 'json' }`,
"/foo.json": `{}`,
},
/* TODO FIX expectedScanLog: `entry.js: ERROR: The file "foo.json" was loaded with the "js" loader
entry.js: NOTE: This import assertion requires the loader to be "json" instead:
NOTE: You need to either reconfigure esbuild to ensure that the loader for this file is "json" or you need to remove this import assertion.
`, */
});
itBundled("loader/EmptyLoaderJS", {
// GENERATED
files: {
"/entry.js": /* js */ `
import './a.empty'
import * as ns from './b.empty'
import def from './c.empty'
import { named } from './d.empty'
console.log(ns, def, named)
`,
"/a.empty": `throw 'FAIL'`,
"/b.empty": `throw 'FAIL'`,
"/c.empty": `throw 'FAIL'`,
"/d.empty": `throw 'FAIL'`,
},
sourceMap: "external",
metafile: true,
/* TODO FIX expectedCompileLog: `entry.js: WARNING: Import "named" will always be undefined because the file "d.empty" has no exports
`, */
});
itBundled("loader/EmptyLoaderCSS", {
// GENERATED
files: {
"/entry.css": /* css */ `
@import 'a.empty';
a { background: url(b.empty) }
`,
"/a.empty": `body { color: fail }`,
"/b.empty": `fail`,
},
sourceMap: "external",
metafile: true,
});
itBundled("loader/ExtensionlessLoaderJS", {
// GENERATED
files: {
"/entry.js": `import './what'`,
"/what": `foo()`,
},
});
itBundled("loader/ExtensionlessLoaderCSS", {
// GENERATED
files: {
"/entry.css": `@import './what';`,
"/what": `.foo { color: red }`,
},
});
itBundled("loader/CopyEntryPointAdvanced", {
// GENERATED
files: {
"/project/entry.js": /* js */ `
import xyz from './xyz.copy'
console.log(xyz)
`,
"/project/TEST FAILED.copy": `some stuff`,
"/project/xyz.copy": `more stuff`,
},
/* TODO FIX entryPathsAdvanced: []bundler.EntryPoint{
{
InputPath: "/project/entry.js",
OutputPath: "js/input/path",
InputPathInFileNamespace: true,
},
{
InputPath: "/project/TEST FAILED.copy",
OutputPath: "copy/input/path",
InputPathInFileNamespace: true,
},
}, */
});
itBundled("loader/CopyUseIndex", {
// GENERATED
files: {
"/Users/user/project/src/index.copy": `some stuff`,
},
});
itBundled("loader/CopyExplicitOutputFile", {
// GENERATED
files: {
"/project/TEST FAILED.copy": `some stuff`,
},
outfile: "/out/this.worked",
});
itBundled("loader/CopyStartsWithDotAbsPath", {
// GENERATED
files: {
"/project/src/.htaccess": `some stuff`,
"/project/src/entry.js": `some.stuff()`,
"/project/src/.ts": `foo as number`,
},
entryPoints: ["/project/src/.htaccess", "/project/src/entry.js", "/project/src/.ts"],
});
itBundled("loader/CopyStartsWithDotRelPath", {
// GENERATED
files: {
"/project/src/.htaccess": `some stuff`,
"/project/src/entry.js": `some.stuff()`,
"/project/src/.ts": `foo as number`,
},
entryPoints: ["./.htaccess", "./entry.js", "./.ts"],
/* TODO FIX absWorkingDir: "/project/src", */
});
});
File diff suppressed because it is too large Load Diff
+345
View File
@@ -0,0 +1,345 @@
import { describe, expect } from "bun:test";
import { existsSync, readFileSync } from "fs";
import { itBundled } from "../expectBundled";
// Tests ported from:
// https://github.com/evanw/esbuild/blob/main/internal/bundler_tests/bundler_default_test.go
describe("bundler", () => {
itBundled("metafile/ImportWithTypeJSON", {
files: {
"/project/entry.js": /* js */ `
import a from './data.json'
import b from './data.json' assert { type: 'json' }
import c from './data.json' with { type: 'json' }
x = [a, b, c]
`,
"/project/data.json": `{"some": "data"}`,
},
outdir: "/out",
metafile: "/metafile.json",
onAfterBundle(api) {
const metafilePath = api.join("metafile.json");
expect(existsSync(metafilePath)).toBe(true);
const metafile = JSON.parse(readFileSync(metafilePath, "utf-8"));
expect(metafile.inputs).toBeDefined();
expect(metafile.outputs).toBeDefined();
// Should have imports with 'with' clause for JSON
const entryInputKey = Object.keys(metafile.inputs).find(k => k.includes("entry.js"));
expect(entryInputKey).toBeDefined();
const entryInput = metafile.inputs[entryInputKey!];
expect(entryInput.imports.length).toBeGreaterThan(0);
// At least one import should have a 'with' clause
const hasWithClause = entryInput.imports.some((imp: any) => imp.with?.type === "json");
expect(hasWithClause).toBe(true);
},
});
itBundled("metafile/BasicStructure", {
files: {
"/entry.js": /* js */ `
import { foo } from './foo.js';
console.log(foo);
`,
"/foo.js": /* js */ `
export const foo = 42;
`,
},
outdir: "/out",
metafile: "/metafile.json",
onAfterBundle(api) {
const metafilePath = api.join("metafile.json");
expect(existsSync(metafilePath)).toBe(true);
const metafile = JSON.parse(readFileSync(metafilePath, "utf-8"));
// Check basic structure
expect(metafile.inputs).toBeDefined();
expect(metafile.outputs).toBeDefined();
expect(Object.keys(metafile.inputs).length).toBeGreaterThanOrEqual(2);
expect(Object.keys(metafile.outputs).length).toBeGreaterThanOrEqual(1);
// Check input has bytes and imports
for (const input of Object.values(metafile.inputs) as any[]) {
expect(typeof input.bytes).toBe("number");
expect(Array.isArray(input.imports)).toBe(true);
}
// Check output has bytes, inputs, imports, exports
for (const output of Object.values(metafile.outputs) as any[]) {
expect(typeof output.bytes).toBe("number");
expect(typeof output.inputs).toBe("object");
expect(Array.isArray(output.imports)).toBe(true);
expect(Array.isArray(output.exports)).toBe(true);
}
},
});
itBundled("metafile/MultipleEntryPoints", {
files: {
"/a.js": /* js */ `
import { shared } from './shared.js';
console.log('a', shared);
`,
"/b.js": /* js */ `
import { shared } from './shared.js';
console.log('b', shared);
`,
"/shared.js": /* js */ `
export const shared = 'shared value';
`,
},
entryPoints: ["/a.js", "/b.js"],
outdir: "/out",
metafile: "/metafile.json",
splitting: true,
onAfterBundle(api) {
const metafilePath = api.join("metafile.json");
expect(existsSync(metafilePath)).toBe(true);
const metafile = JSON.parse(readFileSync(metafilePath, "utf-8"));
expect(metafile.inputs).toBeDefined();
expect(metafile.outputs).toBeDefined();
// With splitting, we should have multiple outputs
expect(Object.keys(metafile.outputs).length).toBeGreaterThanOrEqual(2);
},
});
itBundled("metafile/ExternalImports", {
files: {
"/entry.js": /* js */ `
import ext1 from 'external-pkg-1';
import ext2 from 'external-pkg-2';
console.log(ext1, ext2);
`,
},
outdir: "/out",
metafile: "/metafile.json",
external: ["external-pkg-1", "external-pkg-2"],
onAfterBundle(api) {
const metafilePath = api.join("metafile.json");
expect(existsSync(metafilePath)).toBe(true);
const metafile = JSON.parse(readFileSync(metafilePath, "utf-8"));
// Find the entry file
const entryKey = Object.keys(metafile.inputs).find(k => k.includes("entry.js"));
expect(entryKey).toBeDefined();
const entry = metafile.inputs[entryKey!];
// Check that external imports are marked
const externalImports = entry.imports.filter((imp: any) => imp.external === true);
expect(externalImports.length).toBe(2);
},
});
itBundled("metafile/DynamicImport", {
files: {
"/entry.js": /* js */ `
import('./dynamic.js').then(m => console.log(m));
`,
"/dynamic.js": /* js */ `
export const value = 123;
`,
},
outdir: "/out",
metafile: "/metafile.json",
splitting: true,
onAfterBundle(api) {
const metafilePath = api.join("metafile.json");
expect(existsSync(metafilePath)).toBe(true);
const metafile = JSON.parse(readFileSync(metafilePath, "utf-8"));
expect(metafile.inputs).toBeDefined();
expect(metafile.outputs).toBeDefined();
// Find the entry file
const entryKey = Object.keys(metafile.inputs).find(k => k.includes("entry.js"));
expect(entryKey).toBeDefined();
const entry = metafile.inputs[entryKey!];
// Should have a dynamic import
const dynamicImports = entry.imports.filter((imp: any) => imp.kind === "dynamic-import");
expect(dynamicImports.length).toBe(1);
},
});
itBundled("metafile/RequireCall", {
files: {
"/entry.js": /* js */ `
const foo = require('./foo.js');
console.log(foo);
`,
"/foo.js": /* js */ `
module.exports = { value: 42 };
`,
},
outdir: "/out",
metafile: "/metafile.json",
onAfterBundle(api) {
const metafilePath = api.join("metafile.json");
expect(existsSync(metafilePath)).toBe(true);
const metafile = JSON.parse(readFileSync(metafilePath, "utf-8"));
expect(metafile.inputs).toBeDefined();
// Find the entry file
const entryKey = Object.keys(metafile.inputs).find(k => k.includes("entry.js"));
expect(entryKey).toBeDefined();
const entry = metafile.inputs[entryKey!];
// Should have a require call
const requireImports = entry.imports.filter((imp: any) => imp.kind === "require-call");
expect(requireImports.length).toBe(1);
},
});
itBundled("metafile/ReExports", {
files: {
"/entry.js": /* js */ `
export { foo } from './foo.js';
export * from './bar.js';
`,
"/foo.js": /* js */ `
export const foo = 1;
`,
"/bar.js": /* js */ `
export const bar = 2;
export const baz = 3;
`,
},
outdir: "/out",
metafile: "/metafile.json",
onAfterBundle(api) {
const metafilePath = api.join("metafile.json");
expect(existsSync(metafilePath)).toBe(true);
const metafile = JSON.parse(readFileSync(metafilePath, "utf-8"));
expect(metafile.outputs).toBeDefined();
// Find the output
const outputKey = Object.keys(metafile.outputs)[0];
const output = metafile.outputs[outputKey];
// Should have exports
expect(output.exports.length).toBeGreaterThanOrEqual(3); // foo, bar, baz
},
});
itBundled("metafile/NestedImports", {
files: {
"/entry.js": /* js */ `
import { a } from './a.js';
console.log(a);
`,
"/a.js": /* js */ `
import { b } from './b.js';
export const a = b + 1;
`,
"/b.js": /* js */ `
import { c } from './c.js';
export const b = c + 1;
`,
"/c.js": /* js */ `
export const c = 1;
`,
},
outdir: "/out",
metafile: "/metafile.json",
onAfterBundle(api) {
const metafilePath = api.join("metafile.json");
expect(existsSync(metafilePath)).toBe(true);
const metafile = JSON.parse(readFileSync(metafilePath, "utf-8"));
expect(metafile.inputs).toBeDefined();
// Should have 4 input files
expect(Object.keys(metafile.inputs).length).toBe(4);
// Each file should have proper imports
for (const [path, input] of Object.entries(metafile.inputs) as any) {
expect(typeof input.bytes).toBe("number");
expect(Array.isArray(input.imports)).toBe(true);
}
},
});
itBundled("metafile/JSONImport", {
files: {
"/entry.js": /* js */ `
import data from './data.json';
console.log(data);
`,
"/data.json": `{"key": "value", "number": 42}`,
},
outdir: "/out",
metafile: "/metafile.json",
onAfterBundle(api) {
const metafilePath = api.join("metafile.json");
expect(existsSync(metafilePath)).toBe(true);
const metafile = JSON.parse(readFileSync(metafilePath, "utf-8"));
// Find the entry file
const entryKey = Object.keys(metafile.inputs).find(k => k.includes("entry.js"));
expect(entryKey).toBeDefined();
const entry = metafile.inputs[entryKey!];
// Should have an import to the JSON file with 'with' clause
const jsonImport = entry.imports.find((imp: any) => imp.path.includes("data.json"));
expect(jsonImport).toBeDefined();
expect(jsonImport.with?.type).toBe("json");
},
});
itBundled("metafile/TextImport", {
files: {
"/entry.js": /* js */ `
import text from './file.txt';
console.log(text);
`,
"/file.txt": `Hello, World!`,
},
outdir: "/out",
metafile: "/metafile.json",
loader: {
".txt": "text",
},
onAfterBundle(api) {
const metafilePath = api.join("metafile.json");
expect(existsSync(metafilePath)).toBe(true);
const metafile = JSON.parse(readFileSync(metafilePath, "utf-8"));
// Find the entry file
const entryKey = Object.keys(metafile.inputs).find(k => k.includes("entry.js"));
expect(entryKey).toBeDefined();
const entry = metafile.inputs[entryKey!];
// Should have an import to the text file with 'with' clause
const textImport = entry.imports.find((imp: any) => imp.path.includes("file.txt"));
expect(textImport).toBeDefined();
expect(textImport.with?.type).toBe("text");
},
});
itBundled("metafile/EntryPoint", {
files: {
"/entry.js": /* js */ `
console.log('entry');
`,
},
outdir: "/out",
metafile: "/metafile.json",
onAfterBundle(api) {
const metafilePath = api.join("metafile.json");
expect(existsSync(metafilePath)).toBe(true);
const metafile = JSON.parse(readFileSync(metafilePath, "utf-8"));
expect(metafile.outputs).toBeDefined();
// Find an output with entryPoint
const outputWithEntryPoint = Object.values(metafile.outputs).find((o: any) => o.entryPoint);
expect(outputWithEntryPoint).toBeDefined();
expect(typeof (outputWithEntryPoint as any).entryPoint).toBe("string");
},
});
itBundled("metafile/OriginalPath", {
files: {
"/entry.js": /* js */ `
import { helper } from './lib/helper.js';
console.log(helper);
`,
"/lib/helper.js": /* js */ `
export const helper = 'helper';
`,
},
outdir: "/out",
metafile: "/metafile.json",
onAfterBundle(api) {
const metafilePath = api.join("metafile.json");
expect(existsSync(metafilePath)).toBe(true);
const metafile = JSON.parse(readFileSync(metafilePath, "utf-8"));
// Find the entry file
const entryKey = Object.keys(metafile.inputs).find(k => k.includes("entry.js"));
expect(entryKey).toBeDefined();
const entry = metafile.inputs[entryKey!];
// Should have an import with original path
expect(entry.imports.length).toBe(1);
expect(entry.imports[0].original).toBe("./lib/helper.js");
},
});
});
File diff suppressed because it is too large Load Diff
+664
View File
@@ -0,0 +1,664 @@
import assert from "assert";
import { describe, expect } from "bun:test";
import { readdirSync } from "fs";
import { itBundled } from "../expectBundled";
// Tests ported from:
// https://github.com/evanw/esbuild/blob/main/internal/bundler_tests/bundler_splitting_test.go
// For debug, all files are written to $TEMP/bun-bundle-tests/splitting
describe("bundler", () => {
itBundled("splitting/SharedES6IntoES6", {
files: {
"/a.js": /* js */ `
import {foo} from "./shared.js"
console.log(foo)
`,
"/b.js": /* js */ `
import {foo} from "./shared.js"
console.log(foo)
`,
"/shared.js": `export let foo = 123`,
},
entryPoints: ["/a.js", "/b.js"],
splitting: true,
run: [
{ file: "/out/a.js", stdout: "123" },
{ file: "/out/b.js", stdout: "123" },
],
assertNotPresent: {
"/out/a.js": "123",
"/out/b.js": "123",
},
});
itBundled("splitting/SharedCommonJSIntoES6", {
files: {
"/a.js": /* js */ `
const {foo} = require("./shared.js")
console.log(foo)
`,
"/b.js": /* js */ `
const {foo} = require("./shared.js")
console.log(foo)
`,
"/shared.js": `exports.foo = 123`,
},
entryPoints: ["/a.js", "/b.js"],
splitting: true,
run: [
{ file: "/out/a.js", stdout: "123" },
{ file: "/out/b.js", stdout: "123" },
],
assertNotPresent: {
"/out/a.js": "123",
"/out/b.js": "123",
},
});
itBundled("splitting/DynamicES6IntoES6", {
todo: true,
files: {
"/entry.js": `import("./foo.js").then(({bar}) => console.log(bar))`,
"/foo.js": `export let bar = 123`,
},
splitting: true,
outdir: "/out",
assertNotPresent: {
"/out/entry.js": "123",
},
onAfterBundle(api) {
const files = readdirSync(api.outdir);
assert.strictEqual(
files.length,
2,
"should have 2 files: entry.js and foo-[hash].js, found [" + files.join(", ") + "]",
);
assert(files.includes("entry.js"), "has entry.js");
assert(!files.includes("foo.js"), "does not have foo.js");
},
run: {
file: "/out/entry.js",
stdout: "123",
},
});
itBundled("splitting/DynamicCommonJSIntoES6", {
files: {
"/entry.js": `import("./foo.js").then(({default: {bar}}) => console.log(bar))`,
"/foo.js": `exports.bar = 123`,
},
splitting: true,
outdir: "/out",
assertNotPresent: {
"/out/entry.js": "123",
},
run: {
file: "/out/entry.js",
stdout: "123",
},
});
itBundled("splitting/DynamicAndNotDynamicES6IntoES6", {
files: {
"/entry.js": /* js */ `
import {bar as a} from "./foo.js"
import("./foo.js").then(({bar: b}) => console.log(a, b))
`,
"/foo.js": `export let bar = 123`,
},
splitting: true,
outdir: "/out",
});
itBundled("splitting/DynamicAndNotDynamicCommonJSIntoES6", {
skipOnEsbuild: true,
files: {
"/entry.js": /* js */ `
import {bar as a} from "./foo.js"
import("./foo.js").then(({default: {bar: b}}) => console.log(a, b))
`,
"/foo.js": `exports.bar = 123`,
},
outdir: "/out",
splitting: true,
run: {
file: "/out/entry.js",
stdout: "123 123",
},
});
itBundled("splitting/AssignToLocal", {
files: {
"/a.js": /* js */ `
import {foo, setFoo} from "./shared.js"
setFoo(123)
console.log(foo)
`,
"/b.js": /* js */ `
import {foo} from "./shared.js"
console.log(foo)
`,
"/shared.js": /* js */ `
export let foo = 456
export function setFoo(value) {
foo = value
}
`,
},
entryPoints: ["/a.js", "/b.js"],
splitting: true,
runtimeFiles: {
"/test1.js": /* js */ `
await import('./out/a.js')
await import('./out/b.js')
`,
"/test2.js": /* js */ `
await import('./out/b.js')
await import('./out/a.js')
`,
},
run: [
{ file: "/out/a.js", stdout: "123" },
{ file: "/out/b.js", stdout: "456" },
{ file: "/test1.js", stdout: "123\n123" },
{ file: "/test2.js", stdout: "456\n123" },
],
});
itBundled("splitting/SideEffectsWithoutDependencies", {
files: {
"/a.js": /* js */ `
import {a} from "./shared.js"
console.log(a)
`,
"/b.js": /* js */ `
import {b} from "./shared.js"
console.log(b)
`,
"/shared.js": /* js */ `
export let a = 1
export let b = 2
console.log('side effect')
`,
},
entryPoints: ["/a.js", "/b.js"],
splitting: true,
runtimeFiles: {
"/test1.js": /* js */ `
await import('./out/a.js')
await import('./out/b.js')
`,
"/test2.js": /* js */ `
await import('./out/b.js')
await import('./out/a.js')
`,
},
run: [
{ file: "/out/a.js", stdout: "side effect\n1" },
{ file: "/out/b.js", stdout: "side effect\n2" },
{ file: "/test1.js", stdout: "side effect\n1\n2" },
{ file: "/test2.js", stdout: "side effect\n2\n1" },
],
});
itBundled("splitting/NestedDirectories", {
files: {
"/Users/user/project/src/pages/pageA/page.js": /* js */ `
import x from "../shared.js"
console.log(x)
`,
"/Users/user/project/src/pages/pageB/page.js": /* js */ `
import x from "../shared.js"
console.log(-x)
`,
"/Users/user/project/src/pages/shared.js": `export default 123`,
},
entryPoints: ["/Users/user/project/src/pages/pageA/page.js", "/Users/user/project/src/pages/pageB/page.js"],
outputPaths: ["/out/pageA/page.js", "/out/pageB/page.js"],
splitting: true,
run: [
{ file: "/out/pageA/page.js", stdout: "123" },
{ file: "/out/pageB/page.js", stdout: "-123" },
],
});
itBundled("splitting/CircularReferenceESBuildIssue251", {
todo: true,
files: {
"/a.js": /* js */ `
export * from './b.js';
export var p = 5;
`,
"/b.js": /* js */ `
export * from './a.js';
export var q = 6;
export function foo() {
q = 7;
}
`,
},
entryPoints: ["/a.js", "/b.js"],
splitting: true,
runtimeFiles: {
"/test.js": /* js */ `
import { p, q, foo } from './out/a.js';
console.log(p, q)
import { p as p2, q as q2, foo as foo2 } from './out/b.js';
console.log(p2, q2)
console.log(foo === foo2)
foo();
console.log(q, q2)
`,
},
run: [{ file: "/test.js", stdout: "5 6\n5 6\ntrue\n7 7" }],
});
itBundled("splitting/MissingLazyExport", {
files: {
"/a.js": /* js */ `
import {foo} from './common.js'
console.log(JSON.stringify(foo()))
`,
"/b.js": /* js */ `
import {bar} from './common.js'
console.log(JSON.stringify(bar()))
`,
"/common.js": /* js */ `
import * as ns from './empty.js'
export function foo() { return [ns, ns.missing] }
export function bar() { return [ns.missing] }
`,
"/empty.js": /* js */ `
// This forces the module into ES6 mode without importing or exporting anything
import.meta
`,
},
entryPoints: ["/a.js", "/b.js"],
splitting: true,
run: [
{ file: "/out/a.js", stdout: "[{},null]" },
{ file: "/out/b.js", stdout: "[null]" },
],
bundleWarnings: {
"/common.js": [`Import "missing" will always be undefined because there is no matching export in "empty.js"`],
},
});
itBundled("splitting/ReExportESBuildIssue273", {
files: {
"/a.js": `export const a = { value: 1 }`,
"/b.js": `export { a } from './a'`,
},
entryPoints: ["/a.js", "/b.js"],
splitting: true,
runtimeFiles: {
"/test.js": /* js */ `
import { a } from './out/a.js';
import { a as a2 } from './out/b.js';
console.log(a === a2, a.value, a2.value)
`,
},
run: [{ file: "/test.js", stdout: "true 1 1" }],
});
itBundled("splitting/DynamicImportESBuildIssue272", {
files: {
"/a.js": `import('./b')`,
"/b.js": `export default 1; console.log('imported')`,
},
entryPoints: ["/a.js", "/b.js"],
splitting: true,
run: [{ file: "/out/a.js", stdout: "imported" }],
assertNotPresent: {
"/out/a.js": "imported",
},
});
itBundled("splitting/DynamicImportOutsideSourceTreeESBuildIssue264", {
files: {
"/Users/user/project/src/entry1.js": `import('package')`,
"/Users/user/project/src/entry2.js": `import('package')`,
"/Users/user/project/node_modules/package/index.js": `console.log('imported')`,
},
runtimeFiles: {
"/both.js": /* js */ `
import('./out/entry1.js');
import('./out/entry2.js');
`,
},
entryPoints: ["/Users/user/project/src/entry1.js", "/Users/user/project/src/entry2.js"],
splitting: true,
run: [
{ file: "/out/entry1.js", stdout: "imported" },
{ file: "/out/entry2.js", stdout: "imported" },
{ file: "/both.js", stdout: "imported" },
],
});
itBundled("splitting/CrossChunkAssignmentDependencies", {
files: {
"/a.js": /* js */ `
import {setValue} from './shared'
setValue(123)
`,
"/b.js": `import './shared'; console.log('b')`,
"/c.js": /* js */ `
import * as shared from './shared'
globalThis.shared = shared;
`,
"/shared.js": /* js */ `
var observer;
var value;
export function setObserver(cb) {
observer = cb;
}
export function getValue() {
return value;
}
export function setValue(next) {
console.log('setValue', next)
value = next;
if (observer) observer();
}
console.log("side effects!", getValue);
`,
},
entryPoints: ["/a.js", "/b.js", "/c.js"],
splitting: true,
target: "bun",
runtimeFiles: {
"/test.js": /* js */ `
import './out/c.js';
const { getValue, setObserver } = globalThis.shared;
function observer() {
console.log('observer', getValue());
}
setObserver(observer);
await import('./out/a.js');
await import('./out/b.js');
`,
},
run: [
{ file: "/out/a.js", stdout: "side effects! [Function: getValue]\nsetValue 123" },
{ file: "/out/b.js", stdout: "side effects! [Function: getValue]\nb" },
{ file: "/test.js", stdout: "side effects! [Function: getValue]\nsetValue 123\nobserver 123\nb" },
],
});
itBundled("splitting/CrossChunkAssignmentDependenciesRecursive", {
files: {
"/a.js": /* js */ `
import { setX } from './x'
globalThis.a = { setX };
`,
"/b.js": /* js */ `
import { setZ } from './z'
globalThis.b = { setZ };
`,
"/c.js": /* js */ `
import { setX2 } from './x'
import { setY2 } from './y'
import { setZ2 } from './z'
globalThis.c = { setX2, setY2, setZ2 };
`,
"/x.js": /* js */ `
let _x
export function setX(v) { _x = v }
export function setX2(v) { _x = v }
globalThis.x = { setX, setX2 };
`,
"/y.js": /* js */ `
import { setX } from './x'
let _y
export function setY(v) { _y = v }
export function setY2(v) { setX(v); _y = v }
globalThis.y = { setY, setY2 };
`,
"/z.js": /* js */ `
import { setY } from './y'
let _z
export function setZ(v) { _z = v }
export function setZ2(v) { setY(v); _z = v }
globalThis.z = { setZ, setZ2, setY };
`,
},
entryPoints: ["/a.js", "/b.js", "/c.js"],
splitting: true,
runtimeFiles: {
"/test_all.js": /* js */ `
import './out/a.js';
import './out/b.js';
import './out/c.js';
try {
a; b; c; x; y; z; // throw if not defined
} catch (error) {
throw new Error('chunks were not emitted right.')
}
import assert from 'assert';
assert(a.setX === x.setX, 'a.setX');
assert(b.setZ === z.setZ, 'b.setZ');
assert(c.setX2 === x.setX2, 'c.setX2');
assert(c.setY2 === y.setY2, 'c.setY2');
assert(c.setZ2 === z.setZ2, 'c.setZ2');
assert(z.setY === y.setY, 'z.setY');
`,
"/test_a_only.js": /* js */ `
import './out/a.js';
try {
a; x; // throw if not defined
} catch (error) {
throw new Error('chunks were not emitted right.')
}
import assert from 'assert';
assert(a.setX === x.setX, 'a.setX');
assert(globalThis.b === undefined, 'b should not be loaded');
assert(globalThis.c === undefined, 'c should not be loaded');
assert(globalThis.y === undefined, 'y should not be loaded');
assert(globalThis.z === undefined, 'z should not be loaded');
`,
"/test_b_only.js": /* js */ `
import './out/b.js';
try {
b; x; y; z; // throw if not defined
} catch (error) {
throw new Error('chunks were not emitted right.')
}
import assert from 'assert';
assert(globalThis.a === undefined, 'a should not be loaded');
assert(globalThis.c === undefined, 'c should not be loaded');
`,
"/test_c_only.js": /* js */ `
import './out/c.js';
try {
c; x; y; z; // throw if not defined
} catch (error) {
throw new Error('chunks were not emitted right.')
}
import assert from 'assert';
assert(globalThis.a === undefined, 'a should not be loaded');
assert(globalThis.b === undefined, 'b should not be loaded');
`,
},
run: [
{ file: "/test_all.js" },
{ file: "/test_a_only.js" },
{ file: "/test_b_only.js" },
{ file: "/test_c_only.js" },
],
});
itBundled("splitting/DuplicateChunkCollision", {
files: {
"/a.js": `import "./ab"`,
"/b.js": `import "./ab"`,
"/c.js": `import "./cd"`,
"/d.js": `import "./cd"`,
"/ab.js": `console.log(123)`,
"/cd.js": `console.log(123)`,
},
entryPoints: ["/a.js", "/b.js", "/c.js", "/d.js"],
splitting: true,
minifyWhitespace: true,
onAfterBundle(api) {
const files = readdirSync(api.outdir);
expect(files.length).toBe(6);
},
});
itBundled("splitting/MinifyIdentifiersCrashESBuildIssue437", {
files: {
"/a.js": /* js */ `
import {foo} from "./shared"
console.log(foo)
`,
"/b.js": /* js */ `
import {foo} from "./shared"
console.log(foo)
`,
"/c.js": `import "./shared"`,
"/shared.js": `export function foo(bar) {}`,
},
entryPoints: ["/a.js", "/b.js", "/c.js"],
splitting: true,
minifyIdentifiers: true,
run: [
{ file: "/out/a.js", stdout: "[Function: f]" },
{ file: "/out/b.js", stdout: "[Function: f]" },
],
});
itBundled("splitting/HybridESMAndCJSESBuildIssue617", {
files: {
"/a.js": `export let foo = 123`,
"/b.js": `export let bar = require('./a')`,
},
entryPoints: ["/a.js", "/b.js"],
splitting: true,
assertNotPresent: {
"/out/b.js": `123`,
},
runtimeFiles: {
"/test.js": /* js */ `
import { foo } from './out/a.js'
import { bar } from './out/b.js'
console.log(JSON.stringify({ foo, bar }))
`,
},
run: {
file: "/test.js",
stdout: '{"foo":123,"bar":{"foo":123}}',
},
});
itBundled("splitting/PublicPathEntryName", {
files: {
"/a.js": `import("./b")`,
"/b.js": `console.log('b')`,
},
outdir: "/out",
splitting: true,
publicPath: "/www/",
onAfterBundle(api) {
const t = new Bun.Transpiler();
const imports = t.scanImports(api.readFile("/out/a.js"));
expect(imports.length).toBe(1);
expect(imports[0].kind).toBe("dynamic-import");
assert(imports[0].path.startsWith("/www/"), `Expected path to start with "/www/" but got "${imports[0].path}"`);
},
});
itBundled("splitting/ChunkPathDirPlaceholderImplicitOutbase", {
files: {
"/project/entry.js": `console.log(import('./output-path/should-contain/this-text/file'))`,
"/project/output-path/should-contain/this-text/file.js": `console.log('file.js')`,
},
outdir: "/out",
splitting: true,
chunkNaming: "[dir]/[name]-[hash].[ext]",
onAfterBundle(api) {
assert(
readdirSync(api.outdir + "/output-path/should-contain/this-text").length === 1,
"Expected one file in out/output-path/should-contain/this-text/",
);
},
});
const EdgeCaseESBuildIssue2793WithSplitting = itBundled("splitting/EdgeCaseESBuildIssue2793WithSplitting", {
files: {
"/src/a.js": `export const A = 42;`,
"/src/b.js": `export const B = async () => (await import(".")).A`,
"/src/index.js": /* js */ `
export * from "./a"
export * from "./b"
`,
},
outdir: "/out",
entryPoints: ["/src/index.js"],
splitting: true,
target: "browser",
runtimeFiles: {
"/test.js": /* js */ `
import { A, B } from './out/index.js'
console.log(A, B() instanceof Promise, await B())
`,
},
run: {
file: "/test.js",
stdout: "42 true 42",
},
});
itBundled("splitting/EdgeCaseESBuildIssue2793WithoutSplitting", {
...EdgeCaseESBuildIssue2793WithSplitting.options,
splitting: false,
runtimeFiles: {
"/test.js": /* js */ `
import { A, B } from './out/index.js'
console.log(A, B() instanceof Promise, await B())
`,
},
run: {
file: "/test.js",
stdout: "42 true 42",
},
});
// Test that CJS modules with dynamic imports to other CJS entry points work correctly
// when code splitting causes the dynamically imported module to be in a separate chunk.
// The dynamic import should properly unwrap the default export using __toESM.
// Regression test for: dynamic import of CJS chunk returns { default: { __esModule, ... } }
// and needs .then((m)=>__toESM(m.default)) to unwrap correctly.
// Note: __esModule is required because bun optimizes simple CJS to ESM otherwise.
itBundled("splitting/CJSDynamicImportOfCJSChunk", {
files: {
"/main.js": /* js */ `
import("./impl.js").then(mod => console.log(mod.foo()));
`,
"/impl.js": /* js */ `
Object.defineProperty(exports, "__esModule", { value: true });
exports.foo = () => "success";
`,
},
entryPoints: ["/main.js", "/impl.js"],
splitting: true,
outdir: "/out",
run: {
file: "/out/main.js",
stdout: "success",
},
});
// https://github.com/oven-sh/bun/issues/32395
for (const format of ["cjs", "iife"] as const) {
for (const backend of ["cli", "api"] as const) {
itBundled(`splitting/ErrorWithNonEsmFormat_${format}_${backend}`, {
files: {
"/shared.js": /* js */ `
export function sharedFn() { return "shared"; }
export const sharedConst = 42;
`,
"/a.js": /* js */ `
import { sharedFn, sharedConst } from "./shared";
export const a = sharedFn() + sharedConst;
`,
"/b.js": /* js */ `
import { sharedFn, sharedConst } from "./shared";
export const b = sharedFn() + sharedConst;
`,
},
entryPoints: ["/a.js", "/b.js"],
outdir: "/out",
splitting: true,
format,
backend,
bundleErrors: {
"<bun>": ['Code splitting is currently only supported when format is set to "esm"'],
},
});
}
}
});
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff