diff options
author | 2023-05-09 00:55:21 -0400 | |
---|---|---|
committer | 2023-05-08 21:55:21 -0700 | |
commit | 5e366872f659abf116b903e5cece999a04cd018b (patch) | |
tree | d06b5ccd28ea49a7a5e050868ff27e676e0d56f7 /src | |
parent | 1a411e201b71374f515d1f6cdbb1b36186ee48b0 (diff) | |
download | bun-5e366872f659abf116b903e5cece999a04cd018b.tar.gz bun-5e366872f659abf116b903e5cece999a04cd018b.tar.zst bun-5e366872f659abf116b903e5cece999a04cd018b.zip |
implement build api `define` and `loaders` (#2805)
* parse error logs
* clean up types
* remove --jsx-production. use NODE_ENV instead
* add define to js api
* add loaders to js api
* fixups
* sourcemap
* typo fix
* remove label, comment dir just for now
* test tweaks
* test work
* make optional enums actually optional.
allows `sourcemap: undefined`
* overload host ram test
* string tests
* tests
* test for 2815
* requested changes
* sort this list
* remove this test file now that it passes
* oops
* add --format
* finish ts tests
* doc typos related to define and loader
Diffstat (limited to 'src')
-rw-r--r-- | src/bun.js/api/JSBundler.zig | 113 | ||||
-rw-r--r-- | src/bun.js/api/JSTranspiler.zig | 2 | ||||
-rw-r--r-- | src/bun.js/bindings/bindings.zig | 3 | ||||
-rw-r--r-- | src/bun.js/builtins/js/BundlerPlugin.js | 4 | ||||
-rw-r--r-- | src/bundler/bundle_v2.zig | 1 | ||||
-rw-r--r-- | src/cli.zig | 25 | ||||
-rw-r--r-- | src/options.zig | 48 |
7 files changed, 173 insertions, 23 deletions
diff --git a/src/bun.js/api/JSBundler.zig b/src/bun.js/api/JSBundler.zig index cccbca9db..55c224726 100644 --- a/src/bun.js/api/JSBundler.zig +++ b/src/bun.js/api/JSBundler.zig @@ -51,6 +51,7 @@ pub const JSBundler = struct { entry_points: bun.StringSet = bun.StringSet.init(bun.default_allocator), hot: bool = false, define: bun.StringMap = bun.StringMap.init(bun.default_allocator, true), + loaders: ?Api.LoaderMap = null, dir: OwnedString = OwnedString.initEmpty(bun.default_allocator), outdir: OwnedString = OwnedString.initEmpty(bun.default_allocator), serve: Serve = .{}, @@ -60,7 +61,6 @@ pub const JSBundler = struct { server_components: ServerComponents = ServerComponents{}, names: Names = .{}, - label: OwnedString = OwnedString.initEmpty(bun.default_allocator), external: bun.StringSet = bun.StringSet.init(bun.default_allocator), source_map: options.SourceMapOption = .none, public_path: OwnedString = OwnedString.initEmpty(bun.default_allocator), @@ -73,7 +73,6 @@ pub const JSBundler = struct { .external = bun.StringSet.init(allocator), .define = bun.StringMap.init(allocator, true), .dir = OwnedString.initEmpty(allocator), - .label = OwnedString.initEmpty(allocator), .outdir = OwnedString.initEmpty(allocator), .names = .{ .owned_entry_point = OwnedString.initEmpty(allocator), @@ -88,6 +87,20 @@ pub const JSBundler = struct { this.target = target; } + if (try config.getOptionalEnum(globalThis, "sourcemap", options.SourceMapOption)) |source_map| { + this.source_map = source_map; + } + + if (try config.getOptionalEnum(globalThis, "format", options.Format)) |format| { + switch (format) { + .esm => {}, + else => { + globalThis.throwInvalidArguments("Formats besides 'esm' are not implemented", .{}); + return error.JSException; + }, + } + } + // if (try config.getOptional(globalThis, "hot", bool)) |hot| { // this.hot = hot; // } @@ -150,17 +163,12 @@ pub const JSBundler = struct { } } - if (try config.getOptional(globalThis, "label", ZigString.Slice)) |slice| { - defer slice.deinit(); - this.label.appendSliceExact(slice.slice()) catch unreachable; - } - - if (try config.getOptional(globalThis, "dir", ZigString.Slice)) |slice| { - defer slice.deinit(); - this.dir.appendSliceExact(slice.slice()) catch unreachable; - } else { - this.dir.appendSliceExact(globalThis.bunVM().bundler.fs.top_level_dir) catch unreachable; - } + // if (try config.getOptional(globalThis, "dir", ZigString.Slice)) |slice| { + // defer slice.deinit(); + // this.dir.appendSliceExact(slice.slice()) catch unreachable; + // } else { + // this.dir.appendSliceExact(globalThis.bunVM().bundler.fs.top_level_dir) catch unreachable; + // } if (try config.getOptional(globalThis, "publicPath", ZigString.Slice)) |slice| { defer slice.deinit(); @@ -198,6 +206,84 @@ pub const JSBundler = struct { } } + if (try config.getObject(globalThis, "define")) |define| { + if (!define.isObject()) { + globalThis.throwInvalidArguments("define must be an object", .{}); + return error.JSException; + } + + var define_iter = JSC.JSPropertyIterator(.{ + .skip_empty_name = true, + .include_value = true, + }).init(globalThis, define.asObjectRef()); + defer define_iter.deinit(); + + while (define_iter.next()) |prop| { + const property_value = define_iter.value; + const value_type = property_value.jsType(); + + if (!value_type.isStringLike()) { + globalThis.throwInvalidArguments("define \"{s}\" must be a JSON string", .{prop}); + return error.JSException; + } + + var val = JSC.ZigString.init(""); + property_value.toZigString(&val, globalThis); + if (val.len == 0) { + val = JSC.ZigString.init("\"\""); + } + + try this.define.insert(prop.slice(), val.slice()); + } + } + + if (try config.getObject(globalThis, "loader")) |loaders| { + if (!loaders.isUndefinedOrNull()) { + if (!loaders.isObject()) { + globalThis.throwInvalidArguments("loader must be an object", .{}); + return error.JSException; + } + + var loader_iter = JSC.JSPropertyIterator(.{ + .skip_empty_name = true, + .include_value = true, + }).init(globalThis, loaders.asObjectRef()); + defer loader_iter.deinit(); + + var loader_names = try allocator.alloc(string, loader_iter.len); + var loader_values = try allocator.alloc(Api.Loader, loader_iter.len); + + while (loader_iter.next()) |prop| { + if (prop.len == 0 or prop.ptr[0] != '.') { + globalThis.throwInvalidArguments("loader property names must be file extensions, such as '.txt'", .{}); + return error.JSException; + } + + loader_names[loader_iter.i] = prop.slice(); + var property_value = loader_iter.value; + var value_type = property_value.jsType(); + if (!value_type.isStringLike()) { + globalThis.throwInvalidArguments("loader \"{s}\" must be a string", .{prop}); + return error.JSException; + } + + var val = JSC.ZigString.init(""); + property_value.toZigString(&val, globalThis); + if (options.Loader.fromString(val.slice())) |loader| { + loader_values[loader_iter.i] = loader.toAPI(); + } else { + globalThis.throwInvalidArguments("loader \"{s}\" is not a valid loader", .{val}); + return error.JSException; + } + } + + this.loaders = Api.LoaderMap{ + .extensions = loader_names, + .loaders = loader_values, + }; + } + } + if (try config.getArray(globalThis, "plugins")) |array| { var iter = array.arrayIterator(globalThis); while (iter.next()) |plugin| { @@ -355,7 +441,6 @@ pub const JSBundler = struct { self.serve.deinit(allocator); self.server_components.deinit(allocator); self.names.deinit(); - self.label.deinit(); self.outdir.deinit(); self.public_path.deinit(); } diff --git a/src/bun.js/api/JSTranspiler.zig b/src/bun.js/api/JSTranspiler.zig index f1b00f191..2ac6948d1 100644 --- a/src/bun.js/api/JSTranspiler.zig +++ b/src/bun.js/api/JSTranspiler.zig @@ -565,7 +565,7 @@ fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std } } else { var sourcemap = flag.toSlice(globalThis, allocator); - if (options.SourceMapOption.map.get(sourcemap.slice())) |source| { + if (options.SourceMapOption.Map.get(sourcemap.slice())) |source| { transpiler.transform.source_map = source.toAPI(); } else { JSC.throwInvalidArguments("sourcemap must be one of \"inline\", \"external\", or \"none\"", .{}, globalObject, exception); diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig index 12cc81118..71409da4f 100644 --- a/src/bun.js/bindings/bindings.zig +++ b/src/bun.js/bindings/bindings.zig @@ -4009,9 +4009,10 @@ pub const JSValue = enum(JSValueReprInt) { pub fn getOptionalEnum(this: JSValue, globalThis: *JSGlobalObject, comptime property_name: []const u8, comptime Enum: type) !?Enum { if (get(this, globalThis, property_name)) |prop| { + if (prop.isEmptyOrUndefinedOrNull()) + return null; return try toEnum(prop, globalThis, property_name, Enum); } - return null; } diff --git a/src/bun.js/builtins/js/BundlerPlugin.js b/src/bun.js/builtins/js/BundlerPlugin.js index 64c655bbe..ec8fee397 100644 --- a/src/bun.js/builtins/js/BundlerPlugin.js +++ b/src/bun.js/builtins/js/BundlerPlugin.js @@ -66,7 +66,9 @@ function runOnResolvePlugins( path: inputPath, importer, namespace: inputNamespace, + // resolveDir kind, + // pluginData }); while ( @@ -368,6 +370,8 @@ function runOnLoadPlugins(internalID, path, namespace, defaultLoaderId) { var result = callback({ path, namespace, + // suffix + // pluginData loader: defaultLoader, }); diff --git a/src/bundler/bundle_v2.zig b/src/bundler/bundle_v2.zig index aad40b961..6bb307381 100644 --- a/src/bundler/bundle_v2.zig +++ b/src/bundler/bundle_v2.zig @@ -1555,6 +1555,7 @@ pub const BundleV2 = struct { ); bundler.options.jsx = config.jsx; + bundler.options.loaders = try options.loadersFromTransformOptions(allocator, config.loaders, config.target); 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; diff --git a/src/cli.zig b/src/cli.zig index 3f796e798..171593246 100644 --- a/src/cli.zig +++ b/src/cli.zig @@ -141,7 +141,6 @@ pub const Arguments = struct { 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 --target dependent") catch unreachable, @@ -194,6 +193,7 @@ pub const Arguments = struct { pub const params = public_params ++ debug_params; const build_only_params = [_]ParamType{ + clap.parseParam("--format <STR> Specifies the module format to build to. Only esm is supported.") catch unreachable, clap.parseParam("--outdir <STR> Default to \"dist\" if multiple files") catch unreachable, clap.parseParam("--outfile <STR> Write to a file") catch unreachable, clap.parseParam("--splitting Enable code splitting") catch unreachable, @@ -489,6 +489,20 @@ pub const Arguments = struct { } } + if (args.option("--format")) |format_str| { + const format = options.Format.fromString(format_str) orelse { + Output.prettyErrorln("<r><red>error<r>: Invalid format - must be esm, cjs, or iife", .{}); + Global.crash(); + }; + switch (format) { + .esm => {}, + else => { + Output.prettyErrorln("<r><red>error<r>: Formats besides 'esm' are not implemented", .{}); + Global.crash(); + }, + } + } + if (args.flag("--splitting")) { ctx.bundler_options.code_splitting = true; } @@ -569,9 +583,8 @@ pub const Arguments = struct { var jsx_fragment = args.option("--jsx-fragment"); var jsx_import_source = args.option("--jsx-import-source"); var jsx_runtime = args.option("--jsx-runtime"); - var jsx_production = args.flag("--jsx-production"); const react_fast_refresh = switch (comptime cmd) { - .DevCommand => !(args.flag("--disable-react-fast-refresh") or jsx_production), + .DevCommand => !args.flag("--disable-react-fast-refresh"), else => true, }; @@ -689,7 +702,7 @@ pub const Arguments = struct { jsx_fragment != null or jsx_import_source != null or jsx_runtime != null or - jsx_production or !react_fast_refresh) + !react_fast_refresh) { var default_factory = "".*; var default_fragment = "".*; @@ -700,7 +713,7 @@ pub const Arguments = struct { .fragment = constStrToU8(jsx_fragment orelse &default_fragment), .import_source = constStrToU8(jsx_import_source orelse &default_import_source), .runtime = if (jsx_runtime != null) try resolve_jsx_runtime(jsx_runtime.?) else Api.JsxRuntime.automatic, - .development = !jsx_production, + .development = false, .react_fast_refresh = react_fast_refresh, }; } else { @@ -709,7 +722,7 @@ pub const Arguments = struct { .fragment = constStrToU8(jsx_fragment orelse opts.jsx.?.fragment), .import_source = constStrToU8(jsx_import_source orelse opts.jsx.?.import_source), .runtime = if (jsx_runtime != null) try resolve_jsx_runtime(jsx_runtime.?) else opts.jsx.?.runtime, - .development = !jsx_production, + .development = false, .react_fast_refresh = react_fast_refresh, }; } diff --git a/src/options.zig b/src/options.zig index 958b36874..fee9035c4 100644 --- a/src/options.zig +++ b/src/options.zig @@ -636,6 +636,52 @@ pub const Target = enum { }; }; +pub const Format = enum { + esm, + cjs, + iife, + + pub const Map = ComptimeStringMap( + Format, + .{ + .{ + "esm", + Format.esm, + }, + .{ + "cjs", + Format.cjs, + }, + .{ + "iife", + Format.iife, + }, + }, + ); + + pub fn fromJS(global: *JSC.JSGlobalObject, format: JSC.JSValue, exception: JSC.C.ExceptionRef) ?Format { + if (format.isUndefinedOrNull()) return null; + + if (!format.jsType().isStringLike()) { + JSC.throwInvalidArguments("Format must be a string", .{}, global, exception); + return null; + } + + var zig_str = JSC.ZigString.init(""); + format.toZigString(&zig_str, global); + if (zig_str.len == 0) return null; + + return fromString(zig_str.slice()) orelse { + JSC.throwInvalidArguments("Invalid format - must be esm, cjs, or iife", .{}, global, exception); + return null; + }; + } + + pub fn fromString(slice: string) ?Format { + return Map.getWithEql(slice, strings.eqlComptime); + } +}; + pub const Loader = enum(u8) { jsx, js, @@ -1271,7 +1317,7 @@ pub const SourceMapOption = enum { }; } - pub const map = ComptimeStringMap(SourceMapOption, .{ + pub const Map = ComptimeStringMap(SourceMapOption, .{ .{ "none", .none }, .{ "inline", .@"inline" }, .{ "external", .external }, |