diff options
author | 2023-09-13 17:31:59 -0700 | |
---|---|---|
committer | 2023-09-13 17:31:59 -0700 | |
commit | 9c9f4ed6ad39f92cb331e21a6b6dc0847e66510e (patch) | |
tree | 6bff76943ef302cfad33b13e03febdaccdcdeb2f /src/bun.js/javascript.zig | |
parent | 4f8edb825f48d06891de7a77131c6a434c06df88 (diff) | |
download | bun-9c9f4ed6ad39f92cb331e21a6b6dc0847e66510e.tar.gz bun-9c9f4ed6ad39f92cb331e21a6b6dc0847e66510e.tar.zst bun-9c9f4ed6ad39f92cb331e21a6b6dc0847e66510e.zip |
Make --watch instant (#5236)
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
Diffstat (limited to 'src/bun.js/javascript.zig')
-rw-r--r-- | src/bun.js/javascript.zig | 139 |
1 files changed, 122 insertions, 17 deletions
diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index e2e44e63a..60364706e 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -401,6 +401,50 @@ pub const ExitHandler = struct { pub const WebWorker = @import("./web_worker.zig").WebWorker; +pub const ImportWatcher = union(enum) { + none: void, + hot: *HotReloader.Watcher, + watch: *WatchReloader.Watcher, + + pub fn start(this: ImportWatcher) !void { + switch (this) { + inline .hot => |watcher| try watcher.start(), + inline .watch => |watcher| try watcher.start(), + else => {}, + } + } + + pub inline fn watchlist(this: ImportWatcher) Watcher.WatchListArray { + return switch (this) { + inline .hot, .watch => |wacher| wacher.watchlist, + else => .{}, + }; + } + + pub inline fn indexOf(this: ImportWatcher, hash: Watcher.HashType) ?u32 { + return switch (this) { + inline .hot, .watch => |wacher| wacher.indexOf(hash), + else => null, + }; + } + + pub inline fn addFile( + this: ImportWatcher, + fd: StoredFileDescriptorType, + file_path: string, + hash: Watcher.HashType, + loader: options.Loader, + dir_fd: StoredFileDescriptorType, + package_json: ?*PackageJSON, + comptime copy_file_path: bool, + ) !void { + switch (this) { + inline .hot, .watch => |wacher| try wacher.addFile(fd, file_path, hash, loader, dir_fd, package_json, copy_file_path), + else => {}, + } + } +}; + /// TODO: rename this to ScriptExecutionContext /// This is the shared global state for a single JS instance execution /// Today, Bun is one VM per thread, so the name "VirtualMachine" sort of makes sense @@ -410,8 +454,7 @@ pub const VirtualMachine = struct { allocator: std.mem.Allocator, has_loaded_constructors: bool = false, bundler: Bundler, - bun_dev_watcher: ?*http.Watcher = null, - bun_watcher: ?*JSC.Watcher = null, + bun_watcher: ImportWatcher = .{ .none = {} }, console: *ZigConsoleClient, log: *logger.Log, main: string = "", @@ -1006,7 +1049,7 @@ pub const VirtualMachine = struct { } pub fn isWatcherEnabled(this: *VirtualMachine) bool { - return this.bun_dev_watcher != null or this.bun_watcher != null; + return this.bun_watcher != .none; } /// Instead of storing timestamp as a i128, we store it as a u64. @@ -1987,7 +2030,7 @@ pub const VirtualMachine = struct { try this.entry_point.generate( this.allocator, - this.bun_watcher != null, + this.bun_watcher != .none, Fs.PathName.init(entry_path), main_file_name, ); @@ -2044,7 +2087,7 @@ pub const VirtualMachine = struct { defer JSValue.fromCell(promise).unprotect(); // pending_internal_promise can change if hot module reloading is enabled - if (this.bun_watcher != null) { + if (this.isWatcherEnabled()) { this.eventLoop().performGC(); switch (this.pending_internal_promise.status(this.global.vm())) { JSC.JSPromise.Status.Pending => { @@ -2099,7 +2142,7 @@ pub const VirtualMachine = struct { var promise = try this.reloadEntryPoint(entry_path); // pending_internal_promise can change if hot module reloading is enabled - if (this.bun_watcher != null) { + if (this.isWatcherEnabled()) { this.eventLoop().performGC(); switch (this.pending_internal_promise.status(this.global.vm())) { JSC.JSPromise.Status.Pending => { @@ -2125,6 +2168,21 @@ pub const VirtualMachine = struct { return this.pending_internal_promise; } + pub fn addListeningSocketForWatchMode(this: *VirtualMachine, socket: bun.FileDescriptor) void { + if (this.hot_reload != .watch) { + return; + } + + this.rareData().addListeningSocketForWatchMode(socket); + } + pub fn removeListeningSocketForWatchMode(this: *VirtualMachine, socket: bun.FileDescriptor) void { + if (this.hot_reload != .watch) { + return; + } + + this.rareData().removeListeningSocketForWatchMode(socket); + } + pub fn loadMacroEntryPoint(this: *VirtualMachine, entry_path: string, function_name: string, specifier: string, hash: i32) !*JSInternalPromise { var entry_point_entry = try this.macro_entry_points.getOrPut(hash); @@ -2809,6 +2867,7 @@ pub const VirtualMachine = struct { }; pub const HotReloader = NewHotReloader(VirtualMachine, JSC.EventLoop, false); +pub const WatchReloader = NewHotReloader(VirtualMachine, JSC.EventLoop, true); pub const Watcher = HotReloader.Watcher; extern fn BunDebugger__willHotReload() void; @@ -2835,6 +2894,8 @@ pub fn NewHotReloader(comptime Ctx: type, comptime EventLoopType: type, comptime this.eventLoop().enqueueTaskConcurrent(task); } + pub var clear_screen = false; + pub const HotReloadTask = struct { reloader: *Reloader, count: u8 = 0, @@ -2864,7 +2925,11 @@ pub fn NewHotReloader(comptime Ctx: type, comptime EventLoopType: type, comptime return; if (comptime reload_immediately) { - bun.reloadProcess(bun.default_allocator, Output.enable_ansi_colors); + Output.flush(); + if (comptime Ctx == ImportWatcher) { + this.reloader.ctx.rareData().closeAllListenSocketsForWatchMode(); + } + bun.reloadProcess(bun.default_allocator, clear_screen); unreachable; } @@ -2898,23 +2963,51 @@ pub fn NewHotReloader(comptime Ctx: type, comptime EventLoopType: type, comptime ) void); pub fn enableHotModuleReloading(this: *Ctx) void { - if (this.bun_watcher != null) - return; + if (comptime @TypeOf(this.bun_watcher) == ImportWatcher) { + if (this.bun_watcher != .none) + return; + } else { + if (this.bun_watcher != null) + return; + } var reloader = bun.default_allocator.create(Reloader) catch @panic("OOM"); reloader.* = .{ .ctx = this, .verbose = if (@hasField(Ctx, "log")) this.log.level.atLeast(.info) else false, }; - this.bun_watcher = @This().Watcher.init( - reloader, - this.bundler.fs, - bun.default_allocator, - ) catch @panic("Failed to enable File Watcher"); - this.bundler.resolver.watcher = Resolver.ResolveWatcher(*@This().Watcher, onMaybeWatchDirectory).init(this.bun_watcher.?); + if (comptime @TypeOf(this.bun_watcher) == ImportWatcher) { + this.bun_watcher = if (reload_immediately) + .{ .watch = @This().Watcher.init( + reloader, + this.bundler.fs, + bun.default_allocator, + ) catch @panic("Failed to enable File Watcher") } + else + .{ .hot = @This().Watcher.init( + reloader, + this.bundler.fs, + bun.default_allocator, + ) catch @panic("Failed to enable File Watcher") }; + + if (reload_immediately) { + this.bundler.resolver.watcher = Resolver.ResolveWatcher(*@This().Watcher, onMaybeWatchDirectory).init(this.bun_watcher.watch); + } else { + this.bundler.resolver.watcher = Resolver.ResolveWatcher(*@This().Watcher, onMaybeWatchDirectory).init(this.bun_watcher.hot); + } + } else { + this.bun_watcher = @This().Watcher.init( + reloader, + this.bundler.fs, + bun.default_allocator, + ) catch @panic("Failed to enable File Watcher"); + this.bundler.resolver.watcher = Resolver.ResolveWatcher(*@This().Watcher, onMaybeWatchDirectory).init(this.bun_watcher.?); + } + + clear_screen = Output.enable_ansi_colors and !strings.eqlComptime(this.bundler.env.map.get("BUN_CONFIG_NO_CLEAR_TERMINAL_ON_RELOAD") orelse "0", "true"); - this.bun_watcher.?.start() catch @panic("Failed to start File Watcher"); + reloader.getContext().start() catch @panic("Failed to start File Watcher"); } pub fn onMaybeWatchDirectory(watch: *@This().Watcher, file_path: string, dir_fd: StoredFileDescriptorType) void { @@ -2941,6 +3034,18 @@ pub fn NewHotReloader(comptime Ctx: type, comptime EventLoopType: type, comptime Output.prettyErrorln("<r>Watcher crashed: <red><b>{s}<r>", .{@errorName(err)}); } + pub fn getContext(this: *@This()) *@This().Watcher { + if (comptime @TypeOf(this.ctx.bun_watcher) == ImportWatcher) { + if (reload_immediately) { + return this.ctx.bun_watcher.watch; + } else { + return this.ctx.bun_watcher.hot; + } + } else { + return this.ctx.bun_watcher.?; + } + } + pub fn onFileUpdate( this: *@This(), events: []watcher.WatchEvent, @@ -2954,7 +3059,7 @@ pub fn NewHotReloader(comptime Ctx: type, comptime EventLoopType: type, comptime const hashes = slice.items(.hash); const parents = slice.items(.parent_hash); var file_descriptors = slice.items(.fd); - var ctx = this.ctx.bun_watcher.?; + var ctx = this.getContext(); defer ctx.flushEvictions(); defer Output.flush(); |