Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7bea9f1

Browse files
authored
feat: support watchChange hooks (#2412)
<!-- Thank you for contributing! --> ### Description <!-- Please insert your description here and provide especially info about the "what" this PR is solving -->
1 parent 7ab8722 commit 7bea9f1

18 files changed

Lines changed: 278 additions & 87 deletions

File tree

Lines changed: 2 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
1-
use std::{collections::HashMap, fmt::Display, path::PathBuf, sync::Arc};
1+
use std::sync::Arc;
22

33
use dashmap::DashMap;
4+
use rolldown_common::{WatcherEvent, WatcherEventData};
45

56
pub type SharedWatcherEmitter = Arc<WatcherEmitter>;
67

7-
#[allow(dead_code)]
8-
#[derive(Default, Clone)]
9-
pub struct WatcherEventData(Option<Arc<HashMap<String, String>>>);
10-
118
pub type Listener = Box<dyn Fn(WatcherEventData) + Send + Sync>;
129

1310
pub struct WatcherEmitter {
@@ -41,67 +38,3 @@ impl WatcherEmitter {
4138
self.listeners.entry(event).or_default().push(Box::new(listener));
4239
}
4340
}
44-
45-
#[derive(PartialEq, Eq, Hash)]
46-
pub enum WatcherEvent {
47-
Close,
48-
Event,
49-
ReStart,
50-
Change,
51-
}
52-
53-
pub enum BundleEventKind {
54-
Start,
55-
BundleStart,
56-
BundleEnd,
57-
End,
58-
}
59-
60-
impl Display for BundleEventKind {
61-
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
62-
match self {
63-
BundleEventKind::Start => write!(f, "START"),
64-
BundleEventKind::BundleStart => write!(f, "BUNDLE_START"),
65-
BundleEventKind::BundleEnd => write!(f, "BUNDLE_END"),
66-
BundleEventKind::End => write!(f, "END"),
67-
}
68-
}
69-
}
70-
71-
impl From<BundleEventKind> for WatcherEventData {
72-
fn from(kind: BundleEventKind) -> Self {
73-
let mut map = HashMap::default();
74-
map.insert("code".to_string(), kind.to_string());
75-
Self(Some(Arc::new(map)))
76-
}
77-
}
78-
79-
pub enum WatcherChangeKind {
80-
Create,
81-
Update,
82-
Delete,
83-
}
84-
85-
impl Display for WatcherChangeKind {
86-
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
87-
match self {
88-
WatcherChangeKind::Create => write!(f, "create"),
89-
WatcherChangeKind::Update => write!(f, "update"),
90-
WatcherChangeKind::Delete => write!(f, "delete"),
91-
}
92-
}
93-
}
94-
95-
pub struct WatcherChange {
96-
pub path: PathBuf,
97-
pub kind: WatcherChangeKind,
98-
}
99-
100-
impl From<WatcherChange> for WatcherEventData {
101-
fn from(event: WatcherChange) -> Self {
102-
let mut map = HashMap::default();
103-
map.insert("id".to_string(), event.path.to_string_lossy().to_string());
104-
map.insert("kind".to_string(), event.kind.to_string());
105-
Self(Some(Arc::new(map)))
106-
}
107-
}

crates/rolldown/src/watcher/watcher.rs

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,17 @@ use arcstr::ArcStr;
44
use notify::{
55
event::ModifyKind, Config, RecommendedWatcher, RecursiveMode, Watcher as NotifyWatcher,
66
};
7+
use rolldown_common::{BundleEventKind, WatcherChange, WatcherChangeKind, WatcherEvent};
8+
use rolldown_plugin::SharedPluginDriver;
79
use rustc_hash::FxHashSet;
810
use tokio::sync::mpsc::channel;
911

1012
use crate::Bundler;
1113

12-
use super::emitter::{
13-
BundleEventKind, SharedWatcherEmitter, WatcherChange, WatcherChangeKind, WatcherEvent,
14-
};
1514
use anyhow::Result;
1615

16+
use super::emitter::SharedWatcherEmitter;
17+
1718
pub struct Watcher {
1819
inner: RecommendedWatcher,
1920
emitter: SharedWatcherEmitter,
@@ -117,25 +118,20 @@ pub async fn setup_watcher(emitter: SharedWatcherEmitter, bundler: &mut Bundler)
117118
match res {
118119
Ok(event) => {
119120
for path in event.paths {
121+
let id = path.to_string_lossy();
120122
match event.kind {
121123
notify::EventKind::Create(_) => {
122-
emitter.emit(
123-
WatcherEvent::Change,
124-
WatcherChange { path, kind: WatcherChangeKind::Create }.into(),
125-
);
124+
on_change(&emitter, &bundler.plugin_driver, id.as_ref(), WatcherChangeKind::Create)
125+
.await?;
126126
}
127127
notify::EventKind::Modify(ModifyKind::Data(_) | ModifyKind::Any /* windows*/) => {
128-
emitter.emit(
129-
WatcherEvent::Change,
130-
WatcherChange { path, kind: WatcherChangeKind::Update }.into(),
131-
);
128+
on_change(&emitter, &bundler.plugin_driver, id.as_ref(), WatcherChangeKind::Update)
129+
.await?;
132130
watcher.invalidate(bundler);
133131
}
134132
notify::EventKind::Remove(_) => {
135-
emitter.emit(
136-
WatcherEvent::Change,
137-
WatcherChange { path, kind: WatcherChangeKind::Delete }.into(),
138-
);
133+
on_change(&emitter, &bundler.plugin_driver, id.as_ref(), WatcherChangeKind::Delete)
134+
.await?;
139135
}
140136
_ => {}
141137
}
@@ -147,3 +143,14 @@ pub async fn setup_watcher(emitter: SharedWatcherEmitter, bundler: &mut Bundler)
147143

148144
Ok(())
149145
}
146+
147+
async fn on_change(
148+
emitter: &SharedWatcherEmitter,
149+
plugin_driver: &SharedPluginDriver,
150+
path: &str,
151+
kind: WatcherChangeKind,
152+
) -> Result<()> {
153+
emitter.emit(WatcherEvent::Change, WatcherChange { path: path.into(), kind }.into());
154+
plugin_driver.watch_change(path, kind).await?;
155+
Ok(())
156+
}

crates/rolldown_binding/src/options/plugin/binding_plugin_options.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,13 @@ pub struct BindingPluginOptions {
152152
pub close_bundle: Option<MaybeAsyncJsCallback<BindingPluginContext, ()>>,
153153
pub close_bundle_meta: Option<BindingPluginHookMeta>,
154154

155+
#[serde(skip_deserializing)]
156+
#[napi(
157+
ts_type = "(ctx: BindingPluginContext, path: string, event: string) => MaybePromise<VoidNullable>"
158+
)]
159+
pub watch_change: Option<MaybeAsyncJsCallback<(BindingPluginContext, String, String), ()>>,
160+
pub watch_change_meta: Option<BindingPluginHookMeta>,
161+
155162
#[serde(skip_deserializing)]
156163
#[napi(ts_type = "(ctx: BindingPluginContext, chunk: RenderedChunk) => void")]
157164
pub banner: Option<MaybeAsyncJsCallback<(BindingPluginContext, RenderedChunk), Option<String>>>,

crates/rolldown_binding/src/options/plugin/js_plugin.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,22 @@ impl Plugin for JsPlugin {
399399
self.close_bundle_meta.as_ref().map(Into::into)
400400
}
401401

402+
async fn watch_change(
403+
&self,
404+
ctx: &rolldown_plugin::PluginContext,
405+
path: &str,
406+
event: rolldown_common::WatcherChangeKind,
407+
) -> rolldown_plugin::HookNoopReturn {
408+
if let Some(cb) = &self.watch_change {
409+
cb.await_call((ctx.clone().into(), path.to_string(), event.to_string())).await?;
410+
}
411+
Ok(())
412+
}
413+
414+
fn watch_change_meta(&self) -> Option<rolldown_plugin::PluginHookMeta> {
415+
self.watch_change_meta.as_ref().map(Into::into)
416+
}
417+
402418
fn transform_filter(&self) -> anyhow::Result<Option<TransformHookFilter>> {
403419
match self.inner.transform_filter {
404420
Some(ref item) => {

crates/rolldown_common/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ pub use crate::{
9696
types::symbol_or_member_expr_ref::SymbolOrMemberExprRef,
9797
types::symbol_ref::SymbolRef,
9898
types::symbol_ref_db::{SymbolRefDb, SymbolRefDbForModule, SymbolRefFlags},
99+
types::watch::{
100+
BundleEventKind, WatcherChange, WatcherChangeKind, WatcherEvent, WatcherEventData,
101+
},
99102
types::wrap_kind::WrapKind,
100103
};
101104
pub use bundler_options::*;

crates/rolldown_common/src/types/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,5 @@ pub mod str_or_bytes;
3939
pub mod symbol_or_member_expr_ref;
4040
pub mod symbol_ref;
4141
pub mod symbol_ref_db;
42+
pub mod watch;
4243
pub mod wrap_kind;
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
use std::{collections::HashMap, fmt::Display, sync::Arc};
2+
3+
use arcstr::ArcStr;
4+
5+
#[allow(dead_code)]
6+
#[derive(Default, Clone)]
7+
pub struct WatcherEventData(Option<Arc<HashMap<String, String>>>);
8+
9+
#[derive(PartialEq, Eq, Hash)]
10+
pub enum WatcherEvent {
11+
Close,
12+
Event,
13+
ReStart,
14+
Change,
15+
}
16+
17+
pub struct WatcherChange {
18+
pub path: ArcStr,
19+
pub kind: WatcherChangeKind,
20+
}
21+
22+
impl From<WatcherChange> for WatcherEventData {
23+
fn from(event: WatcherChange) -> Self {
24+
let mut map = HashMap::default();
25+
map.insert("id".to_string(), event.path.to_string());
26+
map.insert("kind".to_string(), event.kind.to_string());
27+
Self(Some(Arc::new(map)))
28+
}
29+
}
30+
31+
pub enum BundleEventKind {
32+
Start,
33+
BundleStart,
34+
BundleEnd,
35+
End,
36+
}
37+
38+
impl Display for BundleEventKind {
39+
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
40+
match self {
41+
BundleEventKind::Start => write!(f, "START"),
42+
BundleEventKind::BundleStart => write!(f, "BUNDLE_START"),
43+
BundleEventKind::BundleEnd => write!(f, "BUNDLE_END"),
44+
BundleEventKind::End => write!(f, "END"),
45+
}
46+
}
47+
}
48+
49+
impl From<BundleEventKind> for WatcherEventData {
50+
fn from(kind: BundleEventKind) -> Self {
51+
let mut map = HashMap::default();
52+
map.insert("code".to_string(), kind.to_string());
53+
Self(Some(Arc::new(map)))
54+
}
55+
}
56+
57+
#[derive(Copy, Clone)]
58+
pub enum WatcherChangeKind {
59+
Create,
60+
Update,
61+
Delete,
62+
}
63+
64+
impl Display for WatcherChangeKind {
65+
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
66+
match self {
67+
WatcherChangeKind::Create => write!(f, "create"),
68+
WatcherChangeKind::Update => write!(f, "update"),
69+
WatcherChangeKind::Delete => write!(f, "delete"),
70+
}
71+
}
72+
}

crates/rolldown_plugin/src/plugin.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::{
1414
HookRenderChunkOutput, HookResolveIdArgs, HookResolveIdOutput, HookTransformArgs,
1515
};
1616
use anyhow::Result;
17-
use rolldown_common::{ModuleInfo, Output, RollupRenderedChunk};
17+
use rolldown_common::{ModuleInfo, Output, RollupRenderedChunk, WatcherChangeKind};
1818
use rolldown_ecmascript::EcmaAst;
1919

2020
pub type HookResolveIdReturn = Result<Option<HookResolveIdOutput>>;
@@ -252,6 +252,19 @@ pub trait Plugin: Any + Debug + Send + Sync + 'static {
252252
None
253253
}
254254

255+
fn watch_change(
256+
&self,
257+
_ctx: &PluginContext,
258+
_path: &str,
259+
_event: WatcherChangeKind,
260+
) -> impl std::future::Future<Output = HookNoopReturn> + Send {
261+
async { Ok(()) }
262+
}
263+
264+
fn watch_change_meta(&self) -> Option<PluginHookMeta> {
265+
None
266+
}
267+
255268
// --- experimental hooks ---
256269

257270
fn transform_ast(

crates/rolldown_plugin/src/plugin_driver/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use crate::{
1818
mod build_hooks;
1919
mod hook_filter;
2020
mod output_hooks;
21+
mod watch_hooks;
2122

2223
pub type SharedPluginDriver = Arc<PluginDriver>;
2324

@@ -163,6 +164,7 @@ pub struct HookOrderIndicates {
163164
pub order_by_generate_bundle_meta: Vec<PluginIdx>,
164165
pub order_by_write_bundle_meta: Vec<PluginIdx>,
165166
pub order_by_close_bundle_meta: Vec<PluginIdx>,
167+
pub order_by_watch_change_meta: Vec<PluginIdx>,
166168
pub order_by_transform_ast_meta: Vec<PluginIdx>,
167169
}
168170

@@ -217,6 +219,9 @@ impl HookOrderIndicates {
217219
order_by_close_bundle_meta: Self::sort_plugins_by_hook_meta(index_plugins, |p| {
218220
p.call_close_bundle_meta()
219221
}),
222+
order_by_watch_change_meta: Self::sort_plugins_by_hook_meta(index_plugins, |p| {
223+
p.call_watch_change_meta()
224+
}),
220225
order_by_transform_ast_meta: Self::sort_plugins_by_hook_meta(index_plugins, |p| {
221226
p.call_transform_ast_meta()
222227
}),
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
use crate::HookNoopReturn;
2+
use crate::PluginDriver;
3+
use rolldown_common::WatcherChangeKind;
4+
5+
impl PluginDriver {
6+
pub async fn watch_change(&self, path: &str, event: WatcherChangeKind) -> HookNoopReturn {
7+
for (_, plugin, ctx) in self.iter_plugin_with_context_by_order(&self.order_by_watch_change_meta)
8+
{
9+
plugin.call_watch_change(ctx, path, event).await?;
10+
}
11+
Ok(())
12+
}
13+
}

0 commit comments

Comments
 (0)