dioxus_use_js/
compile.rs

1use std::env::current_dir;
2use std::path::PathBuf;
3use std::process::Command;
4
5use bon::Builder;
6
7#[cfg_attr(docsrs, doc(cfg(feature = "compile")))]
8#[derive(Builder)]
9pub struct BunTsCompile {
10    /// Files to build from
11    src_files: Vec<PathBuf>,
12    /// The output directory
13    output_dir: PathBuf,
14    /// If set the output will be a single file
15    output_file: Option<String>,
16    #[builder(default = true)]
17    minify: bool,
18    /// Extra bun build flags
19    extra_flags: Option<Vec<String>>,
20    /// If true, the normal `bun build ...` command will not execute if bun is not installed, but will instead print a warning.
21    /// This may be useful in CI environment where bun is not installed (and is not needed), since the output was created during
22    /// development and is already in source.
23    #[builder(default = false)]
24    skip_if_no_bun: bool,
25}
26
27impl BunTsCompile {
28    pub fn run(&self) {
29        fn bun_exists() -> bool {
30            Command::new("bun")
31                .arg("--version")
32                .output()
33                .map(|o| o.status.success())
34                .unwrap_or(false)
35        }
36        if self.skip_if_no_bun && !bun_exists() {
37            println!("cargo:warning=Bun does not exist and configuration allows this, skipping bun build.");
38            return;
39        }
40
41        let src_files = self
42            .src_files
43            .iter()
44            .map(|e| {
45                e.to_str()
46                    .expect("a src file is not a valid utf-8 string")
47                    .to_owned()
48            })
49            .collect::<Vec<_>>();
50        let output_dir = self
51            .output_dir
52            .to_str()
53            .expect("The output file is not a valid utf-8 string")
54            .to_owned();
55
56        let mut args = Vec::new();
57        args.push("build".to_owned());
58        args.extend(src_files);
59
60        if let Some(output_file) = &self.output_file {
61            args.extend([
62                "--compile".to_owned(),
63                "--outfile".to_owned(),
64                self.output_dir
65                    .join(output_file)
66                    .to_str()
67                    .unwrap()
68                    .to_owned(),
69            ])
70        } else {
71            args.extend(["--outdir".to_owned(), output_dir]);
72        }
73        if self.minify {
74            args.extend([
75                "--minify-syntax".to_owned(),
76                "--minify-whitespace".to_owned(),
77                // todo Note cannot currently use `--minify-identifiers` since the macro will not find the js functions during validation
78                // "--minify-identifiers".to_owned(),
79            ]);
80        }
81        args.push("--target=browser".to_owned());
82        args.extend(self.extra_flags.iter().flatten().cloned());
83
84        // Run bun build
85        let output = Command::new("bun")
86            .args(&args)
87            .output()
88            .expect("Failed to execute bun build");
89        if !output.status.success() {
90            panic!(
91                "bun build failed.\nArgs: `{}`\nCurrent Directory: `{}`\nStderr:\n{}",
92                args.join(" "),
93                current_dir().unwrap().display(),
94                String::from_utf8_lossy(&output.stderr)
95            );
96        }
97    }
98}