diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index c8efb922eca65..7095dc54da096 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -27,14 +27,15 @@ use owo_colors::OwoColorize; use turbo_malloc::TurboMalloc; use turbo_tasks::{ util::{FormatBytes, FormatDuration}, - RawVc, StatsType, TransientInstance, TransientValue, TurboTasks, TurboTasksBackendApi, Value, + CollectiblesSource, RawVc, StatsType, TransientInstance, TransientValue, TurboTasks, + TurboTasksBackendApi, Value, }; use turbo_tasks_fs::{DiskFileSystemVc, FileSystem, FileSystemVc}; use turbo_tasks_memory::MemoryBackend; -use turbopack_cli_utils::issue::{ConsoleUi, ConsoleUiVc, LogOptions}; +use turbopack_cli_utils::issue::{ConsoleUiVc, LogOptions}; use turbopack_core::{ environment::ServerAddr, - issue::IssueSeverity, + issue::{IssueReporter, IssueReporterVc, IssueSeverity, IssueVc}, resolve::{parse::RequestVc, pattern::QueryMapVc}, server_fs::ServerFileSystemVc, }; @@ -62,6 +63,7 @@ pub struct NextDevServerBuilder { entry_requests: Vec, eager_compile: bool, hostname: Option, + issue_reporter: Option>, port: Option, browserslist_query: String, log_level: IssueSeverity, @@ -83,6 +85,7 @@ impl NextDevServerBuilder { entry_requests: vec![], eager_compile: false, hostname: None, + issue_reporter: None, port: None, browserslist_query: "last 1 Chrome versions, last 1 Firefox versions, last 1 Safari \ versions, last 1 Edge versions" @@ -139,6 +142,14 @@ impl NextDevServerBuilder { self } + pub fn issue_reporter( + mut self, + issue_reporter: Box, + ) -> NextDevServerBuilder { + self.issue_reporter = Some(issue_reporter); + self + } + /// Attempts to find an open port to bind. fn find_port(&self, host: IpAddr, port: u16, max_attempts: u16) -> Result { // max_attempts of 1 means we loop 0 times. @@ -192,17 +203,22 @@ impl NextDevServerBuilder { let show_all = self.show_all; let log_detail = self.log_detail; let browserslist_query = self.browserslist_query; - let log_options = LogOptions { + let log_options = Arc::new(LogOptions { current_dir: current_dir().unwrap(), show_all, log_detail, log_level: self.log_level, - }; + }); let entry_requests = Arc::new(self.entry_requests); - let console_ui = Arc::new(ConsoleUi::new(log_options)); - let console_ui_to_dev_server = console_ui.clone(); let server_addr = Arc::new(server.addr); let tasks = turbo_tasks.clone(); + let issue_provider = self.issue_reporter.unwrap_or_else(|| { + // Initialize a ConsoleUi reporter if no custom reporter was provided + Box::new(move || ConsoleUiVc::new(log_options.clone().into()).into()) + }); + let issue_reporter_arc = Arc::new(move || issue_provider.get_issue_reporter()); + + let get_issue_reporter = issue_reporter_arc.clone(); let source = move || { source( root_dir.clone(), @@ -210,22 +226,31 @@ impl NextDevServerBuilder { entry_requests.clone().into(), eager_compile, turbo_tasks.clone().into(), - console_ui.clone().into(), + get_issue_reporter(), browserslist_query.clone(), server_addr.clone().into(), ) }; - Ok(server.serve(tasks, source, console_ui_to_dev_server)) + Ok(server.serve(tasks, source, issue_reporter_arc.clone())) } } -async fn handle_issues>(source: T, console_ui: ConsoleUiVc) -> Result<()> { - let state = console_ui - .group_and_display_issues(TransientValue::new(source.into())) +async fn handle_issues + CollectiblesSource + Copy>( + source: T, + issue_reporter: IssueReporterVc, +) -> Result<()> { + let issues = IssueVc::peek_issues_with_path(source) + .await? + .strongly_consistent() .await?; - if state.has_fatal { + issue_reporter.report_issues( + TransientInstance::new(issues.clone()), + TransientValue::new(source.into()), + ); + + if issues.has_fatal().await? { Err(anyhow!("Fatal issue(s) occurred")) } else { Ok(()) @@ -233,17 +258,17 @@ async fn handle_issues>(source: T, console_ui: ConsoleUiVc) -> Re } #[turbo_tasks::function] -async fn project_fs(project_dir: &str, console_ui: ConsoleUiVc) -> Result { +async fn project_fs(project_dir: &str, issue_reporter: IssueReporterVc) -> Result { let disk_fs = DiskFileSystemVc::new("project".to_string(), project_dir.to_string()); - handle_issues(disk_fs, console_ui).await?; + handle_issues(disk_fs, issue_reporter).await?; disk_fs.await?.start_watching()?; Ok(disk_fs.into()) } #[turbo_tasks::function] -async fn output_fs(project_dir: &str, console_ui: ConsoleUiVc) -> Result { +async fn output_fs(project_dir: &str, issue_reporter: IssueReporterVc) -> Result { let disk_fs = DiskFileSystemVc::new("output".to_string(), project_dir.to_string()); - handle_issues(disk_fs, console_ui).await?; + handle_issues(disk_fs, issue_reporter).await?; disk_fs.await?.start_watching()?; Ok(disk_fs.into()) } @@ -256,13 +281,12 @@ async fn source( entry_requests: TransientInstance>, eager_compile: bool, turbo_tasks: TransientInstance>, - console_ui: TransientInstance, + issue_reporter: IssueReporterVc, browserslist_query: String, server_addr: TransientInstance, ) -> Result { - let console_ui = (*console_ui).clone().cell(); - let output_fs = output_fs(&project_dir, console_ui); - let fs = project_fs(&root_dir, console_ui); + let output_fs = output_fs(&project_dir, issue_reporter); + let fs = project_fs(&root_dir, issue_reporter); let project_relative = project_dir.strip_prefix(&root_dir).unwrap(); let project_relative = project_relative .strip_prefix(MAIN_SEPARATOR) @@ -372,9 +396,9 @@ async fn source( .cell() .into(); - handle_issues(dev_server_fs, console_ui).await?; - handle_issues(web_source, console_ui).await?; - handle_issues(page_source, console_ui).await?; + handle_issues(dev_server_fs, issue_reporter).await?; + handle_issues(web_source, issue_reporter).await?; + handle_issues(page_source, issue_reporter).await?; Ok(source) } @@ -551,3 +575,16 @@ fn profile_timeout( ) -> impl Future { future } + +pub trait IssueReporterProvider: Send + Sync + 'static { + fn get_issue_reporter(&self) -> IssueReporterVc; +} + +impl IssueReporterProvider for T +where + T: Fn() -> IssueReporterVc + Send + Sync + Clone + 'static, +{ + fn get_issue_reporter(&self) -> IssueReporterVc { + self() + } +}