use std::process::{Command, Stdio};
use camino::{Utf8Path, Utf8PathBuf};
use thiserror::Error;
use crate::{Blueprint, error::HauchiwaError, graph::Handle, loader::GlobAssetsTask};
#[derive(Debug, Error)]
pub enum ScriptError {
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("Esbuild execution failed: {0}")]
Esbuild(String),
#[error("UTF-8 conversion error: {0}")]
Utf8(#[from] std::string::FromUtf8Error),
#[error("Build error: {0}")]
Build(#[from] crate::error::BuildError),
}
#[derive(Clone)]
pub struct Script {
pub path: Utf8PathBuf,
}
impl<G> Blueprint<G>
where
G: Send + Sync + 'static,
{
pub fn load_js(
&mut self,
glob_entry: &'static str,
glob_watch: &'static str,
) -> Result<Handle<super::Assets<Script>>, HauchiwaError> {
Ok(self.add_task_opaque(GlobAssetsTask::new(
vec![glob_entry],
vec![glob_watch],
move |_, store, input| {
let data = compile_esbuild(&input.path)?;
let path = store.save(&data, "js").map_err(ScriptError::Build)?;
Ok((input.path, Script { path }))
},
)?))
}
}
fn compile_esbuild(file: &Utf8Path) -> Result<Vec<u8>, ScriptError> {
let output = Command::new("esbuild")
.arg(file.as_str())
.arg("--format=esm")
.arg("--bundle")
.arg("--minify")
.stdout(Stdio::piped())
.stderr(Stdio::inherit())
.output()?;
if !output.status.success() {
return Err(ScriptError::Esbuild(String::from_utf8(output.stdout)?));
}
Ok(output.stdout)
}