aboutsummaryrefslogtreecommitdiff
path: root/src/cli
diff options
context:
space:
mode:
Diffstat (limited to 'src/cli')
-rw-r--r--src/cli/build_command.zig314
-rw-r--r--src/cli/bun_command.zig242
2 files changed, 192 insertions, 364 deletions
diff --git a/src/cli/build_command.zig b/src/cli/build_command.zig
index 92d2d5b3a..1b8e5c632 100644
--- a/src/cli/build_command.zig
+++ b/src/cli/build_command.zig
@@ -1,167 +1,237 @@
+const std = @import("std");
+const Command = @import("../cli.zig").Command;
const bun = @import("bun");
const string = bun.string;
const Output = bun.Output;
const Global = bun.Global;
const Environment = bun.Environment;
-const FeatureFlags = bun.FeatureFlags;
const strings = bun.strings;
const MutableString = bun.MutableString;
const stringZ = bun.stringZ;
const default_allocator = bun.default_allocator;
const C = bun.C;
-const std = @import("std");
const lex = bun.js_lexer;
const logger = @import("bun").logger;
const options = @import("../options.zig");
const js_parser = bun.js_parser;
+const json_parser = bun.JSON;
+const js_printer = bun.js_printer;
const js_ast = bun.JSAst;
const linker = @import("../linker.zig");
-const allocators = @import("../allocators.zig");
const sync = @import("../sync.zig");
const Api = @import("../api/schema.zig").Api;
const resolve_path = @import("../resolver/resolve_path.zig");
const configureTransformOptionsForBun = @import("../bun.js/config.zig").configureTransformOptionsForBun;
-const Command = @import("../cli.zig").Command;
const bundler = bun.bundler;
const NodeModuleBundle = @import("../node_module_bundle.zig").NodeModuleBundle;
+const GenerateNodeModuleBundle = @import("../bundler/generate_node_modules_bundle.zig");
+const DotEnv = @import("../env_loader.zig");
+
const fs = @import("../fs.zig");
-const constStrToU8 = bun.constStrToU8;
+const Router = @import("../router.zig");
+const BundleV2 = @import("../bundler/bundle_v2.zig").BundleV2;
+var estimated_input_lines_of_code_: usize = undefined;
pub const BuildCommand = struct {
- pub fn exec(ctx: Command.Context) !void {
- var result: options.TransformResult = undefined;
- switch (ctx.args.resolve orelse Api.ResolveMode.dev) {
- .lazy => {
- result = try bundler.Bundler.bundle(
- ctx.allocator,
- ctx.log,
- ctx.args,
- );
- },
- else => {
- result = try bundler.Bundler.bundle(
- ctx.allocator,
- ctx.log,
- ctx.args,
- );
- },
- }
- var did_write = false;
+ pub fn exec(
+ ctx: Command.Context,
+ ) !void {
+ Global.configureAllocator(.{ .long_running = true });
+ var allocator = ctx.allocator;
+ var log = ctx.log;
+ 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.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;
+ this_bundler.resolver.opts.react_server_components = ctx.bundler_options.react_server_components;
+ this_bundler.options.code_splitting = ctx.bundler_options.code_splitting;
+ this_bundler.resolver.opts.code_splitting = ctx.bundler_options.code_splitting;
+
+ this_bundler.configureLinker();
+
+ // This step is optional
+ // If it fails for any reason, ignore it and continue bundling
+ // This is partially a workaround for the 'error.MissingRoutesDir' error
+ this_bundler.configureRouter(true) catch {
+ this_bundler.options.routes.routes_enabled = false;
+ this_bundler.options.framework = null;
+ if (this_bundler.router) |*router| {
+ router.config.routes_enabled = false;
+ router.config.single_page_app_routing = false;
+ router.config.static_dir_enabled = false;
+ this_bundler.router = null;
+ }
+ this_bundler.options.node_modules_bundle = null;
+ this_bundler.options.node_modules_bundle_pretty_path = "";
+ this_bundler.options.node_modules_bundle_url = "";
+ };
- defer Output.flush();
- var writer = Output.errorWriter();
- var err_writer = writer;
+ if (ctx.debug.macros) |macros| {
+ this_bundler.options.macro_remap = macros;
+ }
- var open_file_limit: usize = fs.FileSystem.RealFS.Limit.handles;
- if (ctx.args.write) |write| {
- if (write) {
- const root_dir = result.root_dir orelse unreachable;
+ // var env_loader = this_bundler.env;
- var all_paths = try ctx.allocator.alloc([]const u8, result.output_files.len);
- var max_path_len: usize = 0;
- for (result.output_files, 0..) |f, i| {
- all_paths[i] = f.input.text;
- }
+ if (ctx.debug.dump_environment_variables) {
+ this_bundler.dumpEnvironmentVariables();
+ return;
+ }
- var from_path = resolve_path.longestCommonPath(all_paths);
+ if (ctx.debug.dump_limits) {
+ fs.FileSystem.printLimits();
+ Global.exit(0);
+ return;
+ }
- for (result.output_files) |f| {
- max_path_len = std.math.max(
- std.math.max(from_path.len, f.input.text.len) + 2 - from_path.len,
- max_path_len,
- );
+ // var generated_server = false;
+ // if (this_bundler.options.framework) |*framework| {
+ // if (framework.toAPI(allocator, this_bundler.fs.top_level_dir) catch null) |_server_conf| {
+ // ServerBundleGeneratorThread.generate(
+ // log,
+ // env_loader,
+ // ctx,
+ // server_bundle_filepath,
+ // _server_conf,
+ // loaded_route_config,
+ // this_bundler.router,
+ // );
+ // generated_server = true;
+
+ // if (log.msgs.items.len > 0) {
+ // try log.printForLogLevel(Output.errorWriter());
+ // log.* = logger.Log.init(allocator);
+ // Output.flush();
+ // }
+ // }
+ // }
+
+ {
+
+ // Always generate the client-only bundle
+ // we can revisit this decision if people ask
+ const output_files = BundleV2.generate(
+ &this_bundler,
+ allocator,
+ &estimated_input_lines_of_code_,
+ ctx.debug.package_bundle_map,
+ bun.JSC.AnyEventLoop.init(ctx.allocator),
+ std.crypto.random.int(u64),
+ ctx.debug.hot_reload == .watch,
+ ) catch |err| {
+ if (log.msgs.items.len > 0) {
+ try log.printForLogLevel(Output.errorWriter());
+ } else {
+ try Output.errorWriter().print("error: {s}", .{@errorName(err)});
}
- did_write = true;
-
- // On posix, file handles automatically close on process exit by the OS
- // Closing files shows up in profiling.
- // So don't do that unless we actually need to.
- // const do_we_need_to_close = !FeatureFlags.store_file_descriptors or (@intCast(usize, root_dir.fd) + open_file_limit) < result.output_files.len;
-
- var filepath_buf: [bun.MAX_PATH_BYTES]u8 = undefined;
- filepath_buf[0] = '.';
- filepath_buf[1] = '/';
-
- for (result.output_files) |f| {
- var rel_path: []const u8 = undefined;
- switch (f.value) {
- // easy mode: write the buffer
- .buffer => |value| {
- rel_path = resolve_path.relative(from_path, f.input.text);
-
- try root_dir.writeFile(rel_path, value);
- },
- .move => |value| {
- // const primary = f.input.text[from_path.len..];
- // bun.copy(u8, filepath_buf[2..], primary);
- // rel_path = filepath_buf[0 .. primary.len + 2];
- rel_path = value.pathname;
-
- // try f.moveTo(result.outbase, constStrToU8(rel_path), root_dir.fd);
- },
- .copy => |value| {
- rel_path = value.pathname;
-
- try f.copyTo(result.outbase, constStrToU8(rel_path), root_dir.fd);
- },
- .noop => {},
- .pending => unreachable,
+ Output.flush();
+ exitOrWatch(1, ctx.debug.hot_reload == .watch);
+ unreachable;
+ };
+
+ {
+ dump: {
+ defer Output.flush();
+ var writer = Output.errorWriter();
+ var output_dir = this_bundler.options.output_dir;
+ if (ctx.bundler_options.outfile.len > 0 and output_files.items.len == 1 and output_files.items[0].value == .buffer) {
+ output_dir = std.fs.path.dirname(ctx.bundler_options.outfile) orelse ".";
+ output_files.items[0].input.text = std.fs.path.basename(ctx.bundler_options.outfile);
}
- // Print summary
- _ = try writer.write("\n");
- const padding_count = 2 + (std.math.max(rel_path.len, max_path_len) - rel_path.len);
- try writer.writeByteNTimes(' ', 2);
- try writer.writeAll(rel_path);
- try writer.writeByteNTimes(' ', padding_count);
- const size = @intToFloat(f64, f.size) / 1000.0;
- try std.fmt.formatFloatDecimal(size, .{ .precision = 2 }, writer);
- try writer.writeAll(" KB\n");
- }
- }
- }
+ if (output_dir.len == 0 and output_files.items.len == 1 and output_files.items[0].value == .buffer) {
+ try writer.writeAll(output_files.items[0].value.buffer);
+ break :dump;
+ }
- if (Environment.isDebug) {
- err_writer.print("\nExpr count: {d}\n", .{js_ast.Expr.icount}) catch {};
- err_writer.print("Stmt count: {d}\n", .{js_ast.Stmt.icount}) catch {};
- err_writer.print("Binding count: {d}\n", .{js_ast.Binding.icount}) catch {};
- err_writer.print("File Descriptors: {d} / {d}\n", .{
- fs.FileSystem.max_fd,
- open_file_limit,
- }) catch {};
- }
+ const root_path = output_dir;
+ const root_dir = try std.fs.cwd().makeOpenPathIterable(root_path, .{});
+ var all_paths = try ctx.allocator.alloc([]const u8, output_files.items.len);
+ var max_path_len: usize = 0;
+ for (all_paths, output_files.items) |*dest, src| {
+ dest.* = src.input.text;
+ }
- if (Output.enable_ansi_colors) {
- for (result.errors) |err| {
- try err.writeFormat(err_writer, true);
- _ = try err_writer.write("\n");
- }
+ var from_path = resolve_path.longestCommonPath(all_paths);
- for (result.warnings) |err| {
- try err.writeFormat(err_writer, true);
- _ = try err_writer.write("\n");
- }
- } else {
- for (result.errors) |err| {
- try err.writeFormat(err_writer, false);
- _ = try err_writer.write("\n");
- }
+ for (output_files.items) |f| {
+ max_path_len = std.math.max(
+ std.math.max(from_path.len, f.input.text.len) + 2 - from_path.len,
+ max_path_len,
+ );
+ }
- for (result.warnings) |err| {
- try err.writeFormat(err_writer, false);
- _ = try err_writer.write("\n");
+ // On posix, file handles automatically close on process exit by the OS
+ // Closing files shows up in profiling.
+ // So don't do that unless we actually need to.
+ // const do_we_need_to_close = !FeatureFlags.store_file_descriptors or (@intCast(usize, root_dir.fd) + open_file_limit) < output_files.items.len;
+
+ var filepath_buf: [bun.MAX_PATH_BYTES]u8 = undefined;
+ filepath_buf[0] = '.';
+ filepath_buf[1] = '/';
+
+ for (output_files.items) |f| {
+ var rel_path: []const u8 = undefined;
+ switch (f.value) {
+ // easy mode: write the buffer
+ .buffer => |value| {
+ rel_path = f.input.text;
+ if (f.input.text.len > from_path.len) {
+ rel_path = resolve_path.relative(from_path, f.input.text);
+ if (std.fs.path.dirname(rel_path)) |parent| {
+ if (parent.len > root_path.len) {
+ try root_dir.dir.makePath(parent);
+ }
+ }
+ }
+ try root_dir.dir.writeFile(rel_path, value);
+ },
+ .move => |value| {
+ // const primary = f.input.text[from_path.len..];
+ // bun.copy(u8, filepath_buf[2..], primary);
+ // rel_path = filepath_buf[0 .. primary.len + 2];
+ rel_path = value.pathname;
+
+ // try f.moveTo(result.outbase, constStrToU8(rel_path), root_dir.fd);
+ },
+ .copy => |value| {
+ rel_path = value.pathname;
+
+ try f.copyTo(root_path, bun.constStrToU8(rel_path), root_dir.dir.fd);
+ },
+ .noop => {},
+ .pending => unreachable,
+ }
+
+ // Print summary
+ _ = try writer.write("\n");
+ const padding_count = 2 + (std.math.max(rel_path.len, max_path_len) - rel_path.len);
+ try writer.writeByteNTimes(' ', 2);
+ try writer.writeAll(rel_path);
+ try writer.writeByteNTimes(' ', padding_count);
+ const size = @intToFloat(f64, f.size) / 1000.0;
+ try std.fmt.formatFloatDecimal(size, .{ .precision = 2 }, writer);
+ try writer.writeAll(" KB\n");
+ }
+ }
}
- }
-
- const duration = std.time.nanoTimestamp() - ctx.start_time;
-
- if (did_write and duration < @as(i128, @as(i128, std.time.ns_per_s) * @as(i128, 2))) {
- var elapsed = @divTrunc(duration, @as(i128, std.time.ns_per_ms));
- try err_writer.print("\nCompleted in {d}ms", .{elapsed});
+ try log.printForLogLevel(Output.errorWriter());
+ exitOrWatch(0, ctx.debug.hot_reload == .watch);
}
}
};
+
+fn exitOrWatch(code: u8, watch: bool) void {
+ if (watch) {
+ // the watcher thread will exit the process
+ std.time.sleep(std.math.maxInt(u64) - 1);
+ }
+ Global.exit(code);
+}
diff --git a/src/cli/bun_command.zig b/src/cli/bun_command.zig
deleted file mode 100644
index 0a8894905..000000000
--- a/src/cli/bun_command.zig
+++ /dev/null
@@ -1,242 +0,0 @@
-const std = @import("std");
-const Command = @import("../cli.zig").Command;
-const bun = @import("bun");
-const string = bun.string;
-const Output = bun.Output;
-const Global = bun.Global;
-const Environment = bun.Environment;
-const strings = bun.strings;
-const MutableString = bun.MutableString;
-const stringZ = bun.stringZ;
-const default_allocator = bun.default_allocator;
-const C = bun.C;
-
-const lex = bun.js_lexer;
-const logger = @import("bun").logger;
-
-const options = @import("../options.zig");
-const js_parser = bun.js_parser;
-const json_parser = bun.JSON;
-const js_printer = bun.js_printer;
-const js_ast = bun.JSAst;
-const linker = @import("../linker.zig");
-
-const sync = @import("../sync.zig");
-const Api = @import("../api/schema.zig").Api;
-const resolve_path = @import("../resolver/resolve_path.zig");
-const configureTransformOptionsForBun = @import("../bun.js/config.zig").configureTransformOptionsForBun;
-const bundler = bun.bundler;
-const NodeModuleBundle = @import("../node_module_bundle.zig").NodeModuleBundle;
-const GenerateNodeModuleBundle = @import("../bundler/generate_node_modules_bundle.zig");
-const DotEnv = @import("../env_loader.zig");
-
-const fs = @import("../fs.zig");
-const Router = @import("../router.zig");
-
-var estimated_input_lines_of_code_: usize = undefined;
-const ServerBundleGeneratorThread = struct {
- inline fn _generate(
- logs: *logger.Log,
- env_loader_: *DotEnv.Loader,
- allocator_: std.mem.Allocator,
- ctx: Command.Context,
- _filepath: [*:0]const u8,
- server_conf: Api.LoadedFramework,
- route_conf_: ?Api.LoadedRouteConfig,
- router: ?Router,
- ) anyerror!void {
- var server_bundler = try bundler.Bundler.init(
- allocator_,
- logs,
- try configureTransformOptionsForBun(allocator_, ctx.args),
- null,
- env_loader_,
- );
- server_bundler.configureLinker();
- server_bundler.options.jsx.supports_fast_refresh = false;
-
- server_bundler.router = router;
- server_bundler.configureDefines() catch |err| {
- Output.prettyErrorln("<r><red>{s}<r> loading --define or .env values for node_modules.server.bun\n", .{@errorName(err)});
- return err;
- };
-
- if (ctx.debug.macros) |macros| {
- server_bundler.options.macro_remap = macros;
- }
-
- var estimated_input_lines_of_code: usize = 0;
- _ = try GenerateNodeModuleBundle.generate(
- &server_bundler,
- allocator_,
- server_conf,
- route_conf_,
- _filepath,
- &estimated_input_lines_of_code,
- ctx.debug.package_bundle_map,
- );
- std.mem.doNotOptimizeAway(&server_bundler);
- }
- pub fn generate(
- logs: *logger.Log,
- env_loader_: *DotEnv.Loader,
- ctx: Command.Context,
- _filepath: [*:0]const u8,
- server_conf: Api.LoadedFramework,
- route_conf_: ?Api.LoadedRouteConfig,
- router: ?Router,
- ) void {
- defer Output.flush();
-
- _generate(logs, env_loader_, default_allocator, ctx, _filepath, server_conf, route_conf_, router) catch return;
- }
-};
-
-pub const BunCommand = struct {
- pub fn exec(
- ctx: Command.Context,
- ) !void {
- Global.configureAllocator(.{ .long_running = true });
- var allocator = ctx.allocator;
- var log = ctx.log;
- estimated_input_lines_of_code_ = 0;
-
- var this_bundler = try bundler.Bundler.init(allocator, log, ctx.args, null, null);
- this_bundler.configureLinker();
- var filepath: [*:0]const u8 = "node_modules.bun";
- var server_bundle_filepath: [*:0]const u8 = "node_modules.server.bun";
-
- // This step is optional
- // If it fails for any reason, ignore it and continue bundling
- // This is partially a workaround for the 'error.MissingRoutesDir' error
- this_bundler.configureRouter(true) catch {
- this_bundler.options.routes.routes_enabled = false;
- this_bundler.options.framework = null;
- if (this_bundler.router) |*router| {
- router.config.routes_enabled = false;
- router.config.single_page_app_routing = false;
- router.config.static_dir_enabled = false;
- this_bundler.router = null;
- }
- this_bundler.options.node_modules_bundle = null;
- this_bundler.options.node_modules_bundle_pretty_path = "";
- this_bundler.options.node_modules_bundle_url = "";
- };
-
- if (ctx.debug.macros) |macros| {
- this_bundler.options.macro_remap = macros;
- }
-
- var loaded_route_config: ?Api.LoadedRouteConfig = brk: {
- if (this_bundler.options.routes.routes_enabled) {
- break :brk this_bundler.options.routes.toAPI();
- }
- break :brk null;
- };
- var loaded_framework: ?Api.LoadedFramework = brk: {
- if (this_bundler.options.framework) |*conf| {
- break :brk try conf.toAPI(allocator, this_bundler.fs.top_level_dir);
- }
- break :brk null;
- };
- var env_loader = this_bundler.env;
-
- if (ctx.debug.dump_environment_variables) {
- this_bundler.dumpEnvironmentVariables();
- return;
- }
-
- if (ctx.debug.dump_limits) {
- fs.FileSystem.printLimits();
- Global.exit(0);
- return;
- }
-
- var generated_server = false;
- if (this_bundler.options.framework) |*framework| {
- if (framework.toAPI(allocator, this_bundler.fs.top_level_dir) catch null) |_server_conf| {
- ServerBundleGeneratorThread.generate(
- log,
- env_loader,
- ctx,
- server_bundle_filepath,
- _server_conf,
- loaded_route_config,
- this_bundler.router,
- );
- generated_server = true;
-
- if (log.msgs.items.len > 0) {
- try log.printForLogLevel(Output.errorWriter());
- log.* = logger.Log.init(allocator);
- Output.flush();
- }
- }
- }
-
- {
-
- // Always generate the client-only bundle
- // we can revisit this decision if people ask
- var node_modules_ = try GenerateNodeModuleBundle.generate(
- &this_bundler,
- allocator,
- loaded_framework,
- loaded_route_config,
- filepath,
- &estimated_input_lines_of_code_,
- ctx.debug.package_bundle_map,
- );
-
- const estimated_input_lines_of_code = estimated_input_lines_of_code_;
-
- if (node_modules_) |node_modules| {
- if (log.errors > 0) {
- try log.printForLogLevel(Output.errorWriter());
- } else {
- var elapsed = @divTrunc(@truncate(i64, std.time.nanoTimestamp() - ctx.start_time), @as(i64, std.time.ns_per_ms));
- const print_summary = !(ctx.args.no_summary orelse false);
- if (print_summary) {
- var bundle = NodeModuleBundle.init(node_modules, allocator);
- bundle.printSummary();
- }
- const indent = comptime " ";
-
- switch (estimated_input_lines_of_code) {
- 0...99999 => {
- if (generated_server) {
- Output.prettyln(indent ++ "<d>{d:<5} LOC parsed x2", .{estimated_input_lines_of_code});
- } else {
- Output.prettyln(indent ++ "<d>{d:<5} LOC parsed", .{estimated_input_lines_of_code});
- }
- },
- else => {
- const formatted_loc: f32 = @floatCast(f32, @intToFloat(f64, estimated_input_lines_of_code) / 1000);
- if (generated_server) {
- Output.prettyln(indent ++ "<d>{d:<5.2}k LOC parsed x2", .{formatted_loc});
- } else {
- Output.prettyln(indent ++ "<d>{d:<5.2}k LOC parsed", .{
- formatted_loc,
- });
- }
- },
- }
-
- Output.prettyln(indent ++ "<d>{d:6}ms elapsed", .{@intCast(u32, elapsed)});
-
- if (generated_server) {
- Output.prettyln(indent ++ "<r>Saved to ./{s}, ./{s}", .{ filepath, server_bundle_filepath });
- } else {
- Output.prettyln(indent ++ "<r>Saved to ./{s}", .{filepath});
- }
-
- Output.flush();
-
- try log.printForLogLevel(Output.errorWriter());
- }
- } else {
- try log.printForLogLevel(Output.errorWriter());
- }
- }
- }
-};