mirror of
https://github.com/oven-sh/bun
synced 2026-02-17 22:32:06 +00:00
refactor(bundler): route standalone HTML disk writes through writeOutputFilesToDisk
Instead of custom disk-writing logic in generateChunksInParallel, teach writeOutputFilesToDisk to handle standalone mode: - Accept optional standalone_chunk_contents parameter - Skip non-HTML chunks (insert placeholder output files for index alignment) - Use codeStandalone() for HTML chunks to produce the inlined output - Skip writing additional output files (assets are inlined) - Use chunk.content.loader() for the output file loader field This removes the separate bun.sys.File disk-writing block and lets standalone HTML go through the same writeOutputFilesToDisk code path as all other bundler output. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -432,8 +432,8 @@ pub fn generateChunksInParallel(
|
||||
|
||||
// Don't write to disk if compile mode is enabled - we need buffer values for compilation
|
||||
const is_compile = bundler.transpiler.options.compile;
|
||||
if (root_path.len > 0 and !is_compile and !is_standalone) {
|
||||
try c.writeOutputFilesToDisk(root_path, chunks, &output_files);
|
||||
if (root_path.len > 0 and !is_compile) {
|
||||
try c.writeOutputFilesToDisk(root_path, chunks, &output_files, standalone_chunk_contents);
|
||||
} else {
|
||||
// In-memory build (also used for standalone mode)
|
||||
for (chunks, 0..) |*chunk, chunk_index_in_chunks_list| {
|
||||
@@ -762,37 +762,6 @@ pub fn generateChunksInParallel(
|
||||
}
|
||||
}
|
||||
result.items.len = write_idx;
|
||||
|
||||
// Write standalone HTML files to disk if outdir is specified
|
||||
if (root_path.len > 0) {
|
||||
for (result.items) |*item| {
|
||||
if (item.value == .buffer) {
|
||||
var buf: bun.PathBuffer = undefined;
|
||||
const abs_path = bun.path.joinAbsStringBufZ(root_path, &buf, &.{item.dest_path}, .auto);
|
||||
const file = switch (bun.sys.File.makeOpen(abs_path, bun.O.WRONLY | bun.O.CREAT | bun.O.TRUNC, 0o644)) {
|
||||
.result => |f| f,
|
||||
.err => |err| {
|
||||
try c.log.addErrorFmt(null, Logger.Loc.Empty, bun.default_allocator, "Failed to write {f}: {s}", .{
|
||||
bun.fmt.quote(item.dest_path),
|
||||
@tagName(err.getErrno()),
|
||||
});
|
||||
continue;
|
||||
},
|
||||
};
|
||||
defer file.close();
|
||||
switch (file.writeAll(item.value.buffer.bytes)) {
|
||||
.result => {},
|
||||
.err => |err| {
|
||||
try c.log.addErrorFmt(null, Logger.Loc.Empty, bun.default_allocator, "Failed to write {f}: {s}", .{
|
||||
bun.fmt.quote(item.dest_path),
|
||||
@tagName(err.getErrno()),
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ pub fn writeOutputFilesToDisk(
|
||||
root_path: string,
|
||||
chunks: []Chunk,
|
||||
output_files: *OutputFileListBuilder,
|
||||
standalone_chunk_contents: ?[]const ?[]const u8,
|
||||
) !void {
|
||||
const trace = bun.perf.trace("Bundler.writeOutputFilesToDisk");
|
||||
defer trace.end();
|
||||
@@ -42,6 +43,29 @@ pub fn writeOutputFilesToDisk(
|
||||
const bv2: *bundler.BundleV2 = @fieldParentPtr("linker", c);
|
||||
|
||||
for (chunks, 0..) |*chunk, chunk_index_in_chunks_list| {
|
||||
// In standalone mode, only write HTML chunks to disk.
|
||||
// Insert placeholder output files for non-HTML chunks to keep indices aligned.
|
||||
if (standalone_chunk_contents != null and chunk.content != .html) {
|
||||
_ = output_files.insertForChunk(options.OutputFile.init(.{
|
||||
.data = .{ .saved = 0 },
|
||||
.hash = null,
|
||||
.loader = chunk.content.loader(),
|
||||
.input_path = "",
|
||||
.display_size = 0,
|
||||
.output_kind = .chunk,
|
||||
.input_loader = .js,
|
||||
.output_path = "",
|
||||
.is_executable = false,
|
||||
.source_map_index = null,
|
||||
.bytecode_index = null,
|
||||
.module_info_index = null,
|
||||
.side = .client,
|
||||
.entry_point_index = null,
|
||||
.referenced_css_chunks = &.{},
|
||||
}));
|
||||
continue;
|
||||
}
|
||||
|
||||
const trace2 = bun.perf.trace("Bundler.writeChunkToDisk");
|
||||
defer trace2.end();
|
||||
defer max_heap_allocator.reset();
|
||||
@@ -65,17 +89,31 @@ pub fn writeOutputFilesToDisk(
|
||||
else
|
||||
c.resolver.opts.public_path;
|
||||
|
||||
var code_result = chunk.intermediate_output.code(
|
||||
code_allocator,
|
||||
c.parse_graph,
|
||||
&c.graph,
|
||||
public_path,
|
||||
chunk,
|
||||
chunks,
|
||||
&display_size,
|
||||
c.resolver.opts.compile and !chunk.flags.is_browser_chunk_from_server_build,
|
||||
chunk.content.sourcemap(c.options.source_maps) != .none,
|
||||
) catch |err| bun.Output.panic("Failed to create output chunk: {s}", .{@errorName(err)});
|
||||
var code_result = if (standalone_chunk_contents) |scc|
|
||||
chunk.intermediate_output.codeStandalone(
|
||||
code_allocator,
|
||||
c.parse_graph,
|
||||
&c.graph,
|
||||
public_path,
|
||||
chunk,
|
||||
chunks,
|
||||
&display_size,
|
||||
false,
|
||||
false,
|
||||
scc,
|
||||
) catch |err| bun.Output.panic("Failed to create output chunk: {s}", .{@errorName(err)})
|
||||
else
|
||||
chunk.intermediate_output.code(
|
||||
code_allocator,
|
||||
c.parse_graph,
|
||||
&c.graph,
|
||||
public_path,
|
||||
chunk,
|
||||
chunks,
|
||||
&display_size,
|
||||
c.resolver.opts.compile and !chunk.flags.is_browser_chunk_from_server_build,
|
||||
chunk.content.sourcemap(c.options.source_maps) != .none,
|
||||
) catch |err| bun.Output.panic("Failed to create output chunk: {s}", .{@errorName(err)});
|
||||
|
||||
var source_map_output_file: ?options.OutputFile = null;
|
||||
|
||||
@@ -318,7 +356,7 @@ pub fn writeOutputFilesToDisk(
|
||||
.js,
|
||||
.hash = chunk.template.placeholder.hash,
|
||||
.output_kind = output_kind,
|
||||
.loader = .js,
|
||||
.loader = chunk.content.loader(),
|
||||
.source_map_index = source_map_index,
|
||||
.bytecode_index = bytecode_index,
|
||||
.size = @as(u32, @truncate(code_result.buffer.len)),
|
||||
@@ -344,10 +382,15 @@ pub fn writeOutputFilesToDisk(
|
||||
},
|
||||
}));
|
||||
|
||||
// We want the chunk index to remain the same in `output_files` so the indices in `OutputFile.referenced_css_chunks` work
|
||||
bun.assertf(chunk_index == chunk_index_in_chunks_list, "chunk_index ({d}) != chunk_index_in_chunks_list ({d})", .{ chunk_index, chunk_index_in_chunks_list });
|
||||
// We want the chunk index to remain the same in `output_files` so the indices in `OutputFile.referenced_css_chunks` work.
|
||||
// In standalone mode, non-HTML chunks are skipped so this invariant doesn't apply.
|
||||
if (standalone_chunk_contents == null)
|
||||
bun.assertf(chunk_index == chunk_index_in_chunks_list, "chunk_index ({d}) != chunk_index_in_chunks_list ({d})", .{ chunk_index, chunk_index_in_chunks_list });
|
||||
}
|
||||
|
||||
// In standalone mode, additional output files (assets) are inlined into the HTML.
|
||||
if (standalone_chunk_contents != null) return;
|
||||
|
||||
{
|
||||
const additional_output_files = output_files.getMutableAdditionalOutputFiles();
|
||||
output_files.total_insertions += @intCast(additional_output_files.len);
|
||||
|
||||
Reference in New Issue
Block a user