@@ -256,7 +256,7 @@ async fn async_watch(
256256 if show_progress {
257257 println ! ( "\n Exiting..." ) ;
258258 }
259- clean:: cleanup_after_build ( & build_state) ;
259+ build :: with_build_lock ( path , || clean:: cleanup_after_build ( & build_state) ) ;
260260 break Ok ( ( ) ) ;
261261 }
262262 let mut events: Vec < Event > = vec ! [ ] ;
@@ -281,7 +281,7 @@ async fn async_watch(
281281 if show_progress {
282282 println ! ( "\n Exiting... (lockfile removed)" ) ;
283283 }
284- clean:: cleanup_after_build ( & build_state) ;
284+ build :: with_build_lock ( path , || clean:: cleanup_after_build ( & build_state) ) ;
285285 return Ok ( ( ) ) ;
286286 }
287287
@@ -468,38 +468,44 @@ async fn async_watch(
468468 }
469469
470470 let timing_total = Instant :: now ( ) ;
471- let mut next_build_state = build:: initialize_build (
472- None ,
473- filter,
474- show_progress,
475- path,
476- plain_output,
477- build_state. get_warn_error_override ( ) ,
478- prod,
479- features. clone ( ) ,
480- )
481- . expect ( "Could not initialize build" ) ;
482-
483- // Full rebuilds can be triggered by editor atomic saves that surface as rename events.
484- // Preserve warning state for unchanged modules so their warnings are re-emitted after the
485- // fresh build state replaces the previous one.
486- carry_forward_compile_warnings ( & build_state, & mut next_build_state) ;
487- build_state = next_build_state;
488-
489- // Re-register watches based on the new build state
490- unregister_watches ( watcher, & current_watch_paths) ;
491- current_watch_paths = compute_watch_paths ( & build_state, path) ;
492- register_watches ( watcher, & current_watch_paths) ;
493-
494- let result = build:: incremental_build (
495- & mut build_state,
496- None ,
497- initial_build,
498- show_progress,
499- false ,
500- create_sourcedirs,
501- plain_output,
502- ) ;
471+ // Reinitialization runs cleanup for previous build artifacts, so full rebuilds need
472+ // the same build lock boundary as regular `rescript build`.
473+ let result = build:: with_build_lock ( path, || {
474+ let mut next_build_state = build:: initialize_build (
475+ None ,
476+ filter,
477+ show_progress,
478+ path,
479+ plain_output,
480+ build_state. get_warn_error_override ( ) ,
481+ prod,
482+ features. clone ( ) ,
483+ )
484+ . expect ( "Could not initialize build" ) ;
485+
486+ // Full rebuilds can be triggered by editor atomic saves that surface as rename events.
487+ // Preserve warning state for unchanged modules so their warnings are re-emitted after the
488+ // fresh build state replaces the previous one.
489+ carry_forward_compile_warnings ( & build_state, & mut next_build_state) ;
490+ build_state = next_build_state;
491+
492+ // Re-register watches based on the new build state
493+ unregister_watches ( watcher, & current_watch_paths) ;
494+ current_watch_paths = compute_watch_paths ( & build_state, path) ;
495+ register_watches ( watcher, & current_watch_paths) ;
496+
497+ let result = build:: incremental_build_without_lock (
498+ & mut build_state,
499+ None ,
500+ initial_build,
501+ show_progress,
502+ false ,
503+ create_sourcedirs,
504+ plain_output,
505+ ) ;
506+ build:: write_build_ninja ( & build_state) ;
507+ result
508+ } ) ;
503509 match result {
504510 Ok ( result) => {
505511 if let Some ( a) = after_build. clone ( ) {
@@ -528,8 +534,6 @@ async fn async_watch(
528534 }
529535 }
530536 }
531-
532- build:: write_build_ninja ( & build_state) ;
533537 needs_compile_type = CompileType :: None ;
534538 initial_build = false ;
535539 }
@@ -565,18 +569,21 @@ pub fn start(
565569
566570 let path = Path :: new ( folder) ;
567571
568- // Do an initial build to discover packages and source folders
569- let build_state: BuildCommandState = build:: initialize_build (
570- None ,
571- filter,
572- show_progress,
573- path,
574- plain_output,
575- warn_error. clone ( ) ,
576- prod,
577- features. clone ( ) ,
578- )
579- . with_context ( || "Could not initialize build" ) ?;
572+ // Do an initial build to discover packages and source folders. Initialization can clean
573+ // previous build artifacts, so it has to be serialized with other build operations.
574+ let build_state: BuildCommandState = build:: with_build_lock ( path, || {
575+ build:: initialize_build (
576+ None ,
577+ filter,
578+ show_progress,
579+ path,
580+ plain_output,
581+ warn_error. clone ( ) ,
582+ prod,
583+ features. clone ( ) ,
584+ )
585+ . with_context ( || "Could not initialize build" )
586+ } ) ?;
580587
581588 // Compute and register targeted watches based on source folders
582589 let current_watch_paths = compute_watch_paths ( & build_state, path) ;
0 commit comments