summaryrefslogtreecommitdiff
path: root/cli/worker.rs
diff options
context:
space:
mode:
authorBartek IwaƄczuk <biwanczuk@gmail.com>2023-10-31 01:25:58 +0100
committerGitHub <noreply@github.com>2023-10-31 01:25:58 +0100
commit1713df13524ad20c6bd0413bcf4aa57adc3f9735 (patch)
treea558239a7f483cab10b83305b333d5ef9657bd3e /cli/worker.rs
parent48c5c3a3fb2f43716528db8915b36e55c411d94f (diff)
feat: deno run --unstable-hmr (#20876)
This commit adds `--unstable-hmr` flag, that enabled Hot Module Replacement. This flag works like `--watch` and accepts the same arguments. If HMR is not possible the process will be restarted instead. Currently HMR is only supported in `deno run` subcommand. Upon HMR a `CustomEvent("hmr")` will be dispatched that contains information which file was changed in its `details` property. --------- Co-authored-by: Valentin Anger <syrupthinker@gryphno.de> Co-authored-by: David Sherret <dsherret@gmail.com>
Diffstat (limited to 'cli/worker.rs')
-rw-r--r--cli/worker.rs74
1 files changed, 70 insertions, 4 deletions
diff --git a/cli/worker.rs b/cli/worker.rs
index d8738d492..58bd96642 100644
--- a/cli/worker.rs
+++ b/cli/worker.rs
@@ -43,15 +43,20 @@ use deno_runtime::BootstrapOptions;
use deno_runtime::WorkerLogLevel;
use deno_semver::npm::NpmPackageReqReference;
use deno_semver::package::PackageReqReference;
+use tokio::select;
use crate::args::package_json::PackageJsonDeps;
use crate::args::StorageKeyResolver;
+use crate::emit::Emitter;
use crate::errors;
use crate::npm::CliNpmResolver;
use crate::ops;
use crate::tools;
use crate::tools::coverage::CoverageCollector;
+use crate::tools::run::hmr::HmrRunner;
use crate::util::checksum;
+use crate::util::file_watcher::WatcherCommunicator;
+use crate::util::file_watcher::WatcherRestartMode;
use crate::version;
pub trait ModuleLoaderFactory: Send + Sync {
@@ -83,6 +88,7 @@ pub struct CliMainWorkerOptions {
pub coverage_dir: Option<String>,
pub enable_testing_features: bool,
pub has_node_modules_dir: bool,
+ pub hmr: bool,
pub inspect_brk: bool,
pub inspect_wait: bool,
pub is_inspecting: bool,
@@ -108,6 +114,8 @@ struct SharedWorkerState {
module_loader_factory: Box<dyn ModuleLoaderFactory>,
root_cert_store_provider: Arc<dyn RootCertStoreProvider>,
fs: Arc<dyn deno_fs::FileSystem>,
+ emitter: Option<Arc<Emitter>>,
+ maybe_file_watcher_communicator: Option<Arc<WatcherCommunicator>>,
maybe_inspector_server: Option<Arc<InspectorServer>>,
maybe_lockfile: Option<Arc<Mutex<Lockfile>>>,
feature_checker: Arc<FeatureChecker>,
@@ -137,6 +145,8 @@ impl CliMainWorker {
pub async fn run(&mut self) -> Result<i32, AnyError> {
let mut maybe_coverage_collector =
self.maybe_setup_coverage_collector().await?;
+ let mut maybe_hmr_runner = self.maybe_setup_hmr_runner().await?;
+
log::debug!("main_module {}", self.main_module);
if self.is_main_cjs {
@@ -153,10 +163,34 @@ impl CliMainWorker {
self.worker.dispatch_load_event(located_script_name!())?;
loop {
- self
- .worker
- .run_event_loop(maybe_coverage_collector.is_none())
- .await?;
+ if let Some(hmr_runner) = maybe_hmr_runner.as_mut() {
+ let watcher_communicator =
+ self.shared.maybe_file_watcher_communicator.clone().unwrap();
+
+ let hmr_future = hmr_runner.run().boxed_local();
+ let event_loop_future = self.worker.run_event_loop(false).boxed_local();
+
+ let result;
+ select! {
+ hmr_result = hmr_future => {
+ result = hmr_result;
+ },
+ event_loop_result = event_loop_future => {
+ result = event_loop_result;
+ }
+ }
+ if let Err(e) = result {
+ watcher_communicator
+ .change_restart_mode(WatcherRestartMode::Automatic);
+ return Err(e);
+ }
+ } else {
+ self
+ .worker
+ .run_event_loop(maybe_coverage_collector.is_none())
+ .await?;
+ }
+
if !self
.worker
.dispatch_beforeunload_event(located_script_name!())?
@@ -173,6 +207,12 @@ impl CliMainWorker {
.with_event_loop(coverage_collector.stop_collecting().boxed_local())
.await?;
}
+ if let Some(hmr_runner) = maybe_hmr_runner.as_mut() {
+ self
+ .worker
+ .with_event_loop(hmr_runner.stop().boxed_local())
+ .await?;
+ }
Ok(self.worker.exit_code())
}
@@ -287,6 +327,28 @@ impl CliMainWorker {
}
}
+ pub async fn maybe_setup_hmr_runner(
+ &mut self,
+ ) -> Result<Option<HmrRunner>, AnyError> {
+ if !self.shared.options.hmr {
+ return Ok(None);
+ }
+
+ let watcher_communicator =
+ self.shared.maybe_file_watcher_communicator.clone().unwrap();
+ let emitter = self.shared.emitter.clone().unwrap();
+
+ let session = self.worker.create_inspector_session().await;
+ let mut hmr_runner = HmrRunner::new(emitter, session, watcher_communicator);
+
+ self
+ .worker
+ .with_event_loop(hmr_runner.start().boxed_local())
+ .await?;
+
+ Ok(Some(hmr_runner))
+ }
+
pub fn execute_script_static(
&mut self,
name: &'static str,
@@ -313,6 +375,8 @@ impl CliMainWorkerFactory {
module_loader_factory: Box<dyn ModuleLoaderFactory>,
root_cert_store_provider: Arc<dyn RootCertStoreProvider>,
fs: Arc<dyn deno_fs::FileSystem>,
+ emitter: Option<Arc<Emitter>>,
+ maybe_file_watcher_communicator: Option<Arc<WatcherCommunicator>>,
maybe_inspector_server: Option<Arc<InspectorServer>>,
maybe_lockfile: Option<Arc<Mutex<Lockfile>>>,
feature_checker: Arc<FeatureChecker>,
@@ -330,7 +394,9 @@ impl CliMainWorkerFactory {
compiled_wasm_module_store: Default::default(),
module_loader_factory,
root_cert_store_provider,
+ emitter,
fs,
+ maybe_file_watcher_communicator,
maybe_inspector_server,
maybe_lockfile,
feature_checker,