diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index 3f27f22036..8963ad39ff 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -115,6 +115,7 @@ pub const SavedSourceMap = struct { mutex: bun.Mutex = .{}, pub const vlq_offset = 24; + const debug = bun.Output.scoped(.SourceMap, true); pub fn init(this: *SavedSourceMap, map: *HashTable) void { this.* = .{ @@ -240,7 +241,7 @@ pub const SavedSourceMap = struct { pub const HashTable = std.HashMap(u64, *anyopaque, IdentityContext(u64), 80); - pub fn onSourceMapChunk(this: *SavedSourceMap, chunk: SourceMap.Chunk, source: logger.Source) anyerror!void { + pub fn onSourceMapChunk(this: *SavedSourceMap, chunk: SourceMap.Chunk, source: *const logger.Source) anyerror!void { try this.putMappings(source, chunk.buffer); } @@ -269,7 +270,8 @@ pub const SavedSourceMap = struct { this.map.deinit(); } - pub fn putMappings(this: *SavedSourceMap, source: logger.Source, mappings: MutableString) !void { + pub fn putMappings(this: *SavedSourceMap, source: *const logger.Source, mappings: MutableString) !void { + debug("put {s} = {}", .{ source.path.text, bun.fmt.size(mappings.list.items.len, .{}) }); try this.putValue(source.path.text, Value.init(bun.cast(*SavedMappings, mappings.list.items.ptr))); } @@ -278,6 +280,7 @@ pub const SavedSourceMap = struct { defer this.unlock(); const entry = try this.map.getOrPut(bun.hash(path)); + if (entry.found_existing) { var old_value = Value.from(entry.value_ptr.*); if (old_value.get(ParsedSourceMap)) |parsed_source_map| { @@ -1056,7 +1059,7 @@ pub const VirtualMachine = struct { /// When the inspector is enabled, we want to generate an inline sourcemap. /// And, for now, we also store it in source_mappings like normal /// This is hideously expensive memory-wise... - pub fn onChunk(this: *SourceMapHandlerGetter, chunk: SourceMap.Chunk, source: logger.Source) anyerror!void { + pub fn onChunk(this: *SourceMapHandlerGetter, chunk: SourceMap.Chunk, source: *const logger.Source) anyerror!void { var temp_json_buffer = bun.MutableString.initEmpty(bun.default_allocator); defer temp_json_buffer.deinit(); temp_json_buffer = try chunk.printSourceMapContentsAtOffset(source, temp_json_buffer, true, SavedSourceMap.vlq_offset, true); diff --git a/src/bun.js/module_loader.zig b/src/bun.js/module_loader.zig index 4548299185..cc9d58c327 100644 --- a/src/bun.js/module_loader.zig +++ b/src/bun.js/module_loader.zig @@ -548,7 +548,7 @@ pub const RuntimeTranspilerStore = struct { } if (cache.entry) |*entry| { - vm.source_mappings.putMappings(parse_result.source, .{ + vm.source_mappings.putMappings(&parse_result.source, .{ .list = .{ .items = @constCast(entry.sourcemap), .capacity = entry.sourcemap.len }, .allocator = bun.default_allocator, }) catch {}; @@ -1787,7 +1787,7 @@ pub const ModuleLoader = struct { } if (cache.entry) |*entry| { - jsc_vm.source_mappings.putMappings(parse_result.source, .{ + jsc_vm.source_mappings.putMappings(&parse_result.source, .{ .list = .{ .items = @constCast(entry.sourcemap), .capacity = entry.sourcemap.len }, .allocator = bun.default_allocator, }) catch {}; diff --git a/src/js_printer.zig b/src/js_printer.zig index 4e5fcbd960..7c1cda949d 100644 --- a/src/js_printer.zig +++ b/src/js_printer.zig @@ -420,14 +420,14 @@ pub const SourceMapHandler = struct { ctx: *anyopaque, callback: Callback, - const Callback = *const fn (*anyopaque, chunk: SourceMap.Chunk, source: logger.Source) anyerror!void; - pub fn onSourceMapChunk(self: *const @This(), chunk: SourceMap.Chunk, source: logger.Source) anyerror!void { + const Callback = *const fn (*anyopaque, chunk: SourceMap.Chunk, source: *const logger.Source) anyerror!void; + pub fn onSourceMapChunk(self: *const @This(), chunk: SourceMap.Chunk, source: *const logger.Source) anyerror!void { try self.callback(self.ctx, chunk, source); } - pub fn For(comptime Type: type, comptime handler: (fn (t: *Type, chunk: SourceMap.Chunk, source: logger.Source) anyerror!void)) type { + pub fn For(comptime Type: type, comptime handler: (fn (t: *Type, chunk: SourceMap.Chunk, source: *const logger.Source) anyerror!void)) type { return struct { - pub fn onChunk(self: *anyopaque, chunk: SourceMap.Chunk, source: logger.Source) anyerror!void { + pub fn onChunk(self: *anyopaque, chunk: SourceMap.Chunk, source: *const logger.Source) anyerror!void { try handler(@as(*Type, @ptrCast(@alignCast(self))), chunk, source); } @@ -454,6 +454,18 @@ pub const Options = struct { source_map_allocator: ?std.mem.Allocator = null, source_map_handler: ?SourceMapHandler = null, source_map_builder: ?*bun.sourcemap.Chunk.Builder = null, + + // Necessary for the `source-map` library to work correctly, which means we + // only need it if we're generating source maps externally, such as when + // bundling or when the debugger is enabled. + // + // _tsc.js sourcemap size: + // + // on: 3.18 MB + // off: 2.49 MB + // + source_map_cover_lines_without_mappings: bool = true, + css_import_behavior: Api.CssInJsBehavior = Api.CssInJsBehavior.facade, target: options.Target = .browser, @@ -5848,7 +5860,7 @@ pub fn getSourceMapBuilder( opts.source_map_allocator orelse opts.allocator, is_bun_platform and generate_source_map == .lazy, ), - .cover_lines_without_mappings = true, + .cover_lines_without_mappings = opts.source_map_cover_lines_without_mappings, .approximate_input_line_count = tree.approximate_newline_count, .prepend_count = is_bun_platform and generate_source_map == .lazy, .line_offset_tables = opts.line_offset_tables orelse brk: { @@ -6016,7 +6028,7 @@ pub fn printAst( cache.put(printer.writer.ctx.getWritten(), source_maps_chunk.buffer.list.items); } - try handler.onSourceMapChunk(source_maps_chunk, source.*); + try handler.onSourceMapChunk(source_maps_chunk, source); } else { if (opts.runtime_transpiler_cache) |cache| { cache.put(printer.writer.ctx.getWritten(), ""); @@ -6024,7 +6036,7 @@ pub fn printAst( } } else if (comptime generate_source_map) { if (opts.source_map_handler) |handler| { - try handler.onSourceMapChunk(printer.source_map_builder.generateChunk(printer.writer.ctx.getWritten()), source.*); + try handler.onSourceMapChunk(printer.source_map_builder.generateChunk(printer.writer.ctx.getWritten()), source); } } @@ -6271,7 +6283,7 @@ pub fn printCommonJS( if (comptime generate_source_map) { if (opts.source_map_handler) |handler| { - try handler.onSourceMapChunk(printer.source_map_builder.generateChunk(printer.writer.ctx.getWritten()), source.*); + try handler.onSourceMapChunk(printer.source_map_builder.generateChunk(printer.writer.ctx.getWritten()), source); } } diff --git a/src/sourcemap/sourcemap.zig b/src/sourcemap/sourcemap.zig index e0e2ef31da..6ce9bf0786 100644 --- a/src/sourcemap/sourcemap.zig +++ b/src/sourcemap/sourcemap.zig @@ -1226,7 +1226,7 @@ pub const Chunk = struct { pub fn printSourceMapContents( chunk: Chunk, - source: Logger.Source, + source: *const Logger.Source, mutable: MutableString, include_sources_contents: bool, comptime ascii_only: bool, @@ -1243,7 +1243,7 @@ pub const Chunk = struct { pub fn printSourceMapContentsAtOffset( chunk: Chunk, - source: Logger.Source, + source: *const Logger.Source, mutable: MutableString, include_sources_contents: bool, offset: usize, diff --git a/src/transpiler.zig b/src/transpiler.zig index 506b87aa3d..eaef555488 100644 --- a/src/transpiler.zig +++ b/src/transpiler.zig @@ -910,6 +910,12 @@ pub const Transpiler = struct { .print_dce_annotations = transpiler.options.emit_dce_annotations, .hmr_ref = ast.wrapper_ref, .mangled_props = null, + + .source_map_cover_lines_without_mappings = if (is_bun) + // If the sourcemaps are strictly for internal usage, we can disable this + transpiler.options.debugger or transpiler.options.code_coverage or transpiler.options.dead_code_elimination == false + else + true, }, enable_source_map, ),