aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar dave caruso <me@paperdave.net> 2023-04-29 00:08:48 -0400
committerGravatar GitHub <noreply@github.com> 2023-04-28 21:08:48 -0700
commit96e113f41c0dae1ccd58c6d1e3b6dd2c54769636 (patch)
tree1f8c0b88d2daa925abff610f4a458d744bc0bf36
parentbc0c0f7d203567a5538f271a3bc37c450eeaee46 (diff)
downloadbun-96e113f41c0dae1ccd58c6d1e3b6dd2c54769636.tar.gz
bun-96e113f41c0dae1ccd58c6d1e3b6dd2c54769636.tar.zst
bun-96e113f41c0dae1ccd58c6d1e3b6dd2c54769636.zip
bundler tests: rest of default.test.ts and starting jsx tests (#2765)
-rw-r--r--completions/bun.bash2
-rw-r--r--docs/api/transpiler.md2
-rw-r--r--docs/cli/build.md40
-rw-r--r--packages/bun-types/bun.d.ts21
-rw-r--r--src/api/demo/schema.peechy6
-rw-r--r--src/api/demo/schema.zig12
-rw-r--r--src/api/schema.d.ts6
-rw-r--r--src/api/schema.js16
-rw-r--r--src/api/schema.peechy4
-rw-r--r--src/api/schema.zig12
-rw-r--r--src/bun.js/api/JSBundler.zig14
-rw-r--r--src/bun.js/api/JSTranspiler.zig12
-rw-r--r--src/bun.js/builtins/cpp/BundlerPluginBuiltins.cpp22
-rw-r--r--src/bun.js/builtins/js/BundlerPlugin.js20
-rw-r--r--src/bun.js/config.zig2
-rw-r--r--src/bun.js/javascript.zig4
-rw-r--r--src/bundler.zig40
-rw-r--r--src/bundler/bundle_v2.zig72
-rw-r--r--src/cli.zig70
-rw-r--r--src/cli/build_command.zig8
-rw-r--r--src/js_ast.zig5
-rw-r--r--src/js_printer.zig16
-rw-r--r--src/linker.zig12
-rw-r--r--src/options.zig227
-rw-r--r--src/resolver/package_json.zig2
-rw-r--r--src/resolver/resolver.zig4
-rw-r--r--src/router.zig4
-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
40 files changed, 1399 insertions, 776 deletions
diff --git a/completions/bun.bash b/completions/bun.bash
index a42705789..7eb83c48b 100644
--- a/completions/bun.bash
+++ b/completions/bun.bash
@@ -119,7 +119,7 @@ _bun_completions() {
--jsx-runtime)
COMPREPLY=( $(compgen -W "automatic classic" -- "${cur_word}") );
return;;
- --platform)
+ --target)
COMPREPLY=( $(compgen -W "browser node bun" -- "${cur_word}") );
return;;
-l|--loader)
diff --git a/docs/api/transpiler.md b/docs/api/transpiler.md
index 09e28ba0d..bfe0b5ee9 100644
--- a/docs/api/transpiler.md
+++ b/docs/api/transpiler.md
@@ -195,7 +195,7 @@ interface TranspilerOptions {
// Default platform to target
// This affects how import and/or require is used
- platform?: "browser" | "bun" | "macro" | "node",
+ target?: "browser" | "bun" | "node",
// Specify a tsconfig.json file as stringified JSON or an object
// Use this to set a custom JSX factory, fragment, or import source
diff --git a/docs/cli/build.md b/docs/cli/build.md
index b4c7984dc..3ce34df1d 100644
--- a/docs/cli/build.md
+++ b/docs/cli/build.md
@@ -184,7 +184,7 @@ If the bundler encounters an import with an unrecognized extension, it treats th
{% codetabs %}
-```ts#Build_file
+```ts#Build file
await Bun.build({
entrypoints: ['./index.ts'],
outdir: './out'
@@ -315,7 +315,7 @@ Depending on the target, Bun will apply different module resolution rules and op
- `bun`
- For generating bundles that are intended to be run by the Bun runtime. In many cases, it isn't necessary to bundle server-side code; you can directly execute the source code without modification. However, bundling your server code can reduce startup times and improve running performance.
- All bundles generated with `target: "bun"` are marked with a special `// @bun` pragma, which indicates to the Bun runtime that there's no need to re-transpile the file before execution. This
+ All bundles generated with `target: "bun"` are marked with a special `// @bun` pragma, which indicates to the Bun runtime that there's no need to re-transpile the file before execution.
---
@@ -493,7 +493,6 @@ const result = await Bun.build({
console.log(result.manifest);
```
-The manifest takes the following form:
{% details summary="Manifest structure" %}
The manifest has the following form:
@@ -571,7 +570,7 @@ $ bun build ./index.tsx --outdir ./out --sourcemap=inline
---
- `"inline"`
-- A sourcemap is generated and appended to the end of the generated bundle as a base64 payload inside a `//# sourceMappingURL= ` comment.
+- A sourcemap is generated and appended to the end of the generated bundle as a base64 payload inside a `//# sourceMappingURL=` comment.
---
@@ -705,12 +704,12 @@ Customizes the generated file names. Defaults to `./[dir]/[name].[ext]`.
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
- naming: "./[dir]/[name].[ext]", // default
+ naming: "[dir]/[name].[ext]", // default
})
```
```bash#CLI
-n/a
+$ bun build ./index.tsx --outdir ./out --entry-naming [dir]/[name].[ext]
```
{% /codetabs %}
@@ -785,7 +784,7 @@ await Bun.build({
```
```bash#CLI
-$ bun build ./index.tsx --outdir ./out --naming [name]-[hash].[ext]
+$ bun build ./index.tsx --outdir ./out --entry-naming [name]-[hash].[ext]
```
{% /codetabs %}
@@ -809,15 +808,16 @@ await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
naming: {
- entrypoint: '[dir]/[name]-[hash].[ext]',
- chunk: '[dir]/[name]-[hash].[ext]',
- asset: '[dir]/[name]-[hash].[ext]',
+ // default values
+ entry: '[dir]/[name].[ext]',
+ chunk: '[name]-[hash].[ext]',
+ asset: '[name]-[hash].[ext]',
},
})
```
```bash#CLI
-n/a
+$ bun build ./index.tsx --outdir ./out --entry-naming "[dir]/[name].[ext]" --chunk-naming "[name]-[hash].[ext]" --asset-naming "[name]-[hash].[ext]"
```
{% /codetabs %}
@@ -973,19 +973,19 @@ The output file would now look something like this.
```ts
await Bun.build({
entrypoints: string[]; // list of file path
- outdir?: string; // output directory
+ outdir?: string; // default to in-memory build
target?: "browser" | "bun" | "node"; // default: "browser"
- splitting?: boolean, // default true, enable code splitting
+ splitting?: boolean; // default true
plugins?: BunPlugin[];
- manifest?: boolean; // whether to return manifest
- external?: Array<string>;
+ manifest?: boolean; // default false
+ external?: string[];
naming?: string | {
- entrypoint?: string;
- chunk?: string;
- asset?: string;
- }, // default './[dir]/[name].[ext]'
+ entry?: string; // default '[dir]/[name].[ext]'
+ chunk?: string; // default '[name]-[hash].[ext]'
+ asset?: string; // default '[name]-[hash].[ext]'
+ };
publicPath?: string; // e.g. http://mydomain.com/
- minify?: boolean | {
+ minify?: boolean | { // default false
identifiers?: boolean;
whitespace?: boolean;
syntax?: boolean;
diff --git a/packages/bun-types/bun.d.ts b/packages/bun-types/bun.d.ts
index 14b9d3a38..e14118680 100644
--- a/packages/bun-types/bun.d.ts
+++ b/packages/bun-types/bun.d.ts
@@ -711,21 +711,6 @@ declare module "bun" {
) => number | bigint;
}
- export type Platform =
- /**
- * When building for bun.js
- */
- | "bun"
- /**
- * When building for the web
- */
- | "browser"
- /**
- * When building for node.js
- */
- | "node"
- | "neutral";
-
export type JavaScriptLoader = "jsx" | "js" | "ts" | "tsx";
/**
@@ -776,7 +761,7 @@ declare module "bun" {
/** What platform are we targeting? This may affect how import and/or require is used */
/** @example "browser" */
- platform?: Platform;
+ target?: Target;
/**
* TSConfig.json file as stringified JSON or an object
@@ -974,7 +959,7 @@ declare module "bun" {
| string
| {
chunk?: string;
- entrypoint?: string;
+ entry?: string;
asset?: string;
}; // | string;
// root?: string; // project root
@@ -1000,7 +985,7 @@ declare module "bun" {
outputs: Array<{ path: string; result: T }>;
};
- function build(config: BuildConfig): BuildResult<Blob>;
+ function build(config: BuildConfig): Promise<BuildResult<Blob>>;
/**
* **0** means the message was **dropped**
diff --git a/src/api/demo/schema.peechy b/src/api/demo/schema.peechy
index 59cb1edf5..09d3c1fac 100644
--- a/src/api/demo/schema.peechy
+++ b/src/api/demo/schema.peechy
@@ -107,7 +107,7 @@ smol ResolveMode {
bundle = 4;
}
-smol Platform {
+smol Target {
browser = 1;
node = 2;
bun = 3;
@@ -326,7 +326,7 @@ message TransformOptions {
LoaderMap loaders = 13;
string[] main_fields = 14;
- Platform platform = 15;
+ Target target = 15;
bool serve = 16;
@@ -550,4 +550,4 @@ message BunInstall {
bool disable_manifest_cache = 16;
string global_dir = 17;
string global_bin_dir = 18;
-} \ No newline at end of file
+}
diff --git a/src/api/demo/schema.zig b/src/api/demo/schema.zig
index e4871b902..748422ed8 100644
--- a/src/api/demo/schema.zig
+++ b/src/api/demo/schema.zig
@@ -792,7 +792,7 @@ pub const Api = struct {
}
};
- pub const Platform = enum(u8) {
+ pub const Target = enum(u8) {
_none,
/// browser
browser,
@@ -1708,8 +1708,8 @@ pub const Api = struct {
/// main_fields
main_fields: []const []const u8,
- /// platform
- platform: ?Platform = null,
+ /// target
+ target: ?Target = null,
/// serve
serve: ?bool = null,
@@ -1796,7 +1796,7 @@ pub const Api = struct {
this.main_fields = try reader.readArray([]const u8);
},
15 => {
- this.platform = try reader.readValue(Platform);
+ this.target = try reader.readValue(Target);
},
16 => {
this.serve = try reader.readValue(bool);
@@ -1896,9 +1896,9 @@ pub const Api = struct {
try writer.writeFieldID(14);
try writer.writeArray([]const u8, main_fields);
}
- if (this.platform) |platform| {
+ if (this.target) |target| {
try writer.writeFieldID(15);
- try writer.writeEnum(platform);
+ try writer.writeEnum(target);
}
if (this.serve) |serve| {
try writer.writeFieldID(16);
diff --git a/src/api/schema.d.ts b/src/api/schema.d.ts
index ed58db778..4114d951d 100644
--- a/src/api/schema.d.ts
+++ b/src/api/schema.d.ts
@@ -135,13 +135,13 @@ export const ResolveModeKeys: {
4: "bundle";
bundle: "bundle";
};
-export const enum Platform {
+export const enum Target {
browser = 1,
node = 2,
bun = 3,
bun_macro = 4,
}
-export const PlatformKeys: {
+export const TargetKeys: {
1: "browser";
browser: "browser";
2: "node";
@@ -534,7 +534,7 @@ export interface TransformOptions {
external?: string[];
loaders?: LoaderMap;
main_fields?: string[];
- platform?: Platform;
+ target?: Target;
serve?: boolean;
extension_order?: string[];
generate_node_module_bundle?: boolean;
diff --git a/src/api/schema.js b/src/api/schema.js
index 3ec60fb4f..c4f2400ed 100644
--- a/src/api/schema.js
+++ b/src/api/schema.js
@@ -548,7 +548,7 @@ const ResolveModeKeys = {
"dev": "dev",
"bundle": "bundle",
};
-const Platform = {
+const Target = {
"1": 1,
"2": 2,
"3": 3,
@@ -558,7 +558,7 @@ const Platform = {
"bun": 3,
"bun_macro": 4,
};
-const PlatformKeys = {
+const TargetKeys = {
"1": "browser",
"2": "node",
"3": "bun",
@@ -1655,7 +1655,7 @@ function decodeTransformOptions(bb) {
break;
case 15:
- result["platform"] = Platform[bb.readByte()];
+ result["target"] = Target[bb.readByte()];
break;
case 16:
@@ -1825,11 +1825,11 @@ function encodeTransformOptions(message, bb) {
}
}
- var value = message["platform"];
+ var value = message["target"];
if (value != null) {
bb.writeByte(15);
- var encoded = Platform[value];
- if (encoded === void 0) throw new Error("Invalid value " + JSON.stringify(value) + ' for enum "Platform"');
+ var encoded = Target[value];
+ if (encoded === void 0) throw new Error("Invalid value " + JSON.stringify(value) + ' for enum "Target"');
bb.writeByte(encoded);
}
@@ -3321,8 +3321,8 @@ export { decodeFallbackMessageContainer };
export { encodeFallbackMessageContainer };
export { ResolveMode };
export { ResolveModeKeys };
-export { Platform };
-export { PlatformKeys };
+export { Target };
+export { TargetKeys };
export { CSSInJSBehavior };
export { CSSInJSBehaviorKeys };
export { JSXRuntime };
diff --git a/src/api/schema.peechy b/src/api/schema.peechy
index a6c0fed8a..71e85d68e 100644
--- a/src/api/schema.peechy
+++ b/src/api/schema.peechy
@@ -111,7 +111,7 @@ smol ResolveMode {
bundle = 4;
}
-smol Platform {
+smol Target {
browser = 1;
node = 2;
bun = 3;
@@ -331,7 +331,7 @@ message TransformOptions {
LoaderMap loaders = 13;
string[] main_fields = 14;
- Platform platform = 15;
+ Target target = 15;
bool serve = 16;
diff --git a/src/api/schema.zig b/src/api/schema.zig
index 2629f1c5e..227d1296b 100644
--- a/src/api/schema.zig
+++ b/src/api/schema.zig
@@ -804,7 +804,7 @@ pub const Api = struct {
}
};
- pub const Platform = enum(u8) {
+ pub const Target = enum(u8) {
_none,
/// browser
browser,
@@ -1723,8 +1723,8 @@ pub const Api = struct {
/// main_fields
main_fields: []const []const u8,
- /// platform
- platform: ?Platform = null,
+ /// target
+ target: ?Target = null,
/// serve
serve: ?bool = null,
@@ -1814,7 +1814,7 @@ pub const Api = struct {
this.main_fields = try reader.readArray([]const u8);
},
15 => {
- this.platform = try reader.readValue(Platform);
+ this.target = try reader.readValue(Target);
},
16 => {
this.serve = try reader.readValue(bool);
@@ -1917,9 +1917,9 @@ pub const Api = struct {
try writer.writeFieldID(14);
try writer.writeArray([]const u8, main_fields);
}
- if (this.platform) |platform| {
+ if (this.target) |target| {
try writer.writeFieldID(15);
- try writer.writeEnum(platform);
+ try writer.writeEnum(target);
}
if (this.serve) |serve| {
try writer.writeFieldID(16);
diff --git a/src/bun.js/api/JSBundler.zig b/src/bun.js/api/JSBundler.zig
index 1c774e1f4..022c83cb4 100644
--- a/src/bun.js/api/JSBundler.zig
+++ b/src/bun.js/api/JSBundler.zig
@@ -32,7 +32,7 @@ const TSConfigJSON = @import("../../resolver/tsconfig_json.zig").TSConfigJSON;
const PackageJSON = @import("../../resolver/package_json.zig").PackageJSON;
const logger = bun.logger;
const Loader = options.Loader;
-const Platform = options.Platform;
+const Target = options.Target;
const JSAst = bun.JSAst;
const JSParser = bun.js_parser;
const JSPrinter = bun.js_printer;
@@ -47,7 +47,7 @@ pub const JSBundler = struct {
const OwnedString = bun.MutableString;
pub const Config = struct {
- target: options.Platform = options.Platform.browser,
+ target: Target = Target.browser,
entry_points: bun.StringSet = bun.StringSet.init(bun.default_allocator),
hot: bool = false,
define: bun.StringMap = bun.StringMap.init(bun.default_allocator, true),
@@ -84,7 +84,7 @@ pub const JSBundler = struct {
errdefer this.deinit(allocator);
errdefer if (plugins.*) |plugin| plugin.deinit();
- if (try config.getOptionalEnum(globalThis, "target", options.Platform)) |target| {
+ if (try config.getOptionalEnum(globalThis, "target", options.Target)) |target| {
this.target = target;
}
@@ -175,7 +175,7 @@ pub const JSBundler = struct {
this.names.entry_point.data = this.names.owned_entry_point.list.items;
}
} else if (naming.isObject()) {
- if (try naming.getOptional(globalThis, "entrypoint", ZigString.Slice)) |slice| {
+ if (try naming.getOptional(globalThis, "entry", ZigString.Slice)) |slice| {
defer slice.deinit();
this.names.owned_entry_point.appendSliceExact(slice.slice()) catch unreachable;
this.names.entry_point.data = this.names.owned_entry_point.list.items;
@@ -414,7 +414,7 @@ pub const JSBundler = struct {
importer_source_index: ?u32 = null,
import_record_index: u32 = 0,
range: logger.Range = logger.Range.None,
- original_platform: options.Platform,
+ original_target: Target,
};
pub fn create(
@@ -424,7 +424,7 @@ pub const JSBundler = struct {
importer_source_index: u32,
import_record_index: u32,
source_file: []const u8 = "",
- original_platform: options.Platform,
+ original_target: Target,
record: *const bun.ImportRecord,
},
},
@@ -443,7 +443,7 @@ pub const JSBundler = struct {
.importer_source_index = file.importer_source_index,
.import_record_index = file.import_record_index,
.range = file.record.range,
- .original_platform = file.original_platform,
+ .original_target = file.original_target,
},
},
.completion = completion,
diff --git a/src/bun.js/api/JSTranspiler.zig b/src/bun.js/api/JSTranspiler.zig
index c4968a6ee..f1b00f191 100644
--- a/src/bun.js/api/JSTranspiler.zig
+++ b/src/bun.js/api/JSTranspiler.zig
@@ -32,7 +32,7 @@ const TSConfigJSON = @import("../../resolver/tsconfig_json.zig").TSConfigJSON;
const PackageJSON = @import("../../resolver/package_json.zig").PackageJSON;
const logger = bun.logger;
const Loader = options.Loader;
-const Platform = options.Platform;
+const Target = options.Target;
const JSAst = bun.JSAst;
const Transpiler = @This();
const JSParser = bun.js_parser;
@@ -54,7 +54,7 @@ buffer_writer: ?JSPrinter.BufferWriter = null,
const default_transform_options: Api.TransformOptions = brk: {
var opts = std.mem.zeroes(Api.TransformOptions);
opts.disable_hmr = true;
- opts.platform = Api.Platform.browser;
+ opts.target = Api.Target.browser;
opts.serve = false;
break :brk opts;
};
@@ -427,9 +427,9 @@ fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std
}
}
- if (object.get(globalThis, "platform")) |platform| {
- if (Platform.fromJS(globalThis, platform, exception)) |resolved| {
- transpiler.transform.platform = resolved.toAPI();
+ if (object.get(globalThis, "target")) |target| {
+ if (Target.fromJS(globalThis, target, exception)) |resolved| {
+ transpiler.transform.target = resolved.toAPI();
}
if (exception.* != null) {
@@ -471,7 +471,7 @@ fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std
}
transpiler.runtime.allow_runtime = false;
- transpiler.runtime.dynamic_require = switch (transpiler.transform.platform orelse .browser) {
+ transpiler.runtime.dynamic_require = switch (transpiler.transform.target orelse .browser) {
.bun, .bun_macro => true,
else => false,
};
diff --git a/src/bun.js/builtins/cpp/BundlerPluginBuiltins.cpp b/src/bun.js/builtins/cpp/BundlerPluginBuiltins.cpp
index 1f2053ad5..552057d51 100644
--- a/src/bun.js/builtins/cpp/BundlerPluginBuiltins.cpp
+++ b/src/bun.js/builtins/cpp/BundlerPluginBuiltins.cpp
@@ -192,7 +192,7 @@ const char* const s_bundlerPluginRunOnResolvePluginsCode =
const JSC::ConstructAbility s_bundlerPluginRunSetupFunctionCodeConstructAbility = JSC::ConstructAbility::CannotConstruct;
const JSC::ConstructorKind s_bundlerPluginRunSetupFunctionCodeConstructorKind = JSC::ConstructorKind::None;
const JSC::ImplementationVisibility s_bundlerPluginRunSetupFunctionCodeImplementationVisibility = JSC::ImplementationVisibility::Public;
-const int s_bundlerPluginRunSetupFunctionCodeLength = 3262;
+const int s_bundlerPluginRunSetupFunctionCodeLength = 3786;
static const JSC::Intrinsic s_bundlerPluginRunSetupFunctionCodeIntrinsic = JSC::NoIntrinsic;
const char* const s_bundlerPluginRunSetupFunctionCode =
"(function (setup) {\n" \
@@ -248,6 +248,19 @@ const char* const s_bundlerPluginRunSetupFunctionCode =
" validate(filterObject, callback, onResolvePlugins);\n" \
" }\n" \
"\n" \
+ " function onStart(callback) {\n" \
+ " //\n" \
+ " @throwTypeError(\"On-start callbacks are not implemented yet. See https:/\\/github.com/oven-sh/bun/issues/2771\");\n" \
+ " }\n" \
+ "\n" \
+ " function onEnd(callback) {\n" \
+ " @throwTypeError(\"On-end callbacks are not implemented yet. See https:/\\/github.com/oven-sh/bun/issues/2771\");\n" \
+ " }\n" \
+ "\n" \
+ " function onDispose(callback) {\n" \
+ " @throwTypeError(\"On-dispose callbacks are not implemented yet. See https:/\\/github.com/oven-sh/bun/issues/2771\");\n" \
+ " }\n" \
+ "\n" \
" const processSetupResult = () => {\n" \
" var anyOnLoad = false,\n" \
" anyOnResolve = false;\n" \
@@ -277,7 +290,7 @@ const char* const s_bundlerPluginRunSetupFunctionCode =
" if (!existing) {\n" \
" onResolveObject.@set(namespace, callbacks);\n" \
" } else {\n" \
- " onResolveObject.@set(existing.concat(callbacks));\n" \
+ " onResolveObject.@set(namespace, existing.concat(callbacks));\n" \
" }\n" \
" }\n" \
" }\n" \
@@ -294,7 +307,7 @@ const char* const s_bundlerPluginRunSetupFunctionCode =
" if (!existing) {\n" \
" onLoadObject.@set(namespace, callbacks);\n" \
" } else {\n" \
- " onLoadObject.@set(existing.concat(callbacks));\n" \
+ " onLoadObject.@set(namespace, existing.concat(callbacks));\n" \
" }\n" \
" }\n" \
" }\n" \
@@ -304,8 +317,11 @@ const char* const s_bundlerPluginRunSetupFunctionCode =
" };\n" \
"\n" \
" var setupResult = setup({\n" \
+ " onDispose,\n" \
+ " onEnd,\n" \
" onLoad,\n" \
" onResolve,\n" \
+ " onStart,\n" \
" });\n" \
"\n" \
" if (setupResult && @isPromise(setupResult)) {\n" \
diff --git a/src/bun.js/builtins/js/BundlerPlugin.js b/src/bun.js/builtins/js/BundlerPlugin.js
index 9fbb323ed..4daa2dcbb 100644
--- a/src/bun.js/builtins/js/BundlerPlugin.js
+++ b/src/bun.js/builtins/js/BundlerPlugin.js
@@ -221,6 +221,19 @@ function runSetupFunction(setup) {
validate(filterObject, callback, onResolvePlugins);
}
+ function onStart(callback) {
+ // builtin generator thinks the // in the link is a comment and removes it
+ @throwTypeError("On-start callbacks are not implemented yet. See https:/\/github.com/oven-sh/bun/issues/2771");
+ }
+
+ function onEnd(callback) {
+ @throwTypeError("On-end callbacks are not implemented yet. See https:/\/github.com/oven-sh/bun/issues/2771");
+ }
+
+ function onDispose(callback) {
+ @throwTypeError("On-dispose callbacks are not implemented yet. See https:/\/github.com/oven-sh/bun/issues/2771");
+ }
+
const processSetupResult = () => {
var anyOnLoad = false,
anyOnResolve = false;
@@ -250,7 +263,7 @@ function runSetupFunction(setup) {
if (!existing) {
onResolveObject.@set(namespace, callbacks);
} else {
- onResolveObject.@set(existing.concat(callbacks));
+ onResolveObject.@set(namespace, existing.concat(callbacks));
}
}
}
@@ -267,7 +280,7 @@ function runSetupFunction(setup) {
if (!existing) {
onLoadObject.@set(namespace, callbacks);
} else {
- onLoadObject.@set(existing.concat(callbacks));
+ onLoadObject.@set(namespace, existing.concat(callbacks));
}
}
}
@@ -277,8 +290,11 @@ function runSetupFunction(setup) {
};
var setupResult = setup({
+ onDispose,
+ onEnd,
onLoad,
onResolve,
+ onStart,
});
if (setupResult && @isPromise(setupResult)) {
diff --git a/src/bun.js/config.zig b/src/bun.js/config.zig
index b3614854e..6e304d526 100644
--- a/src/bun.js/config.zig
+++ b/src/bun.js/config.zig
@@ -42,6 +42,6 @@ pub fn configureTransformOptionsForBunVM(allocator: std.mem.Allocator, _args: Ap
pub fn configureTransformOptionsForBun(_: std.mem.Allocator, _args: Api.TransformOptions) !Api.TransformOptions {
var args = _args;
- args.platform = Api.Platform.bun;
+ args.target = Api.Target.bun;
return args;
}
diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig
index a0fd52546..06f833e3b 100644
--- a/src/bun.js/javascript.zig
+++ b/src/bun.js/javascript.zig
@@ -648,7 +648,7 @@ pub const VirtualMachine = struct {
this.macro_event_loop.concurrent_tasks = .{};
}
- this.bundler.options.platform = .bun_macro;
+ this.bundler.options.target = .bun_macro;
this.bundler.resolver.caches.fs.use_alternate_source_cache = true;
this.macro_mode = true;
this.event_loop = &this.macro_event_loop;
@@ -656,7 +656,7 @@ pub const VirtualMachine = struct {
}
pub fn disableMacroMode(this: *VirtualMachine) void {
- this.bundler.options.platform = .bun;
+ this.bundler.options.target = .bun;
this.bundler.resolver.caches.fs.use_alternate_source_cache = false;
this.macro_mode = false;
this.event_loop = &this.regular_event_loop;
diff --git a/src/bundler.zig b/src/bundler.zig
index 9030aaf8c..b6f9eac26 100644
--- a/src/bundler.zig
+++ b/src/bundler.zig
@@ -549,7 +549,7 @@ pub const Bundler = struct {
return;
}
- if (this.options.platform == .bun_macro) {
+ if (this.options.target == .bun_macro) {
this.options.env.behavior = .prefix;
this.options.env.prefix = "BUN_";
}
@@ -565,7 +565,7 @@ pub const Bundler = struct {
defer js_ast.Stmt.Data.Store.reset();
if (this.options.framework) |framework| {
- if (this.options.platform.isClient()) {
+ if (this.options.target.isClient()) {
try this.options.loadDefines(this.allocator, this.env, &framework.client.env);
} else {
try this.options.loadDefines(this.allocator, this.env, &framework.server.env);
@@ -607,7 +607,7 @@ pub const Bundler = struct {
}
if (this.options.areDefinesUnset()) {
- if (this.options.platform.isClient()) {
+ if (this.options.target.isClient()) {
this.options.env = framework.client.env;
} else {
this.options.env = framework.server.env;
@@ -872,7 +872,7 @@ pub const Bundler = struct {
return BuildResolveResultPair{ .written = 0, .input_fd = result.input_fd, .empty = true };
}
- if (bundler.options.platform.isBun()) {
+ if (bundler.options.target.isBun()) {
try bundler.linker.link(file_path, &result, origin, import_path_format, false, true);
return BuildResolveResultPair{
.written = switch (result.ast.exports_kind) {
@@ -989,7 +989,7 @@ pub const Bundler = struct {
) orelse {
return null;
};
- if (!bundler.options.platform.isBun())
+ if (!bundler.options.target.isBun())
try bundler.linker.link(
file_path,
&result,
@@ -1008,8 +1008,8 @@ pub const Bundler = struct {
true,
);
- output_file.size = switch (bundler.options.platform) {
- .neutral, .browser, .node => try bundler.print(
+ output_file.size = switch (bundler.options.target) {
+ .browser, .node => try bundler.print(
result,
js_printer.FileWriter,
js_printer.NewFileWriter(file),
@@ -1150,7 +1150,7 @@ pub const Bundler = struct {
.require_ref = ast.require_ref,
.css_import_behavior = bundler.options.cssImportBehavior(),
.source_map_handler = source_map_context,
- .rewrite_require_resolve = bundler.options.platform != .node,
+ .rewrite_require_resolve = bundler.options.target != .node,
.minify_whitespace = bundler.options.minify_whitespace,
.minify_syntax = bundler.options.minify_syntax,
.minify_identifiers = bundler.options.minify_identifiers,
@@ -1172,7 +1172,7 @@ pub const Bundler = struct {
.require_ref = ast.require_ref,
.source_map_handler = source_map_context,
.css_import_behavior = bundler.options.cssImportBehavior(),
- .rewrite_require_resolve = bundler.options.platform != .node,
+ .rewrite_require_resolve = bundler.options.target != .node,
.minify_whitespace = bundler.options.minify_whitespace,
.minify_syntax = bundler.options.minify_syntax,
.minify_identifiers = bundler.options.minify_identifiers,
@@ -1180,7 +1180,7 @@ pub const Bundler = struct {
},
enable_source_map,
),
- .esm_ascii => switch (bundler.options.platform.isBun()) {
+ .esm_ascii => switch (bundler.options.target.isBun()) {
inline else => |is_bun| try js_printer.printAst(
Writer,
writer,
@@ -1376,18 +1376,18 @@ pub const Bundler = struct {
};
}
- const platform = bundler.options.platform;
+ const target = bundler.options.target;
var jsx = this_parse.jsx;
jsx.parse = loader.isJSX();
var opts = js_parser.Parser.Options.init(jsx, loader);
opts.enable_legacy_bundling = false;
- opts.legacy_transform_require_to_import = bundler.options.allow_runtime and !bundler.options.platform.isBun();
+ opts.legacy_transform_require_to_import = bundler.options.allow_runtime and !bundler.options.target.isBun();
opts.features.allow_runtime = bundler.options.allow_runtime;
opts.features.trim_unused_imports = bundler.options.trim_unused_imports orelse loader.isTypeScript();
- opts.features.should_fold_typescript_constant_expressions = loader.isTypeScript() or platform.isBun() or bundler.options.inlining;
- opts.features.dynamic_require = platform.isBun();
+ opts.features.should_fold_typescript_constant_expressions = loader.isTypeScript() or target.isBun() or bundler.options.inlining;
+ opts.features.dynamic_require = target.isBun();
opts.transform_only = bundler.options.transform_only;
// @bun annotation
@@ -1403,7 +1403,7 @@ pub const Bundler = struct {
// or you're running in SSR
// or the file is a node_module
opts.features.hot_module_reloading = bundler.options.hot_module_reloading and
- platform.isNotBun() and
+ target.isNotBun() and
(!opts.can_import_from_bundle or
(opts.can_import_from_bundle and !path.isNodeModule()));
opts.features.react_fast_refresh = opts.features.hot_module_reloading and
@@ -1411,8 +1411,8 @@ pub const Bundler = struct {
bundler.options.jsx.supports_fast_refresh;
opts.filepath_hash_for_hmr = file_hash orelse 0;
opts.features.auto_import_jsx = bundler.options.auto_import_jsx;
- opts.warn_about_unbundled_modules = platform.isNotBun();
- opts.features.jsx_optimization_inline = opts.features.allow_runtime and (bundler.options.jsx_optimization_inline orelse (platform.isBun() and jsx.parse and
+ opts.warn_about_unbundled_modules = target.isNotBun();
+ opts.features.jsx_optimization_inline = opts.features.allow_runtime and (bundler.options.jsx_optimization_inline orelse (target.isBun() and jsx.parse and
!jsx.development)) and
(jsx.runtime == .automatic or jsx.runtime == .classic);
@@ -1432,12 +1432,12 @@ pub const Bundler = struct {
opts.macro_context = &bundler.macro_context.?;
if (comptime !JSC.is_bindgen) {
- if (platform != .bun_macro) {
+ if (target != .bun_macro) {
opts.macro_context.javascript_object = this_parse.macro_js_ctx;
}
}
- opts.features.is_macro_runtime = platform == .bun_macro;
+ opts.features.is_macro_runtime = target == .bun_macro;
opts.features.replace_exports = this_parse.replace_exports;
return switch ((bundler.resolver.caches.js.parse(
@@ -1530,7 +1530,7 @@ pub const Bundler = struct {
};
},
.wasm => {
- if (bundler.options.platform.isBun()) {
+ if (bundler.options.target.isBun()) {
if (!source.isWebAssembly()) {
bundler.log.addErrorFmt(
null,
diff --git a/src/bundler/bundle_v2.zig b/src/bundler/bundle_v2.zig
index 788404bd3..168ef3137 100644
--- a/src/bundler/bundle_v2.zig
+++ b/src/bundler/bundle_v2.zig
@@ -411,7 +411,7 @@ pub const BundleV2 = struct {
pub fn runResolver(
this: *BundleV2,
import_record: bun.JSC.API.JSBundler.Resolve.MiniImportRecord,
- platform: options.Platform,
+ target: options.Target,
) void {
var resolve_result = this.bundler.resolver.resolve(
Fs.PathName.init(import_record.source_file).dirWithTrailingSlash(),
@@ -441,7 +441,7 @@ pub const BundleV2 = struct {
if (!handles_import_errors) {
if (isPackagePath(import_record.specifier)) {
- if (platform.isWebLike() and options.ExternalModules.isNodeBuiltin(path_to_use)) {
+ if (target.isWebLike() and options.ExternalModules.isNodeBuiltin(path_to_use)) {
addError(
this.bundler.log,
source,
@@ -548,7 +548,7 @@ pub const BundleV2 = struct {
task.jsx = this.bundler.options.jsx;
task.task.node.next = null;
task.tree_shaking = this.linker.options.tree_shaking;
- task.known_platform = import_record.original_platform;
+ task.known_target = import_record.original_target;
_ = @atomicRmw(usize, &this.graph.parse_pending, .Add, 1, .Monotonic);
@@ -630,8 +630,8 @@ pub const BundleV2 = struct {
heap: ?ThreadlocalArena,
) !*BundleV2 {
var generator = try allocator.create(BundleV2);
- bundler.options.mark_builtins_as_external = bundler.options.platform.isBun() or bundler.options.platform == .node;
- bundler.resolver.opts.mark_builtins_as_external = bundler.options.platform.isBun() or bundler.options.platform == .node;
+ bundler.options.mark_builtins_as_external = bundler.options.target.isBun() or bundler.options.target == .node;
+ bundler.resolver.opts.mark_builtins_as_external = bundler.options.target.isBun() or bundler.options.target == .node;
var this = generator;
generator.* = BundleV2{
@@ -814,8 +814,8 @@ pub const BundleV2 = struct {
const key = unique_key_for_additional_files[index];
if (key.len > 0) {
var template = PathTemplate.asset;
- if (this.bundler.options.asset_names.len > 0)
- template.data = this.bundler.options.asset_names;
+ if (this.bundler.options.asset_naming.len > 0)
+ template.data = this.bundler.options.asset_naming;
const source = &sources[index];
var pathname = source.path.name;
// TODO: outbase
@@ -1116,7 +1116,7 @@ pub const BundleV2 = struct {
//
// The file could be on disk.
if (strings.eqlComptime(resolve.import_record.namespace, "file")) {
- this.runResolver(resolve.import_record, resolve.import_record.original_platform);
+ this.runResolver(resolve.import_record, resolve.import_record.original_target);
return;
}
@@ -1190,7 +1190,7 @@ pub const BundleV2 = struct {
.module_type = .unknown,
.loader = loader,
.tree_shaking = this.linker.options.tree_shaking,
- .known_platform = resolve.import_record.original_platform,
+ .known_target = resolve.import_record.original_target,
};
task.task.node.next = null;
@@ -1299,7 +1299,7 @@ pub const BundleV2 = struct {
Api.TransformOptions{
.define = if (config.define.count() > 0) config.define.toAPI() else null,
.entry_points = config.entry_points.keys(),
- .platform = config.target.toAPI(),
+ .target = config.target.toAPI(),
.absolute_working_dir = if (config.dir.list.items.len > 0) config.dir.toOwnedSliceLeaky() else null,
.inject = &.{},
.external = config.external.keys(),
@@ -1311,9 +1311,9 @@ pub const BundleV2 = struct {
);
bundler.options.jsx = config.jsx;
- bundler.options.entry_names = config.names.entry_point.data;
- bundler.options.chunk_names = config.names.chunk.data;
- bundler.options.asset_names = config.names.asset.data;
+ bundler.options.entry_naming = config.names.entry_point.data;
+ bundler.options.chunk_naming = config.names.chunk.data;
+ bundler.options.asset_naming = config.names.asset.data;
bundler.options.public_path = config.public_path.list.items;
@@ -1437,7 +1437,7 @@ pub const BundleV2 = struct {
import_record: *const ImportRecord,
source_file: []const u8,
import_record_index: u32,
- original_platform: ?options.Platform,
+ original_target: ?options.Target,
) bool {
if (this.plugins) |plugins| {
if (plugins.hasAnyMatches(&import_record.path, false)) {
@@ -1456,7 +1456,7 @@ pub const BundleV2 = struct {
.source_file = source_file,
.import_record_index = import_record_index,
.importer_source_index = source_index,
- .original_platform = original_platform orelse this.bundler.options.platform,
+ .original_target = original_target orelse this.bundler.options.target,
},
},
this.completion.?,
@@ -1707,7 +1707,7 @@ pub const ParseTask = struct {
source_index: Index = Index.invalid,
task: ThreadPoolLib.Task = .{ .callback = &callback },
tree_shaking: bool = false,
- known_platform: ?options.Platform = null,
+ known_target: ?options.Target = null,
module_type: options.ModuleType = .unknown,
ctx: *BundleV2,
@@ -1997,7 +1997,7 @@ pub const ParseTask = struct {
};
const source_dir = file_path.sourceDir();
- const platform = use_directive.platform(task.known_platform orelse bundler.options.platform);
+ const target = use_directive.target(task.known_target orelse bundler.options.target);
var resolve_queue = ResolveQueue.init(bun.default_allocator);
// TODO: server ESM condition
@@ -2008,12 +2008,12 @@ pub const ParseTask = struct {
opts.legacy_transform_require_to_import = false;
opts.can_import_from_bundle = false;
opts.features.allow_runtime = !source.index.isRuntime();
- opts.features.dynamic_require = platform.isBun();
+ opts.features.dynamic_require = target.isBun();
opts.warn_about_unbundled_modules = false;
opts.macro_context = &this.data.macro_context;
opts.bundle = true;
opts.features.top_level_await = true;
- opts.features.jsx_optimization_inline = platform.isBun() and (bundler.options.jsx_optimization_inline orelse !task.jsx.development);
+ opts.features.jsx_optimization_inline = target.isBun() and (bundler.options.jsx_optimization_inline orelse !task.jsx.development);
opts.features.auto_import_jsx = task.jsx.parse and bundler.options.auto_import_jsx;
opts.features.trim_unused_imports = loader.isTypeScript() or (bundler.options.trim_unused_imports orelse false);
opts.features.inlining = bundler.options.minify_syntax;
@@ -2034,7 +2034,7 @@ pub const ParseTask = struct {
else
try getEmptyAST(log, bundler, opts, allocator, source);
- ast.platform = platform;
+ ast.target = target;
if (ast.parts.len <= 1) {
task.side_effects = _resolver.SideEffects.no_side_effects__empty_ast;
}
@@ -2066,7 +2066,7 @@ pub const ParseTask = struct {
continue;
}
- if (platform.isBun()) {
+ if (target.isBun()) {
if (JSC.HardcodedModule.Aliases.get(import_record.path.text)) |replacement| {
import_record.path.text = replacement.path;
import_record.tag = replacement.tag;
@@ -2110,7 +2110,7 @@ pub const ParseTask = struct {
}
}
- if (this.ctx.enqueueOnResolvePluginIfNeeded(source.index.get(), import_record, source.path.text, @truncate(u32, i), platform)) {
+ if (this.ctx.enqueueOnResolvePluginIfNeeded(source.index.get(), import_record, source.path.text, @truncate(u32, i), target)) {
continue;
}
@@ -2128,7 +2128,7 @@ pub const ParseTask = struct {
if (!import_record.handles_import_errors) {
last_error = err;
if (isPackagePath(import_record.path.text)) {
- if (platform.isWebLike() and options.ExternalModules.isNodeBuiltin(import_record.path.text)) {
+ if (target.isWebLike() and options.ExternalModules.isNodeBuiltin(import_record.path.text)) {
try addError(
log,
&source,
@@ -2220,9 +2220,9 @@ pub const ParseTask = struct {
resolve_task.secondary_path_for_commonjs_interop = secondary_path_to_copy;
if (use_directive != .none) {
- resolve_task.known_platform = platform;
- } else if (task.known_platform) |known_platform| {
- resolve_task.known_platform = known_platform;
+ resolve_task.known_target = target;
+ } else if (task.known_target) |known_target| {
+ resolve_task.known_target = known_target;
}
resolve_task.jsx.development = task.jsx.development;
@@ -2244,7 +2244,7 @@ pub const ParseTask = struct {
std.debug.assert(use_directive == .none or bundler.options.react_server_components);
step.* = .resolve;
- ast.platform = platform;
+ ast.target = target;
return Result.Success{
.ast = ast,
@@ -3389,16 +3389,16 @@ const LinkerContext = struct {
if (chunk.entry_point.is_entry_point) {
chunk.template = PathTemplate.file;
- if (this.resolver.opts.entry_names.len > 0)
- chunk.template.data = this.resolver.opts.entry_names;
+ if (this.resolver.opts.entry_naming.len > 0)
+ chunk.template.data = this.resolver.opts.entry_naming;
const pathname = Fs.PathName.init(this.graph.entry_points.items(.output_path)[chunk.entry_point.entry_point_id].slice());
chunk.template.placeholder.name = pathname.base;
chunk.template.placeholder.ext = "js";
chunk.template.placeholder.dir = pathname.dir;
} else {
chunk.template = PathTemplate.chunk;
- if (this.resolver.opts.chunk_names.len > 0)
- chunk.template.data = this.resolver.opts.chunk_names;
+ if (this.resolver.opts.chunk_naming.len > 0)
+ chunk.template.data = this.resolver.opts.chunk_naming;
}
}
@@ -5872,7 +5872,7 @@ const LinkerContext = struct {
cross_chunk_prefix = js_printer.print(
allocator,
- c.resolver.opts.platform,
+ c.resolver.opts.target,
print_options,
cross_chunk_import_records.slice(),
&[_]js_ast.Part{
@@ -5882,7 +5882,7 @@ const LinkerContext = struct {
).result.code;
cross_chunk_suffix = js_printer.print(
allocator,
- c.resolver.opts.platform,
+ c.resolver.opts.target,
print_options,
&.{},
&[_]js_ast.Part{
@@ -5935,7 +5935,7 @@ const LinkerContext = struct {
}
}
- if (chunk.entry_point.is_entry_point and ctx.c.graph.ast.items(.platform)[chunk.entry_point.source_index].isBun()) {
+ if (chunk.entry_point.is_entry_point and ctx.c.graph.ast.items(.target)[chunk.entry_point.source_index].isBun()) {
j.push("// @bun\n");
}
@@ -6488,7 +6488,7 @@ const LinkerContext = struct {
.javascript = .{
.result = js_printer.print(
allocator,
- c.resolver.opts.platform,
+ c.resolver.opts.target,
print_options,
ast.import_records.slice(),
&[_]js_ast.Part{
@@ -7758,7 +7758,7 @@ const LinkerContext = struct {
return js_printer.printWithWriter(
*js_printer.BufferPrinter,
&printer,
- ast.platform,
+ ast.target,
print_options,
ast.import_records.slice(),
parts_to_print,
diff --git a/src/cli.zig b/src/cli.zig
index 86dce4dca..53b421282 100644
--- a/src/cli.zig
+++ b/src/cli.zig
@@ -82,11 +82,11 @@ const LoaderMatcher = strings.ExactSizeMatcher(4);
const ColonListType = @import("./cli/colon_list_type.zig").ColonListType;
pub const LoaderColonList = ColonListType(Api.Loader, Arguments.loader_resolver);
pub const DefineColonList = ColonListType(string, Arguments.noop_resolver);
-fn invalidPlatform(diag: *clap.Diagnostic, _platform: []const u8) noreturn {
+fn invalidTarget(diag: *clap.Diagnostic, _target: []const u8) noreturn {
@setCold(true);
- diag.name.long = "--platform";
- diag.arg = _platform;
- diag.report(Output.errorWriter(), error.InvalidPlatform) catch {};
+ diag.name.long = "--target";
+ diag.arg = _target;
+ diag.report(Output.errorWriter(), error.InvalidTarget) catch {};
std.process.exit(1);
}
pub const Arguments = struct {
@@ -144,24 +144,23 @@ pub const Arguments = struct {
pub const ParamType = clap.Param(clap.Help);
const shared_public_params = [_]ParamType{
+ clap.parseParam("-h, --help Display this help and exit.") catch unreachable,
clap.parseParam("-b, --bun Force a script or package to use Bun.js instead of Node.js (via symlinking node)") catch unreachable,
clap.parseParam("--cwd <STR> Absolute path to resolve files & entry points from. This just changes the process' cwd.") catch unreachable,
- clap.parseParam("-c, --config <PATH>? Config file to load bun from (e.g. -c bunfig.toml") catch unreachable,
- clap.parseParam("--extension-order <STR>... defaults to: .tsx,.ts,.jsx,.js,.json ") catch unreachable,
+ clap.parseParam("-c, --config <PATH>? Config file to load bun from (e.g. -c bunfig.toml") catch unreachable,
+ clap.parseParam("--extension-order <STR>... Defaults to: .tsx,.ts,.jsx,.js,.json ") catch unreachable,
clap.parseParam("--jsx-factory <STR> Changes the function called when compiling JSX elements using the classic JSX runtime") catch unreachable,
clap.parseParam("--jsx-fragment <STR> Changes the function called when compiling JSX fragments") catch unreachable,
clap.parseParam("--jsx-import-source <STR> Declares the module specifier to be used for importing the jsx and jsxs factory functions. Default: \"react\"") catch unreachable,
clap.parseParam("--jsx-production Use jsx instead of jsxDEV (default) for the automatic runtime") catch unreachable,
clap.parseParam("--jsx-runtime <STR> \"automatic\" (default) or \"classic\"") catch unreachable,
clap.parseParam("-r, --preload <STR>... Import a module before other modules are loaded") catch unreachable,
- clap.parseParam("--main-fields <STR>... Main fields to lookup in package.json. Defaults to --platform dependent") catch unreachable,
- clap.parseParam("--no-summary Don't print a summary (when generating .bun") catch unreachable,
- clap.parseParam("-v, --version Print version and exit") catch unreachable,
- clap.parseParam("--platform <STR> \"bun\" or \"browser\" or \"node\", used when building or bundling") catch unreachable,
+ clap.parseParam("--main-fields <STR>... Main fields to lookup in package.json. Defaults to --target dependent") catch unreachable,
+ clap.parseParam("--no-summary Don't print a summary (when generating .bun)") catch unreachable,
+ clap.parseParam("-v, --version Print version and exit") catch unreachable,
clap.parseParam("--tsconfig-override <STR> Load tsconfig from path instead of cwd/tsconfig.json") catch unreachable,
clap.parseParam("-d, --define <STR>... Substitute K:V while parsing, e.g. --define process.env.NODE_ENV:\"development\". Values are parsed as JSON.") catch unreachable,
clap.parseParam("-e, --external <STR>... Exclude module from transpilation (can use * wildcards). ex: -e react") catch unreachable,
- clap.parseParam("-h, --help Display this help and exit. ") catch unreachable,
clap.parseParam("-l, --loader <STR>... Parse files with .ext:loader, e.g. --loader .js:jsx. Valid loaders: js, jsx, ts, tsx, json, toml, text, file, wasm, napi") catch unreachable,
clap.parseParam("-u, --origin <STR> Rewrite import URLs to start with --origin. Default: \"\"") catch unreachable,
clap.parseParam("-p, --port <STR> Port to serve bun's dev server on. Default: \"3000\"") catch unreachable,
@@ -169,6 +168,7 @@ pub const Arguments = struct {
clap.parseParam("--minify-syntax Minify syntax and inline data (experimental)") catch unreachable,
clap.parseParam("--minify-whitespace Minify whitespace (experimental)") catch unreachable,
clap.parseParam("--minify-identifiers Minify identifiers") catch unreachable,
+ clap.parseParam("--target <STR> The intended execution environment for the bundle. \"browser\", \"bun\" or \"node\"") catch unreachable,
clap.parseParam("<POS>... ") catch unreachable,
};
@@ -205,13 +205,17 @@ pub const Arguments = struct {
pub const params = public_params ++ debug_params;
const build_only_params = [_]ParamType{
- clap.parseParam("--sourcemap <STR>? Build with sourcemaps - 'inline', 'external', or 'none'") catch unreachable,
clap.parseParam("--outdir <STR> Default to \"dist\" if multiple files") catch unreachable,
- clap.parseParam("--entry-names <STR> Pattern to use for entry point filenames") catch unreachable,
clap.parseParam("--outfile <STR> Write to a file") catch unreachable,
- clap.parseParam("--server-components Enable React Server Components (experimental)") catch unreachable,
- clap.parseParam("--splitting Split up code!") catch unreachable,
- clap.parseParam("--transform Do not bundle") catch unreachable,
+ clap.parseParam("--splitting Enable code splitting") catch unreachable,
+ // clap.parseParam("--manifest <STR> Write JSON manifest") catch unreachable,
+ // clap.parseParam("--public-path <STR> A prefix to be appended to any import paths in bundled code") catch unreachable,
+ clap.parseParam("--sourcemap <STR>? Build with sourcemaps - 'inline', 'external', or 'none'") catch unreachable,
+ clap.parseParam("--entry-naming <STR> Customize entry point filenames. Defaults to \"[dir]/[name].[ext]\"") catch unreachable,
+ clap.parseParam("--chunk-naming <STR> Customize chunk filenames. Defaults to \"[name]-[hash].[ext]\"") catch unreachable,
+ clap.parseParam("--asset-naming <STR> Customize asset filenames. Defaults to \"[name]-[hash].[ext]\"") catch unreachable,
+ clap.parseParam("--server-components Enable React Server Components (experimental)") catch unreachable,
+ clap.parseParam("--transform Single file transform, do not bundle") catch unreachable,
};
// TODO: update test completions
@@ -500,8 +504,16 @@ pub const Arguments = struct {
ctx.bundler_options.code_splitting = true;
}
- if (args.option("--entry-names")) |entry_names| {
- ctx.bundler_options.entry_names = entry_names;
+ if (args.option("--entry-naming")) |entry_naming| {
+ ctx.bundler_options.entry_naming = try strings.concat(allocator, &.{ "./", entry_naming });
+ }
+
+ if (args.option("--chunk-naming")) |chunk_naming| {
+ ctx.bundler_options.chunk_naming = try strings.concat(allocator, &.{ "./", chunk_naming });
+ }
+
+ if (args.option("--asset-naming")) |asset_naming| {
+ ctx.bundler_options.asset_naming = try strings.concat(allocator, &.{ "./", asset_naming });
}
if (comptime FeatureFlags.react_server_components) {
@@ -668,18 +680,18 @@ pub const Arguments = struct {
else => {},
}
- const PlatformMatcher = strings.ExactSizeMatcher(8);
+ const TargetMatcher = strings.ExactSizeMatcher(8);
- if (args.option("--platform")) |_platform| {
- opts.platform = opts.platform orelse switch (PlatformMatcher.match(_platform)) {
- PlatformMatcher.case("browser") => Api.Platform.browser,
- PlatformMatcher.case("node") => Api.Platform.node,
- PlatformMatcher.case("macro") => if (cmd == .BuildCommand) Api.Platform.bun_macro else Api.Platform.bun,
- PlatformMatcher.case("bun") => Api.Platform.bun,
- else => invalidPlatform(&diag, _platform),
+ if (args.option("--target")) |_target| {
+ opts.target = opts.target orelse switch (TargetMatcher.match(_target)) {
+ TargetMatcher.case("browser") => Api.Target.browser,
+ TargetMatcher.case("node") => Api.Target.node,
+ TargetMatcher.case("macro") => if (cmd == .BuildCommand) Api.Target.bun_macro else Api.Target.bun,
+ TargetMatcher.case("bun") => Api.Target.bun,
+ else => invalidTarget(&diag, _target),
};
- ctx.debug.run_in_bun = opts.platform.? == .bun;
+ ctx.debug.run_in_bun = opts.target.? == .bun;
}
ctx.debug.run_in_bun = args.flag("--bun") or ctx.debug.run_in_bun;
@@ -922,7 +934,9 @@ pub const Command = struct {
pub const BundlerOptions = struct {
outdir: []const u8 = "",
outfile: []const u8 = "",
- entry_names: []const u8 = "./[name].[ext]",
+ entry_naming: []const u8 = "./[name].[ext]",
+ chunk_naming: []const u8 = "./[name]-[hash].[ext]",
+ asset_naming: []const u8 = "./[name]-[hash].[ext]",
react_server_components: bool = false,
code_splitting: bool = false,
transform_only: bool = false,
diff --git a/src/cli/build_command.zig b/src/cli/build_command.zig
index 196d43f23..0518c7b5a 100644
--- a/src/cli/build_command.zig
+++ b/src/cli/build_command.zig
@@ -44,8 +44,12 @@ pub const BuildCommand = struct {
estimated_input_lines_of_code_ = 0;
var this_bundler = try bundler.Bundler.init(allocator, log, ctx.args, null, null);
- this_bundler.options.entry_names = ctx.bundler_options.entry_names;
- this_bundler.resolver.opts.entry_names = ctx.bundler_options.entry_names;
+ this_bundler.options.entry_naming = ctx.bundler_options.entry_naming;
+ this_bundler.options.chunk_naming = ctx.bundler_options.chunk_naming;
+ this_bundler.options.asset_naming = ctx.bundler_options.asset_naming;
+ this_bundler.resolver.opts.entry_naming = ctx.bundler_options.entry_naming;
+ this_bundler.resolver.opts.chunk_naming = ctx.bundler_options.chunk_naming;
+ this_bundler.resolver.opts.asset_naming = ctx.bundler_options.asset_naming;
this_bundler.options.output_dir = ctx.bundler_options.outdir;
this_bundler.resolver.opts.output_dir = ctx.bundler_options.outdir;
this_bundler.options.react_server_components = ctx.bundler_options.react_server_components;
diff --git a/src/js_ast.zig b/src/js_ast.zig
index d2cb467d1..410539761 100644
--- a/src/js_ast.zig
+++ b/src/js_ast.zig
@@ -5730,7 +5730,7 @@ pub const Ast = struct {
redirect_import_record_index: ?u32 = null,
/// Only populated when bundling
- platform: bun.options.Platform = .browser,
+ target: bun.options.Target = .browser,
const_values: ConstValuesMap = .{},
@@ -9698,7 +9698,7 @@ pub const UseDirective = enum {
return .none;
}
- pub fn platform(this: UseDirective, default: bun.options.Platform) bun.options.Platform {
+ pub fn target(this: UseDirective, default: bun.options.Target) bun.options.Target {
return switch (this) {
.none => default,
.@"use client" => .browser,
@@ -9921,4 +9921,3 @@ pub const GlobalStoreHandle = struct {
// Stmt | 192
// STry | 384
// -- ESBuild bit sizes
-
diff --git a/src/js_printer.zig b/src/js_printer.zig
index 2dc1b7b74..8832ffb9d 100644
--- a/src/js_printer.zig
+++ b/src/js_printer.zig
@@ -5762,7 +5762,7 @@ pub fn printJSON(
pub fn print(
allocator: std.mem.Allocator,
- platform: options.Platform,
+ target: options.Target,
opts: Options,
import_records: []const ImportRecord,
parts: []const js_ast.Part,
@@ -5774,7 +5774,7 @@ pub fn print(
return printWithWriter(
*BufferPrinter,
&buffer_printer,
- platform,
+ target,
opts,
import_records,
parts,
@@ -5785,17 +5785,17 @@ pub fn print(
pub fn printWithWriter(
comptime Writer: type,
_writer: Writer,
- platform: options.Platform,
+ target: options.Target,
opts: Options,
import_records: []const ImportRecord,
parts: []const js_ast.Part,
renamer: bun.renamer.Renamer,
) PrintResult {
- return switch (platform.isBun()) {
- inline else => |is_bun_platform| printWithWriterAndPlatform(
+ return switch (target.isBun()) {
+ inline else => |is_bun| printWithWriterAndPlatform(
Writer,
_writer,
- is_bun_platform,
+ is_bun,
opts,
import_records,
parts,
@@ -5808,7 +5808,7 @@ pub fn printWithWriter(
pub fn printWithWriterAndPlatform(
comptime Writer: type,
_writer: Writer,
- comptime is_bun_platform: bool,
+ comptime is_bun: bool,
opts: Options,
import_records: []const ImportRecord,
parts: []const js_ast.Part,
@@ -5818,7 +5818,7 @@ pub fn printWithWriterAndPlatform(
false,
Writer,
false,
- is_bun_platform,
+ is_bun,
false,
false,
);
diff --git a/src/linker.zig b/src/linker.zig
index 27a1db2b6..6c5e0e50b 100644
--- a/src/linker.zig
+++ b/src/linker.zig
@@ -172,7 +172,7 @@ pub const Linker = struct {
}
pub inline fn nodeModuleBundleImportPath(this: *const ThisLinker, origin: URL) string {
- if (this.options.platform.isBun()) return "/node_modules.server.bun";
+ if (this.options.target.isBun()) return "/node_modules.server.bun";
return std.fmt.allocPrint(this.allocator, "{s}://{}{s}", .{ origin.displayProtocol(), origin.displayHost(), this.options.node_modules_bundle.?.bundle.import_from_name }) catch unreachable;
}
@@ -334,7 +334,7 @@ pub const Linker = struct {
import_record.range.loc,
if (is_bun)
JSC.JSGlobalObject.BunPluginTarget.bun
- else if (linker.options.platform == .browser)
+ else if (linker.options.target == .browser)
JSC.JSGlobalObject.BunPluginTarget.browser
else
JSC.JSGlobalObject.BunPluginTarget.node,
@@ -731,12 +731,12 @@ pub const Linker = struct {
had_resolve_errors = true;
if (import_record.path.text.len > 0 and Resolver.isPackagePath(import_record.path.text)) {
- if (linker.options.platform.isWebLike() and Options.ExternalModules.isNodeBuiltin(import_record.path.text)) {
+ if (linker.options.target.isWebLike() and Options.ExternalModules.isNodeBuiltin(import_record.path.text)) {
try linker.log.addResolveError(
&result.source,
import_record.range,
linker.allocator,
- "Could not resolve: \"{s}\". Try setting --platform=\"node\" (after bun build exists)",
+ "Could not resolve: \"{s}\". Try setting --target=\"node\"",
.{import_record.path.text},
import_record.kind,
err,
@@ -998,7 +998,7 @@ pub const Linker = struct {
import_record.path = try linker.generateImportPath(
source_dir,
- if (path.is_symlink and import_path_format == .absolute_url and linker.options.platform.isNotBun()) path.pretty else path.text,
+ if (path.is_symlink and import_path_format == .absolute_url and linker.options.target.isNotBun()) path.pretty else path.text,
loader == .file or loader == .wasm,
path.namespace,
origin,
@@ -1026,7 +1026,7 @@ pub const Linker = struct {
// it's more complicated
// loader plugins could be executed between when this is called and the import is evaluated
// but we want to preserve the semantics of "file" returning import paths for compatibiltiy with frontend frameworkss
- if (!linker.options.platform.isBun()) {
+ if (!linker.options.target.isBun()) {
import_record.print_mode = .import_path;
}
},
diff --git a/src/options.zig b/src/options.zig
index 0ad92a5e1..3cb5c333c 100644
--- a/src/options.zig
+++ b/src/options.zig
@@ -112,7 +112,7 @@ pub const ExternalModules = struct {
cwd: string,
externals: []const string,
log: *logger.Log,
- platform: Platform,
+ target: Target,
) ExternalModules {
var result = ExternalModules{
.node_modules = std.BufSet.init(allocator),
@@ -120,7 +120,7 @@ pub const ExternalModules = struct {
.patterns = default_wildcard_patterns[0..],
};
- switch (platform) {
+ switch (target) {
.node => {
// TODO: fix this stupid copy
result.node_modules.hash_map.ensureTotalCapacity(NodeBuiltinPatterns.len) catch unreachable;
@@ -377,42 +377,37 @@ pub const ModuleType = enum {
});
};
-pub const Platform = enum {
- neutral,
+pub const Target = enum {
browser,
bun,
bun_macro,
node,
pub const Map = ComptimeStringMap(
- Platform,
+ Target,
.{
.{
- "neutral",
- Platform.neutral,
- },
- .{
"browser",
- Platform.browser,
+ Target.browser,
},
.{
"bun",
- Platform.bun,
+ Target.bun,
},
.{
"bun_macro",
- Platform.bun_macro,
+ Target.bun_macro,
},
.{
"node",
- Platform.node,
+ Target.node,
},
},
);
- pub fn fromJS(global: *JSC.JSGlobalObject, value: JSC.JSValue, exception: JSC.C.ExceptionRef) ?Platform {
+ pub fn fromJS(global: *JSC.JSGlobalObject, value: JSC.JSValue, exception: JSC.C.ExceptionRef) ?Target {
if (!value.jsType().isStringLike()) {
- JSC.throwInvalidArguments("platform must be a string", .{}, global, exception);
+ JSC.throwInvalidArguments("target must be a string", .{}, global, exception);
return null;
}
@@ -424,60 +419,58 @@ pub const Platform = enum {
const Eight = strings.ExactSizeMatcher(8);
return switch (Eight.match(slice)) {
- Eight.case("deno"), Eight.case("browser") => Platform.browser,
- Eight.case("bun") => Platform.bun,
- Eight.case("macro") => Platform.bun_macro,
- Eight.case("node") => Platform.node,
- Eight.case("neutral") => Platform.neutral,
+ Eight.case("deno"), Eight.case("browser") => Target.browser,
+ Eight.case("bun") => Target.bun,
+ Eight.case("macro") => Target.bun_macro,
+ Eight.case("node") => Target.node,
else => {
- JSC.throwInvalidArguments("platform must be one of: deno, browser, bun, macro, node, neutral", .{}, global, exception);
+ JSC.throwInvalidArguments("target must be one of: deno, browser, bun, macro, node", .{}, global, exception);
return null;
},
};
}
- pub fn toAPI(this: Platform) Api.Platform {
+ pub fn toAPI(this: Target) Api.Target {
return switch (this) {
.node => .node,
.browser => .browser,
.bun => .bun,
.bun_macro => .bun_macro,
- else => ._none,
};
}
- pub inline fn isServerSide(this: Platform) bool {
+ pub inline fn isServerSide(this: Target) bool {
return switch (this) {
.bun_macro, .node, .bun => true,
else => false,
};
}
- pub inline fn isBun(this: Platform) bool {
+ pub inline fn isBun(this: Target) bool {
return switch (this) {
.bun_macro, .bun => true,
else => false,
};
}
- pub inline fn isNotBun(this: Platform) bool {
+ pub inline fn isNotBun(this: Target) bool {
return switch (this) {
.bun_macro, .bun => false,
else => true,
};
}
- pub inline fn isClient(this: Platform) bool {
+ pub inline fn isClient(this: Target) bool {
return switch (this) {
.bun_macro, .bun => false,
else => true,
};
}
- pub inline fn supportsBrowserField(this: Platform) bool {
+ pub inline fn supportsBrowserField(this: Target) bool {
return switch (this) {
- .neutral, .browser => true,
+ .browser => true,
else => false,
};
}
@@ -485,17 +478,16 @@ pub const Platform = enum {
const browser_define_value_true = "true";
const browser_define_value_false = "false";
- pub inline fn processBrowserDefineValue(this: Platform) ?string {
+ pub inline fn processBrowserDefineValue(this: Target) ?string {
return switch (this) {
.browser => browser_define_value_true,
.bun_macro, .bun, .node => browser_define_value_false,
- else => null,
};
}
- pub inline fn isWebLike(platform: Platform) bool {
- return switch (platform) {
- .neutral, .browser => true,
+ pub inline fn isWebLike(target: Target) bool {
+ return switch (target) {
+ .browser => true,
else => false,
};
}
@@ -512,13 +504,13 @@ pub const Platform = enum {
};
};
- pub fn outExtensions(platform: Platform, allocator: std.mem.Allocator) bun.StringHashMap(string) {
+ pub fn outExtensions(target: Target, allocator: std.mem.Allocator) bun.StringHashMap(string) {
var exts = bun.StringHashMap(string).init(allocator);
const js = Extensions.Out.JavaScript[0];
const mjs = Extensions.Out.JavaScript[1];
- if (platform == .node) {
+ if (target == .node) {
exts.ensureTotalCapacity(Extensions.In.JavaScript.len * 2) catch unreachable;
for (Extensions.In.JavaScript) |ext| {
exts.put(ext, mjs) catch unreachable;
@@ -535,8 +527,8 @@ pub const Platform = enum {
return exts;
}
- pub fn from(plat: ?api.Api.Platform) Platform {
- return switch (plat orelse api.Api.Platform._none) {
+ pub fn from(plat: ?api.Api.Target) Target {
+ return switch (plat orelse api.Api.Target._none) {
.node => .node,
.browser => .browser,
.bun => .bun,
@@ -555,8 +547,8 @@ pub const Platform = enum {
// Older packages might use jsnext:main in place of module
"jsnext:main",
};
- pub const DefaultMainFields: std.EnumArray(Platform, []const string) = brk: {
- var array = std.EnumArray(Platform, []const string).initUndefined();
+ pub const DefaultMainFields: std.EnumArray(Target, []const string) = brk: {
+ var array = std.EnumArray(Target, []const string).initUndefined();
// Note that this means if a package specifies "module" and "main", the ES6
// module will not be selected. This means tree shaking will not work when
@@ -572,7 +564,7 @@ pub const Platform = enum {
// This is unfortunate but it's a problem on the side of those packages.
// They won't work correctly with other popular bundlers (with node as a target) anyway.
var list = [_]string{ MAIN_FIELD_NAMES[2], MAIN_FIELD_NAMES[1] };
- array.set(Platform.node, &list);
+ array.set(Target.node, &list);
// Note that this means if a package specifies "main", "module", and
// "browser" then "browser" will win out over "module". This is the
@@ -584,24 +576,23 @@ pub const Platform = enum {
var listc = [_]string{ MAIN_FIELD_NAMES[0], MAIN_FIELD_NAMES[1], MAIN_FIELD_NAMES[3], MAIN_FIELD_NAMES[2] };
var listd = [_]string{ MAIN_FIELD_NAMES[1], MAIN_FIELD_NAMES[2], MAIN_FIELD_NAMES[3] };
- array.set(Platform.browser, &listc);
- array.set(Platform.bun, &listd);
- array.set(Platform.bun_macro, &listd);
+ array.set(Target.browser, &listc);
+ array.set(Target.bun, &listd);
+ array.set(Target.bun_macro, &listd);
// Original comment:
- // The neutral platform is for people that don't want esbuild to try to
+ // The neutral target is for people that don't want esbuild to try to
// pick good defaults for their platform. In that case, the list of main
// fields is empty by default. You must explicitly configure it yourself.
-
- array.set(Platform.neutral, &listc);
+ // array.set(Target.neutral, &listc);
break :brk array;
};
- pub const DefaultConditions: std.EnumArray(Platform, []const string) = brk: {
- var array = std.EnumArray(Platform, []const string).initUndefined();
+ pub const DefaultConditions: std.EnumArray(Target, []const string) = brk: {
+ var array = std.EnumArray(Target, []const string).initUndefined();
- array.set(Platform.node, &[_]string{
+ array.set(Target.node, &[_]string{
"node",
"module",
});
@@ -610,9 +601,9 @@ pub const Platform = enum {
"browser",
"module",
};
- array.set(Platform.browser, &listc);
+ array.set(Target.browser, &listc);
array.set(
- Platform.bun,
+ Target.bun,
&[_]string{
"bun",
"worker",
@@ -623,7 +614,7 @@ pub const Platform = enum {
},
);
array.set(
- Platform.bun_macro,
+ Target.bun_macro,
&[_]string{
"bun",
"worker",
@@ -633,14 +624,13 @@ pub const Platform = enum {
"browser",
},
);
- // array.set(Platform.bun_macro, [_]string{ "bun_macro", "browser", "default", },);
+ // array.set(Target.bun_macro, [_]string{ "bun_macro", "browser", "default", },);
// Original comment:
- // The neutral platform is for people that don't want esbuild to try to
+ // The neutral target is for people that don't want esbuild to try to
// pick good defaults for their platform. In that case, the list of main
// fields is empty by default. You must explicitly configure it yourself.
-
- array.set(Platform.neutral, &listc);
+ // array.set(Target.neutral, &listc);
break :brk array;
};
@@ -965,7 +955,7 @@ pub const JSX = struct {
&pragma.import_source.development,
&[_]string{
pragma.package_name,
- "jsx-dev-runtime",
+ "/jsx-dev-runtime",
},
&.{
Defaults.ImportSourceDev,
@@ -977,7 +967,7 @@ pub const JSX = struct {
&pragma.import_source.production,
&[_]string{
pragma.package_name,
- "jsx-runtime",
+ "/jsx-runtime",
},
&.{
Defaults.ImportSource,
@@ -1093,8 +1083,7 @@ pub const DefaultUserDefines = struct {
pub const Key = "process.env.NODE_ENV";
pub const Value = "\"development\"";
};
-
- pub const PlatformDefine = struct {
+ pub const ProcessBrowserDefine = struct {
pub const Key = "process.browser";
pub const Value = []string{ "false", "true" };
};
@@ -1105,7 +1094,7 @@ pub fn definesFromTransformOptions(
log: *logger.Log,
_input_define: ?Api.StringMap,
hmr: bool,
- platform: Platform,
+ target: Target,
loader: ?*DotEnv.Loader,
framework_env: ?*const Env,
NODE_ENV: ?string,
@@ -1148,36 +1137,38 @@ pub fn definesFromTransformOptions(
}
}
- if (NODE_ENV) |node_env| {
- if (node_env.len > 0) {
- var quoted_node_env: string = "";
- if ((strings.startsWithChar(node_env, '"') and strings.endsWithChar(node_env, '"')) or
- (strings.startsWithChar(node_env, '\'') and strings.endsWithChar(node_env, '\'')))
- {
- quoted_node_env = node_env;
- } else {
+ var quoted_node_env: string = brk: {
+ if (NODE_ENV) |node_env| {
+ if (node_env.len > 0) {
+ if ((strings.startsWithChar(node_env, '"') and strings.endsWithChar(node_env, '"')) or
+ (strings.startsWithChar(node_env, '\'') and strings.endsWithChar(node_env, '\'')))
+ {
+ break :brk node_env;
+ }
+
// avoid allocating if we can
if (strings.eqlComptime(node_env, "production")) {
- quoted_node_env = "\"production\"";
+ break :brk "\"production\"";
} else if (strings.eqlComptime(node_env, "development")) {
- quoted_node_env = "\"development\"";
+ break :brk "\"development\"";
} else if (strings.eqlComptime(node_env, "test")) {
- quoted_node_env = "\"test\"";
+ break :brk "\"test\"";
} else {
- quoted_node_env = try std.fmt.allocPrint(allocator, "\"{s}\"", .{node_env});
+ break :brk try std.fmt.allocPrint(allocator, "\"{s}\"", .{node_env});
}
}
-
- _ = try user_defines.getOrPutValue(
- "process.env.NODE_ENV",
- quoted_node_env,
- );
- _ = try user_defines.getOrPutValue(
- "process.env.BUN_ENV",
- quoted_node_env,
- );
}
- }
+ break :brk "\"development\"";
+ };
+
+ _ = try user_defines.getOrPutValue(
+ "process.env.NODE_ENV",
+ quoted_node_env,
+ );
+ _ = try user_defines.getOrPutValue(
+ "process.env.BUN_ENV",
+ quoted_node_env,
+ );
if (hmr) {
try user_defines.put(DefaultUserDefines.HotModuleReloading.Key, DefaultUserDefines.HotModuleReloading.Value);
@@ -1185,11 +1176,11 @@ pub fn definesFromTransformOptions(
// Automatically set `process.browser` to `true` for browsers and false for node+js
// This enables some extra dead code elimination
- if (platform.processBrowserDefineValue()) |value| {
- _ = try user_defines.getOrPutValue(DefaultUserDefines.PlatformDefine.Key, value);
+ if (target.processBrowserDefineValue()) |value| {
+ _ = try user_defines.getOrPutValue(DefaultUserDefines.ProcessBrowserDefine.Key, value);
}
- if (platform.isBun()) {
+ if (target.isBun()) {
if (!user_defines.contains("window")) {
_ = try environment_defines.getOrPutValue("window", .{
.valueless = true,
@@ -1222,11 +1213,11 @@ const default_loader_ext = [_]string{
".txt", ".text",
};
-pub fn loadersFromTransformOptions(allocator: std.mem.Allocator, _loaders: ?Api.LoaderMap, platform: Platform) !bun.StringArrayHashMap(Loader) {
+pub fn loadersFromTransformOptions(allocator: std.mem.Allocator, _loaders: ?Api.LoaderMap, target: Target) !bun.StringArrayHashMap(Loader) {
var input_loaders = _loaders orelse std.mem.zeroes(Api.LoaderMap);
var loader_values = try allocator.alloc(Loader, input_loaders.loaders.len);
- if (platform.isBun()) {
+ if (target.isBun()) {
for (loader_values, 0..) |_, i| {
const loader = switch (input_loaders.loaders[i]) {
.jsx => Loader.jsx,
@@ -1274,7 +1265,7 @@ pub fn loadersFromTransformOptions(allocator: std.mem.Allocator, _loaders: ?Api.
_ = try loaders.getOrPutValue(ext, defaultLoaders.get(ext).?);
}
- if (platform.isBun()) {
+ if (target.isBun()) {
inline for (default_loader_ext_bun) |ext| {
_ = try loaders.getOrPutValue(ext, defaultLoaders.get(ext).?);
}
@@ -1379,14 +1370,14 @@ pub const BundleOptions = struct {
resolve_mode: api.Api.ResolveMode,
tsconfig_override: ?string = null,
- platform: Platform = Platform.browser,
- main_fields: []const string = Platform.DefaultMainFields.get(Platform.browser),
+ target: Target = Target.browser,
+ main_fields: []const string = Target.DefaultMainFields.get(Target.browser),
log: *logger.Log,
external: ExternalModules = ExternalModules{},
entry_points: []const string,
- entry_names: []const u8 = "",
- asset_names: []const u8 = "",
- chunk_names: []const u8 = "",
+ entry_naming: []const u8 = "",
+ asset_naming: []const u8 = "",
+ chunk_naming: []const u8 = "",
public_path: []const u8 = "",
extension_order: []const string = &Defaults.ExtensionOrder,
esm_extension_order: []const string = &Defaults.ModuleExtensionOrder,
@@ -1446,8 +1437,8 @@ pub const BundleOptions = struct {
};
pub inline fn cssImportBehavior(this: *const BundleOptions) Api.CssInJsBehavior {
- switch (this.platform) {
- .neutral, .browser => {
+ switch (this.target) {
+ .browser => {
if (this.framework) |framework| {
return framework.client_css_in_js;
}
@@ -1471,7 +1462,7 @@ pub const BundleOptions = struct {
this.log,
this.transform_options.define,
this.transform_options.serve orelse false,
- this.platform,
+ this.target,
loader_,
env,
if (loader_) |e|
@@ -1540,9 +1531,9 @@ pub const BundleOptions = struct {
.log = log,
.resolve_mode = transform.resolve orelse .dev,
.define = undefined,
- .loaders = try loadersFromTransformOptions(allocator, transform.loaders, Platform.from(transform.platform)),
+ .loaders = try loadersFromTransformOptions(allocator, transform.loaders, Target.from(transform.target)),
.output_dir = transform.output_dir orelse "out",
- .platform = Platform.from(transform.platform),
+ .target = Target.from(transform.target),
.write = transform.write orelse false,
.external = undefined,
.entry_points = transform.entry_points,
@@ -1566,12 +1557,12 @@ pub const BundleOptions = struct {
opts.extension_order = transform.extension_order;
}
- if (transform.platform) |plat| {
- opts.platform = Platform.from(plat);
- opts.main_fields = Platform.DefaultMainFields.get(opts.platform);
+ if (transform.target) |t| {
+ opts.target = Target.from(t);
+ opts.main_fields = Target.DefaultMainFields.get(opts.target);
}
- opts.conditions = try ESMConditions.init(allocator, Platform.DefaultConditions.get(opts.platform));
+ opts.conditions = try ESMConditions.init(allocator, Target.DefaultConditions.get(opts.target));
if (transform.serve orelse false) {
// When we're serving, we need some kind of URL.
@@ -1596,7 +1587,7 @@ pub const BundleOptions = struct {
}
}
- switch (opts.platform) {
+ switch (opts.target) {
.node => {
opts.import_path_format = .relative;
opts.allow_runtime = false;
@@ -1695,8 +1686,8 @@ pub const BundleOptions = struct {
if (opts.framework == null and is_generating_bundle)
opts.env.behavior = .load_all;
- opts.external = ExternalModules.init(allocator, &fs.fs, fs.top_level_dir, transform.external, log, opts.platform);
- opts.out_extensions = opts.platform.outExtensions(allocator);
+ opts.external = ExternalModules.init(allocator, &fs.fs, fs.top_level_dir, transform.external, log, opts.target);
+ opts.out_extensions = opts.target.outExtensions(allocator);
if (transform.serve orelse false) {
opts.preserve_extensions = true;
@@ -1839,7 +1830,7 @@ pub const BundleOptions = struct {
if (Environment.isWindows and opts.routes.static_dir_handle != null) {
opts.routes.static_dir_handle.?.close();
}
- opts.hot_module_reloading = opts.platform.isWebLike();
+ opts.hot_module_reloading = opts.target.isWebLike();
if (transform.disable_hmr orelse false)
opts.hot_module_reloading = false;
@@ -1849,7 +1840,7 @@ pub const BundleOptions = struct {
opts.sourcemap = SourceMapOption.fromApi(transform.source_map orelse Api.SourceMapMode._none);
}
- opts.tree_shaking = opts.serve or opts.platform.isBun() or opts.production or is_generating_bundle;
+ opts.tree_shaking = opts.serve or opts.target.isBun() or opts.production or is_generating_bundle;
opts.inlining = opts.tree_shaking;
if (opts.inlining)
opts.minify_syntax = true;
@@ -1863,7 +1854,7 @@ pub const BundleOptions = struct {
opts.output_dir = try fs.getFdPath(opts.output_dir_handle.?.fd);
}
- opts.polyfill_node_globals = opts.platform != .node;
+ opts.polyfill_node_globals = opts.target != .node;
Analytics.Features.framework = Analytics.Features.framework or opts.framework != null;
Analytics.Features.filesystem_router = Analytics.Features.filesystem_router or opts.routes.routes_enabled;
@@ -1871,7 +1862,7 @@ pub const BundleOptions = struct {
Analytics.Features.public_folder = Analytics.Features.public_folder or opts.routes.static_dir_enabled;
Analytics.Features.bun_bun = Analytics.Features.bun_bun or transform.node_modules_bundle_path != null;
Analytics.Features.bunjs = Analytics.Features.bunjs or transform.node_modules_bundle_path_server != null;
- Analytics.Features.macros = Analytics.Features.macros or opts.platform == .bun_macro;
+ Analytics.Features.macros = Analytics.Features.macros or opts.target == .bun_macro;
Analytics.Features.external = Analytics.Features.external or transform.external.len > 0;
Analytics.Features.single_page_app_routing = Analytics.Features.single_page_app_routing or opts.routes.single_page_app_routing;
return opts;
@@ -1908,8 +1899,8 @@ pub const TransformOptions = struct {
resolve_paths: bool = false,
tsconfig_override: ?string = null,
- platform: Platform = Platform.browser,
- main_fields: []string = Platform.DefaultMainFields.get(Platform.browser),
+ target: Target = Target.browser,
+ main_fields: []string = Target.DefaultMainFields.get(Target.browser),
pub fn initUncached(allocator: std.mem.Allocator, entryPointName: string, code: string) !TransformOptions {
assert(entryPointName.len > 0);
@@ -1940,7 +1931,7 @@ pub const TransformOptions = struct {
.define = define,
.loader = loader,
.resolve_dir = entryPoint.path.name.dir,
- .main_fields = Platform.DefaultMainFields.get(Platform.browser),
+ .main_fields = Target.DefaultMainFields.get(Target.browser),
.jsx = if (Loader.isJSX(loader)) JSX.Pragma{} else null,
};
}
@@ -1958,7 +1949,7 @@ pub const OutputFile = struct {
mtime: ?i128 = null,
// Depending on:
- // - The platform
+ // - The target
// - The number of open file handles
// - Whether or not a file of the same name exists
// We may use a different system call
@@ -2389,9 +2380,9 @@ pub const Framework = struct {
pub const fallback_html: string = @embedFile("./fallback.html");
- pub fn platformEntryPoint(this: *const Framework, platform: Platform) ?*const EntryPoint {
- const entry: *const EntryPoint = switch (platform) {
- .neutral, .browser => &this.client,
+ pub fn platformEntryPoint(this: *const Framework, target: Target) ?*const EntryPoint {
+ const entry: *const EntryPoint = switch (target) {
+ .browser => &this.client,
.bun => &this.server,
.node => return null,
};
diff --git a/src/resolver/package_json.zig b/src/resolver/package_json.zig
index 75b7a9e00..63bc5b20b 100644
--- a/src/resolver/package_json.zig
+++ b/src/resolver/package_json.zig
@@ -708,7 +708,7 @@ pub const PackageJSON = struct {
}
// Read the "browser" property, but only when targeting the browser
- if (r.opts.platform.supportsBrowserField()) {
+ if (r.opts.target.supportsBrowserField()) {
// We both want the ability to have the option of CJS vs. ESM and the
// option of having node vs. browser. The way to do this is to use the
// object literal form of the "browser" field like this:
diff --git a/src/resolver/resolver.zig b/src/resolver/resolver.zig
index 61717ada9..48c6b2889 100644
--- a/src/resolver/resolver.zig
+++ b/src/resolver/resolver.zig
@@ -570,7 +570,7 @@ pub const Resolver = struct {
.node_module_bundle = opts.node_modules_bundle,
.log = log,
.extension_order = opts.extension_order,
- .care_about_browser_field = opts.platform.isWebLike(),
+ .care_about_browser_field = opts.target.isWebLike(),
};
}
@@ -3170,7 +3170,7 @@ pub const Resolver = struct {
const main_field_values = pkg_json.main_fields;
const main_field_keys = r.opts.main_fields;
// TODO: check this works right. Not sure this will really work.
- const auto_main = r.opts.main_fields.ptr == options.Platform.DefaultMainFields.get(r.opts.platform).ptr;
+ const auto_main = r.opts.main_fields.ptr == options.Target.DefaultMainFields.get(r.opts.target).ptr;
if (r.debug_logs) |*debug| {
debug.addNoteFmt("Searching for main fields in \"{s}\"", .{pkg_json.source.path.text});
diff --git a/src/router.zig b/src/router.zig
index 5b4c56722..eab4b5351 100644
--- a/src/router.zig
+++ b/src/router.zig
@@ -963,7 +963,7 @@ pub const Test = struct {
var opts = Options.BundleOptions{
.resolve_mode = .lazy,
- .platform = .browser,
+ .target = .browser,
.loaders = undefined,
.define = undefined,
.log = &logger,
@@ -1020,7 +1020,7 @@ pub const Test = struct {
var opts = Options.BundleOptions{
.resolve_mode = .lazy,
- .platform = .browser,
+ .target = .browser,
.loaders = undefined,
.define = undefined,
.log = &logger,
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("");
+ });
});