aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/bundler/bundler_browser.test.ts18
-rw-r--r--test/bundler/bundler_edgecase.test.ts162
-rw-r--r--test/bundler/bundler_jsx.test.ts322
-rw-r--r--test/bundler/bundler_minify.test.ts15
-rw-r--r--test/bundler/bundler_plugin.test.ts146
-rw-r--r--test/bundler/esbuild/css.test.ts2
-rw-r--r--test/bundler/esbuild/default.test.ts227
-rw-r--r--test/bundler/esbuild/importstar_ts.test.ts2
-rw-r--r--test/bundler/esbuild/loader.test.ts347
-rw-r--r--test/bundler/esbuild/packagejson.test.ts93
-rw-r--r--test/bundler/esbuild/splitting.test.ts4
-rw-r--r--test/bundler/expectBundled.ts174
-rw-r--r--test/bundler/transpiler.test.js8
13 files changed, 1059 insertions, 461 deletions
diff --git a/test/bundler/bundler_browser.test.ts b/test/bundler/bundler_browser.test.ts
index 422e860b5..be2e5a43e 100644
--- a/test/bundler/bundler_browser.test.ts
+++ b/test/bundler/bundler_browser.test.ts
@@ -52,7 +52,7 @@ describe("bundler", () => {
console.log(typeof readFileSync);
`,
},
- platform: "browser",
+ target: "browser",
run: {
stdout: "function\nfunction\nundefined",
},
@@ -137,7 +137,7 @@ describe("bundler", () => {
console.log('zlib :', scan(zlib))
`,
},
- platform: "browser",
+ target: "browser",
onAfterBundle(api) {
assert(!api.readFile("/out.js").includes("\0"), "bundle should not contain null bytes");
const file = api.readFile("/out.js");
@@ -189,7 +189,7 @@ describe("bundler", () => {
files: {
"/entry.js": NodePolyfills.options.files["/entry.js"],
},
- platform: "browser",
+ target: "browser",
external: Object.keys(nodePolyfillList),
onAfterBundle(api) {
const file = api.readFile("/out.js");
@@ -211,7 +211,7 @@ describe("bundler", () => {
"bun:dns": "error",
"bun:test": "error",
"bun:sqlite": "error",
- "bun:wrap": "error",
+ // "bun:wrap": "error",
"bun:internal": "error",
"bun:jsc": "error",
};
@@ -220,7 +220,7 @@ describe("bundler", () => {
.filter(x => x[1] !== "error")
.map(x => x[0]);
- // segfaults the test runner
+ // all of them are set to error so this test doesnt make sense to run
itBundled.skip("browser/BunPolyfill", {
skipOnEsbuild: true,
files: {
@@ -233,7 +233,7 @@ describe("bundler", () => {
${nonErroringBunModules.map((x, i) => `console.log("${x.padEnd(12, " ")}:", scan(bun_${i}));`).join("\n")}
`,
},
- platform: "browser",
+ target: "browser",
onAfterBundle(api) {
assert(!api.readFile("/out.js").includes("\0"), "bundle should not contain null bytes");
const file = api.readFile("/out.js");
@@ -257,7 +257,7 @@ describe("bundler", () => {
.join("\n")}
`,
},
- platform: "browser",
+ target: "browser",
bundleErrors: {
"/entry.js": Object.keys(bunModules)
.filter(x => bunModules[x] === "error")
@@ -266,10 +266,10 @@ describe("bundler", () => {
});
// not implemented right now
- itBundled.skip("browser/BunPolyfillExternal", {
+ itBundled("browser/BunPolyfillExternal", {
skipOnEsbuild: true,
files: ImportBunError.options.files,
- platform: "browser",
+ target: "browser",
external: Object.keys(bunModules),
onAfterBundle(api) {
const file = api.readFile("/out.js");
diff --git a/test/bundler/bundler_edgecase.test.ts b/test/bundler/bundler_edgecase.test.ts
index cd4b57bc8..216e813d6 100644
--- a/test/bundler/bundler_edgecase.test.ts
+++ b/test/bundler/bundler_edgecase.test.ts
@@ -74,10 +74,11 @@ describe("bundler", () => {
external: ["external"],
mode: "transform",
minifySyntax: true,
- platform: "bun",
+ target: "bun",
run: { file: "/entry.ts" },
});
itBundled("edgecase/TemplateStringIssue622", {
+ notImplemented: true,
files: {
"/entry.ts": /* js */ `
capture(\`\\?\`);
@@ -85,7 +86,7 @@ describe("bundler", () => {
`,
},
capture: ["`\\\\?`", "hello`\\\\?`"],
- platform: "bun",
+ target: "bun",
});
itBundled("edgecase/StringNullBytes", {
files: {
@@ -121,7 +122,7 @@ describe("bundler", () => {
capture(process.env.NODE_ENV === 'development');
`,
},
- platform: "browser",
+ target: "browser",
capture: ['"development"', "false", "true"],
env: {
// undefined will ensure this variable is not passed to the bundler
@@ -136,7 +137,7 @@ describe("bundler", () => {
capture(process.env.NODE_ENV === 'development');
`,
},
- platform: "browser",
+ target: "browser",
capture: ['"development"', "false", "true"],
env: {
NODE_ENV: "development",
@@ -150,19 +151,40 @@ describe("bundler", () => {
capture(process.env.NODE_ENV === 'development');
`,
},
- platform: "browser",
+ target: "browser",
capture: ['"production"', "true", "false"],
env: {
NODE_ENV: "production",
},
});
+ itBundled("edgecase/NodeEnvOptionalChaining", {
+ notImplemented: true,
+ files: {
+ "/entry.js": /* js */ `
+ capture(process?.env?.NODE_ENV);
+ capture(process?.env?.NODE_ENV === 'production');
+ capture(process?.env?.NODE_ENV === 'development');
+ capture(process.env?.NODE_ENV);
+ capture(process.env?.NODE_ENV === 'production');
+ capture(process.env?.NODE_ENV === 'development');
+ capture(process?.env.NODE_ENV);
+ capture(process?.env.NODE_ENV === 'production');
+ capture(process?.env.NODE_ENV === 'development');
+ `,
+ },
+ target: "browser",
+ capture: ['"development"', "false", "true", '"development"', "false", "true", '"development"', "false", "true"],
+ env: {
+ NODE_ENV: "development",
+ },
+ });
itBundled("edgecase/ProcessEnvArbitrary", {
files: {
"/entry.js": /* js */ `
capture(process.env.ARBITRARY);
`,
},
- platform: "browser",
+ target: "browser",
capture: ["process.env.ARBITRARY"],
env: {
ARBITRARY: "secret environment stuff!",
@@ -228,4 +250,132 @@ describe("bundler", () => {
stdout: "1",
},
});
+ itBundled("edgecase/ValidLoaderSeenAsInvalid", {
+ files: {
+ "/entry.js": /* js */ `console.log(1)`,
+ },
+ outdir: "/out",
+ loader: {
+ ".a": "file", // segfaults
+ ".b": "text", // InvalidLoader
+ ".c": "toml", // InvalidLoader
+ ".d": "json",
+ ".e": "js",
+ ".f": "ts",
+ ".g": "jsx",
+ ".h": "tsx",
+ // ".i": "wasm",
+ // ".j": "napi",
+ // ".k": "base64",
+ // ".l": "dataurl",
+ // ".m": "binary",
+ // ".n": "empty",
+ // ".o": "copy",
+ },
+ });
+ itBundled("edgecase/InvalidLoaderSegfault", {
+ files: {
+ "/entry.js": /* js */ `console.log(1)`,
+ },
+ outdir: "/out",
+ loader: {
+ ".cool": "wtf",
+ },
+ bundleErrors: {
+ // todo: get the exact error
+ "<bun>": ["InvalidLoader"],
+ },
+ });
+ itBundled("edgecase/ScriptTagEscape", {
+ files: {
+ "/entry.js": /* js */ `
+ console.log('<script></script>');
+ console.log(await import('./text-file.txt'))
+ `,
+ "/text-file.txt": /* txt */ `
+ <script></script>
+ `,
+ },
+ outdir: "/out",
+ onAfterBundle(api) {
+ try {
+ expect(api.readFile("/out/entry.js")).not.toContain("</script>");
+ } catch (error) {
+ console.error("Bundle contains </script> which will break if this bundle is placed in a script tag.");
+ throw error;
+ }
+ },
+ });
+ itBundled("edgecase/JSONDefaultImport", {
+ files: {
+ "/entry.js": /* js */ `
+ import def from './test.json'
+ console.log(JSON.stringify(def))
+ `,
+ "/test.json": `{ "hello": 234, "world": 123 }`,
+ },
+ run: {
+ stdout: '{"hello":234,"world":123}',
+ },
+ });
+ itBundled("edgecase/JSONDefaultKeyImport", {
+ files: {
+ "/entry.js": /* js */ `
+ import def from './test.json'
+ console.log(def.hello)
+ `,
+ "/test.json": `{ "hello": 234, "world": "REMOVE" }`,
+ },
+ run: {
+ stdout: "234",
+ },
+ });
+ itBundled("edgecase/JSONDefaultAndNamedImport", {
+ files: {
+ "/entry.js": /* js */ `
+ import def from './test.json'
+ import { hello } from './test.json'
+ console.log(def.hello, hello)
+ `,
+ "/test.json": `{ "hello": 234, "world": "REMOVE" }`,
+ },
+ dce: true,
+ run: {
+ stdout: "234 234",
+ },
+ });
+ itBundled("edgecase/JSONWithDefaultKey", {
+ files: {
+ "/entry.js": /* js */ `
+ import def from './test.json'
+ console.log(JSON.stringify(def))
+ `,
+ "/test.json": `{ "default": 234 }`,
+ },
+ dce: true,
+ run: {
+ stdout: '{"default":234}',
+ },
+ });
+ itBundled("edgecase/JSONWithDefaultKeyNamespace", {
+ files: {
+ "/entry.js": /* js */ `
+ import * as ns from './test.json'
+ console.log(JSON.stringify(ns))
+ `,
+ "/test.json": `{ "default": 234 }`,
+ },
+ dce: true,
+ run: {
+ stdout: '{"default":234}',
+ },
+ });
+ itBundled("edgecase/RequireUnknownExtension", {
+ files: {
+ "/entry.js": /* js */ `
+ require('./x.aaaa')
+ `,
+ "/x.aaaa": `x`,
+ },
+ });
});
diff --git a/test/bundler/bundler_jsx.test.ts b/test/bundler/bundler_jsx.test.ts
new file mode 100644
index 000000000..3129f06be
--- /dev/null
+++ b/test/bundler/bundler_jsx.test.ts
@@ -0,0 +1,322 @@
+import assert from "assert";
+import dedent from "dedent";
+import { BundlerTestInput, itBundled, testForFile } from "./expectBundled";
+var { describe, test, expect } = testForFile(import.meta.path);
+
+const helpers = {
+ "/node_modules/bun-test-helpers/index.js": /* js */ `
+ export function print(arg) {
+ const replacer = (_, val) => {
+ if(typeof val === "function") {
+ if(val.name) return 'Function:' + val.name;
+ return val.toString();
+ }
+ if(typeof val === "symbol") return val.toString();
+ if(val === undefined) return "undefined";
+ if(val === null) return "null";
+ return val;
+ }
+ const stringified = JSON.stringify(arg, replacer);
+ if(!process.env.IS_TEST_RUNNER) {
+ console.log(arg);
+ }
+ console.log(stringified);
+ }
+ `,
+ "/node_modules/react/jsx-dev-runtime.js": /* js */ `
+ const $$typeof = Symbol.for("jsxdev");
+ export function jsxDEV(type, props, key, source, self) {
+ return {
+ $$typeof, type, props, key, source, self
+ }
+ }
+ export const Fragment = Symbol.for("jsxdev.fragment");
+ `,
+ "/node_modules/react/jsx-runtime.js": /* js */ `
+ const $$typeof = Symbol.for("jsx");
+ export function jsx(type, props, key) {
+ return {
+ $$typeof, type, props, key
+ }
+ }
+ export const Fragment = Symbol.for("jsx.fragment");
+ `,
+ "/node_modules/custom-jsx-dev/index.js": /* js */ `
+ export function jsxDEV(type, props, key, source, self) {
+ return ['custom-jsx-dev', type, props, key, source, self]
+ }
+ export const Fragment = "CustomFragment"
+ `,
+ "/node_modules/custom-jsx/index.js": /* js */ `
+ export function jsx(a, b, c) {
+ return ['custom-jsx', a, b, c]
+ }
+ export const Fragment = "CustomFragment"
+ `,
+ "/node_modules/custom-classic/index.js": /* js */ `
+ export function createElement(type, props, ...children) {
+ return ['custom-classic', type, props, children]
+ }
+ export const Fragment = "CustomFragment"
+ export const something = "something"
+ `,
+ "/node_modules/custom-automatic/jsx-runtime.js": /* js */ `
+ const $$typeof = Symbol.for("custom_jsx");
+ export function jsx(type, props, key) {
+ return {
+ $$typeof, type, props, key
+ }
+ }
+ export const Fragment = Symbol.for("custom.fragment");
+ `,
+ "/node_modules/custom-automatic/jsx-dev-runtime.js": /* js */ `
+ const $$typeof = Symbol.for("custom_jsxdev");
+ export function jsxDEV(type, props, key, source, self) {
+ return {
+ $$typeof, type, props, key, source, self
+ }
+ }
+ export const Fragment = Symbol.for("custom_dev.fragment");
+ `,
+ "/node_modules/custom-automatic/index.js": /* js */ `
+ export const Fragment = "FAILED"
+ `,
+ "/node_modules/react/index.js": /* js */ `
+ export function createElement(type, props, ...children) {
+ return ['react', type, props, children]
+ }
+ export const Fragment = Symbol.for("react.fragment")
+
+ export const fn = () => {
+ throw new Error('test failed')
+ }
+ export const something = 'test failed';
+ `,
+ "/node_modules/custom-renamed/index.js": /* js */ `
+ export function fn(type, props, ...children) {
+ return ['custom-renamed', type, props, children]
+ }
+ export const Fragment = "CustomFragment"
+ export const something = "something"
+ `,
+ "/node_modules/preact/index.js": /* js */ `
+ export function h(type, props, ...children) {
+ return ['preact', type, props, children]
+ }
+ export const Fragment = "PreactFragment"
+ `,
+};
+
+function itBundledDevAndProd(
+ id: string,
+ opts: BundlerTestInput & {
+ devStdout?: string;
+ prodStdout?: string;
+ devNotImplemented?: boolean;
+ prodNotImplemented?: boolean;
+ },
+) {
+ const { devStdout, prodStdout, ...rest } = opts;
+ itBundled(id + "Dev", {
+ notImplemented: opts.devNotImplemented,
+ ...rest,
+ env: {
+ NODE_ENV: "development",
+ },
+ run: devStdout
+ ? {
+ ...(rest.run === true ? {} : rest.run),
+ stdout: devStdout,
+ }
+ : rest.run,
+ });
+ itBundled(id + "Prod", {
+ notImplemented: opts.prodNotImplemented,
+ ...rest,
+ env: {
+ NODE_ENV: "production",
+ },
+ run: prodStdout
+ ? {
+ ...(rest.run === true ? {} : rest.run),
+ stdout: prodStdout,
+ }
+ : rest.run,
+ });
+}
+
+describe("bundler", () => {
+ itBundledDevAndProd("jsx/Automatic", {
+ files: {
+ "index.jsx": /* js*/ `
+ import { print } from 'bun-test-helpers'
+ const Component = 'hello'
+ print(<div>Hello World</div>)
+ print(<div className="container"><Component prop={2}><h1 onClick={() => 1}>hello</h1></Component></div>)
+ `,
+ ...helpers,
+ },
+ target: "bun",
+ devStdout: `
+ {"$$typeof":"Symbol(jsxdev)","type":"div","props":{"children":"Hello World"},"key":"undefined","source":false,"self":"undefined"}
+ {"$$typeof":"Symbol(jsxdev)","type":"div","props":{"className":"container","children":{"$$typeof":"Symbol(jsxdev)","type":"hello","props":{"prop":2,"children":{"$$typeof":"Symbol(jsxdev)","type":"h1","props":{"onClick":"Function:onClick","children":"hello"},"key":"undefined","source":false,"self":"undefined"}},"key":"undefined","source":false,"self":"undefined"}},"key":"undefined","source":false,"self":"undefined"}
+ `,
+ prodStdout: `
+ {"$$typeof":"Symbol(react.element)","type":"div","key":"null","ref":"null","props":{"children":"Hello World"},"_owner":"null"}
+ {"$$typeof":"Symbol(react.element)","type":"div","key":"null","ref":"null","props":{"className":"container","children":{"$$typeof":"Symbol(react.element)","type":"hello","key":"null","ref":"null","props":{"prop":2,"children":{"$$typeof":"Symbol(react.element)","type":"h1","key":"null","ref":"null","props":{"onClick":"Function:onClick","children":"hello"},"_owner":"null"}},"_owner":"null"}},"_owner":"null"}
+ `,
+ });
+ // bun does not do the production transform for fragments as good as it could be right now.
+ itBundledDevAndProd("jsx/AutomaticFragment", {
+ notImplemented: true,
+ files: {
+ "index.jsx": /* js*/ `
+ import { print } from 'bun-test-helpers'
+ const Component = 'hello'
+ print(<div>Hello World</div>)
+ print(<div className="container"><Component prop={2}><h1 onClick={() => 1}>hello</h1></Component></div>)
+ print(<>Fragment</>)
+ `,
+ ...helpers,
+ },
+ target: "bun",
+ devStdout: `
+ {"$$typeof":"Symbol(jsxdev)","type":"Symbol(jsxdev.fragment)","props":{"children":"Fragment"},"key":"undefined","source":false,"self":"undefined"}
+ `,
+ prodStdout: `
+ {"$$typeof":"Symbol(react.element)","type":"Symbol("jsx.fragment")","key":"null","ref":"null","props":{"children":"Fragment"},"_owner":"null"}
+ `,
+ });
+ itBundledDevAndProd("jsx/ImportSource", {
+ files: {
+ "/index.jsx": /* js*/ `
+ import { print } from 'bun-test-helpers'
+ print([<div props={123}>Hello World</div>, <>Fragment</>])
+ `,
+ ...helpers,
+ },
+ target: "bun",
+ jsx: {
+ importSource: "custom-automatic",
+ },
+ devStdout: `
+ [{"$$typeof":"Symbol(custom_jsxdev)","type":"div","props":{"props":123,"children":"Hello World"},"key":"undefined","source":false,"self":"undefined"},{"$$typeof":"Symbol(custom_jsxdev)","type":"Symbol(custom_dev.fragment)","props":{"children":"Fragment"},"key":"undefined","source":false,"self":"undefined"}]
+ `,
+ prodStdout: `
+ [{"$$typeof":"Symbol(custom_jsx)","type":"div","props":{"props":123,"children":"Hello World"},"key":"undefined"},{"$$typeof":"Symbol(custom_jsx)","type":"Symbol(custom_dev.fragment)","props":{"children":"Fragment"},"key":"undefined"}]
+ `,
+ });
+ itBundledDevAndProd("jsx/Classic", {
+ files: {
+ "/index.jsx": /* js*/ `
+ import { print } from 'bun-test-helpers'
+ // not react to catch if bun auto imports or uses the global
+ import * as React from 'custom-classic'
+ print([<div props={123}>Hello World</div>, <>Fragment</>])
+ `,
+ ...helpers,
+ },
+ target: "bun",
+ jsx: {
+ runtime: "classic",
+ importSource: "ignore-me",
+ },
+ run: {
+ stdout: `
+ [["custom-classic","div",{"props":123},["Hello World"]],["custom-classic","CustomFragment","null",["Fragment"]]]
+ `,
+ },
+ });
+ itBundledDevAndProd("jsx/ClassicPragma", {
+ files: {
+ "/index.jsx": /* js*/ `
+ // @jsx fn
+ // @jsxFrag something
+ import { print } from 'bun-test-helpers'
+ import { fn, something } from 'custom-renamed'
+ print([<div props={123}>Hello World</div>, <>Fragment</>])
+ `,
+ ...helpers,
+ },
+ target: "bun",
+ jsx: {
+ runtime: "classic",
+ importSource: "ignore-me",
+ },
+ run: {
+ stdout: `
+ [["custom-renamed","div",{"props":123},["Hello World"]],["custom-renamed","something","null",["Fragment"]]]
+ `,
+ },
+ });
+ itBundledDevAndProd("jsx/PragmaMultiple", {
+ files: {
+ "/index.jsx": /* js*/ `
+ import './classic.jsx'
+ import './classic-renamed.jsx'
+ import './automatic.jsx'
+ import './automatic-source2.jsx'
+ `,
+ "/classic.jsx": /* js*/ `
+ /* @jsxRuntime classic */
+ import { print } from 'bun-test-helpers'
+ // not react to catch if bun auto imports or uses the global
+ import * as React from 'custom-classic'
+ print(['classic.jsx',<div props={123}>Hello World</div>, <>Fragment</>])
+ `,
+ "/classic-renamed.jsx": /* js*/ `
+ /* @jsxRuntime classic */
+ // @jsx fn
+ // @jsxFrag something
+ import { print } from 'bun-test-helpers'
+ import { fn, something } from 'custom-renamed'
+ print(['classic-renamed.jsx',<div props={123}>Hello World</div>, <>Fragment</>])
+ `,
+ "/automatic.jsx": /* js*/ `
+ import { print } from 'bun-test-helpers'
+ print(['automatic.jsx',<div props={123}>Hello World</div>, process.env.NODE_ENV === 'production' ? '' : <>Fragment</>])
+ `,
+ "/automatic-source2.jsx": /* js*/ `
+ // @jsxImportSource custom-automatic
+ import { print } from 'bun-test-helpers'
+ print(['automatic-source2.jsx',<div props={123}>Hello World</div>, <>Fragment</>])
+ `,
+ ...helpers,
+ },
+ target: "bun",
+ devStdout: `
+ ["classic.jsx",["custom-classic","div",{"props":123},["Hello World"]],["custom-classic","CustomFragment","null",["Fragment"]]]
+ ["classic-renamed.jsx",["custom-renamed","div",{"props":123},["Hello World"]],["custom-renamed","something","null",["Fragment"]]]
+ ["automatic.jsx",{"$$typeof":"Symbol(jsxdev)","type":"div","props":{"props":123,"children":"Hello World"},"key":"undefined","source":false,"self":"undefined"},{"$$typeof":"Symbol(jsxdev)","type":"Symbol(jsxdev.fragment)","props":{"children":"Fragment"},"key":"undefined","source":false,"self":"undefined"}]
+ ["automatic-source2.jsx",{"$$typeof":"Symbol(custom_jsxdev)","type":"div","props":{"props":123,"children":"Hello World"},"key":"undefined","source":false,"self":"undefined"},{"$$typeof":"Symbol(custom_jsxdev)","type":"Symbol(custom_dev.fragment)","props":{"children":"Fragment"},"key":"undefined","source":false,"self":"undefined"}]
+ `,
+ prodStdout: `
+ ["classic.jsx",["custom-classic","div",{"props":123},["Hello World"]],["custom-classic","CustomFragment","null",["Fragment"]]]
+ ["classic-renamed.jsx",["custom-renamed","div",{"props":123},["Hello World"]],["custom-renamed","something","null",["Fragment"]]]
+ ["automatic.jsx",{"$$typeof":"Symbol(react.element)","type":"div","key":"null","ref":"null","props":{"props":123,"children":"Hello World"},"_owner":"null"},""]
+ ["automatic-source2.jsx",{"$$typeof":"Symbol(custom_jsx)","type":"div","props":{"props":123,"children":"Hello World"},"key":"undefined"},{"$$typeof":"Symbol(custom_jsx)","type":"Symbol(custom.fragment)","props":{"children":"Fragment"},"key":"undefined"}]
+ `,
+ });
+ itBundledDevAndProd("jsx/Factory", {
+ files: {
+ "/index.jsx": /* js*/ `
+ const h = () => 'hello'
+ const Fragment = 123;
+
+ import { print } from 'bun-test-helpers'
+ print([<div props={123}>Hello World</div>, <>Fragment</>])
+ `,
+ ...helpers,
+ },
+ target: "bun",
+ jsx: {
+ runtime: "classic",
+ factory: "h",
+ },
+ run: {
+ stdout: `
+ hello hello
+ `,
+ },
+ });
+});
diff --git a/test/bundler/bundler_minify.test.ts b/test/bundler/bundler_minify.test.ts
index cad991f2a..1bd255e46 100644
--- a/test/bundler/bundler_minify.test.ts
+++ b/test/bundler/bundler_minify.test.ts
@@ -52,7 +52,7 @@ describe("bundler", () => {
"!1",
],
minifySyntax: true,
- platform: "bun",
+ target: "bun",
});
itBundled("minify/FunctionExpressionRemoveName", {
notImplemented: true,
@@ -67,7 +67,7 @@ describe("bundler", () => {
capture: ["function(", "function(", "function e("],
minifySyntax: true,
minifyIdentifiers: true,
- platform: "bun",
+ target: "bun",
});
itBundled("minify/PrivateIdentifiersNameCollision", {
files: {
@@ -123,4 +123,15 @@ describe("bundler", () => {
assert([...code.matchAll(/var /g)].length === 1, "expected only 1 variable declaration statement");
},
});
+ itBundled("minify/InlineArraySpread", {
+ files: {
+ "/entry.js": /* js */ `
+ capture([1, 2, ...[3, 4], 5, 6, ...[7, ...[...[...[...[8, 9]]]]], 10, ...[...[...[...[...[...[...[11]]]]]]]]);
+ capture([1, 2, ...[3, 4], 5, 6, ...[7, [...[...[...[8, 9]]]]], 10, ...[...[...[...[...[...[...11]]]]]]]);
+ `,
+ },
+ capture: ["[1,2,3,4,5,6,7,8,9,10,11]", "[1,2,3,4,5,6,7,[8,9],10,...11]"],
+ minifySyntax: true,
+ minifyWhitespace: true,
+ });
});
diff --git a/test/bundler/bundler_plugin.test.ts b/test/bundler/bundler_plugin.test.ts
index bde2f180c..312c8f252 100644
--- a/test/bundler/bundler_plugin.test.ts
+++ b/test/bundler/bundler_plugin.test.ts
@@ -425,6 +425,152 @@ describe("bundler", () => {
onAfterBundle(api) {},
};
});
+ itBundled("plugin/TwoPluginBug", ({ root }) => {
+ return {
+ files: {
+ "index.ts": /* ts */ `
+ import { foo } from "plugin1";
+ console.log(foo);
+ `,
+ },
+ plugins: [
+ {
+ name: "1",
+ setup(builder) {
+ builder.onResolve({ filter: /plugin1/ }, args => {
+ return {
+ path: "plugin1",
+ namespace: "plugin1",
+ };
+ });
+ builder.onLoad({ filter: /plugin1/, namespace: "plugin1" }, args => {
+ return {
+ contents: "export * from 'plugin2';",
+ loader: "js",
+ };
+ });
+ },
+ },
+ {
+ name: "2",
+ setup(builder) {
+ builder.onResolve({ filter: /plugin2/ }, args => {
+ return {
+ path: "plugin2",
+ namespace: "plugin2",
+ };
+ });
+ builder.onLoad({ filter: /plugin2/, namespace: "plugin2" }, args => {
+ return {
+ contents: "export const foo = 'foo';",
+ loader: "js",
+ };
+ });
+ },
+ },
+ ],
+ run: {
+ stdout: "foo",
+ },
+ };
+ });
+ itBundled("plugin/LoadCalledOnce", ({ root }) => {
+ let resolveCount = 0;
+ let loadCount = 0;
+ return {
+ files: {
+ "index.ts": /* ts */ `
+ import { foo } from "plugin:first";
+ import { foo as foo2 } from "plugin:second";
+ import { foo as foo3 } from "plugin:third";
+ console.log(foo === foo2, foo === foo3);
+ `,
+ },
+ plugins: [
+ {
+ name: "1",
+ setup(builder) {
+ builder.onResolve({ filter: /^plugin:/ }, args => {
+ resolveCount++;
+ return {
+ path: "plugin",
+ namespace: "plugin",
+ };
+ });
+ builder.onLoad({ filter: /^plugin$/, namespace: "plugin" }, args => {
+ loadCount++;
+ return {
+ contents: "export const foo = { };",
+ loader: "js",
+ };
+ });
+ },
+ },
+ ],
+ run: {
+ stdout: "true true",
+ },
+ onAfterBundle(api) {
+ expect(resolveCount).toBe(3);
+ expect(loadCount).toBe(1);
+ },
+ };
+ });
+ itBundled("plugin/ResolveManySegfault", ({ root }) => {
+ let resolveCount = 0;
+ let loadCount = 0;
+ return {
+ files: {
+ "index.ts": /* ts */ `
+ import { foo as foo1 } from "plugin:100";
+ console.log(foo1);
+ `,
+ },
+ plugins: [
+ {
+ name: "1",
+ setup(builder) {
+ builder.onResolve({ filter: /^plugin:/ }, args => {
+ resolveCount++;
+ return {
+ path: args.path,
+ namespace: "plugin",
+ };
+ });
+ builder.onLoad({ filter: /^plugin:/, namespace: "plugin" }, args => {
+ loadCount++;
+ const number = parseInt(args.path.replace("plugin:", ""));
+ if (number > 1) {
+ const numberOfImports = number > 100 ? 100 : number;
+ const imports = Array.from({ length: numberOfImports })
+ .map((_, i) => `import { foo as foo${i} } from "plugin:${number - i - 1}";`)
+ .join("\n");
+ const exports = `export const foo = ${Array.from({ length: numberOfImports })
+ .map((_, i) => `foo${i}`)
+ .join(" + ")};`;
+ return {
+ contents: `${imports}\n${exports}`,
+ loader: "js",
+ };
+ } else {
+ return {
+ contents: `export const foo = 1;`,
+ loader: "js",
+ };
+ }
+ });
+ },
+ },
+ ],
+ run: {
+ stdout: "101 102",
+ },
+ onAfterBundle(api) {
+ expect(resolveCount).toBe(103);
+ expect(loadCount).toBe(102);
+ },
+ };
+ });
});
// TODO: add async on resolve stuff
diff --git a/test/bundler/esbuild/css.test.ts b/test/bundler/esbuild/css.test.ts
index 75eeb21c5..f1bfde569 100644
--- a/test/bundler/esbuild/css.test.ts
+++ b/test/bundler/esbuild/css.test.ts
@@ -484,7 +484,7 @@ var { describe, test, expect } = testForFile(import.meta.path);
// },
// metafile: true,
// entryPoints: ["/foo/entry.js", "/bar/entry.js"],
-// entryNames: "[ext]/[hash]",
+// entryNaming: "[ext]/[hash]",
// outdir: "/",
// });
// itBundled("css/DeduplicateRules", {
diff --git a/test/bundler/esbuild/default.test.ts b/test/bundler/esbuild/default.test.ts
index 83822411f..03a7f1adf 100644
--- a/test/bundler/esbuild/default.test.ts
+++ b/test/bundler/esbuild/default.test.ts
@@ -494,11 +494,15 @@ describe("bundler", () => {
itBundled("default/JSXSyntaxInJS", {
files: {
"/entry.mjs": `console.log(<div/>)`,
+ "/entry.cjs": `console.log(<div/>)`,
},
bundleErrors: {
// TODO: this could be a nicer error
"/entry.mjs": [`Unexpected <`],
+ "/entry.cjs": [`Unexpected <`],
},
+ outdir: "/out",
+ entryPoints: ["/entry.mjs", "/entry.cjs"],
});
itBundled("default/JSXConstantFragments", {
notImplemented: true, // jsx in bun is too different to esbuild
@@ -856,7 +860,7 @@ describe("bundler", () => {
require.resolve(v ? y ? 'a' : 'b' : c)
`,
},
- platform: "node",
+ target: "node",
format: "cjs",
// esbuild seems to not need externals for require.resolve, but it should be specified
external: ["a", "b", "c"],
@@ -925,7 +929,7 @@ describe("bundler", () => {
await import('./out/b');
`,
},
- entryNames: "[name].[ext]",
+ entryNaming: "[name].[ext]",
entryPoints: ["/a.js", "/b.js"],
external: ["a", "b", "c"],
run: [
@@ -1023,42 +1027,6 @@ describe("bundler", () => {
stdout: "./test.txt",
},
});
- itBundled("default/RequireWithoutCallPlatformNeutral", {
- notImplemented: true,
- // `require` on line one has to be renamed to `__require`
- files: {
- "/entry.js": /* js */ `
- const req = require
- req('./entry')
- capture(req)
- `,
- },
- platform: "neutral",
- onAfterBundle(api) {
- const varName = api.captureFile("/out.js")[0];
- const assignmentValue = api.readFile("/out.js").match(new RegExp(`${varName} = (.*);`))![1];
- expect(assignmentValue).not.toBe("require");
- },
- });
- itBundled("default/NestedRequireWithoutCallPlatformNeutral", {
- notImplemented: true,
- // `require` on line one has to be renamed to `__require`
- files: {
- "/entry.js": /* js */ `
- (() => {
- const req = require
- req('./entry')
- capture(req)
- })()
- `,
- },
- platform: "neutral",
- onAfterBundle(api) {
- const varName = api.captureFile("/out.js")[0];
- const assignmentValue = api.readFile("/out.js").match(new RegExp(`${varName} = (.*);`))![1];
- expect(assignmentValue).not.toBe("require");
- },
- });
itBundled("default/RequireWithCallInsideTry", {
files: {
"/entry.js": /* js */ `
@@ -1093,27 +1061,6 @@ describe("bundler", () => {
},
run: [{ file: "/test1.js" }, { file: "/test2.js" }],
});
- itBundled("default/RequireWithoutCallInsideTry", {
- notImplemented: true,
- // `require` has to be renamed to `__require`
- files: {
- "/entry.js": /* js */ `
- try {
- oldLocale = globalLocale._abbr;
- var aliasedRequire = require;
- aliasedRequire('./locale/' + name);
- getSetGlobalLocale(oldLocale);
- capture(aliasedRequire)
- } catch (e) {}
- `,
- },
- platform: "neutral",
- onAfterBundle(api) {
- const varName = api.captureFile("/out.js")[0];
- const assignmentValue = api.readFile("/out.js").match(new RegExp(`${varName} = (.*);`))![1];
- expect(assignmentValue).not.toBe("require");
- },
- });
itBundled("default/RequirePropertyAccessCommonJS", {
files: {
"/entry.js": /* js */ `
@@ -1124,7 +1071,7 @@ describe("bundler", () => {
delete require.extensions['.json']
`,
},
- platform: "node",
+ target: "node",
format: "cjs",
onAfterBundle(api) {
api.prependFile(
@@ -1252,18 +1199,6 @@ describe("bundler", () => {
assert(api.readFile("/out.js").startsWith("#!/usr/bin/env a"), "hashbang exists on bundle");
},
});
- itBundled("default/HashbangNoBundle", {
- files: {
- "/entry.js": /* js */ `
- #!/usr/bin/env node
- process.exit(0);
- `,
- },
- mode: "transform",
- onAfterBundle(api) {
- assert(api.readFile("/out.js").startsWith("#!/usr/bin/env node"), "hashbang exists on bundle");
- },
- });
itBundled("default/HashbangBannerUseStrictOrder", {
files: {
"/entry.js": /* js */ `
@@ -1281,7 +1216,7 @@ describe("bundler", () => {
files: {
"/entry.js": `console.log(require('fs'))`,
},
- platform: "browser",
+ target: "browser",
run: {
stdout: "[Function]",
},
@@ -1291,7 +1226,7 @@ describe("bundler", () => {
"/entry.js": `console.log('existsSync' in require('fs'))`,
},
format: "cjs",
- platform: "node",
+ target: "node",
run: {
stdout: "true",
},
@@ -1302,7 +1237,7 @@ describe("bundler", () => {
},
minifyWhitespace: true,
format: "cjs",
- platform: "node",
+ target: "node",
run: {
stdout: "true",
},
@@ -1320,7 +1255,7 @@ describe("bundler", () => {
run: {
stdout: "[Function] undefined undefined",
},
- platform: "browser",
+ target: "browser",
});
itBundled("default/ImportFSNodeCommonJS", {
files: {
@@ -1332,7 +1267,7 @@ describe("bundler", () => {
console.log('writeFileSync' in fs, readFileSync, 'writeFileSync' in defaultValue)
`,
},
- platform: "node",
+ target: "node",
format: "cjs",
run: {
stdout: "true [Function: readFileSync] true",
@@ -1348,7 +1283,7 @@ describe("bundler", () => {
console.log('writeFileSync' in fs, readFileSync, 'writeFileSync' in defaultValue)
`,
},
- platform: "node",
+ target: "node",
run: {
stdout: "true [Function: readFileSync] true",
},
@@ -1360,7 +1295,7 @@ describe("bundler", () => {
export {readFileSync} from 'fs'
`,
},
- platform: "browser",
+ target: "browser",
run: {
file: "out.js",
},
@@ -1380,7 +1315,7 @@ describe("bundler", () => {
assert(module.readFileSync === fs.readFileSync, 'export {readFileSync} from "fs"; works')
`,
},
- platform: "node",
+ target: "node",
run: {
file: "/test.js",
},
@@ -1404,7 +1339,7 @@ describe("bundler", () => {
assert(module.rfs === fs.readFileSync, 'export {rfs} works')
`,
},
- platform: "node",
+ target: "node",
run: {
file: "/test.js",
},
@@ -1428,7 +1363,7 @@ describe("bundler", () => {
assert(mod.foo === 123, 'exports.foo')
`,
},
- platform: "node",
+ target: "node",
run: {
file: "/test.js",
},
@@ -1444,7 +1379,7 @@ describe("bundler", () => {
`,
},
format: "esm",
- platform: "node",
+ target: "node",
run: {
file: "/test.js",
},
@@ -1460,7 +1395,7 @@ describe("bundler", () => {
`,
},
format: "cjs",
- platform: "node",
+ target: "node",
run: {
file: "/test.js",
},
@@ -2310,7 +2245,7 @@ describe("bundler", () => {
},
});
itBundled("default/AutoExternalNode", {
- notImplemented: true,
+ // notImplemented: true,
files: {
"/entry.js": /* js */ `
// These URLs should be external automatically
@@ -2325,7 +2260,7 @@ describe("bundler", () => {
import "node:what-is-this";
`,
},
- platform: "node",
+ target: "node",
treeShaking: true,
onAfterBundle(api) {
const file = api.readFile("/out.js");
@@ -2356,7 +2291,7 @@ describe("bundler", () => {
import "bun:what-is-this";
`,
},
- platform: "bun",
+ target: "bun",
onAfterBundle(api) {
const file = api.readFile("/out.js");
const imports = new Bun.Transpiler().scanImports(file);
@@ -2613,7 +2548,7 @@ describe("bundler", () => {
`,
},
inject: ["/shims.js"],
- platform: "node",
+ target: "node",
run: {
stdout: "function",
},
@@ -3794,7 +3729,7 @@ describe("bundler", () => {
`,
"/present-file.js": ``,
},
- platform: "node",
+ target: "node",
format: "cjs",
external: ["external-pkg", "@scope/external-pkg", "{{root}}/external-file"],
});
@@ -4315,6 +4250,7 @@ describe("bundler", () => {
},
});
itBundled("default/DefineOptionalChain", {
+ notImplemented: true,
files: {
"/entry.js": /* js */ `
log([
@@ -5205,7 +5141,7 @@ describe("bundler", () => {
"/node_modules/second-path/index.js": `module.exports = 567`,
},
external: ["*"],
- platform: "browser",
+ target: "browser",
format: "esm",
outfile: "/out.mjs",
run: {
@@ -5232,7 +5168,7 @@ describe("bundler", () => {
files: RequireShimSubstitutionBrowser.options.files,
runtimeFiles: RequireShimSubstitutionBrowser.options.runtimeFiles,
external: ["*"],
- platform: "node",
+ target: "node",
format: "esm",
outfile: "/out.mjs",
run: {
@@ -5292,7 +5228,7 @@ describe("bundler", () => {
"/node_modules/fs/index.js": `console.log('include this too')`,
"/node_modules/fs/promises.js": `throw 'DO NOT INCLUDE THIS'`,
},
- platform: "node",
+ target: "node",
});
itBundled("default/EntryNamesNoSlashAfterDir", {
// GENERATED
@@ -5303,7 +5239,7 @@ describe("bundler", () => {
},
entryPoints: ["/src/app1/main.ts", "/src/app2/main.ts", "/src/app3/main.ts"],
outputPaths: ["/out/app1-main.js", "/out/app2-main.js", "/out/app3-main.js"],
- entryNames: "[dir]-[name].[ext]",
+ entryNaming: "[dir]-[name].[ext]",
});
// itBundled("default/EntryNamesNonPortableCharacter", {
// // GENERATED
@@ -5331,7 +5267,7 @@ describe("bundler", () => {
// entryPoints: ["/src/entries/entry1.js", "/src/entries/entry2.js"],
// outbase: "/src",
// splitting: true,
- // entryNames: "main/[ext]/[name]-[hash].[ext]",
+ // entryNaming: "main/[ext]/[name]-[hash].[ext]",
// });
itBundled("default/MinifyIdentifiersImportPathFrequencyAnalysis", {
files: {
@@ -5350,10 +5286,22 @@ describe("bundler", () => {
minifyWhitespace: true,
minifyIdentifiers: true,
onAfterBundle(api) {
- let importFile = api.readFile("/out/import.js").replace(/remove\(.*?\)/g, "remove()");
- let requireFile = api.readFile("/out/require.js").replace(/remove\(.*?\)/g, "remove()");
- assert(!["W", "X", "Y", "Z"].some(x => importFile.includes(x)));
- assert(!["A", "B", "C", "D"].some(x => requireFile.includes(x)));
+ let importFile = api
+ .readFile("/out/import.js")
+ .replace(/remove\(.*?\)/g, "remove()")
+ .replace(/Object\.[a-z]+\b/gi, "null");
+ let requireFile = api
+ .readFile("/out/require.js")
+ .replace(/remove\(.*?\)/g, "remove()")
+ .replace(/Object\.[a-z]+\b/gi, "null");
+ assert(
+ !["W", "X", "Y", "Z"].some(x => importFile.includes(x)),
+ 'import.js should not contain "W", "X", "Y", or "Z"',
+ );
+ assert(
+ !["A", "B", "C", "D"].some(x => requireFile.includes(x)),
+ 'require.js should not contain "A", "B", "C", or "D"',
+ );
},
});
itBundled("default/ToESMWrapperOmission", {
@@ -6199,28 +6147,6 @@ describe("bundler", () => {
// NOTE: You can either keep the import assertion and only use the "default" import, or you can remove the import assertion and use the "prop" import (which is non-standard behavior).
// `, */
// });
- return;
- itBundled("default/ExternalPackages", {
- // GENERATED
- files: {
- "/project/entry.js": /* js */ `
- import 'pkg1'
- import './file'
- import './node_modules/pkg2/index.js'
- import '#pkg3'
- `,
- "/project/package.json": /* json */ `
- {
- "imports": {
- "#pkg3": "./libs/pkg3.js"
- }
- }
- `,
- "/project/file.js": `console.log('file')`,
- "/project/node_modules/pkg2/index.js": `console.log('pkg2')`,
- "/project/libs/pkg3.js": `console.log('pkg3')`,
- },
- });
itBundled("default/MetafileVariousCases", {
// GENERATED
files: {
@@ -6290,7 +6216,8 @@ describe("bundler", () => {
`,
},
entryPoints: ["/project/entry.js", "/project/entry.css"],
- mode: "convertformat",
+ external: ["*"],
+ metafile: true,
});
itBundled("default/MetafileVeryLongExternalPaths", {
// GENERATED
@@ -6321,7 +6248,7 @@ describe("bundler", () => {
},
});
itBundled("default/CommentPreservation", {
- // GENERATED
+ notImplemented: true,
files: {
"/entry.js": /* js */ `
console.log(
@@ -6467,28 +6394,54 @@ describe("bundler", () => {
for (a of /*foo*/b);
if (/*foo*/a);
- with (/*foo*/a);
while (/*foo*/a);
do {} while (/*foo*/a);
switch (/*foo*/a) {}
`,
},
- format: "cjs",
+ external: ["foo"],
+ onAfterBundle(api) {
+ const commentCounts: Record<string, number> = {
+ before: 44,
+ after: 18,
+ "comment before": 4,
+ "comment after": 4,
+ foo: 21,
+ bar: 4,
+ a: 1,
+ b: 1,
+ c: 1,
+ };
+ const file = api.readFile("/out.js");
+ const comments = [...file.matchAll(/\/\*([^*]+)\*\//g), ...file.matchAll(/\/\/([^\n]+)/g)]
+ .map(m => m[1].trim())
+ .filter(m => m && !m.includes("__PURE__"));
+
+ for (const key in commentCounts) {
+ const count = comments.filter(c => c === key).length;
+ if (count !== commentCounts[key]) {
+ throw new Error(`Expected ${commentCounts[key]} comments with "${key}", got ${count}`);
+ }
+ }
+ },
});
itBundled("default/CommentPreservationImportAssertions", {
// GENERATED
+ notImplemented: true,
files: {
"/entry.jsx": /* jsx */ `
- import 'foo' /* before */ assert { type: 'json' }
- import 'foo' assert /* before */ { type: 'json' }
- import 'foo' assert { /* before */ type: 'json' }
- import 'foo' assert { type: /* before */ 'json' }
- import 'foo' assert { type: 'json' /* before */ }
+ import 'foo' /* a */ assert { type: 'json' }
+ import 'foo' assert /* b */ { type: 'json' }
+ import 'foo' assert { /* c */ type: 'json' }
+ import 'foo' assert { type: /* d */ 'json' }
+ import 'foo' assert { type: 'json' /* e */ }
`,
},
+ external: ["foo"],
});
itBundled("default/CommentPreservationTransformJSX", {
// GENERATED
+ notImplemented: true,
files: {
"/entry.jsx": /* jsx */ `
console.log(
@@ -6518,6 +6471,7 @@ describe("bundler", () => {
});
itBundled("default/CommentPreservationPreserveJSX", {
// GENERATED
+ notImplemented: true,
files: {
"/entry.jsx": /* jsx */ `
console.log(
@@ -6545,19 +6499,4 @@ describe("bundler", () => {
`,
},
});
- itBundled("default/ErrorMessageCrashStdinESBuildIssue2913", {
- // GENERATED
- files: {
- "/project/node_modules/fflate/package.json": `{ "main": "main.js" }`,
- "/project/node_modules/fflate/main.js": ``,
- },
- stdin: {
- contents: `import "node_modules/fflate"`,
- cwd: "/project",
- },
- platform: "neutral",
- /* TODO FIX expectedScanLog: `<stdin>: ERROR: Could not resolve "node_modules/fflate"
- NOTE: You can mark the path "node_modules/fflate" as external to exclude it from the bundle, which will remove this error.
- `, */
- });
});
diff --git a/test/bundler/esbuild/importstar_ts.test.ts b/test/bundler/esbuild/importstar_ts.test.ts
index 5bbb0567e..0e39f0b29 100644
--- a/test/bundler/esbuild/importstar_ts.test.ts
+++ b/test/bundler/esbuild/importstar_ts.test.ts
@@ -7,7 +7,7 @@ import { RUN_UNCHECKED_TESTS, itBundled } from "../expectBundled";
// For debug, all files are written to $TEMP/bun-bundle-tests/ts
describe("bundler", () => {
- if (!RUN_UNCHECKED_TESTS) return;
+ return;
itBundled("ts/TSImportStarUnused", {
// GENERATED
files: {
diff --git a/test/bundler/esbuild/loader.test.ts b/test/bundler/esbuild/loader.test.ts
index 93a4e5fff..0b946d0b3 100644
--- a/test/bundler/esbuild/loader.test.ts
+++ b/test/bundler/esbuild/loader.test.ts
@@ -7,8 +7,7 @@ var { describe, test, expect } = testForFile(import.meta.path);
// For debug, all files are written to $TEMP/bun-bundle-tests/loader
describe("bundler", () => {
- itBundled("loader/LoaderJSONCommonJSAndES6", {
- // GENERATED
+ itBundled("loader/JSONCommonJSAndES6", {
files: {
"/entry.js": /* js */ `
const x_json = require('./x.json')
@@ -20,19 +19,19 @@ describe("bundler", () => {
"/y.json": `{"y1": true, "y2": false}`,
"/z.json": /* json */ `
{
- "big": "this is a big long line of text that should be discarded",
- "small": "some small text",
- "if": "test keyword imports"
- }
+ "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} {} some small text test keyword imports',
+ stdout: '{"x":true} {"y1":true,"y2":false} some small text test keyword imports',
},
});
- itBundled("loader/LoaderJSONSharedWithMultipleEntriesESBuildIssue413", {
- // GENERATED
+ itBundled("loader/JSONSharedWithMultipleEntriesESBuildIssue413", {
files: {
"/a.js": /* js */ `
import data from './data.json'
@@ -54,137 +53,192 @@ describe("bundler", () => {
run: [
{
file: "/out/a.js",
- stdout: 'a: {"test":123} 123 true true true true {"test":123,"default":{"test":123}}',
+ 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,"default":{"test":123}}',
+ stdout: 'b: {"test":123} 123 true true true true {"test":123}',
},
],
});
- if (!RUN_UNCHECKED_TESTS) return;
- itBundled("loader/LoaderFile", {
- // GENERATED
+ itBundled("loader/File", {
files: {
"/entry.js": `console.log(require('./test.svg'))`,
"/test.svg": `<svg></svg>`,
},
- outdir: "/out/",
+ outdir: "/out",
+ loader: {
+ // ".svg": "file",
+ },
+ run: {
+ stdout: /\.\/test-.*\.svg/,
+ },
});
- itBundled("loader/LoaderFileMultipleNoCollision", {
- // GENERATED
+ itBundled("loader/FileMultipleNoCollision", {
files: {
"/entry.js": /* js */ `
- console.log(
- require('./a/test.txt'),
- require('./b/test.txt'),
- )
+ console.log(require('./a/test.svg'))
+ console.log(require('./b/test.svg'))
`,
- "/a/test.txt": `test`,
- "/b/test.txt": `test`,
+ "/a/test.svg": `<svg></svg>`,
+ "/b/test.svg": `<svg></svg>`,
},
- outfile: "/dist/out.js",
- });
- itBundled("loader/JSXSyntaxInJSWithJSXLoader", {
- // GENERATED
- files: {
- "/entry.js": `console.log(<div/>)`,
+ loader: {
+ ".svg": "file",
},
- });
- itBundled("loader/JSXPreserveCapitalLetter", {
- // GENERATED
- files: {
- "/entry.jsx": /* jsx */ `
- import { mustStartWithUpperCaseLetter as Test } from './foo'
- console.log(<Test/>)
- `,
- "/foo.js": `export class mustStartWithUpperCaseLetter {}`,
+ outdir: "/out",
+ run: {
+ stdout: /\.\/test-.*\.svg\n\.\/test-.*\.svg/,
},
});
- itBundled("loader/JSXPreserveCapitalLetterMinify", {
+ itBundled("loader/FileMultipleNoCollisionAssetNames", {
files: {
- "/entry.jsx": /* jsx */ `
- import { mustStartWithUpperCaseLetter as XYYYY } from './foo'
- // This should be named "Y" due to frequency analysis
- console.log(<XYYYY YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY />)
+ "/entry.js": /* js */ `
+ console.log(require('./a/test.svg'))
+ console.log(require('./b/test.svg'))
`,
- "/foo.js": `export class mustStartWithUpperCaseLetter {}`,
+ "/a/test.svg": `<svg></svg>`,
+ "/b/test.svg": `<svg></svg>`,
},
- 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 />
- }
- `,
+ outdir: "/out",
+ assetNaming: "assets/[name]-[hash].[ext]",
+ loader: {
+ ".svg": "file",
+ },
+ run: {
+ stdout: /\.\/test-.*\.svg \.\/test-.*\.svg/,
},
- external: ["react"],
- minifyIdentifiers: true,
});
+ itBundled("loader/JSXSyntaxInJSWithJSXLoader", {
+ files: {
+ "/entry.cjs": `console.log(<div/>)`,
+ },
+ loader: {
+ ".cjs": "jsx",
+ },
+ external: ["*"],
+ });
+ // 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", {
- // GENERATED
files: {
"/entry.js": `console.log(require('./test.custom'))`,
"/test.custom": `#include <stdio.h>`,
},
+ loader: {
+ ".custom": "text",
+ },
+ run: {
+ stdout: "#include <stdio.h>",
+ },
});
itBundled("loader/RequireCustomExtensionBase64", {
- // GENERATED
files: {
"/entry.js": `console.log(require('./test.custom'))`,
"/test.custom": `a\x00b\x80c\xFFd`,
},
+ loader: {
+ ".custom": "base64",
+ },
+ run: {
+ stdout: "YQBiwoBjw79k",
+ },
});
itBundled("loader/RequireCustomExtensionDataURL", {
- // GENERATED
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", {
- // GENERATED
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", {
- // GENERATED
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/LoaderJSONInvalidIdentifierES6", {
- // GENERATED
+ itBundled("loader/JSONInvalidIdentifierES6", {
files: {
"/entry.js": /* js */ `
import * as ns from './test.json'
import * as ns2 from './test2.json'
- console.log(ns['invalid-identifier'], ns2)
+ 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/LoaderJSONMissingES6", {
- // GENERATED
+ itBundled("loader/JSONMissingES6", {
files: {
"/entry.js": `import {missing} from './test.json'`,
"/test.json": `{"present": true}`,
},
- /* TODO FIX expectedCompileLog: `entry.js: ERROR: No matching export in "test.json" for import "missing"
- `, */
+ bundleErrors: {
+ "/entry.js": [`No matching export in "test.json" for import "missing"`],
+ },
});
- itBundled("loader/LoaderTextCommonJSAndES6", {
- // GENERATED
+ itBundled("loader/TextCommonJSAndES6", {
files: {
"/entry.js": /* js */ `
const x_txt = require('./x.txt')
@@ -194,9 +248,11 @@ describe("bundler", () => {
"/x.txt": `x`,
"/y.txt": `y`,
},
+ run: {
+ stdout: "x y",
+ },
});
- itBundled("loader/LoaderBase64CommonJSAndES6", {
- // GENERATED
+ itBundled("loader/Base64CommonJSAndES6", {
files: {
"/entry.js": /* js */ `
const x_b64 = require('./x.b64')
@@ -206,9 +262,14 @@ describe("bundler", () => {
"/x.b64": `x`,
"/y.b64": `y`,
},
+ loader: {
+ ".b64": "base64",
+ },
+ run: {
+ stdout: "eA== eQ==",
+ },
});
- itBundled("loader/LoaderDataURLCommonJSAndES6", {
- // GENERATED
+ itBundled("loader/DataURLCommonJSAndES6", {
files: {
"/entry.js": /* js */ `
const x_url = require('./x.txt')
@@ -218,9 +279,14 @@ describe("bundler", () => {
"/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/LoaderFileCommonJSAndES6", {
- // GENERATED
+ itBundled("loader/FileCommonJSAndES6", {
files: {
"/entry.js": /* js */ `
const x_url = require('./x.txt')
@@ -231,8 +297,7 @@ describe("bundler", () => {
"/y.txt": `y`,
},
});
- itBundled("loader/LoaderFileRelativePathJS", {
- // GENERATED
+ itBundled("loader/FileRelativePathJS", {
files: {
"/src/entries/entry.js": /* js */ `
import x from '../images/image.png'
@@ -241,20 +306,28 @@ describe("bundler", () => {
"/src/images/image.png": `x`,
},
outbase: "/src",
- });
- itBundled("loader/LoaderFileRelativePathCSS", {
- // GENERATED
- files: {
- "/src/entries/entry.css": /* css */ `
- div {
- background: url(../images/image.png);
- }
- `,
- "/src/images/image.png": `x`,
+ outdir: "/out",
+ outputPaths: ["/out/entries/entry.js"],
+ loader: {
+ ".png": "file",
+ },
+ run: {
+ stdout: /^..\/image-.*\.png$/,
},
- outbase: "/src",
});
- itBundled("loader/LoaderFileRelativePathAssetNamesJS", {
+ // itBundled("loader/FileRelativePathCSS", {
+ // // GENERATED
+ // files: {
+ // "/src/entries/entry.css": /* css */ `
+ // div {
+ // background: url(../images/image.png);
+ // }
+ // `,
+ // "/src/images/image.png": `x`,
+ // },
+ // outbase: "/src",
+ // });
+ itBundled("loader/FileRelativePathAssetNamesJS", {
// GENERATED
files: {
"/src/entries/entry.js": /* js */ `
@@ -264,9 +337,17 @@ describe("bundler", () => {
"/src/images/image.png": `x`,
},
outbase: "/src",
- assetNames: "[dir]/[name]-[hash]",
+ assetNaming: "[dir]/[name]-[hash]",
+ outdir: "/out",
+ outputPaths: ["/out/entries/entry.js"],
+ loader: {
+ ".png": "file",
+ },
+ run: {
+ stdout: /^..\/images\/image-.*\.png$/,
+ },
});
- itBundled("loader/LoaderFileExtPathAssetNamesJS", {
+ itBundled("loader/FileExtPathAssetNamesJS", {
// GENERATED
files: {
"/src/entries/entry.js": /* js */ `
@@ -278,9 +359,9 @@ describe("bundler", () => {
"/src/uploads/file.txt": `y`,
},
outbase: "/src",
- assetNames: "[ext]/[name]-[hash]",
+ assetNaming: "[ext]/[name]-[hash]",
});
- itBundled("loader/LoaderFileRelativePathAssetNamesCSS", {
+ itBundled("loader/FileRelativePathAssetNamesCSS", {
// GENERATED
files: {
"/src/entries/entry.css": /* css */ `
@@ -291,9 +372,9 @@ describe("bundler", () => {
"/src/images/image.png": `x`,
},
outbase: "/src",
- assetNames: "[dir]/[name]-[hash]",
+ assetNaming: "[dir]/[name]-[hash]",
});
- itBundled("loader/LoaderFilePublicPathJS", {
+ itBundled("loader/FilePublicPathJS", {
// GENERATED
files: {
"/src/entries/entry.js": /* js */ `
@@ -305,7 +386,7 @@ describe("bundler", () => {
outbase: "/src",
publicPath: "https://example.com",
});
- itBundled("loader/LoaderFilePublicPathCSS", {
+ itBundled("loader/FilePublicPathCSS", {
// GENERATED
files: {
"/src/entries/entry.css": /* css */ `
@@ -318,7 +399,7 @@ describe("bundler", () => {
outbase: "/src",
publicPath: "https://example.com",
});
- itBundled("loader/LoaderFilePublicPathAssetNamesJS", {
+ itBundled("loader/FilePublicPathAssetNamesJS", {
// GENERATED
files: {
"/src/entries/entry.js": /* js */ `
@@ -329,9 +410,9 @@ describe("bundler", () => {
},
outbase: "/src",
publicPath: "https://example.com",
- assetNames: "[dir]/[name]-[hash]",
+ assetNaming: "[dir]/[name]-[hash]",
});
- itBundled("loader/LoaderFilePublicPathAssetNamesCSS", {
+ itBundled("loader/FilePublicPathAssetNamesCSS", {
// GENERATED
files: {
"/src/entries/entry.css": /* css */ `
@@ -343,9 +424,9 @@ describe("bundler", () => {
},
outbase: "/src",
publicPath: "https://example.com",
- assetNames: "[dir]/[name]-[hash]",
+ assetNaming: "[dir]/[name]-[hash]",
});
- itBundled("loader/LoaderFileOneSourceTwoDifferentOutputPathsJS", {
+ itBundled("loader/FileOneSourceTwoDifferentOutputPathsJS", {
// GENERATED
files: {
"/src/entries/entry.js": `import '../shared/common.js'`,
@@ -359,7 +440,7 @@ describe("bundler", () => {
entryPoints: ["/src/entries/entry.js", "/src/entries/other/entry.js"],
outbase: "/src",
});
- itBundled("loader/LoaderFileOneSourceTwoDifferentOutputPathsCSS", {
+ itBundled("loader/FileOneSourceTwoDifferentOutputPathsCSS", {
// GENERATED
files: {
"/src/entries/entry.css": `@import "../shared/common.css";`,
@@ -374,14 +455,14 @@ describe("bundler", () => {
entryPoints: ["/src/entries/entry.css", "/src/entries/other/entry.css"],
outbase: "/src",
});
- itBundled("loader/LoaderJSONNoBundle", {
+ itBundled("loader/JSONNoBundle", {
// GENERATED
files: {
"/test.json": `{"test": 123, "invalid-identifier": true}`,
},
mode: "transform",
});
- itBundled("loader/LoaderJSONNoBundleES6", {
+ itBundled("loader/JSONNoBundleES6", {
// GENERATED
files: {
"/test.json": `{"test": 123, "invalid-identifier": true}`,
@@ -390,7 +471,7 @@ describe("bundler", () => {
unsupportedJSFeatures: "ArbitraryModuleNamespaceNames",
mode: "convertformat",
});
- itBundled("loader/LoaderJSONNoBundleES6ArbitraryModuleNamespaceNames", {
+ itBundled("loader/JSONNoBundleES6ArbitraryModuleNamespaceNames", {
// GENERATED
files: {
"/test.json": `{"test": 123, "invalid-identifier": true}`,
@@ -398,7 +479,7 @@ describe("bundler", () => {
format: "esm",
mode: "convertformat",
});
- itBundled("loader/LoaderJSONNoBundleCommonJS", {
+ itBundled("loader/JSONNoBundleCommonJS", {
// GENERATED
files: {
"/test.json": `{"test": 123, "invalid-identifier": true}`,
@@ -406,7 +487,7 @@ describe("bundler", () => {
format: "cjs",
mode: "convertformat",
});
- itBundled("loader/LoaderJSONNoBundleIIFE", {
+ itBundled("loader/JSONNoBundleIIFE", {
// GENERATED
files: {
"/test.json": `{"test": 123, "invalid-identifier": true}`,
@@ -414,7 +495,7 @@ describe("bundler", () => {
format: "iife",
mode: "convertformat",
});
- itBundled("loader/LoaderFileWithQueryParameter", {
+ itBundled("loader/FileWithQueryParameter", {
// GENERATED
files: {
"/entry.js": /* js */ `
@@ -426,7 +507,7 @@ describe("bundler", () => {
"/file.txt": `This is some text`,
},
});
- itBundled("loader/LoaderFromExtensionWithQueryParameter", {
+ itBundled("loader/FromExtensionWithQueryParameter", {
// GENERATED
files: {
"/entry.js": /* js */ `
@@ -436,7 +517,7 @@ describe("bundler", () => {
"/file.abc": `This should not be base64 encoded`,
},
});
- itBundled("loader/LoaderDataURLTextCSS", {
+ itBundled("loader/DataURLTextCSS", {
// GENERATED
files: {
"/entry.css": /* css */ `
@@ -447,7 +528,7 @@ describe("bundler", () => {
`,
},
});
- itBundled("loader/LoaderDataURLTextCSSCannotImport", {
+ itBundled("loader/DataURLTextCSSCannotImport", {
// GENERATED
files: {
"/entry.css": `@import "data:text/css,@import './other.css';";`,
@@ -456,7 +537,7 @@ describe("bundler", () => {
/* TODO FIX expectedScanLog: `<data:text/css,@import './other.css';>: ERROR: Could not resolve "./other.css"
`, */
});
- itBundled("loader/LoaderDataURLTextJavaScript", {
+ itBundled("loader/DataURLTextJavaScript", {
// GENERATED
files: {
"/entry.js": /* js */ `
@@ -467,7 +548,7 @@ describe("bundler", () => {
`,
},
});
- itBundled("loader/LoaderDataURLTextJavaScriptCannotImport", {
+ itBundled("loader/DataURLTextJavaScriptCannotImport", {
// GENERATED
files: {
"/entry.js": `import "data:text/javascript,import './other.js'"`,
@@ -476,13 +557,13 @@ describe("bundler", () => {
/* TODO FIX expectedScanLog: `<data:text/javascript,import './other.js'>: ERROR: Could not resolve "./other.js"
`, */
});
- itBundled("loader/LoaderDataURLTextJavaScriptPlusCharacter", {
+ itBundled("loader/DataURLTextJavaScriptPlusCharacter", {
// GENERATED
files: {
"/entry.js": `import "data:text/javascript,console.log(1+2)";`,
},
});
- itBundled("loader/LoaderDataURLApplicationJSON", {
+ itBundled("loader/DataURLApplicationJSON", {
// GENERATED
files: {
"/entry.js": /* js */ `
@@ -496,7 +577,7 @@ describe("bundler", () => {
`,
},
});
- itBundled("loader/LoaderDataURLUnknownMIME", {
+ itBundled("loader/DataURLUnknownMIME", {
// GENERATED
files: {
"/entry.js": /* js */ `
@@ -506,7 +587,7 @@ describe("bundler", () => {
`,
},
});
- itBundled("loader/LoaderDataURLExtensionBasedMIME", {
+ itBundled("loader/DataURLExtensionBasedMIME", {
// GENERATED
files: {
"/entry.foo": /* foo */ `
@@ -555,7 +636,7 @@ describe("bundler", () => {
"/example.xml": `xml`,
},
});
- itBundled("loader/LoaderDataURLBase64VsPercentEncoding", {
+ itBundled("loader/DataURLBase64VsPercentEncoding", {
// GENERATED
files: {
"/entry.js": /* js */ `
@@ -576,7 +657,7 @@ describe("bundler", () => {
"/shouldUseBase64_2.txt": `\n\n\n\n\n\n`,
},
});
- itBundled("loader/LoaderDataURLBase64InvalidUTF8", {
+ itBundled("loader/DataURLBase64InvalidUTF8", {
// GENERATED
files: {
"/entry.js": /* js */ `
@@ -586,7 +667,7 @@ describe("bundler", () => {
"/binary.txt": `\xFF`,
},
});
- itBundled("loader/LoaderDataURLEscapePercents", {
+ itBundled("loader/DataURLEscapePercents", {
// GENERATED
files: {
"/entry.js": /* js */ `
@@ -600,7 +681,7 @@ describe("bundler", () => {
`,
},
});
- itBundled("loader/LoaderCopyWithBundleFromJS", {
+ itBundled("loader/CopyWithBundleFromJS", {
// GENERATED
files: {
"/Users/user/project/src/entry.js": /* js */ `
@@ -611,7 +692,7 @@ describe("bundler", () => {
},
outbase: "/Users/user/project",
});
- itBundled("loader/LoaderCopyWithBundleFromCSS", {
+ itBundled("loader/CopyWithBundleFromCSS", {
// GENERATED
files: {
"/Users/user/project/src/entry.css": /* css */ `
@@ -623,7 +704,7 @@ describe("bundler", () => {
},
outbase: "/Users/user/project",
});
- itBundled("loader/LoaderCopyWithBundleEntryPoint", {
+ itBundled("loader/CopyWithBundleEntryPoint", {
// GENERATED
files: {
"/Users/user/project/src/entry.js": /* js */ `
@@ -644,7 +725,7 @@ describe("bundler", () => {
],
outbase: "/Users/user/project",
});
- itBundled("loader/LoaderCopyWithTransform", {
+ itBundled("loader/CopyWithTransform", {
// GENERATED
files: {
"/Users/user/project/src/entry.js": `console.log('entry')`,
@@ -654,7 +735,7 @@ describe("bundler", () => {
outbase: "/Users/user/project",
mode: "passthrough",
});
- itBundled("loader/LoaderCopyWithFormat", {
+ itBundled("loader/CopyWithFormat", {
// GENERATED
files: {
"/Users/user/project/src/entry.js": `console.log('entry')`,
@@ -734,7 +815,7 @@ describe("bundler", () => {
"/what": `.foo { color: red }`,
},
});
- itBundled("loader/LoaderCopyEntryPointAdvanced", {
+ itBundled("loader/CopyEntryPointAdvanced", {
// GENERATED
files: {
"/project/entry.js": /* js */ `
@@ -757,20 +838,20 @@ describe("bundler", () => {
},
}, */
});
- itBundled("loader/LoaderCopyUseIndex", {
+ itBundled("loader/CopyUseIndex", {
// GENERATED
files: {
"/Users/user/project/src/index.copy": `some stuff`,
},
});
- itBundled("loader/LoaderCopyExplicitOutputFile", {
+ itBundled("loader/CopyExplicitOutputFile", {
// GENERATED
files: {
"/project/TEST FAILED.copy": `some stuff`,
},
outfile: "/out/this.worked",
});
- itBundled("loader/LoaderCopyStartsWithDotAbsPath", {
+ itBundled("loader/CopyStartsWithDotAbsPath", {
// GENERATED
files: {
"/project/src/.htaccess": `some stuff`,
@@ -779,7 +860,7 @@ describe("bundler", () => {
},
entryPoints: ["/project/src/.htaccess", "/project/src/entry.js", "/project/src/.ts"],
});
- itBundled("loader/LoaderCopyStartsWithDotRelPath", {
+ itBundled("loader/CopyStartsWithDotRelPath", {
// GENERATED
files: {
"/project/src/.htaccess": `some stuff`,
diff --git a/test/bundler/esbuild/packagejson.test.ts b/test/bundler/esbuild/packagejson.test.ts
index c3b241561..f1bb556a2 100644
--- a/test/bundler/esbuild/packagejson.test.ts
+++ b/test/bundler/esbuild/packagejson.test.ts
@@ -417,7 +417,7 @@ describe("bundler", () => {
}
`,
},
- platform: "browser",
+ target: "browser",
run: {
stdout: "345",
},
@@ -451,7 +451,7 @@ describe("bundler", () => {
}
`,
},
- platform: "node",
+ target: "node",
run: {
stdout: "123",
},
@@ -493,7 +493,7 @@ describe("bundler", () => {
}
`,
},
- platform: "browser",
+ target: "browser",
run: {
stdout: "456",
},
@@ -535,7 +535,7 @@ describe("bundler", () => {
}
`,
},
- platform: "node",
+ target: "node",
run: {
stdout: "123",
},
@@ -957,65 +957,6 @@ describe("bundler", () => {
stdout: "b",
},
});
- itBundled("packagejson/NeutralNoDefaultMainFields", {
- notImplemented: true,
- files: {
- "/Users/user/project/src/entry.js": /* js */ `
- import fn from 'demo-pkg'
- console.log(fn())
- `,
- "/Users/user/project/node_modules/demo-pkg/package.json": /* json */ `
- {
- "main": "./main.js",
- "module": "./main.esm.js"
- }
- `,
- "/Users/user/project/node_modules/demo-pkg/main.js": /* js */ `
- module.exports = function() {
- return 123
- }
- `,
- "/Users/user/project/node_modules/demo-pkg/main.esm.js": /* js */ `
- export default function() {
- return 123
- }
- `,
- },
- platform: "neutral",
- /* TODO FIX expectedScanLog: `Users/user/project/src/entry.js: ERROR: Could not resolve "demo-pkg"
- Users/user/project/node_modules/demo-pkg/package.json: NOTE: The "main" field here was ignored. Main fields must be configured explicitly when using the "neutral" platform.
- NOTE: You can mark the path "demo-pkg" as external to exclude it from the bundle, which will remove this error.
- `, */
- });
- itBundled("packagejson/NeutralExplicitMainFields", {
- files: {
- "/Users/user/project/src/entry.js": /* js */ `
- import fn from 'demo-pkg'
- console.log(fn())
- `,
- "/Users/user/project/node_modules/demo-pkg/package.json": /* json */ `
- {
- "hello": "./main.js",
- "module": "./main.esm.js"
- }
- `,
- "/Users/user/project/node_modules/demo-pkg/main.js": /* js */ `
- module.exports = function() {
- return 123
- }
- `,
- "/Users/user/project/node_modules/demo-pkg/main.esm.js": /* js */ `
- export default function() {
- return 234
- }
- `,
- },
- platform: "neutral",
- mainFields: ["hello"],
- run: {
- stdout: "123",
- },
- });
itBundled("packagejson/ExportsErrorInvalidModuleSpecifier", {
files: {
"/Users/user/project/src/entry.js": /* js */ `
@@ -1264,7 +1205,7 @@ describe("bundler", () => {
"/Users/user/project/node_modules/pkg/node.js": `console.log('FAILURE')`,
"/Users/user/project/node_modules/pkg/browser.js": `console.log('SUCCESS')`,
},
- platform: "browser",
+ target: "browser",
outfile: "/Users/user/project/out.js",
run: {
stdout: "SUCCESS",
@@ -1286,30 +1227,8 @@ describe("bundler", () => {
"/Users/user/project/node_modules/pkg/browser.js": `console.log('FAILURE')`,
"/Users/user/project/node_modules/pkg/node.js": `console.log('SUCCESS')`,
},
- platform: "node",
- outfile: "/Users/user/project/out.js",
- run: {
- stdout: "SUCCESS",
- },
- });
- itBundled("packagejson/ExportsNeutral", {
- files: {
- "/Users/user/project/src/entry.js": `import 'pkg'`,
- "/Users/user/project/node_modules/pkg/package.json": /* json */ `
- {
- "exports": {
- "node": "./node.js",
- "browser": "./browser.js",
- "default": "./default.js"
- }
- }
- `,
- "/Users/user/project/node_modules/pkg/node.js": `console.log('FAILURE')`,
- "/Users/user/project/node_modules/pkg/browser.js": `console.log('FAILURE')`,
- "/Users/user/project/node_modules/pkg/default.js": `console.log('SUCCESS')`,
- },
+ target: "node",
outfile: "/Users/user/project/out.js",
- platform: "neutral",
run: {
stdout: "SUCCESS",
},
diff --git a/test/bundler/esbuild/splitting.test.ts b/test/bundler/esbuild/splitting.test.ts
index 361b51ef6..c10a1a36f 100644
--- a/test/bundler/esbuild/splitting.test.ts
+++ b/test/bundler/esbuild/splitting.test.ts
@@ -549,7 +549,7 @@ describe("bundler", () => {
},
outdir: "/out",
splitting: true,
- chunkNames: "[dir]/[name]-[hash].[ext]",
+ chunkNaming: "[dir]/[name]-[hash].[ext]",
onAfterBundle(api) {
assert(
readdirSync(api.outdir + "/output-path/should-contain/this-text").length === 1,
@@ -569,7 +569,7 @@ describe("bundler", () => {
outdir: "/out",
entryPoints: ["/src/index.js"],
splitting: true,
- platform: "browser",
+ target: "browser",
runtimeFiles: {
"/test.js": /* js */ `
import { A, B } from './out/index.js'
diff --git a/test/bundler/expectBundled.ts b/test/bundler/expectBundled.ts
index e029787c8..f6ad423f9 100644
--- a/test/bundler/expectBundled.ts
+++ b/test/bundler/expectBundled.ts
@@ -75,13 +75,13 @@ export interface BundlerTestInput {
// bundler options
alias?: Record<string, string>;
- assetNames?: string;
+ assetNaming?: string;
banner?: string;
define?: Record<string, string | number>;
/** Default is "[name].[ext]" */
- entryNames?: string;
+ entryNaming?: string;
/** Default is "[name]-[hash].[ext]" */
- chunkNames?: string;
+ chunkNaming?: string;
extensionOrder?: string[];
/** Replaces "{{root}}" with the file root */
external?: string[];
@@ -91,11 +91,10 @@ export interface BundlerTestInput {
ignoreDCEAnnotations?: boolean;
inject?: string[];
jsx?: {
- factory?: string;
- fragment?: string;
- automaticRuntime?: boolean;
- development?: boolean;
- preserve?: boolean;
+ runtime?: "automatic" | "classic";
+ importSource?: string; // for automatic
+ factory?: string; // for classic
+ fragment?: string; // for classic
};
outbase?: string;
/** Defaults to `/out.js` */
@@ -103,7 +102,7 @@ export interface BundlerTestInput {
/** Defaults to `/out` */
outdir?: string;
/** Defaults to "browser". "bun" is set to "node" when using esbuild. */
- platform?: "bun" | "node" | "neutral" | "browser";
+ target?: "bun" | "node" | "browser";
publicPath?: string;
keepNames?: boolean;
legalComments?: "none" | "inline" | "eof" | "linked" | "external";
@@ -215,7 +214,7 @@ export interface BundlerTestRunOptions {
/** Pass args to bun itself (before the filename) */
bunArgs?: string[];
/** match exact stdout */
- stdout?: string;
+ stdout?: string | RegExp;
/** partial match stdout (toContain()) */
partialStdout?: string;
/** match exact error message, example "ReferenceError: Can't find variable: bar" */
@@ -253,21 +252,23 @@ function expectBundled(
ignoreFilter = false,
): Promise<BundlerTestRef> | BundlerTestRef {
var { expect, it, test } = testForFile(callerSourceOrigin());
- if (!ignoreFilter && FILTER && id !== FILTER) return testRef(id, opts);
+ if (!ignoreFilter && FILTER && !filterMatches(id)) return testRef(id, opts);
let {
+ notImplemented,
bundleWarnings,
bundleErrors,
banner,
backend,
assertNotPresent,
capture,
- chunkNames,
+ assetNaming,
+ chunkNaming,
cjs2esm,
dce,
dceKeepMarkerCount,
define,
- entryNames,
+ entryNaming,
entryPoints,
entryPointsRaw,
env,
@@ -292,7 +293,7 @@ function expectBundled(
outdir,
outfile,
outputPaths,
- platform,
+ target,
plugins,
publicPath,
run,
@@ -321,7 +322,7 @@ function expectBundled(
// Resolve defaults for options and some related things
mode ??= "bundle";
- platform ??= "browser";
+ target ??= "browser";
format ??= "esm";
entryPoints ??= entryPointsRaw ? [] : [Object.keys(files)[0]];
if (run === true) run = {};
@@ -333,9 +334,6 @@ function expectBundled(
if (!ESBUILD && format !== "esm") {
throw new Error("formats besides esm not implemented in bun build");
}
- if (!ESBUILD && platform === "neutral") {
- throw new Error("platform=neutral not implemented in bun build");
- }
if (!ESBUILD && metafile) {
throw new Error("metafile not implemented in bun build");
}
@@ -357,9 +355,6 @@ function expectBundled(
if (!ESBUILD && mainFields) {
throw new Error("mainFields not implemented in bun build");
}
- if (!ESBUILD && loader) {
- throw new Error("loader not implemented in bun build");
- }
if (!ESBUILD && sourceMap) {
throw new Error("sourceMap not implemented in bun build");
}
@@ -369,11 +364,13 @@ function expectBundled(
if (!ESBUILD && inject) {
throw new Error("inject not implemented in bun build");
}
- if (!ESBUILD && publicPath) {
- throw new Error("publicPath not implemented in bun build");
- }
- if (!ESBUILD && chunkNames) {
- throw new Error("chunkNames is not implemented in bun build");
+ if (!ESBUILD && loader) {
+ const loaderValues = [...new Set(Object.values(loader))];
+ const supportedLoaderTypes = ["js", "jsx", "ts", "tsx", "css", "json", "text", "file"];
+ const unsupportedLoaderTypes = loaderValues.filter(x => !supportedLoaderTypes.includes(x));
+ if (unsupportedLoaderTypes.length) {
+ throw new Error(`loader '${unsupportedLoaderTypes.join("', '")}' not implemented in bun build`);
+ }
}
if (ESBUILD && skipOnEsbuild) {
return testRef(id, opts);
@@ -413,8 +410,8 @@ function expectBundled(
}
if (outdir) {
- entryNames ??= "[name].[ext]";
- chunkNames ??= "[name]-[hash].[ext]";
+ entryNaming ??= "[name].[ext]";
+ chunkNaming ??= "[name]-[hash].[ext]";
}
// Option validation
@@ -469,31 +466,32 @@ function expectBundled(
...(entryPointsRaw ?? []),
mode === "bundle" ? [outfile ? `--outfile=${outfile}` : `--outdir=${outdir}`] : [],
define && Object.entries(define).map(([k, v]) => ["--define", `${k}=${v}`]),
- `--platform=${platform}`,
+ `--target=${target}`,
external && external.map(x => ["--external", x]),
minifyIdentifiers && `--minify-identifiers`,
minifySyntax && `--minify-syntax`,
minifyWhitespace && `--minify-whitespace`,
globalName && `--global-name=${globalName}`,
// inject && inject.map(x => ["--inject", path.join(root, x)]),
- jsx.preserve && "--jsx=preserve",
- jsx.automaticRuntime === false && "--jsx=classic",
- jsx.factory && `--jsx-factory=${jsx.factory}`,
- jsx.fragment && `--jsx-fragment=${jsx.fragment}`,
- jsx.development === false && `--jsx-production`,
- // metafile && `--metafile=${metafile}`,
+ // jsx.preserve && "--jsx=preserve",
+ jsx.runtime && ["--jsx-runtime", jsx.runtime],
+ jsx.factory && ["--jsx-factory", jsx.factory],
+ jsx.fragment && ["--jsx-fragment", jsx.fragment],
+ jsx.importSource && ["--jsx-import-source", jsx.importSource],
+ // metafile && `--manifest=${metafile}`,
// sourceMap && `--sourcemap${sourceMap !== true ? `=${sourceMap}` : ""}`,
- entryNames && entryNames !== "[name].[ext]" && [`--entry-names`, entryNames],
- // chunkNames && chunkNames !== "[name]-[hash].[ext]" && [`--chunk-names`, chunkNames],
+ entryNaming && entryNaming !== "[name].[ext]" && [`--entry-naming`, entryNaming],
+ chunkNaming && chunkNaming !== "[name]-[hash].[ext]" && [`--chunk-naming`, chunkNaming],
+ assetNaming && assetNaming !== "[name]-[hash].[ext]" && [`--asset-naming`, chunkNaming],
// `--format=${format}`,
// legalComments && `--legal-comments=${legalComments}`,
splitting && `--splitting`,
- // treeShaking && `--tree-shaking`,
+ // treeShaking === false && `--no-tree-shaking`, // ??
// outbase && `--outbase=${outbase}`,
// keepNames && `--keep-names`,
// mainFields && `--main-fields=${mainFields}`,
- // loader && Object.entries(loader).map(([k, v]) => ["--loader", `${k}=${v}`]),
- // publicPath && `--public-path=${publicPath}`,
+ loader && Object.entries(loader).map(([k, v]) => ["--loader", `${k}:${v}`]),
+ publicPath && `--public-path=${publicPath}`,
mode === "transform" && "--transform",
]
: [
@@ -501,7 +499,7 @@ function expectBundled(
mode === "bundle" && "--bundle",
outfile ? `--outfile=${outfile}` : `--outdir=${outdir}`,
`--format=${format}`,
- `--platform=${platform === "bun" ? "node" : platform}`,
+ `--platform=${target === "bun" ? "node" : target}`,
minifyIdentifiers && `--minify-identifiers`,
minifySyntax && `--minify-syntax`,
minifyWhitespace && `--minify-whitespace`,
@@ -509,15 +507,18 @@ function expectBundled(
external && external.map(x => `--external:${x}`),
inject && inject.map(x => `--inject:${path.join(root, x)}`),
define && Object.entries(define).map(([k, v]) => `--define:${k}=${v}`),
- jsx.automaticRuntime && "--jsx=automatic",
- jsx.preserve && "--jsx=preserve",
+ `--jsx=${jsx.runtime ?? "automatic"}`,
+ // jsx.preserve && "--jsx=preserve",
jsx.factory && `--jsx-factory=${jsx.factory}`,
jsx.fragment && `--jsx-fragment=${jsx.fragment}`,
- jsx.development && `--jsx-dev`,
- entryNames && entryNames !== "[name].[ext]" && `--entry-names=${entryNames.replace(/\.\[ext]$/, "")}`,
- chunkNames &&
- chunkNames !== "[name]-[hash].[ext]" &&
- `--chunk-names=${chunkNames.replace(/\.\[ext]$/, "")}`,
+ env?.NODE_ENV !== "production" && `--jsx-dev`,
+ entryNaming && entryNaming !== "[name].[ext]" && `--entry-names=${entryNaming.replace(/\.\[ext]$/, "")}`,
+ chunkNaming &&
+ chunkNaming !== "[name]-[hash].[ext]" &&
+ `--chunk-names=${chunkNaming.replace(/\.\[ext]$/, "")}`,
+ assetNaming &&
+ assetNaming !== "[name]-[hash].[ext]" &&
+ `--asset-names=${assetNaming.replace(/\.\[ext]$/, "")}`,
metafile && `--metafile=${metafile}`,
sourceMap && `--sourcemap${sourceMap !== true ? `=${sourceMap}` : ""}`,
banner && `--banner:js=${banner}`,
@@ -758,33 +759,35 @@ function expectBundled(
syntax: minifySyntax,
},
naming: {
- entrypoint: useOutFile ? path.basename(outfile!) : entryNames,
- chunk: chunkNames,
+ entry: useOutFile ? path.basename(outfile!) : entryNaming,
+ chunk: chunkNaming,
+ asset: assetNaming,
},
plugins: pluginArray,
treeShaking,
outdir: buildOutDir,
sourcemap: sourceMap === true ? "external" : sourceMap || "none",
splitting,
- target: platform === "neutral" ? "browser" : platform,
+ target,
+ publicPath,
} as BuildConfig;
if (DEBUG) {
if (_referenceFn) {
const x = _referenceFn.toString().replace(/^\s*expect\(.*$/gm, "// $&");
const debugFile = `import path from 'path';
- import assert from 'assert';
- const {plugins} = (${x})({ root: ${JSON.stringify(root)} });
- const options = ${JSON.stringify({ ...buildConfig, plugins: undefined }, null, 2)};
- options.plugins = typeof plugins === "function" ? [{ name: "plugin", setup: plugins }] : plugins;
- const build = await Bun.build(options);
- if (build.logs) {
- throw build.logs;
- }
- for (const blob of build.outputs) {
- await Bun.write(path.join(options.outdir, blob.path), blob.result);
- }
- `;
+import assert from 'assert';
+const {plugins} = (${x})({ root: ${JSON.stringify(root)} });
+const options = ${JSON.stringify({ ...buildConfig, plugins: undefined }, null, 2)};
+options.plugins = typeof plugins === "function" ? [{ name: "plugin", setup: plugins }] : plugins;
+const build = await Bun.build(options);
+if (build.logs) {
+ throw build.logs;
+}
+for (const blob of build.outputs) {
+ await Bun.write(path.join(options.outdir, blob.path), blob.result);
+}
+`;
writeFileSync(path.join(root, "run.js"), debugFile);
} else {
console.log("TODO: generate run.js, currently only works if options are wrapped in a function");
@@ -795,14 +798,12 @@ function expectBundled(
const build = await Bun.build(buildConfig);
Bun.gc(true);
+ console.log(build);
+
if (build.logs) {
console.log(build.logs);
throw new Error("TODO: handle build logs, but we should make this api nicer");
}
-
- for (const blob of build.outputs) {
- await Bun.write(path.join(buildOutDir, blob.path), blob.result);
- }
} else {
await esbuild.build({
bundle: true,
@@ -896,7 +897,7 @@ function expectBundled(
}
} else {
// entryNames makes it so we cannot predict the output file
- if (!entryNames || entryNames === "[name].[ext]") {
+ if (!entryNaming || entryNaming === "[name].[ext]") {
for (const fullpath of outputPaths) {
if (!existsSync(fullpath)) {
throw new Error("Bundle was not written to disk: " + fullpath);
@@ -1027,7 +1028,7 @@ function expectBundled(
if (file) {
file = path.join(root, file);
} else if (entryPaths.length === 1) {
- file = outfile;
+ file = outfile ?? outputPaths[0];
} else {
throw new Error(prefix + "run.file is required when there is more than one entrypoint.");
}
@@ -1042,6 +1043,7 @@ function expectBundled(
env: {
...bunEnv,
FORCE_COLOR: "0",
+ IS_TEST_RUNNER: "1",
},
stdio: ["ignore", "pipe", "pipe"],
});
@@ -1100,18 +1102,34 @@ function expectBundled(
if (run.stdout !== undefined) {
const result = stdout!.toString("utf-8").trim();
- const expected = dedent(run.stdout).trim();
- if (expected !== result) {
- console.log({ file });
+ if (typeof run.stdout === "string") {
+ const expected = dedent(run.stdout).trim();
+ if (expected !== result) {
+ console.log(`runtime failed file=${file}`);
+ console.log(`reference stdout:`);
+ console.log(result);
+ console.log(`---`);
+ }
+ expect(result).toBe(expected);
+ } else {
+ if (!run.stdout.test(result)) {
+ console.log(`runtime failed file=${file}`);
+ console.log(`reference stdout:`);
+ console.log(result);
+ console.log(`---`);
+ }
+ expect(result).toMatch(run.stdout);
}
- expect(result).toBe(expected);
}
if (run.partialStdout !== undefined) {
const result = stdout!.toString("utf-8").trim();
const expected = dedent(run.partialStdout).trim();
if (!result.includes(expected)) {
- console.log({ file });
+ console.log(`runtime failed file=${file}`);
+ console.log(`reference stdout:`);
+ console.log(result);
+ console.log(`---`);
}
expect(result).toContain(expected);
}
@@ -1137,7 +1155,7 @@ export function itBundled(
const ref = testRef(id, opts);
const { it } = testForFile(callerSourceOrigin());
- if (FILTER && id !== FILTER) {
+ if (FILTER && !filterMatches(id)) {
return ref;
} else if (!FILTER) {
try {
@@ -1165,7 +1183,7 @@ export function itBundled(
return ref;
}
itBundled.skip = (id: string, opts: BundlerTestInput) => {
- if (FILTER && id !== FILTER) {
+ if (FILTER && !filterMatches(id)) {
return testRef(id, opts);
}
const { it } = testForFile(callerSourceOrigin());
@@ -1176,3 +1194,7 @@ itBundled.skip = (id: string, opts: BundlerTestInput) => {
function formatError(err: { file: string; error: string; line?: string; col?: string }) {
return `${err.file}${err.line ? " :" + err.line : ""}${err.col ? ":" + err.col : ""}: ${err.error}`;
}
+
+function filterMatches(id: string) {
+ return FILTER === id || FILTER + "Dev" === id || FILTER + "Prod" === id;
+}
diff --git a/test/bundler/transpiler.test.js b/test/bundler/transpiler.test.js
index 7af8f2d27..1fc599771 100644
--- a/test/bundler/transpiler.test.js
+++ b/test/bundler/transpiler.test.js
@@ -2969,4 +2969,12 @@ console.log(foo, array);
expectPrinted_('const x = "``" + ``;', 'const x = "``"');
});
});
+
+ it("scan on empty file does not segfault", () => {
+ new Bun.Transpiler().scan("");
+ });
+
+ it("scanImports on empty file does not segfault", () => {
+ new Bun.Transpiler().scanImports("");
+ });
});