diff options
author | Yusuke Tanaka <yusuktan@maguro.dev> | 2020-11-23 05:45:44 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-11-22 21:45:44 +0100 |
commit | e3f73d3ec0aa822c9d125374ec34b7d8d5dfc0a5 (patch) | |
tree | 1f61389d70aeb116bb7075d5489c042d5d8a2d52 /cli/main.rs | |
parent | 17d4cd92133bb822ff3a4f2f5bb32dfd17f99282 (diff) |
feat(unstable): Support --watch flag for bundle and fmt subcommands (#8276)
This commit adds support for "--watch" flag for "bundle"
and "fmt" subcommands.
In addition to this, it refactors "run --watch" command so that
module resolution will occur every time the file watcher detects
file addition/deletion, which allows the watcher to observe a file
that is newly added to the dependency as well.
Diffstat (limited to 'cli/main.rs')
-rw-r--r-- | cli/main.rs | 281 |
1 files changed, 176 insertions, 105 deletions
diff --git a/cli/main.rs b/cli/main.rs index e351060f1..47dd4087d 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -302,84 +302,130 @@ async fn bundle_command( source_file: String, out_file: Option<PathBuf>, ) -> Result<(), AnyError> { - let module_specifier = ModuleSpecifier::resolve_url_or_path(&source_file)?; + let debug = flags.log_level == Some(log::Level::Debug); - debug!(">>>>> bundle START"); - let program_state = ProgramState::new(flags.clone())?; + let module_resolver = || { + let flags = flags.clone(); + let source_file = source_file.clone(); + async move { + let module_specifier = + ModuleSpecifier::resolve_url_or_path(&source_file)?; + + debug!(">>>>> bundle START"); + let program_state = ProgramState::new(flags.clone())?; + + info!( + "{} {}", + colors::green("Bundle"), + module_specifier.to_string() + ); + + let handler = Rc::new(RefCell::new(FetchHandler::new( + &program_state, + // when bundling, dynamic imports are only access for their type safety, + // therefore we will allow the graph to access any module. + Permissions::allow_all(), + )?)); + let mut builder = module_graph::GraphBuilder::new( + handler, + program_state.maybe_import_map.clone(), + program_state.lockfile.clone(), + ); + builder.add(&module_specifier, false).await?; + let module_graph = builder.get_graph(); + + if !flags.no_check { + // TODO(@kitsonk) support bundling for workers + let lib = if flags.unstable { + module_graph::TypeLib::UnstableDenoWindow + } else { + module_graph::TypeLib::DenoWindow + }; + let result_info = + module_graph.clone().check(module_graph::CheckOptions { + debug, + emit: false, + lib, + maybe_config_path: flags.config_path.clone(), + reload: flags.reload, + })?; + + debug!("{}", result_info.stats); + if let Some(ignored_options) = result_info.maybe_ignored_options { + eprintln!("{}", ignored_options); + } + if !result_info.diagnostics.is_empty() { + return Err(generic_error(result_info.diagnostics.to_string())); + } + } - info!( - "{} {}", - colors::green("Bundle"), - module_specifier.to_string() - ); + let mut paths_to_watch: Vec<PathBuf> = module_graph + .get_modules() + .iter() + .filter_map(|specifier| specifier.as_url().to_file_path().ok()) + .collect(); - let handler = Rc::new(RefCell::new(FetchHandler::new( - &program_state, - // when bundling, dynamic imports are only access for their type safety, - // therefore we will allow the graph to access any module. - Permissions::allow_all(), - )?)); - let mut builder = module_graph::GraphBuilder::new( - handler, - program_state.maybe_import_map.clone(), - program_state.lockfile.clone(), - ); - builder.add(&module_specifier, false).await?; - let graph = builder.get_graph(); + if let Some(import_map) = program_state.flags.import_map_path.as_ref() { + paths_to_watch + .push(fs_util::resolve_from_cwd(std::path::Path::new(import_map))?); + } - let debug = flags.log_level == Some(log::Level::Debug); - if !flags.no_check { - // TODO(@kitsonk) support bundling for workers - let lib = if flags.unstable { - module_graph::TypeLib::UnstableDenoWindow - } else { - module_graph::TypeLib::DenoWindow - }; - let graph = graph.clone(); - let result_info = graph.check(module_graph::CheckOptions { - debug, - emit: false, - lib, - maybe_config_path: flags.config_path.clone(), - reload: flags.reload, - })?; - - debug!("{}", result_info.stats); - if let Some(ignored_options) = result_info.maybe_ignored_options { - eprintln!("{}", ignored_options); + Ok((paths_to_watch, module_graph)) } - if !result_info.diagnostics.is_empty() { - return Err(generic_error(result_info.diagnostics.to_string())); - } - } + .boxed_local() + }; - let (output, stats, maybe_ignored_options) = - graph.bundle(module_graph::BundleOptions { - debug, - maybe_config_path: flags.config_path, - })?; + let operation = |module_graph: module_graph::Graph| { + let flags = flags.clone(); + let out_file = out_file.clone(); + async move { + let (output, stats, maybe_ignored_options) = + module_graph.bundle(module_graph::BundleOptions { + debug, + maybe_config_path: flags.config_path, + })?; - if flags.no_check && maybe_ignored_options.is_some() { - let ignored_options = maybe_ignored_options.unwrap(); - eprintln!("{}", ignored_options); - } - debug!("{}", stats); - - debug!(">>>>> bundle END"); - - if let Some(out_file_) = out_file.as_ref() { - let output_bytes = output.as_bytes(); - let output_len = output_bytes.len(); - fs_util::write_file(out_file_, output_bytes, 0o644)?; - info!( - "{} {:?} ({})", - colors::green("Emit"), - out_file_, - colors::gray(&info::human_size(output_len as f64)) - ); + match maybe_ignored_options { + Some(ignored_options) if flags.no_check => { + eprintln!("{}", ignored_options); + } + _ => {} + } + debug!("{}", stats); + + debug!(">>>>> bundle END"); + + if let Some(out_file) = out_file.as_ref() { + let output_bytes = output.as_bytes(); + let output_len = output_bytes.len(); + fs_util::write_file(out_file, output_bytes, 0o644)?; + info!( + "{} {:?} ({})", + colors::green("Emit"), + out_file, + colors::gray(&info::human_size(output_len as f64)) + ); + } else { + println!("{}", output); + } + + Ok(()) + } + .boxed_local() + }; + + if flags.watch { + file_watcher::watch_func_with_module_resolution( + module_resolver, + operation, + "Bundle", + ) + .await?; } else { - println!("{}", output); + let (_, module_graph) = module_resolver().await?; + operation(module_graph).await?; } + Ok(()) } @@ -504,6 +550,20 @@ async fn doc_command( } } +async fn format_command( + flags: Flags, + args: Vec<PathBuf>, + ignore: Vec<PathBuf>, + check: bool, +) -> Result<(), AnyError> { + if args.len() == 1 && args[0].to_string_lossy() == "-" { + return tools::fmt::format_stdin(check); + } + + tools::fmt::format(args, ignore, check, flags.watch).await?; + Ok(()) +} + async fn run_repl(flags: Flags) -> Result<(), AnyError> { let main_module = ModuleSpecifier::resolve_url_or_path("./$deno$repl.ts").unwrap(); @@ -548,44 +608,49 @@ async fn run_from_stdin(flags: Flags) -> Result<(), AnyError> { } async fn run_with_watch(flags: Flags, script: String) -> Result<(), AnyError> { - let main_module = ModuleSpecifier::resolve_url_or_path(&script)?; - let program_state = ProgramState::new(flags.clone())?; + let module_resolver = || { + let script = script.clone(); + let flags = flags.clone(); + async move { + let main_module = ModuleSpecifier::resolve_url_or_path(&script)?; + let program_state = ProgramState::new(flags)?; + let handler = Rc::new(RefCell::new(FetchHandler::new( + &program_state, + Permissions::allow_all(), + )?)); + let mut builder = module_graph::GraphBuilder::new( + handler, + program_state.maybe_import_map.clone(), + program_state.lockfile.clone(), + ); + builder.add(&main_module, false).await?; + let module_graph = builder.get_graph(); + + // Find all local files in graph + let mut paths_to_watch: Vec<PathBuf> = module_graph + .get_modules() + .iter() + .filter_map(|specifier| specifier.as_url().to_file_path().ok()) + .collect(); + + if let Some(import_map) = program_state.flags.import_map_path.as_ref() { + paths_to_watch + .push(fs_util::resolve_from_cwd(std::path::Path::new(import_map))?); + } - let handler = Rc::new(RefCell::new(FetchHandler::new( - &program_state, - Permissions::allow_all(), - )?)); - let mut builder = module_graph::GraphBuilder::new( - handler, - program_state.maybe_import_map.clone(), - program_state.lockfile.clone(), - ); - builder.add(&main_module, false).await?; - let module_graph = builder.get_graph(); - - // Find all local files in graph - let mut paths_to_watch: Vec<PathBuf> = module_graph - .get_modules() - .iter() - .filter(|specifier| specifier.as_url().scheme() == "file") - .map(|specifier| specifier.as_url().to_file_path().unwrap()) - .collect(); - - if let Some(import_map) = program_state.flags.import_map_path.clone() { - paths_to_watch.push( - fs_util::resolve_from_cwd(std::path::Path::new(&import_map)).unwrap(), - ); - } + Ok((paths_to_watch, main_module)) + } + .boxed_local() + }; - // FIXME(bartlomieju): new file watcher is created on after each restart - file_watcher::watch_func(&paths_to_watch, move || { - // FIXME(bartlomieju): ProgramState must be created on each restart - otherwise file fetcher - // will use cached source files - let gs = ProgramState::new(flags.clone()).unwrap(); + let operation = |main_module: ModuleSpecifier| { + let flags = flags.clone(); let permissions = Permissions::from_flags(&flags); - let main_module = main_module.clone(); async move { - let mut worker = MainWorker::new(&gs, main_module.clone(), permissions); + let main_module = main_module.clone(); + let program_state = ProgramState::new(flags)?; + let mut worker = + MainWorker::new(&program_state, main_module.clone(), permissions); debug!("main_module {}", main_module); worker.execute_module(&main_module).await?; worker.execute("window.dispatchEvent(new Event('load'))")?; @@ -594,7 +659,13 @@ async fn run_with_watch(flags: Flags, script: String) -> Result<(), AnyError> { Ok(()) } .boxed_local() - }) + }; + + file_watcher::watch_func_with_module_resolution( + module_resolver, + operation, + "Process", + ) .await } @@ -806,7 +877,7 @@ pub fn main() { check, files, ignore, - } => tools::fmt::format(files, check, ignore).boxed_local(), + } => format_command(flags, files, ignore, check).boxed_local(), DenoSubcommand::Info { file, json } => { info_command(flags, file, json).boxed_local() } |