Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion rewatch/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,13 @@ pub fn initialize_build(
path: &Path,
plain_output: bool,
warn_error: Option<String>,
prod: bool,
) -> Result<BuildCommandState> {
let project_context = ProjectContext::new(path)?;
let compiler = get_compiler_info(&project_context)?;

let timing_clean_start = Instant::now();
let packages = packages::make(filter, &project_context, show_progress)?;
let packages = packages::make(filter, &project_context, show_progress, prod)?;

let compiler_check = verify_compiler_info(&packages, &compiler);

Expand Down Expand Up @@ -489,6 +490,7 @@ pub fn build(
create_sourcedirs: bool,
plain_output: bool,
warn_error: Option<String>,
prod: bool,
) -> Result<BuildCommandState> {
let default_timing: Option<std::time::Duration> = if no_timing {
Some(std::time::Duration::new(0.0 as u64, 0.0 as u32))
Expand All @@ -503,6 +505,7 @@ pub fn build(
path,
plain_output,
warn_error,
prod,
)
.with_context(|| "Could not initialize build")?;

Expand Down
4 changes: 2 additions & 2 deletions rewatch/src/build/clean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -332,10 +332,10 @@ pub fn cleanup_after_build(build_state: &BuildCommandState) {
});
}

pub fn clean(path: &Path, show_progress: bool, plain_output: bool) -> Result<()> {
pub fn clean(path: &Path, show_progress: bool, plain_output: bool, prod: bool) -> Result<()> {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would happen if I compile in normal mode, but clean in prod mode?
Are 'dev' packages left intact then? Do we want that behavior?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point 🤔, I suppose if it doesn't require the dependency to be there then we can just clean everything

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we just ignore errors returned from remove_dir_all and remove_file while cleaning.
I think we can clean everything.

Copy link
Copy Markdown
Contributor Author

@JonoPrest JonoPrest Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just tested, if you don't have the dev dep installed then the clean fails. It always needs to resolve dependencies. I don't think clean is really going to be used in this way so I'm happy to remove the prod flag from clean entirely. It's mainly for building. But I think it doesn't hurt to keep it and make it possible to run clean on a prod environment.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, thanks for testing! I am fine with this approach as well 👍

let project_context = ProjectContext::new(path)?;
let compiler_info = build::get_compiler_info(&project_context)?;
let packages = packages::make(&None, &project_context, show_progress)?;
let packages = packages::make(&None, &project_context, show_progress, prod)?;

let timing_clean_compiler_assets = Instant::now();
if !plain_output && show_progress {
Expand Down
24 changes: 18 additions & 6 deletions rewatch/src/build/packages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,11 +285,15 @@ fn read_dependencies(
package_config: &Config,
show_progress: bool,
is_local_dep: bool,
prod: bool,
) -> Vec<Dependency> {
let mut dependencies = package_config.dependencies.to_owned().unwrap_or_default();

// Concatenate dev dependencies if is_local_dep is true
if is_local_dep && let Some(dev_deps) = package_config.dev_dependencies.to_owned() {
// Concatenate dev dependencies if is_local_dep is true and not in prod mode
if is_local_dep
&& !prod
&& let Some(dev_deps) = package_config.dev_dependencies.to_owned()
{
dependencies.extend(dev_deps);
}

Expand Down Expand Up @@ -395,6 +399,7 @@ fn read_dependencies(
&config,
show_progress,
is_local_dep,
prod,
);

Dependency {
Expand Down Expand Up @@ -509,7 +514,11 @@ This inconsistency will cause issues with package resolution.\n",
})
}

fn read_packages(project_context: &ProjectContext, show_progress: bool) -> Result<AHashMap<String, Package>> {
fn read_packages(
project_context: &ProjectContext,
show_progress: bool,
prod: bool,
) -> Result<AHashMap<String, Package>> {
// Store all packages and completely deduplicate them
let mut map: AHashMap<String, Package> = AHashMap::new();

Expand All @@ -531,6 +540,7 @@ fn read_packages(project_context: &ProjectContext, show_progress: bool) -> Resul
&project_context.current_config,
show_progress,
/* is local dep */ true,
prod,
));

for d in dependencies.iter() {
Expand Down Expand Up @@ -594,6 +604,7 @@ pub fn get_source_files(
fn extend_with_children(
filter: &Option<regex::Regex>,
mut build: AHashMap<String, Package>,
prod: bool,
) -> AHashMap<String, Package> {
for (_key, package) in build.iter_mut() {
let mut map: AHashMap<PathBuf, SourceFileMeta> = AHashMap::new();
Expand All @@ -606,7 +617,7 @@ fn extend_with_children(
Path::new(&package.path),
filter,
source,
package.is_local_dep,
package.is_local_dep && !prod,
)
})
.collect::<Vec<AHashMap<PathBuf, SourceFileMeta>>>()
Expand Down Expand Up @@ -649,12 +660,13 @@ pub fn make(
filter: &Option<regex::Regex>,
project_context: &ProjectContext,
show_progress: bool,
prod: bool,
) -> Result<AHashMap<String, Package>> {
let map = read_packages(project_context, show_progress)?;
let map = read_packages(project_context, show_progress, prod)?;

/* Once we have the deduplicated packages, we can add the source files for each - to minimize
* the IO */
let result = extend_with_children(filter, map);
let result = extend_with_children(filter, map, prod);

Ok(result)
}
Expand Down
64 changes: 64 additions & 0 deletions rewatch/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,10 @@ pub struct BuildArgs {
/// Disable output timing
#[arg(short, long, default_value_t = false, num_args = 0..=1)]
pub no_timing: bool,

/// Skip dev-dependencies and dev sources (type: "dev")
#[arg(long, default_value_t = false)]
pub prod: bool,
}

#[cfg(test)]
Expand Down Expand Up @@ -348,6 +352,57 @@ mod tests {
assert_eq!(err.kind(), ErrorKind::DisplayVersion);
}

// --prod flag tests.
#[test]
fn build_prod_flag_is_parsed() {
let cli = parse(&["rescript", "build", "--prod"]).expect("expected build command");

match cli.command {
Command::Build(build_args) => assert!(build_args.prod),
other => panic!("expected build command, got {other:?}"),
}
}

#[test]
fn build_prod_flag_defaults_to_false() {
let cli = parse(&["rescript", "build"]).expect("expected build command");

match cli.command {
Command::Build(build_args) => assert!(!build_args.prod),
other => panic!("expected build command, got {other:?}"),
}
}

#[test]
fn watch_prod_flag_is_parsed() {
let cli = parse(&["rescript", "watch", "--prod"]).expect("expected watch command");

match cli.command {
Command::Watch(watch_args) => assert!(watch_args.prod),
other => panic!("expected watch command, got {other:?}"),
}
}

#[test]
fn clean_prod_flag_is_parsed() {
let cli = parse(&["rescript", "clean", "--prod"]).expect("expected clean command");

match cli.command {
Command::Clean { prod, .. } => assert!(prod),
other => panic!("expected clean command, got {other:?}"),
}
}

#[test]
fn prod_flag_defaults_to_build_command() {
let cli = parse(&["rescript", "--prod"]).expect("expected default build command");

match cli.command {
Command::Build(build_args) => assert!(build_args.prod),
other => panic!("expected build command, got {other:?}"),
}
}

#[cfg(unix)]
#[test]
fn non_utf_argument_returns_error() {
Expand All @@ -372,6 +427,10 @@ pub struct WatchArgs {

#[command(flatten)]
pub warn_error: WarnErrorArg,

/// Skip dev-dependencies and dev sources (type: "dev")
#[arg(long, default_value_t = false)]
pub prod: bool,
}

impl From<BuildArgs> for WatchArgs {
Expand All @@ -381,6 +440,7 @@ impl From<BuildArgs> for WatchArgs {
filter: build_args.filter,
after_build: build_args.after_build,
warn_error: build_args.warn_error,
prod: build_args.prod,
}
}
}
Expand All @@ -395,6 +455,10 @@ pub enum Command {
Clean {
#[command(flatten)]
folder: FolderArg,

/// Skip dev-dependencies and dev sources (type: "dev")
#[arg(long, default_value_t = false)]
prod: bool,
},
/// Format ReScript files.
Format {
Expand Down
2 changes: 1 addition & 1 deletion rewatch/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ fn get_files_in_scope() -> Result<Vec<String>> {
let current_dir = std::env::current_dir()?;
let project_context = project_context::ProjectContext::new(&current_dir)?;

let packages = packages::make(&None, &project_context, false)?;
let packages = packages::make(&None, &project_context, false, false)?;
let mut files: Vec<String> = Vec::new();
let packages_to_format = project_context.get_scoped_local_packages();

Expand Down
6 changes: 4 additions & 2 deletions rewatch/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ fn main() -> Result<()> {
true, // create_sourcedirs is now always enabled
plain_output,
(*build_args.warn_error).clone(),
build_args.prod,
) {
Err(e) => {
eprintln!("{:#}", e);
Expand All @@ -78,6 +79,7 @@ fn main() -> Result<()> {
true, // create_sourcedirs is now always enabled
plain_output,
(*watch_args.warn_error).clone(),
watch_args.prod,
) {
Err(e) => {
eprintln!("{:#}", e);
Expand All @@ -86,9 +88,9 @@ fn main() -> Result<()> {
Ok(_) => Ok(()),
}
}
cli::Command::Clean { folder } => {
cli::Command::Clean { folder, prod } => {
let _lock = get_lock_or_exit(LockKind::Build, &folder);
let result = build::clean::clean(Path::new(&folder as &str), show_progress, plain_output);
let result = build::clean::clean(Path::new(&folder as &str), show_progress, plain_output, prod);
let _lock = drop_lock(LockKind::Build, &folder);

result
Expand Down
6 changes: 6 additions & 0 deletions rewatch/src/watcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ struct AsyncWatchArgs<'a> {
after_build: Option<String>,
create_sourcedirs: bool,
plain_output: bool,
prod: bool,
}

async fn async_watch(
Expand All @@ -165,6 +166,7 @@ async fn async_watch(
after_build,
create_sourcedirs,
plain_output,
prod,
}: AsyncWatchArgs<'_>,
) -> Result<()> {
let mut build_state = initial_build_state;
Expand Down Expand Up @@ -381,6 +383,7 @@ async fn async_watch(
path,
plain_output,
build_state.get_warn_error_override(),
prod,
)
.expect("Could not initialize build");

Expand Down Expand Up @@ -434,6 +437,7 @@ pub fn start(
create_sourcedirs: bool,
plain_output: bool,
warn_error: Option<String>,
prod: bool,
) -> Result<()> {
futures::executor::block_on(async {
let queue = Arc::new(FifoQueue::<Result<Event, Error>>::new());
Expand All @@ -453,6 +457,7 @@ pub fn start(
path,
plain_output,
warn_error.clone(),
prod,
)
.with_context(|| "Could not initialize build")?;

Expand All @@ -471,6 +476,7 @@ pub fn start(
after_build,
create_sourcedirs,
plain_output,
prod,
})
.await
})
Expand Down
Loading
Loading