diff --git a/crates/binding/src/js_hook.rs b/crates/binding/src/js_hook.rs index 5b8bbfa09..40f3d57c4 100644 --- a/crates/binding/src/js_hook.rs +++ b/crates/binding/src/js_hook.rs @@ -59,6 +59,10 @@ pub struct JsHooks { pub generate_end: Option, #[napi(ts_type = "() => Promise;")] pub write_bundle: Option, + #[napi( + ts_type = "(id: string, change: { event: 'create' | 'delete' | 'update' }) => Promise | void;" + )] + pub watch_changes: Option, #[napi(ts_type = "(path: string, content: Buffer) => Promise;")] pub _on_generate_file: Option, #[napi(ts_type = "() => Promise;")] @@ -84,6 +88,7 @@ pub struct TsFnHooks { pub generate_end: Option>, pub load: Option>>, pub load_include: Option>>, + pub watch_changes: Option>, pub resolve_id: Option>>, pub _on_generate_file: Option>, @@ -106,6 +111,9 @@ impl TsFnHooks { generate_end: hooks.generate_end.as_ref().map(|hook| unsafe { ThreadsafeFunction::from_napi_value(env.raw(), hook.raw()).unwrap() }), + watch_changes: hooks.watch_changes.as_ref().map(|hook| unsafe { + ThreadsafeFunction::from_napi_value(env.raw(), hook.raw()).unwrap() + }), load: hooks.load.as_ref().map(|hook| unsafe { ThreadsafeFunction::from_napi_value(env.raw(), hook.raw()).unwrap() }), @@ -142,6 +150,11 @@ pub struct LoadResult { pub content_type: String, } +#[napi(object, use_nullable = true)] +pub struct WatchChangesParams { + pub event: String, +} + #[napi(object, use_nullable = true)] pub struct ResolveIdResult { pub id: String, diff --git a/crates/binding/src/js_plugin.rs b/crates/binding/src/js_plugin.rs index b861b68f4..b4d8a7443 100644 --- a/crates/binding/src/js_plugin.rs +++ b/crates/binding/src/js_plugin.rs @@ -8,7 +8,8 @@ use mako::plugin::{Plugin, PluginGenerateEndParams, PluginLoadParam, PluginResol use mako::resolve::{ExternalResource, Resolution, ResolvedResource, ResolverResource}; use crate::js_hook::{ - LoadResult, ResolveIdParams, ResolveIdResult, TransformResult, TsFnHooks, WriteFile, + LoadResult, ResolveIdParams, ResolveIdResult, TransformResult, TsFnHooks, WatchChangesParams, + WriteFile, }; fn content_from_result(result: TransformResult) -> Result { @@ -121,6 +122,18 @@ impl Plugin for JsPlugin { Ok(()) } + fn watch_changes(&self, id: &str, event: &str, _context: &Arc) -> Result<()> { + if let Some(hook) = &self.hooks.watch_changes { + hook.call(( + id.to_string(), + WatchChangesParams { + event: event.to_string(), + }, + ))? + } + Ok(()) + } + fn write_bundle(&self, _context: &Arc) -> Result<()> { if let Some(hook) = &self.hooks.write_bundle { hook.call(())? diff --git a/crates/mako/src/dev.rs b/crates/mako/src/dev.rs index e2a9044cf..4f59f2ac0 100644 --- a/crates/mako/src/dev.rs +++ b/crates/mako/src/dev.rs @@ -346,12 +346,6 @@ impl DevServer { "hot update chunks generated, next_full_hash: {:?}", next_hash ); - // if !has_missing_deps { - // println!( - // "Hot rebuilt in {}", - // format!("{}ms", t_compiler.elapsed().as_millis()).bold() - // ); - // } if let Err(e) = next_hash { eprintln!("Error in watch: {:?}", e); return Err(e); @@ -391,7 +385,6 @@ impl DevServer { "Full rebuilt in {}", format!("{}ms", t_compiler.elapsed().as_millis()).bold() ); - let params = PluginGenerateEndParams { is_first_compile: false, time: t_compiler.elapsed().as_millis() as i64, @@ -401,12 +394,18 @@ impl DevServer { .context .plugin_driver .generate_end(¶ms, &compiler.context) - .unwrap(); + .map_err(|e| { + debug!("generate end failed: {:?}", e); + e + })?; compiler .context .plugin_driver .write_bundle(&compiler.context) - .unwrap(); + .map_err(|e| { + debug!("write bundle failed: {:?}", e); + e + })?; } let receiver_count = txws.receiver_count(); diff --git a/crates/mako/src/dev/update.rs b/crates/mako/src/dev/update.rs index 3f4a22927..3874b17cb 100644 --- a/crates/mako/src/dev/update.rs +++ b/crates/mako/src/dev/update.rs @@ -186,12 +186,27 @@ impl Compiler { for (path, update_type) in paths { match update_type { UpdateType::Add => { + self.context.plugin_driver.watch_changes( + &path.to_string_lossy(), + "create", + &self.context, + )?; added.push(path); } UpdateType::Remove => { + self.context.plugin_driver.watch_changes( + &path.to_string_lossy(), + "delete", + &self.context, + )?; removed.push(path); } UpdateType::Modify => { + self.context.plugin_driver.watch_changes( + &path.to_string_lossy(), + "update", + &self.context, + )?; modified.push(path); } } diff --git a/crates/mako/src/plugin.rs b/crates/mako/src/plugin.rs index bdc4ff793..62ac2ffaf 100644 --- a/crates/mako/src/plugin.rs +++ b/crates/mako/src/plugin.rs @@ -151,6 +151,10 @@ pub trait Plugin: Any + Send + Sync { Ok(()) } + fn watch_changes(&self, _id: &str, _event: &str, _context: &Arc) -> Result<()> { + Ok(()) + } + fn runtime_plugins(&self, _context: &Arc) -> Result> { Ok(Vec::new()) } @@ -335,6 +339,13 @@ impl PluginDriver { Ok(()) } + pub fn watch_changes(&self, id: &str, event: &str, context: &Arc) -> Result<()> { + for plugin in &self.plugins { + plugin.watch_changes(id, event, context)?; + } + Ok(()) + } + pub fn generate_begin(&self, context: &Arc) -> Result<()> { for plugin in &self.plugins { plugin.generate_begin(context)?; diff --git a/docs/config.md b/docs/config.md index 0cdffc366..2a5897b1a 100644 --- a/docs/config.md +++ b/docs/config.md @@ -574,6 +574,7 @@ Specify the plugins to use. }; }) => void; writeBundle?: () => void; + watchChanges?: (id: string, params: { event: "create" | "delete" | "update" }) => void; load?: (filePath: string) => Promise<{ content: string, type: 'css'|'js'|'jsx'|'ts'|'tsx' }>; loadInclude?: (filePath: string) => boolean; resolveId?: (id: string, importer: string, { isEntry: bool }) => Promise<{ id: string, external: bool }>; diff --git a/docs/config.zh-CN.md b/docs/config.zh-CN.md index 08d9868b1..2558196f2 100644 --- a/docs/config.zh-CN.md +++ b/docs/config.zh-CN.md @@ -572,6 +572,7 @@ import(/* webpackIgnore: true */ "./foo"); }; }) => void; writeBundle?: () => void; + watchChanges?: (id: string, params: { event: "create" | "delete" | "update" }) => void; load?: (filePath: string) => Promise<{ content: string, type: 'css'|'js'|'jsx'|'ts'|'tsx' }>; loadInclude?: (filePath: string) => boolean; resolveId?: (id: string, importer: string, { isEntry: bool }) => Promise<{ id: string, external: bool }>; diff --git a/packages/mako/binding.d.ts b/packages/mako/binding.d.ts index a15d2ff1c..fa889880d 100644 --- a/packages/mako/binding.d.ts +++ b/packages/mako/binding.d.ts @@ -52,6 +52,10 @@ export interface JsHooks { }; }) => void; writeBundle?: () => Promise; + watchChanges?: ( + id: string, + change: { event: 'create' | 'delete' | 'update' }, + ) => Promise | void; onGenerateFile?: (path: string, content: Buffer) => Promise; buildStart?: () => Promise; buildEnd?: () => Promise; @@ -74,6 +78,9 @@ export interface LoadResult { content: string; type: string; } +export interface WatchChangesParams { + event: string; +} export interface ResolveIdResult { id: string; external: boolean | null;