Skip to content

Commit ac4efda

Browse files
committed
Initial implementation of js-post-build in rewatch
1 parent 10edf2c commit ac4efda

File tree

3 files changed

+62
-3
lines changed

3 files changed

+62
-3
lines changed

rewatch/src/build/compile.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,33 @@ use std::process::Command;
2121
use std::sync::OnceLock;
2222
use std::time::SystemTime;
2323

24+
/// Execute js-post-build command for a compiled JavaScript file.
25+
/// Unlike bsb which passes relative paths, rewatch passes absolute paths for clarity.
26+
fn execute_post_build_command(cmd: &str, js_file_path: &Path) -> Result<()> {
27+
let full_command = format!("{} {}", cmd, js_file_path.display());
28+
29+
let output = if cfg!(target_os = "windows") {
30+
Command::new("cmd").args(["/C", &full_command]).output()
31+
} else {
32+
Command::new("sh").args(["-c", &full_command]).output()
33+
};
34+
35+
match output {
36+
Ok(output) if !output.status.success() => {
37+
let stderr = String::from_utf8_lossy(&output.stderr);
38+
let stdout = String::from_utf8_lossy(&output.stdout);
39+
Err(anyhow!(
40+
"js-post-build command failed for {}: {}{}",
41+
js_file_path.display(),
42+
stderr,
43+
stdout
44+
))
45+
}
46+
Err(e) => Err(anyhow!("Failed to execute js-post-build command: {}", e)),
47+
Ok(_) => Ok(()),
48+
}
49+
}
50+
2451
pub fn compile(
2552
build_state: &mut BuildCommandState,
2653
show_progress: bool,
@@ -815,6 +842,29 @@ fn compile_file(
815842
}
816843
});
817844

845+
// Execute js-post-build command if configured
846+
// Only run for implementation files (not interfaces)
847+
if !is_interface
848+
&& let Some(js_post_build) = &package.config.js_post_build
849+
&& let SourceType::SourceFile(SourceFile {
850+
implementation: Implementation { path, .. },
851+
..
852+
}) = &module.source_type
853+
{
854+
// Execute post-build command for each package spec (each output format)
855+
for spec in root_config.get_package_specs() {
856+
let js_file = helpers::get_source_file_from_rescript_file(
857+
&package.get_build_path().join(path),
858+
&root_config.get_suffix(&spec),
859+
);
860+
861+
if js_file.exists() {
862+
// Fail the build if post-build command fails (matches bsb behavior with &&)
863+
execute_post_build_command(&js_post_build.cmd, &js_file)?;
864+
}
865+
}
866+
}
867+
818868
if helpers::contains_ascii_characters(&err) {
819869
if package.is_local_dep {
820870
// suppress warnings of external deps

rewatch/src/config.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,13 @@ pub struct JsxSpecs {
219219
/// We do not care about the internal structure because the gentype config is loaded by bsc.
220220
pub type GenTypeConfig = serde_json::Value;
221221

222+
/// Configuration for running a command after each JavaScript file is compiled.
223+
/// Note: Unlike bsb, rewatch passes absolute paths to the command for clarity.
224+
#[derive(Deserialize, Debug, Clone)]
225+
pub struct JsPostBuild {
226+
pub cmd: String,
227+
}
228+
222229
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
223230
pub enum DeprecationWarning {
224231
BsDependencies,
@@ -299,6 +306,8 @@ pub struct Config {
299306
pub experimental_features: Option<HashMap<ExperimentalFeature, bool>>,
300307
#[serde(rename = "gentypeconfig")]
301308
pub gentype_config: Option<GenTypeConfig>,
309+
#[serde(rename = "js-post-build")]
310+
pub js_post_build: Option<JsPostBuild>,
302311
// Used by the VS Code extension; ignored by rewatch but should not emit warnings.
303312
// Payload is not validated here, only in the VS Code extension.
304313
pub editor: Option<serde_json::Value>,
@@ -707,7 +716,6 @@ impl Config {
707716
"generators",
708717
"cut-generators",
709718
"pp-flags",
710-
"js-post-build",
711719
"entries",
712720
"use-stdlib",
713721
"external-stdlib",
@@ -800,6 +808,7 @@ pub mod tests {
800808
namespace: None,
801809
jsx: None,
802810
gentype_config: None,
811+
js_post_build: None,
803812
editor: None,
804813
namespace_entry: None,
805814
deprecation_warnings: vec![],

tests/build_tests/post-build/input.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
import * as assert from "node:assert";
44
import { setup } from "#dev/process";
55

6-
const { execBuildLegacy } = setup(import.meta.dirname);
6+
const { execBuild } = setup(import.meta.dirname);
77

88
if (process.platform === "win32") {
99
console.log("Skipping test on Windows");
1010
process.exit(0);
1111
}
1212

13-
const out = await execBuildLegacy();
13+
const out = await execBuild();
1414

1515
if (out.status !== 0) {
1616
assert.fail(out.stdout + out.stderr);

0 commit comments

Comments
 (0)