diff --git a/src/runtime/bake/production.rs b/src/runtime/bake/production.rs index f5ba9b01cc3..58d6a4872ca 100644 --- a/src/runtime/bake/production.rs +++ b/src/runtime/bake/production.rs @@ -259,6 +259,25 @@ fn write_sourcemap_to_disk( Ok(()) } +struct OutputDir { + dir: bun_sys::Dir, + failed_writes: usize, +} + +impl OutputDir { + fn write(&mut self, file: &OutputFile) { + if let Err(err) = file.write_to_disk(self.dir.fd(), b".") { + bun_core::handle_error_return_trace(err); + Output::err( + err, + "Failed to write {} to output directory", + (bun_core::fmt::quote(&file.dest_path),), + ); + self.failed_writes += 1; + } + } +} + fn build_with_vm(ctx: Context, cwd: &[u8], pt: &mut PerThread) -> crate::Result<()> { // `pt.vm` is the live per-thread VM's BackRef set in `build_command`; // `as_ptr()` is `Copy` and does not borrow `pt`. @@ -641,6 +660,10 @@ fn build_with_vm(ctx: Context, cwd: &[u8], pt: &mut PerThread) -> crate::Result< return Err(crate::Error::BakeBuildFailed); } }; + let mut output_dir = OutputDir { + dir: root_dir, + failed_writes: 0, + }; let mut maybe_runtime_file_index: Option = None; @@ -697,25 +720,11 @@ fn build_with_vm(ctx: Context, cwd: &[u8], pt: &mut PerThread) -> crate::Result< match side { bun_bundler::options::Side::Client => { // Client-side resources will be written to disk for usage on the client side - if let Err(err) = file.write_to_disk(root_dir.fd(), b".") { - bun_core::handle_error_return_trace(err); - Output::err( - err, - "Failed to write {} to output directory", - (bun_core::fmt::quote(&file.dest_path),), - ); - } + output_dir.write(file); } bun_bundler::options::Side::Server => { if ctx.bundler_options.bake_debug_dump_server { - if let Err(err) = file.write_to_disk(root_dir.fd(), b".") { - bun_core::handle_error_return_trace(err); - Output::err( - err, - "Failed to write {} to output directory", - (bun_core::fmt::quote(&file.dest_path),), - ); - } + output_dir.write(file); } // If the file has a sourcemap, store it so we can put it on @@ -787,17 +796,13 @@ fn build_with_vm(ctx: Context, cwd: &[u8], pt: &mut PerThread) -> crate::Result< && file.src_path.text != b"bun-framework-react/client.tsx" }); if any_client_chunks { - let runtime_file: &OutputFile = &bundled_outputs_list[runtime_file_index as usize]; - if let Err(err) = runtime_file.write_to_disk(root_dir.fd(), b".") { - bun_core::handle_error_return_trace(err); - Output::err( - err, - "Failed to write {} to output directory", - (bun_core::fmt::quote(&runtime_file.dest_path),), - ); - } + output_dir.write(&bundled_outputs_list[runtime_file_index as usize]); } } + if output_dir.failed_writes > 0 { + // Every failed write has been reported; the pages would only reference the missing files. + return Err(crate::Error::BakeBuildFailed); + } *pt = PerThread::init( vm_ptr, diff --git a/test/bake/dev/production.test.ts b/test/bake/dev/production.test.ts index 698f840caa3..313a2814346 100644 --- a/test/bake/dev/production.test.ts +++ b/test/bake/dev/production.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from "bun:test"; -import { existsSync, symlinkSync } from "fs"; +import { existsSync, mkdirSync, readdirSync, rmSync, symlinkSync } from "fs"; import { bunEnv, bunExe, isWindows, tempDir } from "harness"; import path from "path"; import { tempDirWithBakeDeps, WAIT_MULTIPLIER } from "../bake-harness"; @@ -742,4 +742,121 @@ export default function IndexPage() { // Verify NO JavaScript imports are included in the HTML expect(htmlContent).not.toContain('