use std::process::{Command, Stdio};
use camino::{Utf8Path, Utf8PathBuf};
use thiserror::Error;
use crate::{SiteConfig, error::HauchiwaError, loader::GlobRegistryTask, task::Handle};
#[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> SiteConfig<G>
where
G: Send + Sync + 'static,
{
pub fn load_js(
&mut self,
glob_entry: &'static str,
glob_watch: &'static str,
) -> Result<Handle<super::Registry<Script>>, HauchiwaError> {
Ok(self.add_task_opaque(GlobRegistryTask::new(
vec![glob_entry],
vec![glob_watch],
move |_, rt, file| {
let data = compile_esbuild(&file.path)?;
let path = rt.store(&data, "js").map_err(ScriptError::Build)?;
Ok((file.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)
}