diff --git a/Cargo.lock b/Cargo.lock index ddf97f291da2..4f56b21490b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2393,16 +2393,6 @@ dependencies = [ "xshell", ] -[[package]] -name = "rspack-codespan-reporting" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc53b3a0e58f509a8b55bde278d44c05879f27a66819346e0fef193c6348e9f8" -dependencies = [ - "termcolor", - "unicode-width", -] - [[package]] name = "rspack_ast" version = "0.1.0" @@ -2634,7 +2624,6 @@ dependencies = [ "futures", "insta", "miette 5.10.0", - "rspack-codespan-reporting", "rspack_binding_options", "rspack_core", "rspack_fs", diff --git a/crates/node_binding/src/lib.rs b/crates/node_binding/src/lib.rs index 86781665b4c1..f08079a30975 100644 --- a/crates/node_binding/src/lib.rs +++ b/crates/node_binding/src/lib.rs @@ -15,7 +15,6 @@ use rspack_binding_options::BuiltinPlugin; use rspack_binding_values::SingleThreadedHashMap; use rspack_core::PluginExt; use rspack_fs_node::{AsyncNodeWritableFileSystem, ThreadsafeNodeFS}; -use rspack_napi_shared::NAPI_ENV; mod hook; mod loader; @@ -29,6 +28,7 @@ use loader::run_builtin_loader; use plugins::*; use rspack_binding_options::*; use rspack_binding_values::*; +use rspack_napi_shared::set_napi_env; use rspack_tracing::chrome::FlushGuard; #[cfg(not(target_os = "linux"))] @@ -223,7 +223,7 @@ impl ObjectFinalize for Rspack { impl Rspack { fn prepare_environment(env: &Env) { - NAPI_ENV.with(|napi_env| *napi_env.borrow_mut() = Some(env.raw())); + set_napi_env(env.raw()); } } diff --git a/crates/rspack_binding_options/src/lib.rs b/crates/rspack_binding_options/src/lib.rs index 4e0c9dc1bb15..d97a0a2b9901 100644 --- a/crates/rspack_binding_options/src/lib.rs +++ b/crates/rspack_binding_options/src/lib.rs @@ -1,2 +1,3 @@ +#![feature(try_blocks)] mod options; pub use options::*; diff --git a/crates/rspack_binding_options/src/options/raw_builtins/raw_banner.rs b/crates/rspack_binding_options/src/options/raw_builtins/raw_banner.rs index 7da6c4ce2c2d..192cd03d1ee6 100644 --- a/crates/rspack_binding_options/src/options/raw_builtins/raw_banner.rs +++ b/crates/rspack_binding_options/src/options/raw_builtins/raw_banner.rs @@ -4,10 +4,11 @@ use derivative::Derivative; use napi::{Either, Env, JsFunction}; use napi_derive::napi; use rspack_binding_values::JsChunk; -use rspack_error::{internal_error, Result}; +use rspack_error::{internal_error, miette::IntoDiagnostic, Result}; use rspack_napi_shared::{ + get_napi_env, threadsafe_function::{ThreadsafeFunction, ThreadsafeFunctionCallMode}, - JsRegExp, JsRegExpExt, NapiResultExt, NAPI_ENV, + JsRegExp, JsRegExpExt, NapiResultExt, }; use rspack_plugin_banner::{ BannerContent, BannerContentFnCtx, BannerPluginOptions, BannerRule, BannerRules, @@ -39,13 +40,11 @@ impl TryFrom for BannerContent { match value.0 { Either::A(s) => Ok(Self::String(s)), Either::B(f) => { - let func: ThreadsafeFunction = - NAPI_ENV.with(|env| -> anyhow::Result<_> { - let env = env.borrow().expect("Failed to get env with external"); - let func_use = rspack_binding_macros::js_fn_into_threadsafe_fn!(f, &Env::from(env)); - Ok(func_use) - })?; - let func = Arc::new(func); + let func: napi::Result> = try { + let env = unsafe { get_napi_env() }; + rspack_binding_macros::js_fn_into_threadsafe_fn!(f, &Env::from(env)) + }; + let func = Arc::new(func.expect("convert to threadsafe function failed")); Ok(BannerContent::Fn(Box::new( move |ctx: BannerContentFnCtx| { let func = func.clone(); diff --git a/crates/rspack_binding_options/src/options/raw_builtins/raw_swc_js_minimizer.rs b/crates/rspack_binding_options/src/options/raw_builtins/raw_swc_js_minimizer.rs index 631115b70fe6..4f3d80f53eb9 100644 --- a/crates/rspack_binding_options/src/options/raw_builtins/raw_swc_js_minimizer.rs +++ b/crates/rspack_binding_options/src/options/raw_builtins/raw_swc_js_minimizer.rs @@ -1,6 +1,6 @@ use napi::{bindgen_prelude::Either3, Either}; use napi_derive::napi; -use rspack_error::Result; +use rspack_error::{miette::IntoDiagnostic, Result}; use rspack_napi_shared::{JsRegExp, JsRegExpExt}; use rspack_plugin_swc_js_minimizer::{ SwcJsMinimizerRspackPluginOptions, SwcJsMinimizerRule, SwcJsMinimizerRules, @@ -34,7 +34,7 @@ fn try_deserialize_into<'de, T: 'de + Deserialize<'de>>( ) -> Result> { Ok(match value { Either::A(b) => BoolOrDataConfig::from_bool(*b), - Either::B(s) => BoolOrDataConfig::from_obj(serde_json::from_str(s)?), + Either::B(s) => BoolOrDataConfig::from_obj(serde_json::from_str(s).into_diagnostic()?), }) } @@ -50,7 +50,7 @@ impl TryFrom for SwcJsMinimizerRspackPlugi extract_comments: value.extract_comments, compress: try_deserialize_into(&value.compress)?, mangle: try_deserialize_into(&value.mangle)?, - format: serde_json::from_str(&value.format)?, + format: serde_json::from_str(&value.format).into_diagnostic()?, module: value.module, test: into_condition(value.test), include: into_condition(value.include), diff --git a/crates/rspack_binding_options/src/options/raw_external.rs b/crates/rspack_binding_options/src/options/raw_external.rs index 246fc85e179b..eaed74fbc237 100644 --- a/crates/rspack_binding_options/src/options/raw_external.rs +++ b/crates/rspack_binding_options/src/options/raw_external.rs @@ -7,9 +7,10 @@ use napi::{Env, JsFunction}; use napi_derive::napi; use rspack_core::ExternalItemFnCtx; use rspack_core::{ExternalItem, ExternalItemFnResult, ExternalItemValue}; -use rspack_error::internal_error; +use rspack_error::miette::IntoDiagnostic; +use rspack_error::{internal_error, AnyhowError}; use rspack_napi_shared::threadsafe_function::{ThreadsafeFunction, ThreadsafeFunctionCallMode}; -use rspack_napi_shared::{JsRegExp, JsRegExpExt, NapiResultExt, NAPI_ENV}; +use rspack_napi_shared::{get_napi_env, JsRegExp, JsRegExpExt, NapiResultExt}; #[napi(object)] pub struct RawHttpExternalsRspackPluginOptions { @@ -92,13 +93,13 @@ impl TryFrom for ExternalItem { .collect(), )), Either4::D(v) => { - let fn_payload: ThreadsafeFunction = - NAPI_ENV.with(|env| -> anyhow::Result<_> { - let env = env.borrow().expect("Failed to get env with external"); - let fn_payload = rspack_binding_macros::js_fn_into_threadsafe_fn!(v, &Env::from(env)); - Ok(fn_payload) - })?; - let fn_payload = Arc::new(fn_payload); + let fn_payload: napi::Result< + ThreadsafeFunction, + > = try { + let env = unsafe { get_napi_env() }; + rspack_binding_macros::js_fn_into_threadsafe_fn!(v, &Env::from(env)) + }; + let fn_payload = Arc::new(fn_payload.expect("convert to threadsafe function failed")); Ok(Self::Fn(Box::new(move |ctx: ExternalItemFnCtx| { let fn_payload = fn_payload.clone(); Box::pin(async move { diff --git a/crates/rspack_binding_options/src/options/raw_module/js_loader.rs b/crates/rspack_binding_options/src/options/raw_module/js_loader.rs index 1ba821c24274..de9700a7d24e 100644 --- a/crates/rspack_binding_options/src/options/raw_module/js_loader.rs +++ b/crates/rspack_binding_options/src/options/raw_module/js_loader.rs @@ -7,6 +7,7 @@ use napi_derive::napi; use rspack_core::{rspack_sources::SourceMap, Content, ResourceData}; use rspack_error::Diagnostic; use rspack_loader_runner::AdditionalData; +use rspack_napi_shared::get_napi_env; use rustc_hash::FxHashSet as HashSet; use tracing::{span_enabled, Level}; use { @@ -17,7 +18,7 @@ use { rspack_error::internal_error, rspack_identifier::{Identifiable, Identifier}, rspack_napi_shared::threadsafe_function::{ThreadsafeFunction, ThreadsafeFunctionCallMode}, - rspack_napi_shared::{NapiResultExt, NAPI_ENV}, + rspack_napi_shared::NapiResultExt, }; use crate::get_builtin_loader; @@ -53,56 +54,48 @@ impl TryFrom for JsLoaderRunner { fn try_from(value: JsFunction) -> std::result::Result { let loader_runner = unsafe { value.raw() }; - - let func = NAPI_ENV.with(|env| -> anyhow::Result<_> { - let env = env - .borrow() - .expect("Failed to get env, did you forget to call it from node?"); - - let mut func = ThreadsafeFunction::::create( - env, - loader_runner, - 0, - |ctx| { - let (ctx, resolver) = ctx.split_into_parts(); - - let env = ctx.env; - let cb = ctx.callback; - let resource = ctx.value.resource.clone(); - - let loader_name = if span_enabled!(Level::TRACE) { - let loader_path = &ctx.value.current_loader; - // try to remove the previous node_modules parts from path for better display - - let parts = loader_path.split("node_modules/"); - let loader_name: &str = parts.last().unwrap_or(loader_path.as_str()); - String::from(loader_name) - } else { - String::from("unknown") - }; - let result = tracing::span!( - tracing::Level::INFO, - "loader_sync_call", - resource = &resource, - loader_name = &loader_name - ) - .in_scope(|| unsafe { call_js_function_with_napi_objects!(env, cb, ctx.value) }); - - let resolve_start = std::time::Instant::now(); - resolver.resolve::>(result, move |_, r| { - tracing::trace!( - "Finish resolving loader result for {}, took {}ms", - resource, - resolve_start.elapsed().as_millis() - ); - Ok(r) - }) - }, - )?; - func.unref(&Env::from(env))?; - Ok(func) - })?; - + let env = unsafe { get_napi_env() }; + let mut func = ThreadsafeFunction::::create( + env, + loader_runner, + 0, + |ctx| { + let (ctx, resolver) = ctx.split_into_parts(); + + let env = ctx.env; + let cb = ctx.callback; + let resource = ctx.value.resource.clone(); + + let loader_name = if span_enabled!(Level::TRACE) { + let loader_path = &ctx.value.current_loader; + // try to remove the previous node_modules parts from path for better display + + let parts = loader_path.split("node_modules/"); + let loader_name: &str = parts.last().unwrap_or(loader_path.as_str()); + String::from(loader_name) + } else { + String::from("unknown") + }; + let result = tracing::span!( + tracing::Level::INFO, + "loader_sync_call", + resource = &resource, + loader_name = &loader_name + ) + .in_scope(|| unsafe { call_js_function_with_napi_objects!(env, cb, ctx.value) }); + + let resolve_start = std::time::Instant::now(); + resolver.resolve::>(result, move |_, r| { + tracing::trace!( + "Finish resolving loader result for {}, took {}ms", + resource, + resolve_start.elapsed().as_millis() + ); + Ok(r) + }) + }, + )?; + func.unref(&Env::from(env))?; Ok(Self::ThreadsafeFunction(func)) } } @@ -132,7 +125,7 @@ impl Loader for JsLoaderAdapter { &self, loader_context: &mut LoaderContext<'_, LoaderRunnerContext>, ) -> rspack_error::Result<()> { - let mut js_loader_context: JsLoaderContext = (&*loader_context).try_into()?; + let mut js_loader_context: JsLoaderContext = loader_context.try_into()?; js_loader_context.is_pitching = true; let loader_result = self @@ -161,7 +154,7 @@ impl Loader for JsLoaderAdapter { &self, loader_context: &mut LoaderContext<'_, LoaderRunnerContext>, ) -> rspack_error::Result<()> { - let mut js_loader_context: JsLoaderContext = (&*loader_context).try_into()?; + let mut js_loader_context: JsLoaderContext = loader_context.try_into()?; // Instruct the JS loader-runner to execute loaders in backwards. js_loader_context.is_pitching = false; @@ -265,13 +258,13 @@ pub struct JsLoaderContext { pub diagnostics_external: External>, } -impl TryFrom<&rspack_core::LoaderContext<'_, rspack_core::LoaderRunnerContext>> +impl TryFrom<&mut rspack_core::LoaderContext<'_, rspack_core::LoaderRunnerContext>> for JsLoaderContext { type Error = rspack_error::Error; fn try_from( - cx: &rspack_core::LoaderContext<'_, rspack_core::LoaderRunnerContext>, + cx: &mut rspack_core::LoaderContext<'_, rspack_core::LoaderRunnerContext>, ) -> std::result::Result { Ok(JsLoaderContext { content: cx @@ -322,7 +315,7 @@ impl TryFrom<&rspack_core::LoaderContext<'_, rspack_core::LoaderRunnerContext>> additional_data_external: External::new(cx.additional_data.clone()), context_external: External::new(cx.context.clone()), - diagnostics_external: External::new(cx.__diagnostics.clone()), + diagnostics_external: External::new(cx.__diagnostics.drain(..).collect()), }) } } @@ -410,7 +403,7 @@ pub async fn run_builtin_loader( cx.__loader_index = 0; } - JsLoaderContext::try_from(&cx).map_err(|e| Error::from_reason(e.to_string())) + JsLoaderContext::try_from(&mut cx).map_err(|e| Error::from_reason(e.to_string())) } // #[napi(object)] diff --git a/crates/rspack_binding_options/src/options/raw_module/mod.rs b/crates/rspack_binding_options/src/options/raw_module/mod.rs index ca76bf74ae3d..b460554fb1df 100644 --- a/crates/rspack_binding_options/src/options/raw_module/mod.rs +++ b/crates/rspack_binding_options/src/options/raw_module/mod.rs @@ -15,14 +15,15 @@ use rspack_core::{ ModuleRule, ModuleRuleEnforce, ModuleRuleUse, ModuleRuleUseLoader, ModuleType, ParserOptions, ParserOptionsByModuleType, }; -use rspack_error::internal_error; +use rspack_error::{internal_error, miette::IntoDiagnostic}; use rspack_loader_react_refresh::REACT_REFRESH_LOADER_IDENTIFIER; use rspack_loader_sass::SASS_LOADER_IDENTIFIER; use rspack_loader_swc::SWC_LOADER_IDENTIFIER; +use rspack_napi_shared::get_napi_env; use serde::Deserialize; use { rspack_napi_shared::threadsafe_function::{ThreadsafeFunction, ThreadsafeFunctionCallMode}, - rspack_napi_shared::{NapiResultExt, NAPI_ENV}, + rspack_napi_shared::NapiResultExt, }; use crate::{RawOptionsApply, RawResolveOptions}; @@ -222,16 +223,13 @@ impl TryFrom for rspack_core::RuleSetCondition { "should have a func_matcher when RawRuleSetCondition.type is \"function\"" ) })?; - let func_matcher: ThreadsafeFunction = - NAPI_ENV.with(|env| -> anyhow::Result<_> { - let env = env - .borrow() - .expect("Failed to get env, did you forget to call it from node?"); - let func_matcher = - rspack_binding_macros::js_fn_into_threadsafe_fn!(func_matcher, &Env::from(env)); - Ok(func_matcher) - })?; - let func_matcher = Arc::new(func_matcher); + + let env =unsafe { get_napi_env()}; + + let func_matcher: napi::Result> = try { + rspack_binding_macros::js_fn_into_threadsafe_fn!(func_matcher, &Env::from(env)) + }; + let func_matcher = Arc::new(func_matcher.expect("convert to threadsafe function failed")); Self::Func(Box::new(move |data: &str| { let func_matcher = func_matcher.clone(); @@ -598,14 +596,11 @@ impl RawOptionsApply for RawModuleRule { "should have a func_matcher when RawRuleSetCondition.type is \"function\"" ) })?; - let func_use: ThreadsafeFunction> = - NAPI_ENV.with(|env| -> anyhow::Result<_> { - let env = env.borrow().expect("Failed to get env with external"); - let func_use = - rspack_binding_macros::js_fn_into_threadsafe_fn!(func_use, &Env::from(env)); - Ok(func_use) - })?; - let func_use = Arc::new(func_use); + let func_use: Result>> = try { + let env = unsafe { get_napi_env() }; + rspack_binding_macros::js_fn_into_threadsafe_fn!(func_use, &Env::from(env)) + }; + let func_use = Arc::new(func_use.into_diagnostic()?); Ok::(ModuleRuleUse::Func(Box::new( move |ctx: FuncUseCtx| { let func_use = func_use.clone(); diff --git a/crates/rspack_binding_options/src/options/raw_resolve.rs b/crates/rspack_binding_options/src/options/raw_resolve.rs index 214221d7b08b..195ba3b75c2a 100644 --- a/crates/rspack_binding_options/src/options/raw_resolve.rs +++ b/crates/rspack_binding_options/src/options/raw_resolve.rs @@ -2,6 +2,7 @@ use std::{collections::HashMap, path::PathBuf}; use napi_derive::napi; use rspack_core::{Alias, AliasMap, ByDependency, Resolve, TsconfigOptions, TsconfigReferences}; +use rspack_error::internal_error; use serde::Deserialize; pub type AliasValue = serde_json::Value; @@ -45,7 +46,7 @@ pub struct RawResolveOptions { pub extension_alias: Option>>, } -fn normalize_alias(alias: Option) -> anyhow::Result> { +fn normalize_alias(alias: Option) -> rspack_error::Result> { alias .map(|alias| { alias @@ -58,22 +59,18 @@ fn normalize_alias(alias: Option) -> anyhow::Result>() + .collect::>() .map(|value| (key, value)) }) - .collect::>() + .collect::>() }) .map_or(Ok(None), |v| v.map(Some)) } diff --git a/crates/rspack_binding_options/src/options/raw_split_chunks/raw_split_chunk_cache_group_test.rs b/crates/rspack_binding_options/src/options/raw_split_chunks/raw_split_chunk_cache_group_test.rs index cdaa557ed439..30455b6c7b5e 100644 --- a/crates/rspack_binding_options/src/options/raw_split_chunks/raw_split_chunk_cache_group_test.rs +++ b/crates/rspack_binding_options/src/options/raw_split_chunks/raw_split_chunk_cache_group_test.rs @@ -6,7 +6,7 @@ use napi_derive::napi; use rspack_binding_values::{JsModule, ToJsModule}; use rspack_error::internal_error; use rspack_napi_shared::threadsafe_function::{ThreadsafeFunction, ThreadsafeFunctionCallMode}; -use rspack_napi_shared::{JsRegExp, JsRegExpExt, NapiResultExt, NAPI_ENV}; +use rspack_napi_shared::{get_napi_env, JsRegExp, JsRegExpExt, NapiResultExt}; use rspack_plugin_split_chunks_new::{CacheGroupTest, CacheGroupTestFnCtx}; pub(super) type RawCacheGroupTest = Either3; @@ -32,14 +32,11 @@ pub(super) fn normalize_raw_cache_group_test(raw: RawCacheGroupTest) -> CacheGro Either3::A(str) => CacheGroupTest::String(str), Either3::B(regexp) => CacheGroupTest::RegExp(regexp.to_rspack_regex()), Either3::C(v) => { - let fn_payload: ThreadsafeFunction> = NAPI_ENV - .with(|env| -> anyhow::Result<_> { - let env = env.borrow().expect("Failed to get env with external"); - let fn_payload = rspack_binding_macros::js_fn_into_threadsafe_fn!(v, &Env::from(env)); - Ok(fn_payload) - }) - .expect("should generate fn_payload success"); - let fn_payload = Arc::new(fn_payload); + let fn_payload: napi::Result>> = try { + let env = unsafe { get_napi_env() }; + rspack_binding_macros::js_fn_into_threadsafe_fn!(v, &Env::from(env)) + }; + let fn_payload = Arc::new(fn_payload.expect("convert to threadsafe function failed")); CacheGroupTest::Fn(Arc::new(move |ctx| { let fn_payload = fn_payload.clone(); Box::pin(async move { diff --git a/crates/rspack_binding_options/src/options/raw_split_chunks/raw_split_chunk_name.rs b/crates/rspack_binding_options/src/options/raw_split_chunks/raw_split_chunk_name.rs index 11605afe3185..2432873a89c1 100644 --- a/crates/rspack_binding_options/src/options/raw_split_chunks/raw_split_chunk_name.rs +++ b/crates/rspack_binding_options/src/options/raw_split_chunks/raw_split_chunk_name.rs @@ -6,7 +6,7 @@ use napi_derive::napi; use rspack_binding_values::{JsModule, ToJsModule}; use rspack_error::internal_error; use rspack_napi_shared::threadsafe_function::{ThreadsafeFunction, ThreadsafeFunctionCallMode}; -use rspack_napi_shared::{NapiResultExt, NAPI_ENV}; +use rspack_napi_shared::{get_napi_env, NapiResultExt}; use rspack_plugin_split_chunks_new::{ChunkNameGetter, ChunkNameGetterFnCtx}; pub(super) type RawChunkOptionName = Either3; @@ -37,14 +37,11 @@ pub(super) fn normalize_raw_chunk_name(raw: RawChunkOptionName) -> ChunkNameGett Either3::A(str) => ChunkNameGetter::String(str), Either3::B(_) => ChunkNameGetter::Disabled, // FIXME: when set bool is true? Either3::C(v) => { - let fn_payload: ThreadsafeFunction> = NAPI_ENV - .with(|env| -> anyhow::Result<_> { - let env = env.borrow().expect("Failed to get env with external"); - let fn_payload = rspack_binding_macros::js_fn_into_threadsafe_fn!(v, &Env::from(env)); - Ok(fn_payload) - }) - .expect("should generate fn_payload success"); - let fn_payload = Arc::new(fn_payload); + let fn_payload: napi::Result>> = try { + let env = unsafe { get_napi_env() }; + rspack_binding_macros::js_fn_into_threadsafe_fn!(v, &Env::from(env)) + }; + let fn_payload = Arc::new(fn_payload.expect("convert to threadsafe function failed")); ChunkNameGetter::Fn(Arc::new(move |ctx| { let fn_payload = fn_payload.clone(); Box::pin(async move { diff --git a/crates/rspack_binding_values/src/compilation.rs b/crates/rspack_binding_values/src/compilation.rs index ec57e2c4c66f..54e683883676 100644 --- a/crates/rspack_binding_values/src/compilation.rs +++ b/crates/rspack_binding_values/src/compilation.rs @@ -315,8 +315,8 @@ impl JsCompilation { #[napi(ts_args_type = r#"severity: "error" | "warning", title: string, message: string"#)] pub fn push_diagnostic(&mut self, severity: String, title: String, message: String) { let diagnostic = match severity.as_str() { - "warning" => rspack_error::Diagnostic::warn(title, message, 0, 0), - _ => rspack_error::Diagnostic::error(title, message, 0, 0), + "warning" => rspack_error::Diagnostic::warn(title, message), + _ => rspack_error::Diagnostic::error(title, message), }; self.inner.push_diagnostic(diagnostic); } diff --git a/crates/rspack_core/src/build_chunk_graph/code_splitter.rs b/crates/rspack_core/src/build_chunk_graph/code_splitter.rs index 36d735aeefe1..28166be6c7f0 100644 --- a/crates/rspack_core/src/build_chunk_graph/code_splitter.rs +++ b/crates/rspack_core/src/build_chunk_graph/code_splitter.rs @@ -1,6 +1,5 @@ -use anyhow::anyhow; use itertools::Itertools; -use rspack_error::{internal_error, Result}; +use rspack_error::{internal_error, Error, Result}; use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet}; use super::remove_parent_modules::RemoveParentModulesContext; @@ -131,7 +130,7 @@ impl<'me> CodeSplitter<'me> { compilation .chunk_group_by_ukey .get(&ukey) - .ok_or_else(|| anyhow::format_err!("no chunk group found"))? + .ok_or_else(|| internal_error!("no chunk group found"))? }; for module_identifier in module_identifiers { @@ -192,12 +191,12 @@ impl<'me> CodeSplitter<'me> { let ukey = compilation .entrypoints .get(name) - .ok_or_else(|| anyhow!("no entrypoints found"))?; + .ok_or_else(|| internal_error!("no entrypoints found"))?; let entry_point = compilation .chunk_group_by_ukey .get_mut(ukey) - .ok_or_else(|| anyhow!("no chunk group found"))?; + .ok_or_else(|| internal_error!("no chunk group found"))?; let chunk = match compilation.named_chunks.get(runtime) { Some(ukey) => { @@ -216,7 +215,7 @@ Or do you want to use the entrypoints '{name}' and '{runtime}' independently on compilation .chunk_by_ukey .get_mut(ukey) - .ok_or_else(|| anyhow!("no chunk found"))? + .ok_or_else(|| internal_error!("no chunk found"))? } None => { let chunk_ukey = Compilation::add_named_chunk( @@ -240,7 +239,7 @@ Or do you want to use the entrypoints '{name}' and '{runtime}' independently on } if let Some(err) = runtime_error { - compilation.push_batch_diagnostic(err.into()); + compilation.push_diagnostic(err.into()); } Ok(input_entrypoints_and_modules) } @@ -257,7 +256,7 @@ Or do you want to use the entrypoints '{name}' and '{runtime}' independently on .compilation .chunk_group_by_ukey .get_mut(&chunk_group) - .ok_or_else(|| anyhow::format_err!("no chunk group found"))?; + .ok_or_else(|| internal_error!("no chunk group found"))?; self.next_chunk_group_index += 1; chunk_group.index = Some(self.next_chunk_group_index); @@ -648,11 +647,11 @@ Or do you want to use the entrypoints '{name}' and '{runtime}' independently on .expect_get(cgi) .is_initial() { - let error = AsyncDependenciesToInitialChunkError { - chunk_name, - loc: block.loc(), - }; - self.compilation.push_diagnostic(error.into()); + let error = AsyncDependenciesToInitialChunkError( + chunk_name.to_string(), + block.loc().map(ToOwned::to_owned), + ); + self.compilation.push_diagnostic(Error::from(error).into()); res = item_chunk_group_ukey; } diff --git a/crates/rspack_core/src/cache/mod.rs b/crates/rspack_core/src/cache/mod.rs index cc3af1c9487f..419eb5b603ad 100644 --- a/crates/rspack_core/src/cache/mod.rs +++ b/crates/rspack_core/src/cache/mod.rs @@ -14,7 +14,10 @@ mod snapshot; mod storage; pub use local::*; use occasion::{ - BuildModuleOccasion, CodeGenerateOccasion, CreateChunkAssetsOccasion, ResolveModuleOccasion, + // BuildModuleOccasion, + CodeGenerateOccasion, + CreateChunkAssetsOccasion, + ResolveModuleOccasion, }; use snapshot::SnapshotManager; use storage::new_storage; @@ -24,7 +27,7 @@ pub struct Cache { is_idle: AtomicBool, snapshot_manager: Arc, pub resolve_module_occasion: ResolveModuleOccasion, - pub build_module_occasion: BuildModuleOccasion, + // pub build_module_occasion: BuildModuleOccasion, pub code_generate_occasion: CodeGenerateOccasion, pub create_chunk_assets_occasion: CreateChunkAssetsOccasion, } @@ -39,10 +42,10 @@ impl Cache { new_storage(&options.cache), snapshot_manager.clone(), ), - build_module_occasion: BuildModuleOccasion::new( - new_storage(&options.cache), - snapshot_manager, - ), + // build_module_occasion: BuildModuleOccasion::new( + // new_storage(&options.cache), + // snapshot_manager, + // ), code_generate_occasion: CodeGenerateOccasion::new(new_storage(&options.cache)), create_chunk_assets_occasion: CreateChunkAssetsOccasion::new(new_storage(&options.cache)), } diff --git a/crates/rspack_core/src/cache/occasion/build_module.rs b/crates/rspack_core/src/cache/occasion/build_module.rs index c5142e4d05eb..59d0f9e74850 100644 --- a/crates/rspack_core/src/cache/occasion/build_module.rs +++ b/crates/rspack_core/src/cache/occasion/build_module.rs @@ -1,180 +1,180 @@ -use std::{collections::HashMap, path::Path, sync::Arc}; +// use std::{collections::HashMap, path::Path, sync::Arc}; -use futures::Future; -use rkyv::AlignedVec; -use rspack_error::{Result, TWithDiagnosticArray}; -use rspack_identifier::Identifier; +// use futures::Future; +// use rkyv::AlignedVec; +// use rspack_error::{Result, TWithDiagnosticArray}; +// use rspack_identifier::Identifier; -use crate::{ - cache::snapshot::{Snapshot, SnapshotManager}, - cache::storage, - BoxModule, BuildExtraDataType, BuildResult, DependencyTemplate, ModuleDependency, - NormalModuleSource, -}; +// use crate::{ +// cache::snapshot::{Snapshot, SnapshotManager}, +// cache::storage, +// BoxModule, BuildExtraDataType, BuildResult, DependencyTemplate, ModuleDependency, +// NormalModuleSource, +// }; -#[derive(Debug, Clone)] -pub struct NormalModuleStorageData { - source: NormalModuleSource, - code_generation_dependencies: Option>>, - presentational_dependencies: Option>>, -} +// #[derive(Debug, Clone)] +// pub struct NormalModuleStorageData { +// source: NormalModuleSource, +// code_generation_dependencies: Option>>, +// presentational_dependencies: Option>>, +// } -type NormalModuleStorageExtraData = HashMap; +// type NormalModuleStorageExtraData = HashMap; -type Storage = dyn storage::Storage<( - // file system info, None when not cacheable - Option, - // build result - TWithDiagnosticArray, - // module data - Option, - // parser and generator data - Option, -)>; +// type Storage = dyn storage::Storage<( +// // file system info, None when not cacheable +// Option, +// // build result +// TWithDiagnosticArray, +// // module data +// Option, +// // parser and generator data +// Option, +// )>; -#[derive(Debug)] -pub struct BuildModuleOccasion { - storage: Option>, - snapshot_manager: Arc, -} +// #[derive(Debug)] +// pub struct BuildModuleOccasion { +// storage: Option>, +// snapshot_manager: Arc, +// } -impl BuildModuleOccasion { - pub fn new(storage: Option>, snapshot_manager: Arc) -> Self { - Self { - storage, - snapshot_manager, - } - } +// impl BuildModuleOccasion { +// pub fn new(storage: Option>, snapshot_manager: Arc) -> Self { +// Self { +// storage, +// snapshot_manager, +// } +// } - pub fn remove_cache(&self, id: &Identifier) { - if let Some(s) = self.storage.as_ref() { - s.remove(id); - } - } +// pub fn remove_cache(&self, id: &Identifier) { +// if let Some(s) = self.storage.as_ref() { +// s.remove(id); +// } +// } - pub async fn use_cache<'a, G, F>( - &self, - module: &'a mut BoxModule, - generator: G, - ) -> Result<(Result>, bool)> - where - G: Fn(&'a mut BoxModule) -> F, - F: Future, &'a mut BoxModule)>>, - { - let storage = match &self.storage { - Some(s) => s, - // no cache return directly - None => return Ok((Ok(generator(module).await?.0), false)), - }; +// pub async fn use_cache<'a, G, F>( +// &self, +// module: &'a mut BoxModule, +// generator: G, +// ) -> Result<(Result>, bool)> +// where +// G: Fn(&'a mut BoxModule) -> F, +// F: Future, &'a mut BoxModule)>>, +// { +// let storage = match &self.storage { +// Some(s) => s, +// // no cache return directly +// None => return Ok((Ok(generator(module).await?.0), false)), +// }; - let mut need_cache = false; - let mut last_build_result = None; - let id = module.identifier().to_owned(); - if module.as_normal_module().is_some() { - // normal module - // TODO cache all module type - if let Some((snapshot, data, module_data, extra_data)) = storage.get(&id) { - let valid = if let Some(snapshot) = snapshot { - self - .snapshot_manager - .check_snapshot_valid(&snapshot) - .await - .unwrap_or(false) - } else { - false - }; - if valid { - if let Some(module) = module.as_normal_module_mut() { - if let Some(module_data) = module_data { - *module.source_mut() = module_data.source; - *module.code_generation_dependencies_mut() = module_data.code_generation_dependencies; - *module.presentational_dependencies_mut() = module_data.presentational_dependencies; - } - if let Some(extra_data) = extra_data { - module.parser_and_generator_mut().resume(&extra_data); - } - } - return Ok((Ok(data), true)); - } else { - last_build_result = Some(data.inner); - } - }; - need_cache = true; - } +// let mut need_cache = false; +// let mut last_build_result = None; +// let id = module.identifier().to_owned(); +// if module.as_normal_module().is_some() { +// // normal module +// // TODO cache all module type +// if let Some((snapshot, data, module_data, extra_data)) = storage.get(&id) { +// let valid = if let Some(snapshot) = snapshot { +// self +// .snapshot_manager +// .check_snapshot_valid(&snapshot) +// .await +// .unwrap_or(false) +// } else { +// false +// }; +// if valid { +// if let Some(module) = module.as_normal_module_mut() { +// if let Some(module_data) = module_data { +// *module.source_mut() = module_data.source; +// *module.code_generation_dependencies_mut() = module_data.code_generation_dependencies; +// *module.presentational_dependencies_mut() = module_data.presentational_dependencies; +// } +// if let Some(extra_data) = extra_data { +// module.parser_and_generator_mut().resume(&extra_data); +// } +// } +// return Ok((Ok(data), true)); +// } else { +// last_build_result = Some(data.inner); +// } +// }; +// need_cache = true; +// } - // run generator and save to cache - let (mut data, module) = generator(module).await?; +// // run generator and save to cache +// let (mut data, module) = generator(module).await?; - if need_cache { - let module = module - .as_normal_module() - .expect("Only normal module supports build cache"); - // only resume the build_meta to make sure other modules will not be affected - if matches!(module.source(), NormalModuleSource::BuiltFailed(_)) - && let Some(last_result) = last_build_result - { - data.inner.build_meta = last_result.build_meta; - return Ok((Ok(data), false)); - } +// if need_cache { +// let module = module +// .as_normal_module() +// .expect("Only normal module supports build cache"); +// // only resume the build_meta to make sure other modules will not be affected +// if matches!(module.source(), NormalModuleSource::BuiltFailed(_)) +// && let Some(last_result) = last_build_result +// { +// data.inner.build_meta = last_result.build_meta; +// return Ok((Ok(data), false)); +// } - if data.inner.build_info.cacheable { - let mut paths: Vec<&Path> = Vec::new(); - paths.extend( - data - .inner - .build_info - .file_dependencies - .iter() - .map(|i| i.as_path()), - ); - paths.extend( - data - .inner - .build_info - .context_dependencies - .iter() - .map(|i| i.as_path()), - ); - paths.extend( - data - .inner - .build_info - .missing_dependencies - .iter() - .map(|i| i.as_path()), - ); - paths.extend( - data - .inner - .build_info - .build_dependencies - .iter() - .map(|i| i.as_path()), - ); +// if data.inner.build_info.cacheable { +// let mut paths: Vec<&Path> = Vec::new(); +// paths.extend( +// data +// .inner +// .build_info +// .file_dependencies +// .iter() +// .map(|i| i.as_path()), +// ); +// paths.extend( +// data +// .inner +// .build_info +// .context_dependencies +// .iter() +// .map(|i| i.as_path()), +// ); +// paths.extend( +// data +// .inner +// .build_info +// .missing_dependencies +// .iter() +// .map(|i| i.as_path()), +// ); +// paths.extend( +// data +// .inner +// .build_info +// .build_dependencies +// .iter() +// .map(|i| i.as_path()), +// ); - let snapshot = self - .snapshot_manager - .create_snapshot(&paths, |option| &option.module) - .await?; - let mut extra_data = HashMap::new(); - module.parser_and_generator().store(&mut extra_data); - storage.set( - id, - ( - Some(snapshot), - data.clone(), - Some(NormalModuleStorageData { - source: module.source().clone(), - code_generation_dependencies: module.code_generation_dependencies().clone(), - presentational_dependencies: module.presentational_dependencies().clone(), - }), - Some(extra_data), - ), - ); - } else if matches!(module.source(), NormalModuleSource::BuiltSucceed(_)) { - storage.set(id, (None, data.clone(), None, None)); - } - } - Ok((Ok(data), false)) - } -} +// let snapshot = self +// .snapshot_manager +// .create_snapshot(&paths, |option| &option.module) +// .await?; +// let mut extra_data = HashMap::new(); +// module.parser_and_generator().store(&mut extra_data); +// storage.set( +// id, +// ( +// Some(snapshot), +// data.clone(), +// Some(NormalModuleStorageData { +// source: module.source().clone(), +// code_generation_dependencies: module.code_generation_dependencies().clone(), +// presentational_dependencies: module.presentational_dependencies().clone(), +// }), +// Some(extra_data), +// ), +// ); +// } else if matches!(module.source(), NormalModuleSource::BuiltSucceed(_)) { +// storage.set(id, (None, data.clone(), None, None)); +// } +// } +// Ok((Ok(data), false)) +// } +// } diff --git a/crates/rspack_core/src/cache/occasion/mod.rs b/crates/rspack_core/src/cache/occasion/mod.rs index 7a63c16294f2..62406ac09640 100644 --- a/crates/rspack_core/src/cache/occasion/mod.rs +++ b/crates/rspack_core/src/cache/occasion/mod.rs @@ -1,7 +1,7 @@ mod resolve_module; pub use resolve_module::*; -mod build_module; -pub use build_module::*; +// mod build_module; +// pub use build_module::*; mod code_generate; pub use code_generate::*; mod create_chunk_assets; diff --git a/crates/rspack_core/src/cache/snapshot/manager.rs b/crates/rspack_core/src/cache/snapshot/manager.rs index 297e418bdab0..8cb38073c908 100644 --- a/crates/rspack_core/src/cache/snapshot/manager.rs +++ b/crates/rspack_core/src/cache/snapshot/manager.rs @@ -5,7 +5,7 @@ use std::{ }; use dashmap::{DashMap, DashSet}; -use rspack_error::Result; +use rspack_error::{miette::IntoDiagnostic, Result}; use rustc_hash::{FxHashMap as HashMap, FxHasher}; use super::Snapshot; @@ -59,15 +59,15 @@ impl SnapshotManager { Some(hash) => *hash, None => { let res = if path.is_dir() { - let dir = &mut tokio::fs::read_dir(path).await?; + let dir = &mut tokio::fs::read_dir(path).await.into_diagnostic()?; let mut sub_files = vec![]; - while let Some(entry) = dir.next_entry().await? { + while let Some(entry) = dir.next_entry().await.into_diagnostic()? { let dir_u8 = entry.path().as_os_str().to_string_lossy().to_string(); sub_files.push(dir_u8); } calc_hash(&sub_files) } else { - calc_hash(&tokio::fs::read(path).await?) + calc_hash(&tokio::fs::read(path).await.into_diagnostic()?) }; hash_cache.insert(path.to_owned(), res); res @@ -100,7 +100,11 @@ impl SnapshotManager { let update_time = match update_time_cache.get(path) { Some(t) => *t, None => { - let t = tokio::fs::metadata(path).await?.modified()?; + let t = tokio::fs::metadata(path) + .await + .into_diagnostic()? + .modified() + .into_diagnostic()?; update_time_cache.insert(path.clone(), t); t } @@ -123,7 +127,7 @@ impl SnapshotManager { let current_hash = match hash_cache.get(path) { Some(h) => *h, None => { - let res = calc_hash(&tokio::fs::read(path).await?); + let res = calc_hash(&tokio::fs::read(path).await.into_diagnostic()?); hash_cache.insert(path.clone(), res); res } diff --git a/crates/rspack_core/src/compiler/compilation.rs b/crates/rspack_core/src/compiler/compilation.rs index ab27cac3bcf1..2febb1395b29 100644 --- a/crates/rspack_core/src/compiler/compilation.rs +++ b/crates/rspack_core/src/compiler/compilation.rs @@ -256,7 +256,7 @@ impl Compilation { filename, is_source_equal ); - self.push_batch_diagnostic( + self.push_diagnostic( internal_error!( "Conflict: Multiple assets emit different content to the same filename {}{}", filename, @@ -380,7 +380,7 @@ impl Compilation { .await .err() { - self.push_batch_diagnostic(e.into()); + self.push_batch_diagnostic(vec![e.into()]); } logger.time_end(start); let make_failed_module = @@ -397,9 +397,9 @@ impl Compilation { &mut self, module_identifiers: HashSet, ) -> Result> { - for id in &module_identifiers { - self.cache.build_module_occasion.remove_cache(id); - } + // for id in &module_identifiers { + // self.cache.build_module_occasion.remove_cache(id); + // } self .update_module_graph(vec![MakeParam::ForceBuildModules( diff --git a/crates/rspack_core/src/compiler/queue.rs b/crates/rspack_core/src/compiler/queue.rs index 11ee98b5228d..eb70455b49d9 100644 --- a/crates/rspack_core/src/compiler/queue.rs +++ b/crates/rspack_core/src/compiler/queue.rs @@ -295,62 +295,89 @@ impl WorkerTask for BuildTask { let mut module = self.module; let compiler_options = self.compiler_options; let resolver_factory = self.resolver_factory; - let cache = self.cache; + // let cache = self.cache; let plugin_driver = self.plugin_driver; - let (build_result, is_cache_valid) = match cache - .build_module_occasion - .use_cache(&mut module, |module| async { - plugin_driver - .build_module(module.as_mut()) - .await - .unwrap_or_else(|e| panic!("Run build_module hook failed: {}", e)); - - let result = module - .build(BuildContext { - compiler_context: CompilerContext { - options: compiler_options.clone(), - resolver_factory: resolver_factory.clone(), - module: Some(module.identifier()), - module_context: module.as_normal_module().and_then(|m| m.get_context()), - }, - plugin_driver: plugin_driver.clone(), - compiler_options: &compiler_options, - }) - .await; - - plugin_driver - .succeed_module(&**module) - .await - .unwrap_or_else(|e| panic!("Run succeed_module hook failed: {}", e)); - - result.map(|t| (t, module)) - }) - .await - { + // match cache + // .build_module_occasion + // .use_cache(&mut module, |module| async { + // plugin_driver + // .build_module(module.as_mut()) + // .await + // .unwrap_or_else(|e| panic!("Run build_module hook failed: {}", e)); + + // let result = module + // .build(BuildContext { + // compiler_context: CompilerContext { + // options: compiler_options.clone(), + // resolver_factory: resolver_factory.clone(), + // module: Some(module.identifier()), + // module_context: module.as_normal_module().and_then(|m| m.get_context()), + // }, + // plugin_driver: plugin_driver.clone(), + // compiler_options: &compiler_options, + // }) + // .await; + + // plugin_driver + // .succeed_module(&**module) + // .await + // .unwrap_or_else(|e| panic!("Run succeed_module hook failed: {}", e)); + + // result.map(|t| (t, module)) + // }) + // .await + let (build_result, module) = match { + plugin_driver + .build_module(module.as_mut()) + .await + .unwrap_or_else(|e| panic!("Run build_module hook failed: {}", e)); + + let result = module + .build(BuildContext { + compiler_context: CompilerContext { + options: compiler_options.clone(), + resolver_factory: resolver_factory.clone(), + module: Some(module.identifier()), + module_context: module.as_normal_module().and_then(|m| m.get_context()), + }, + plugin_driver: plugin_driver.clone(), + compiler_options: &compiler_options, + }) + .await; + + plugin_driver + .succeed_module(&*module) + .await + .unwrap_or_else(|e| panic!("Run succeed_module hook failed: {}", e)); + + result.map(|t| (t, module)) + } { Ok(result) => result, Err(err) => panic!("build module get error: {}", err), }; - if is_cache_valid { - plugin_driver.still_valid_module(module.as_ref()).await?; - } + let is_cache_valid = false; + + // if is_cache_valid { + // plugin_driver.still_valid_module(module.as_ref()).await?; + // } if let Some(current_profile) = &self.current_profile { current_profile.mark_building_end(); } - build_result.map(|build_result| { - let (build_result, diagnostics) = build_result.split_into_parts(); - - TaskResult::Build(Box::new(BuildTaskResult { - module, - build_result: Box::new(build_result), - diagnostics, - current_profile: self.current_profile, - from_cache: is_cache_valid, - })) - }) + // build_result.map(|build_result| { + let (build_result, diagnostics) = build_result.split_into_parts(); + + Ok(TaskResult::Build(Box::new(BuildTaskResult { + module, + build_result: Box::new(build_result), + diagnostics, + current_profile: self.current_profile, + from_cache: is_cache_valid, + }))) + // } } } diff --git a/crates/rspack_core/src/context_module.rs b/crates/rspack_core/src/context_module.rs index d065b06fd9b8..9d77f072c362 100644 --- a/crates/rspack_core/src/context_module.rs +++ b/crates/rspack_core/src/context_module.rs @@ -10,7 +10,9 @@ use std::{ use itertools::Itertools; use once_cell::sync::Lazy; use regex::{Captures, Regex}; -use rspack_error::{internal_error, IntoTWithDiagnosticArray, Result, TWithDiagnosticArray}; +use rspack_error::{ + internal_error, miette::IntoDiagnostic, IntoTWithDiagnosticArray, Result, TWithDiagnosticArray, +}; use rspack_hash::RspackHash; use rspack_identifier::{Identifiable, Identifier}; use rspack_regex::RspackRegex; @@ -688,8 +690,8 @@ impl ContextModule { if !dir.is_dir() { return Ok(()); } - for entry in fs::read_dir(dir)? { - let path = entry?.path(); + for entry in fs::read_dir(dir).into_diagnostic()? { + let path = entry.into_diagnostic()?.path(); if path.is_dir() { if options.context_options.recursive { Self::visit_dirs(ctx, &path, dependencies, options, resolve_options)?; diff --git a/crates/rspack_core/src/context_module_factory.rs b/crates/rspack_core/src/context_module_factory.rs index 226de9a0acb6..7c3307fcca80 100644 --- a/crates/rspack_core/src/context_module_factory.rs +++ b/crates/rspack_core/src/context_module_factory.rs @@ -146,7 +146,9 @@ impl ContextModuleFactory { ) .boxed(); - return Ok(ModuleFactoryResult::new(missing_module).with_diagnostic(internal_error.into())); + return Ok( + ModuleFactoryResult::new(missing_module).with_diagnostic(vec![internal_error.into()]), + ); } }; diff --git a/crates/rspack_core/src/dependencies_block.rs b/crates/rspack_core/src/dependencies_block.rs index 97af82a1b3c5..3c7a7056664d 100644 --- a/crates/rspack_core/src/dependencies_block.rs +++ b/crates/rspack_core/src/dependencies_block.rs @@ -1,4 +1,8 @@ -use rspack_error::{Diagnostic, DIAGNOSTIC_POS_DUMMY}; +use rspack_error::{ + miette::{self, Diagnostic}, + thiserror::{self, Error}, + DIAGNOSTIC_POS_DUMMY, +}; use serde::Serialize; use ustr::Ustr; @@ -158,19 +162,7 @@ impl DependenciesBlock for AsyncDependenciesBlock { } } -pub struct AsyncDependenciesToInitialChunkError<'a> { - pub chunk_name: &'a str, - pub loc: Option<&'a DependencyLocation>, -} - -impl<'a> From> for Diagnostic { - fn from(value: AsyncDependenciesToInitialChunkError<'a>) -> Self { - let title = "AsyncDependencyToInitialChunkError".to_string(); - let message = format!("It's not allowed to load an initial chunk on demand. The chunk name \"{}\" is already used by an entrypoint.", value.chunk_name); - let (start, end) = value - .loc - .map(|loc| (loc.start as usize, loc.end as usize)) - .unwrap_or((DIAGNOSTIC_POS_DUMMY, DIAGNOSTIC_POS_DUMMY)); - Diagnostic::error(title, message, start, end) - } -} +#[derive(Debug, Error, Diagnostic)] +#[diagnostic(code(AsyncDependencyToInitialChunkError))] +#[error("It's not allowed to load an initial chunk on demand. The chunk name \"{0}\" is already used by an entrypoint.")] +pub struct AsyncDependenciesToInitialChunkError(pub String, pub Option); diff --git a/crates/rspack_core/src/diagnostics.rs b/crates/rspack_core/src/diagnostics.rs new file mode 100644 index 000000000000..9d27aeb1c44b --- /dev/null +++ b/crates/rspack_core/src/diagnostics.rs @@ -0,0 +1,4 @@ +use rspack_error::{ + miette::{self, Diagnostic}, + thiserror::{self, Error}, +}; diff --git a/crates/rspack_core/src/lib.rs b/crates/rspack_core/src/lib.rs index 2291c85b444b..d20e23808a0c 100644 --- a/crates/rspack_core/src/lib.rs +++ b/crates/rspack_core/src/lib.rs @@ -8,6 +8,7 @@ use std::sync::atomic::AtomicBool; use std::{fmt, sync::Arc}; mod dependencies_block; +mod diagnostics; pub mod mf; pub use dependencies_block::{ AsyncDependenciesBlock, AsyncDependenciesBlockIdentifier, DependenciesBlock, DependencyLocation, diff --git a/crates/rspack_core/src/mf/sharing/consume_shared_plugin.rs b/crates/rspack_core/src/mf/sharing/consume_shared_plugin.rs index de10ae31963b..e1404c711c61 100644 --- a/crates/rspack_core/src/mf/sharing/consume_shared_plugin.rs +++ b/crates/rspack_core/src/mf/sharing/consume_shared_plugin.rs @@ -74,7 +74,7 @@ fn resolve_matched_configs( resolver.resolve(compilation.options.context.as_ref(), request) else { compilation - .push_batch_diagnostic(internal_error!("Can't resolve shared module {request}").into()); + .push_diagnostic(internal_error!("Can't resolve shared module {request}").into()); continue; }; resolved.insert(resource.path.to_string_lossy().into_owned(), config.clone()); diff --git a/crates/rspack_core/src/normal_module.rs b/crates/rspack_core/src/normal_module.rs index ce3f95ff4ed5..5f75bfcb3fa5 100644 --- a/crates/rspack_core/src/normal_module.rs +++ b/crates/rspack_core/src/normal_module.rs @@ -367,7 +367,7 @@ impl Module for NormalModule { blocks: Vec::new(), analyze_result: Default::default(), } - .with_diagnostic(e.into()), + .with_diagnostic(vec![e.into()]), ); } }; diff --git a/crates/rspack_core/src/normal_module_factory.rs b/crates/rspack_core/src/normal_module_factory.rs index 1728419935d1..5a9706a0b47a 100644 --- a/crates/rspack_core/src/normal_module_factory.rs +++ b/crates/rspack_core/src/normal_module_factory.rs @@ -361,8 +361,7 @@ impl NormalModuleFactory { let module_identifier = ModuleIdentifier::from(format!("missing|{ident}")); let mut file_dependencies = Default::default(); let mut missing_dependencies = Default::default(); - let diagnostics: Vec = internal_error.into(); - let mut diagnostic = diagnostics[0].clone(); + let mut diagnostics: Vec = vec![internal_error.into()]; let mut from_cache_result = from_cache; if !data .resolve_options @@ -405,11 +404,11 @@ impl NormalModuleFactory { "{request_without_match_resource}.{}", extension.to_string_lossy() ); - diagnostic = diagnostic.with_notes(vec![format!("Did you mean '{resource}'? - BREAKING CHANGE: The request '{request_without_match_resource}' failed to resolve only because it was resolved as fully specified - (probably because the origin is strict EcmaScript Module, e. g. a module with javascript mimetype, a '*.mjs' file, or a '*.js' file where the package.json contains '\"type\": \"module\"'). - The extension in the request is mandatory for it to be fully specified. - Add the extension to the request.")]); + // diagnostics[0].add_notes(vec![format!("Did you mean '{resource}'? + // BREAKING CHANGE: The request '{request_without_match_resource}' failed to resolve only because it was resolved as fully specified + // (probably because the origin is strict EcmaScript Module, e. g. a module with javascript mimetype, a '*.mjs' file, or a '*.js' file where the package.json contains '\"type\": \"module\"'). + // The extension in the request is mandatory for it to be fully specified. + // Add the extension to the request.")]); } } } @@ -423,7 +422,7 @@ impl NormalModuleFactory { return Ok(Some( ModuleFactoryResult::new(missing_module) .from_cache(from_cache_result) - .with_diagnostic(vec![diagnostic]), + .with_diagnostic(diagnostics), )); } } diff --git a/crates/rspack_core/src/options/target.rs b/crates/rspack_core/src/options/target.rs index 3eb80a137652..f47aa4bcb770 100644 --- a/crates/rspack_core/src/options/target.rs +++ b/crates/rspack_core/src/options/target.rs @@ -1,4 +1,4 @@ -use anyhow::anyhow; +use rspack_error::{internal_error, Result}; pub use swc_core::ecma::ast::EsVersion; // TODO(swc-loader): Target still coupled with javascript downgrade, it should only affect runtime @@ -24,7 +24,7 @@ pub struct Target { } impl Target { - pub fn new(args: &Vec) -> anyhow::Result { + pub fn new(args: &Vec) -> Result { let mut es_version = TargetEsVersion::None; for item in args { @@ -32,7 +32,7 @@ impl Target { if item.starts_with("es") || item == "browserslist" { // es version if !es_version.is_none() { - return Err(anyhow!("Target es version conflict")); + return Err(internal_error!("Target es version conflict")); } let version = match item { "browserslist" => TargetEsVersion::BrowsersList, @@ -47,7 +47,7 @@ impl Target { "es2021" => TargetEsVersion::Esx(EsVersion::Es2021), "es2022" => TargetEsVersion::Esx(EsVersion::Es2022), _ => { - return Err(anyhow!("Unknown target es version {}", item)); + return Err(internal_error!("Unknown target es version {}", item)); } }; es_version = version; diff --git a/crates/rspack_core/src/resolver/resolver_impl.rs b/crates/rspack_core/src/resolver/resolver_impl.rs index b627309805f5..a6304834359e 100644 --- a/crates/rspack_core/src/resolver/resolver_impl.rs +++ b/crates/rspack_core/src/resolver/resolver_impl.rs @@ -5,7 +5,7 @@ use std::{ }; use rspack_error::{ - internal_error, DiagnosticError, Error, InternalError, Severity, TraceableRspackError, + internal_error, DiagnosticError, ErrorExt, InternalError, Severity, TraceableError, }; use rspack_loader_runner::DescriptionData; use sugar_path::SugarPath; @@ -376,7 +376,10 @@ fn map_nodejs_resolver_error( plugin_driver: &SharedPluginDriver, ) -> ResolveError { match error { - nodejs_resolver::Error::Io(error) => ResolveError(error.to_string(), Error::from(error)), + nodejs_resolver::Error::Io(error) => ResolveError( + error.to_string(), + DiagnosticError::from(error.boxed()).into(), + ), nodejs_resolver::Error::UnexpectedJson((json_path, error)) => ResolveError( format!( "{error:?} in {}", @@ -413,7 +416,7 @@ fn map_oxc_resolver_error( } oxc_resolver::ResolveError::IOError(error) => ResolveError( "IOError".to_string(), - Error::InternalError(DiagnosticError(error.into()).into()), + DiagnosticError::from(error.boxed()).into(), ), oxc_resolver::ResolveError::Builtin(error) => ResolveError( format!("Builtin module: {}", error), @@ -523,7 +526,7 @@ fn map_resolver_error( }; ResolveError( runtime_message, - TraceableRspackError::from_real_file_path( + TraceableError::from_real_file_path( Path::new( importer .split_once('|') @@ -537,14 +540,14 @@ fn map_resolver_error( ) .map(|e| { if args.optional { - Error::TraceableRspackError(e.with_severity(Severity::Warn)) + e.with_severity(Severity::Warn).into() } else { - Error::TraceableRspackError(e) + e.into() } }) .unwrap_or_else(|_| { if args.optional { - Error::InternalError(InternalError::new(internal_message, Severity::Warn)) + InternalError::new(internal_message, Severity::Warn).into() } else { internal_error!(internal_message) } diff --git a/crates/rspack_core/src/tree_shaking/optimizer.rs b/crates/rspack_core/src/tree_shaking/optimizer.rs index 75bdd59377f0..4b1621a92948 100644 --- a/crates/rspack_core/src/tree_shaking/optimizer.rs +++ b/crates/rspack_core/src/tree_shaking/optimizer.rs @@ -1067,10 +1067,7 @@ impl<'a> CodeSizeOptimizer<'a> { }) .collect::>(); error_message += &join_string_component(module_identifier_list); - errors.push(Error::InternalError(InternalError::new( - error_message, - Severity::Warn, - ))); + errors.push(InternalError::new(error_message, Severity::Warn).into()); ret[0].1.clone() } }; @@ -1101,10 +1098,7 @@ impl<'a> CodeSizeOptimizer<'a> { .normal_module_source_path_by_identifier(&star_symbol.src()); if let Some(module_path) = module_path { let error_message = format!("Can't get analyze result of {module_path}"); - errors.push(Error::InternalError(InternalError::new( - error_message, - Severity::Warn, - ))); + errors.push(InternalError::new(error_message, Severity::Warn).into()); } } return; diff --git a/crates/rspack_error/Cargo.toml b/crates/rspack_error/Cargo.toml index 6398a218d57d..06cf9387ce08 100644 --- a/crates/rspack_error/Cargo.toml +++ b/crates/rspack_error/Cargo.toml @@ -8,17 +8,16 @@ version = "0.1.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -anyhow = { workspace = true, features = ["backtrace"] } -codespan-reporting = { version = "=0.11.2", package = "rspack-codespan-reporting" } -futures = { workspace = true } -miette = { version = "5", features = ["fancy"] } -rspack_sources = { workspace = true } -rspack_util = { path = "../rspack_util" } -serde_json = { workspace = true } -sugar_path = { workspace = true } -swc_core = { workspace = true, features = ["common"] } -termcolor = "1.2" -thiserror = "1" +anyhow = { workspace = true, features = ["backtrace"] } +futures = { workspace = true } +miette = { version = "5", features = ["fancy"] } +rspack_sources = { workspace = true } +rspack_util = { path = "../rspack_util" } +serde_json = { workspace = true } +sugar_path = { workspace = true } +swc_core = { workspace = true, features = ["common"] } +termcolor = "1" +thiserror = "1" [dev-dependencies] insta = { workspace = true } diff --git a/crates/rspack_error/src/diagnostic.rs b/crates/rspack_error/src/diagnostic.rs index c55d897f0532..d46c7cae2a17 100644 --- a/crates/rspack_error/src/diagnostic.rs +++ b/crates/rspack_error/src/diagnostic.rs @@ -1,153 +1,136 @@ -use std::fmt; +use std::{ + fmt, + ops::{Deref, DerefMut}, +}; -use crate::{DiagnosticKind, Error, TraceableRspackError}; +use miette::MietteDiagnostic; + +use crate::Error; #[derive(Debug, Clone, Default, Copy, PartialEq, Eq, Hash)] -pub enum Severity { +pub enum RspackSeverity { #[default] Error, Warn, } -impl From for miette::Severity { - fn from(value: Severity) -> Self { +pub type Severity = RspackSeverity; + +impl From for miette::Severity { + fn from(value: RspackSeverity) -> Self { + match value { + RspackSeverity::Error => miette::Severity::Error, + RspackSeverity::Warn => miette::Severity::Warning, + } + } +} + +impl From for RspackSeverity { + fn from(value: miette::Severity) -> Self { match value { - Severity::Error => miette::Severity::Error, - Severity::Warn => miette::Severity::Warning, + miette::Severity::Error => RspackSeverity::Error, + miette::Severity::Warning => RspackSeverity::Warn, + miette::Severity::Advice => unimplemented!("Not supported miette serverity"), } } } -impl fmt::Display for Severity { +impl fmt::Display for RspackSeverity { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "{}", match self { - Severity::Error => "error", - Severity::Warn => "warning", + RspackSeverity::Error => "error", + RspackSeverity::Warn => "warning", } ) } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct DiagnosticSourceInfo { - pub path: String, - pub source: String, -} +#[derive(Debug)] +pub struct Diagnostic(miette::Error); -#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)] -pub struct Diagnostic { - pub(crate) severity: Severity, - pub(crate) message: String, - pub(crate) title: String, - /// Source code and path of current Diagnostic - pub(crate) source_info: Option, - pub(crate) start: usize, - pub(crate) end: usize, - pub(crate) kind: DiagnosticKind, - pub(crate) notes: Vec, +impl From for Diagnostic { + fn from(value: miette::Error) -> Self { + Self(value) + } } -impl Diagnostic { - pub fn warn(title: String, message: String, start: usize, end: usize) -> Self { - Self { - severity: Severity::Warn, - title, - message, - source_info: None, - start, - end, - ..Default::default() - } +impl Deref for Diagnostic { + type Target = miette::Error; + + fn deref(&self) -> &Self::Target { + &self.0 } +} - pub fn error(title: String, message: String, start: usize, end: usize) -> Self { - Self { - severity: Severity::Error, - message, - source_info: None, - start, - end, - title, - ..Default::default() - } +impl DerefMut for Diagnostic { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 } +} - pub fn title(&self) -> &str { - &self.title +/// Shouldn't rely on this in deduping. +/// Have to make sure everything is deduped in the first place. +impl std::hash::Hash for Diagnostic { + fn hash(&self, state: &mut H) { + self.0.to_string().hash(state); + self.0.code().map(|c| c.to_string()).hash(state); + self.0.help().map(|h| h.to_string()).hash(state); + self.0.url().map(|u| u.to_string()).hash(state); + self.0.severity().map(Severity::from).hash(state); } +} - pub fn message(&self) -> &str { - &self.message +/// Shouldn't rely on this in deduping. +/// Have to make sure everything is deduped in the first place. +impl PartialEq for Diagnostic { + fn eq(&self, other: &Self) -> bool { + self.0.to_string() == other.0.to_string() + && self.0.code().map(|c| c.to_string()) == other.0.code().map(|c| c.to_string()) + && self.0.help().map(|h| h.to_string()) == other.0.help().map(|h| h.to_string()) + && self.0.url().map(|u| u.to_string()) == other.0.url().map(|u| u.to_string()) + && self.0.severity() == other.0.severity() } +} - pub fn severity(&self) -> Severity { - self.severity +impl Eq for Diagnostic {} + +impl Diagnostic { + pub fn title(&self) -> String { + self.0.code().map(|v| v.to_string()).unwrap_or_default() } - pub fn with_kind(mut self, kind: DiagnosticKind) -> Self { - self.kind = kind; - self + pub fn message(&self) -> String { + self.0.to_string() } - pub fn with_source_info(mut self, source: DiagnosticSourceInfo) -> Self { - self.source_info = Some(source); - self + pub fn severity(&self) -> Severity { + self.0.severity().unwrap_or_default().into() } - pub fn with_notes(mut self, notes: Vec) -> Self { - self.notes = notes; - self + + pub fn warn(title: String, message: String) -> Self { + Self( + MietteDiagnostic::new(message) + .with_code(title) + .with_severity(miette::Severity::Warning) + .into(), + ) } -} -impl From for Vec { - fn from(err: Error) -> Self { - let diagnostic = match err { - Error::InternalError(err) => Diagnostic { - message: err.error_message().to_string(), - source_info: None, - start: 0, - end: 0, - severity: err.severity(), - ..Default::default() - }, - Error::TraceableRspackError(TraceableRspackError { - start, - end, - error_message, - title, - kind, - severity, - file_path, - file_src, - }) => Diagnostic { - message: error_message, - source_info: Some(DiagnosticSourceInfo { - source: file_src, - path: file_path, - }), - start, - end, - title, - kind, - severity, - ..Default::default() - }, - Error::BatchErrors(diagnostics) => { - return diagnostics - .into_iter() - .flat_map(Vec::::from) - .collect::>() - } - }; - vec![diagnostic] + pub fn error(title: String, message: String) -> Self { + Self( + MietteDiagnostic::new(message) + .with_code(title) + .with_severity(miette::Severity::Error) + .into(), + ) } } pub fn errors_to_diagnostics(errs: Vec) -> Vec { - errs.into_iter().flat_map(Vec::::from).collect() + errs.into_iter().map(Diagnostic).collect() } pub const DIAGNOSTIC_POS_DUMMY: usize = 0; diff --git a/crates/rspack_error/src/emitter.rs b/crates/rspack_error/src/emitter.rs index 209c8eab31a9..a38556b69a6c 100644 --- a/crates/rspack_error/src/emitter.rs +++ b/crates/rspack_error/src/emitter.rs @@ -1,15 +1,16 @@ -use std::io::Write; -use std::path::Path; +use std::io::{IsTerminal, Write}; use anyhow::Context; -use codespan_reporting::diagnostic::{Diagnostic, Label, Severity}; -use codespan_reporting::files::SimpleFiles; -use codespan_reporting::term::termcolor::{ColorChoice, StandardStream}; -use codespan_reporting::term::{self, Config}; -use sugar_path::SugarPath; +use miette::{GraphicalReportHandler, GraphicalTheme, IntoDiagnostic}; use termcolor::{Buffer, ColorSpec, StandardStreamLock, WriteColor}; +use termcolor::{ColorChoice, StandardStream}; -use crate::Diagnostic as RspackDiagnostic; +use crate::Diagnostic; + +/// Detects if's in a terminal. +fn is_terminal() -> bool { + std::io::stdout().is_terminal() && std::io::stderr().is_terminal() +} pub trait FlushDiagnostic { fn flush_diagnostic(&mut self) {} @@ -28,9 +29,9 @@ pub trait DiagnosticDisplay { type Output; fn emit_batch_diagnostic( &mut self, - diagnostics: impl Iterator, + diagnostics: impl Iterator, ) -> Self::Output; - fn emit_diagnostic(&mut self, diagnostic: &RspackDiagnostic) -> Self::Output; + fn emit_diagnostic(&mut self, diagnostic: &Diagnostic) -> Self::Output; } #[derive(Default)] @@ -41,19 +42,17 @@ impl DiagnosticDisplay for StdioDiagnosticDisplay { fn emit_batch_diagnostic( &mut self, - diagnostics: impl Iterator, + diagnostics: impl Iterator, ) -> Self::Output { let writer = StandardStream::stderr(ColorChoice::Always); let mut lock_writer = writer.lock(); emit_batch_diagnostic(diagnostics, &mut lock_writer) } - fn emit_diagnostic(&mut self, diagnostic: &RspackDiagnostic) -> Self::Output { + fn emit_diagnostic(&mut self, diagnostic: &Diagnostic) -> Self::Output { let writer = StandardStream::stderr(ColorChoice::Always); let mut lock_writer = writer.lock(); - let mut files = SimpleFiles::new(); - let pwd = std::env::current_dir()?; - emit_diagnostic(diagnostic, &mut lock_writer, &pwd, &mut files) + emit_diagnostic(diagnostic, &mut lock_writer) } } @@ -102,7 +101,7 @@ impl DiagnosticDisplay for StringDiagnosticDisplay { fn emit_batch_diagnostic( &mut self, - diagnostics: impl Iterator, + diagnostics: impl Iterator, ) -> Self::Output { emit_batch_diagnostic(diagnostics, self)?; if self.sorted { @@ -111,16 +110,15 @@ impl DiagnosticDisplay for StringDiagnosticDisplay { Ok(self.diagnostic_vector.drain(..).collect()) } - fn emit_diagnostic(&mut self, diagnostic: &RspackDiagnostic) -> Self::Output { - let mut files = SimpleFiles::new(); - let pwd = std::env::current_dir()?; - emit_diagnostic(diagnostic, self, &pwd, &mut files)?; + fn emit_diagnostic(&mut self, diagnostic: &Diagnostic) -> Self::Output { + emit_diagnostic(diagnostic, self)?; self.flush_diagnostic(); Ok( self .diagnostic_vector .pop() - .context("diagnostic_vector should not empty after flush_diagnostic")?, + .context("diagnostic_vector should not empty after flush_diagnostic") + .map_err(|e| miette::miette!(e.to_string()))?, ) } } @@ -133,35 +131,28 @@ impl DiagnosticDisplay for ColoredStringDiagnosticDisplay { fn emit_batch_diagnostic( &mut self, - diagnostics: impl Iterator, + diagnostics: impl Iterator, ) -> Self::Output { - let mut files = SimpleFiles::new(); - let pwd = std::env::current_dir()?; let mut buf = Buffer::ansi(); for d in diagnostics { - emit_diagnostic(d, &mut buf, &pwd, &mut files)?; + emit_diagnostic(d, &mut buf)?; } Ok(String::from_utf8_lossy(buf.as_slice()).to_string()) } - fn emit_diagnostic(&mut self, diagnostic: &RspackDiagnostic) -> Self::Output { - let mut files = SimpleFiles::new(); - let pwd = std::env::current_dir()?; + fn emit_diagnostic(&mut self, diagnostic: &Diagnostic) -> Self::Output { let mut buf = Buffer::ansi(); - emit_diagnostic(diagnostic, &mut buf, &pwd, &mut files)?; + emit_diagnostic(diagnostic, &mut buf)?; Ok(String::from_utf8_lossy(buf.as_slice()).to_string()) } } fn emit_batch_diagnostic( - diagnostics: impl Iterator, + diagnostics: impl Iterator, writer: &mut T, ) -> crate::Result<()> { - let mut files = SimpleFiles::new(); - let pwd = std::env::current_dir()?; - for diagnostic in diagnostics { - emit_diagnostic(diagnostic, writer, &pwd, &mut files)?; + emit_diagnostic(diagnostic, writer)?; // `codespan_reporting` will not write the diagnostic message in a whole, // we need to insert some helper flag for sorting writer.flush_diagnostic(); @@ -170,53 +161,23 @@ fn emit_batch_diagnostic( } fn emit_diagnostic( - diagnostic: &RspackDiagnostic, + diagnostic: &Diagnostic, writer: &mut T, - pwd: impl AsRef, - files: &mut SimpleFiles, ) -> crate::Result<()> { - let (labels, message) = match &diagnostic.source_info { - Some(info) => { - let file_path = Path::new(&info.path); - let relative_path = file_path.relative(&pwd); - let relative_path = relative_path.as_os_str().to_string_lossy().to_string(); - let file_id = files.add(relative_path, info.source.clone()); - ( - vec![Label::primary(file_id, diagnostic.start..diagnostic.end) - .with_message(&diagnostic.message)], - diagnostic.title.clone(), - ) - } - None => (vec![], diagnostic.message.clone()), - }; - - let diagnostic = Diagnostic::new(diagnostic.severity.into()) - .with_message(message) - // Because we don't have error code now, and I don't think we have - // enough energy to matain error code either in the future, so I use - // this field to represent diagnostic kind, looks pretty neat. - .with_code(diagnostic.kind.to_string()) - .with_notes(diagnostic.notes.clone()) - .with_labels(labels); - - let config = Config { - before_label_lines: 4, - after_label_lines: 4, - ..Config::default() - }; - - term::emit(writer, &config, files, &diagnostic).expect("TODO:"); + let h = GraphicalReportHandler::new().with_theme(if !is_terminal() { + GraphicalTheme::ascii() + } else if writer.supports_color() { + GraphicalTheme::unicode() + } else { + GraphicalTheme::unicode_nocolor() + }); + let mut buf = String::new(); + h.render_report(&mut buf, diagnostic.as_ref()) + .into_diagnostic()?; + writer.write_all(buf.as_bytes()).into_diagnostic()?; // reset to original color after emitting a diagnostic, this avoids interference stdio of other procedure. - writer.reset().map_err(|e| e.into()) -} - -impl From for Severity { - fn from(severity: crate::Severity) -> Self { - match severity { - crate::Severity::Error => Self::Error, - crate::Severity::Warn => Self::Warning, - } - } + writer.reset().into_diagnostic()?; + Ok(()) } #[derive(Debug, Clone)] @@ -240,7 +201,7 @@ impl DiagnosticDisplay for DiagnosticDisplayer { fn emit_batch_diagnostic( &mut self, - diagnostics: impl Iterator, + diagnostics: impl Iterator, ) -> Self::Output { match self { Self::Colored(d) => d.emit_batch_diagnostic(diagnostics), @@ -248,7 +209,7 @@ impl DiagnosticDisplay for DiagnosticDisplayer { } } - fn emit_diagnostic(&mut self, diagnostic: &RspackDiagnostic) -> Self::Output { + fn emit_diagnostic(&mut self, diagnostic: &Diagnostic) -> Self::Output { match self { Self::Colored(d) => d.emit_diagnostic(diagnostic), Self::Plain(d) => d.emit_diagnostic(diagnostic), diff --git a/crates/rspack_error/src/error.rs b/crates/rspack_error/src/error.rs index e1ea315ac5eb..3fbf4f89a6ed 100644 --- a/crates/rspack_error/src/error.rs +++ b/crates/rspack_error/src/error.rs @@ -1,73 +1,101 @@ -use std::{fmt, io, path::Path}; - -use miette::{Diagnostic, IntoDiagnostic, MietteDiagnostic, NamedSource, SourceSpan}; +use std::{ + fmt, + path::{Path, PathBuf}, +}; + +use miette::{ + Diagnostic, IntoDiagnostic, LabeledSpan, MietteDiagnostic, NamedSource, SourceCode, SourceSpan, +}; use rspack_util::swc::normalize_custom_filename; +use sugar_path::SugarPath; use swc_core::common::SourceFile; use thiserror::Error; -use crate::Severity; - -#[derive(Debug)] -pub struct InternalError(miette::Report); +use crate::RspackSeverity; -impl From for InternalError { - fn from(value: T) -> Self { - InternalError(value.into()) - } -} +#[derive(Debug, Error)] +#[error(transparent)] +pub struct InternalError(#[from] Box); impl InternalError { - pub fn new(error_message: String, severity: Severity) -> Self { - Self(miette::Report::new( - MietteDiagnostic::new(error_message.clone()).with_severity(severity.into()), + pub fn new(message: String, severity: RspackSeverity) -> Self { + Self(Box::new( + MietteDiagnostic::new(message).with_severity(severity.into()), )) } - - fn cast_to_miette(&self) -> &MietteDiagnostic { - match self.0.downcast_ref::() { - Some(e) => e, - None => unreachable!(), - } - } - - pub fn error_message(&self) -> &str { - match self.0.downcast_ref::() { - Some(e) => &e.message, - None => unreachable!(), - } - } - - pub fn severity(&self) -> Severity { - let severity = self.cast_to_miette().severity.as_ref(); - match severity.expect("severity should available") { - miette::Severity::Advice => unreachable!(), - miette::Severity::Warning => Severity::Warn, - miette::Severity::Error => Severity::Error, - } - } } -impl fmt::Display for InternalError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - writeln!(f, "{}[internal]: {}", self.severity(), self.error_message()) +/// Convenience [`Diagnostic`] that can be used as an "anonymous" wrapper for +/// Errors. This is intended to be paired with [`IntoDiagnostic`]. +#[derive(Debug, Error)] +#[error(transparent)] +pub struct DiagnosticError(Box); +impl Diagnostic for DiagnosticError {} + +impl From> for DiagnosticError { + fn from(value: Box) -> Self { + Self(value) } } +/// Handle [anyhow::Error] +/// Please try NOT to use this as much as possible. #[derive(Debug, Error, Diagnostic)] -#[diagnostic(code(TraceableError))] -#[error("error[{kind}]: {title}")] +#[error(transparent)] +pub struct AnyhowError(#[from] anyhow::Error); + +/// ## Warning +/// For a [TraceableError], the path is required. +/// Because if the source code is missing when you construct a [TraceableError], we could read it from file system later +/// when convert it into [crate::Diagnostic], but the reverse will not working. +#[derive(Debug, Error)] +#[error("{severity:?}[{kind}]: {title}")] pub struct TraceableError { title: String, kind: DiagnosticKind, message: String, - // file_path: String, - #[source_code] + severity: miette::Severity, src: NamedSource, - #[label("{message}")] label: SourceSpan, } +impl miette::Diagnostic for TraceableError { + fn severity(&self) -> Option { + Some(self.severity) + } + fn labels(&self) -> Option + '_>> { + use miette::macro_helpers::{OptionalWrapper, ToOption}; + let Self { message, .. } = self; + std::option::Option::Some(Box::new( + vec![OptionalWrapper::::new() + .to_option(&self.label) + .map(|label| { + miette::LabeledSpan::new_with_span( + Some(format!("{message}", message = message)), + label.clone(), + ) + })] + .into_iter() + .filter(Option::is_some) + .map(Option::unwrap), + )) + } + fn source_code(&self) -> Option<&dyn SourceCode> { + Some(&self.src) + } +} + impl TraceableError { + pub fn with_severity(mut self, severity: impl Into) -> Self { + self.severity = severity.into(); + self + } + + pub fn with_kind(mut self, kind: DiagnosticKind) -> Self { + self.kind = kind; + self + } + pub fn from_source_file( source_file: &SourceFile, start: usize, @@ -76,12 +104,17 @@ impl TraceableError { message: String, ) -> Self { let file_path = normalize_custom_filename(&source_file.name.to_string()).to_string(); + let file_path = relative_to_pwd(PathBuf::from(file_path)); let file_src = source_file.src.to_string(); Self { title, kind: Default::default(), message, - src: NamedSource::new(file_path, file_src), + severity: Default::default(), + src: NamedSource::new( + file_path.as_os_str().to_string_lossy().to_string(), + file_src, + ), label: SourceSpan::new(start.into(), (end - start).into()), } } @@ -94,11 +127,16 @@ impl TraceableError { title: String, message: String, ) -> Self { + let file_path = relative_to_pwd(PathBuf::from(file_path)); Self { title, kind: Default::default(), message, - src: NamedSource::new(file_path, file_src), + severity: Default::default(), + src: NamedSource::new( + file_path.as_os_str().to_string_lossy().to_string(), + file_src, + ), label: SourceSpan::new(start.into(), (end - start).into()), } } @@ -109,7 +147,7 @@ impl TraceableError { end: usize, title: String, message: String, - ) -> Result { + ) -> Result { let file_src = std::fs::read_to_string(path).into_diagnostic()?; Ok(Self::from_file( path.to_string_lossy().into_owned(), @@ -122,182 +160,86 @@ impl TraceableError { } } -#[derive(Debug)] -/// ## Warning -/// For a [TraceableRspackError], the path is required. -/// Because if the source code is missing when you construct a [TraceableRspackError], we could read it from file system later -/// when convert it into [crate::Diagnostic], but the reverse will not working. -pub struct TraceableRspackError { - /// path of a file (real file or virtual file) - pub(crate) file_path: String, - /// source content of a file (real file or virtual file) - pub(crate) file_src: String, - pub(crate) start: usize, - pub(crate) end: usize, - pub(crate) error_message: String, - pub(crate) title: String, - pub(crate) kind: DiagnosticKind, - pub(crate) severity: Severity, -} +/// Multiple errors to represent different kinds of errors. +/// NEVER implement this with [miette::Diagnostic], +/// because it makes code hard to maintain. +#[derive(Debug, Default)] +pub struct BatchErrors(pub Vec); -impl TraceableRspackError { - pub fn from_source_file( - source_file: &SourceFile, - start: usize, - end: usize, - title: String, - error_message: String, - ) -> Self { - let file_path = normalize_custom_filename(&source_file.name.to_string()).to_string(); - let file_src = source_file.src.to_string(); - Self { - file_path, - file_src, - start, - end, - error_message, - title, - kind: DiagnosticKind::Internal, - severity: Severity::Error, - } - } - - pub fn from_file( - file_path: String, - file_src: String, - start: usize, - end: usize, - title: String, - error_message: String, - ) -> Self { - Self { - file_path, - file_src, - start, - end, - error_message, - title, - kind: DiagnosticKind::Internal, - severity: Severity::Error, - } - } - - pub fn from_real_file_path( - path: &Path, - start: usize, - end: usize, - title: String, - error_message: String, - ) -> Result { - let file_src = std::fs::read_to_string(path)?; - Ok(Self::from_file( - path.to_string_lossy().into_owned(), - file_src, - start, - end, - title, - error_message, - )) - } - - pub fn with_kind(mut self, kind: DiagnosticKind) -> Self { - self.kind = kind; - self - } - - pub fn with_severity(mut self, severity: Severity) -> Self { - self.severity = severity; - self +impl BatchErrors { + pub fn into_inner(self) -> Vec { + self.0 } } -impl fmt::Display for TraceableRspackError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - writeln!(f, "{}[{}]: {}", self.severity, self.kind, self.title)?; - writeln!(f, "{}", self.error_message)?; - writeln!(f, "in {}", self.file_path) +impl From for Vec { + fn from(value: BatchErrors) -> Self { + value + .0 + .into_iter() + .map(|v| crate::Diagnostic::from(v)) + .collect() } } -#[derive(Debug)] -pub enum Error { - InternalError(InternalError), - TraceableRspackError(TraceableRspackError), - BatchErrors(Vec), -} - -impl From for Error { +impl From for BatchErrors { fn from(value: miette::Error) -> Self { - Self::InternalError(InternalError(value)) + Self(vec![value]) } } -impl std::error::Error for Error { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match self { - Error::InternalError(InternalError(i)) => i.source(), - _ => None, - } +impl From> for BatchErrors { + fn from(value: Vec) -> Self { + Self(value) } } -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Error::InternalError(e) => write!(f, "{e}"), - Error::TraceableRspackError(v) => write!(f, "{v}"), - Error::BatchErrors(errs) => write!( - f, - "{}", - errs - .iter() - .map(|e| e.to_string()) - .collect::>() - .join("\n") - ), - } - } -} +macro_rules! impl_diagnostic_transparent { + ($ty:ty) => { + impl miette::Diagnostic for $ty { + fn code<'a>(&'a self) -> Option> { + (&*self.0).code() + } -impl From for Error { - fn from(value: serde_json::Error) -> Self { - Error::InternalError(InternalError::new(value.to_string(), Severity::Error)) - } -} + fn severity(&self) -> Option { + (&*self.0).severity() + } -impl From for Error { - fn from(source: io::Error) -> Self { - Error::InternalError(DiagnosticError(source.into()).into()) - } -} + fn help<'a>(&'a self) -> Option> { + (&*self.0).help() + } -impl From for Error { - fn from(source: anyhow::Error) -> Self { - Error::InternalError(DiagnosticError(source.into()).into()) - } -} + fn url<'a>(&'a self) -> Option> { + (&*self.0).url() + } -impl From for Error { - fn from(value: rspack_sources::Error) -> Self { - Error::InternalError(DiagnosticError(value.into()).into()) - } -} + fn source_code(&self) -> Option<&dyn SourceCode> { + (&*self.0).source_code() + } -impl Error { - pub fn kind(&self) -> DiagnosticKind { - match self { - Error::InternalError(_) => DiagnosticKind::Internal, - Error::TraceableRspackError(TraceableRspackError { kind, .. }) => *kind, - Error::BatchErrors(_) => DiagnosticKind::Internal, - } - } - pub fn severity(&self) -> Severity { - match self { - Error::InternalError(_) => Severity::Error, - Error::TraceableRspackError(TraceableRspackError { severity, .. }) => *severity, - Error::BatchErrors(_) => Severity::Error, + fn labels(&self) -> Option + '_>> { + (&*self.0).labels() + } + + fn related<'a>(&'a self) -> Option + 'a>> { + (&*self.0).related() + } + + fn diagnostic_source(&self) -> Option<&dyn Diagnostic> { + (&*self.0).diagnostic_source() + } } - } + }; +} + +impl_diagnostic_transparent!(InternalError); + +/// # Panic +/// +/// Panics if `current_dir` is not accessible. +/// See [std::env::current_dir] for details. +fn relative_to_pwd(file: impl AsRef) -> PathBuf { + file.as_ref().relative(std::env::current_dir().unwrap()) } #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)] @@ -334,9 +276,8 @@ impl std::fmt::Display for DiagnosticKind { } } -/// Convenience [`Diagnostic`] that can be used as an "anonymous" wrapper for -/// Errors. This is intended to be paired with [`IntoDiagnostic`]. -#[derive(Debug, Error)] -#[error(transparent)] -pub struct DiagnosticError(pub Box); -impl Diagnostic for DiagnosticError {} +fn _assert() { + fn _assert_send_sync() {} + _assert_send_sync::(); + _assert_send_sync::(); +} diff --git a/crates/rspack_error/src/ext.rs b/crates/rspack_error/src/ext.rs new file mode 100644 index 000000000000..7a5129f31aa6 --- /dev/null +++ b/crates/rspack_error/src/ext.rs @@ -0,0 +1,12 @@ +use std::error::Error; + +/// Useful to convert [std::error::Error] to [crate::DiagnosticError] +pub trait ErrorExt { + fn boxed(self) -> Box; +} + +impl ErrorExt for T { + fn boxed(self) -> Box { + Box::new(self) + } +} diff --git a/crates/rspack_error/src/lib.rs b/crates/rspack_error/src/lib.rs index 3f61fdf1a0eb..09bf745605ec 100644 --- a/crates/rspack_error/src/lib.rs +++ b/crates/rspack_error/src/lib.rs @@ -4,9 +4,11 @@ mod catch_unwind; mod diagnostic; mod error; +mod ext; pub use catch_unwind::*; pub use diagnostic::*; pub use error::*; +pub use ext::*; pub mod emitter; mod macros; @@ -14,7 +16,9 @@ mod macros; pub use miette; pub use thiserror; -pub type Result = std::result::Result; +pub type Error = miette::Error; + +pub type Result = std::result::Result; /// A helper struct for change logic from /// return something to something with diagnostics array @@ -42,14 +46,14 @@ impl TWithDiagnosticArray { } } -impl Clone for TWithDiagnosticArray { - fn clone(&self) -> Self { - Self { - inner: self.inner.clone(), - diagnostic: self.diagnostic.clone(), - } - } -} +// impl Clone for TWithDiagnosticArray { +// fn clone(&self) -> Self { +// Self { +// inner: self.inner.clone(), +// diagnostic: self.diagnostic.clone(), +// } +// } +// } // Helper trait to make `TWithDiagnosticArray` conversion more easily. pub trait IntoTWithDiagnosticArray { @@ -84,7 +88,9 @@ impl IntoTWithDiagnosticArray for T { pub mod __private { pub use core::result::Result::Err; + pub use miette::miette; + pub use crate::diagnostic::Severity; - pub use crate::error::{Error, InternalError}; + pub use crate::error::InternalError; pub use crate::internal_error; } diff --git a/crates/rspack_error/src/macros.rs b/crates/rspack_error/src/macros.rs index edc2b256bb4e..582c42ab01bb 100644 --- a/crates/rspack_error/src/macros.rs +++ b/crates/rspack_error/src/macros.rs @@ -1,9 +1,7 @@ #[macro_export] macro_rules! internal_error { (@base $expr:expr) => { - $crate::__private::Error::InternalError( - $crate::__private::InternalError::new($expr, $crate::__private::Severity::Error) - ) + $crate::__private::miette!($expr) }; ($str:literal $(,)?) => {{ let err = format!($str); diff --git a/crates/rspack_fs/src/error.rs b/crates/rspack_fs/src/error.rs index 81e6f2f568c2..73c6d9d63b3d 100644 --- a/crates/rspack_fs/src/error.rs +++ b/crates/rspack_fs/src/error.rs @@ -1,5 +1,16 @@ use std::fmt::Display; +#[cfg(feature = "rspack-error")] +use rspack_error::{ + miette::{self, Diagnostic}, + thiserror::{self, Error}, +}; + +#[cfg(feature = "rspack-error")] +#[derive(Debug, Error, Diagnostic)] +#[error("Rspack FS Error: {0}")] +struct FsError(#[source] std::io::Error); + #[derive(Debug)] pub enum Error { /// Generic I/O error @@ -16,7 +27,7 @@ impl From for Error { impl From for rspack_error::Error { fn from(value: Error) -> Self { match value { - Error::Io(err) => rspack_error::Error::from(err), + Error::Io(err) => FsError(err).into(), } } } diff --git a/crates/rspack_loader_sass/src/lib.rs b/crates/rspack_loader_sass/src/lib.rs index af8a80327f9d..4192d4928a13 100644 --- a/crates/rspack_loader_sass/src/lib.rs +++ b/crates/rspack_loader_sass/src/lib.rs @@ -16,7 +16,7 @@ use rspack_core::{ }; use rspack_error::{ internal_error, Diagnostic, DiagnosticKind, Error, InternalError, Result, Severity, - TraceableRspackError, + TraceableError, }; use rspack_loader_runner::{Identifiable, Identifier, Loader, LoaderContext}; use sass_embedded::{ @@ -473,7 +473,7 @@ impl Loader for SassLoader { let sass_options = self.get_sass_options(loader_context, content.try_into_string()?, logger); let result = Sass::new(&self.options.__exe_path) .map_err(|e| { - rspack_error::Error::InternalError(InternalError::new( + InternalError::new( format!( "{}: The dart-sass-embedded path is {}, your OS is {}, your Arch is {}", e.message(), @@ -482,7 +482,7 @@ impl Loader for SassLoader { get_arch(), ), Severity::Error, - )) + ) })? .render(sass_options) .map_err(sass_exception_to_error)?; @@ -524,7 +524,7 @@ fn sass_exception_to_error(e: Box) -> Error { && let Some(message) = e.sass_message() && let Some(e) = make_traceable_error("Sass Error", message, span) { - Error::TraceableRspackError(e.with_kind(DiagnosticKind::Scss)) + e.with_kind(DiagnosticKind::Scss).into() } else { internal_error!(e.message().to_string()) } @@ -542,21 +542,18 @@ fn sass_log_to_diagnostics( if let Some(span) = span && let Some(e) = make_traceable_error(title, message, span) { - Error::TraceableRspackError(e.with_kind(DiagnosticKind::Scss).with_severity(severity)).into() + vec![Error::from(e.with_kind(DiagnosticKind::Scss).with_severity(severity)).into()] } else { let f = match severity { Severity::Error => Diagnostic::error, Severity::Warn => Diagnostic::warn, }; - vec![f(title.to_string(), message.to_string(), 0, 0).with_kind(DiagnosticKind::Scss)] + let title = "sass-loader: ".to_string() + title; + vec![f(title, message.to_string())] } } -fn make_traceable_error( - title: &str, - message: &str, - span: &SourceSpan, -) -> Option { +fn make_traceable_error(title: &str, message: &str, span: &SourceSpan) -> Option { span .url .as_ref() @@ -575,7 +572,7 @@ fn make_traceable_error( .map(|(path, source)| { let start = utf16::to_byte_idx(&source, span.start.offset); let end = utf16::to_byte_idx(&source, span.end.offset); - TraceableRspackError::from_file( + TraceableError::from_file( path, source, start, diff --git a/crates/rspack_loader_swc/src/lib.rs b/crates/rspack_loader_swc/src/lib.rs index 135520009509..cbabcdf0e358 100644 --- a/crates/rspack_loader_swc/src/lib.rs +++ b/crates/rspack_loader_swc/src/lib.rs @@ -11,7 +11,7 @@ use options::SwcCompilerOptionsWithAdditional; pub use options::SwcLoaderJsOptions; use rspack_ast::RspackAst; use rspack_core::{rspack_sources::SourceMap, LoaderRunnerContext, Mode}; -use rspack_error::{internal_error, Diagnostic, Result}; +use rspack_error::{internal_error, AnyhowError, Diagnostic, Result}; use rspack_loader_runner::{Identifiable, Identifier, Loader, LoaderContext}; use rspack_plugin_javascript::ast::{self, SourceMapConfig}; use rspack_plugin_javascript::TransformOutput; @@ -73,8 +73,6 @@ impl Loader for SwcLoader { loader_context.emit_diagnostic(Diagnostic::warn( SWC_LOADER_IDENTIFIER.to_string(), "Experimental plugins are not currently supported.".to_string(), - 0, - 0, )); } @@ -82,8 +80,6 @@ impl Loader for SwcLoader { loader_context.emit_diagnostic(Diagnostic::warn( SWC_LOADER_IDENTIFIER.to_string(), "`env` and `jsc.target` cannot be used together".to_string(), - 0, - 0, )); } swc_options @@ -91,7 +87,8 @@ impl Loader for SwcLoader { let devtool = &loader_context.context.options.devtool; let source = content.try_into_string()?; - let c = SwcCompiler::new(resource_path.clone(), source.clone(), swc_options)?; + let c = SwcCompiler::new(resource_path.clone(), source.clone(), swc_options) + .map_err(AnyhowError::from)?; let rspack_options = &*loader_context.context.options; let swc_options = c.options(); @@ -102,18 +99,20 @@ impl Loader for SwcLoader { .unresolved_mark .expect("`unresolved_mark` should be initialized"); - let built = c.parse(None, |_| { - transformer::transform( - &resource_path, - rspack_options, - Some(c.comments()), - top_level_mark, - unresolved_mark, - c.cm().clone(), - &source, - &self.options_with_additional.rspack_experiments, - ) - })?; + let built = c + .parse(None, |_| { + transformer::transform( + &resource_path, + rspack_options, + Some(c.comments()), + top_level_mark, + unresolved_mark, + c.cm().clone(), + &source, + &self.options_with_additional.rspack_experiments, + ) + }) + .map_err(AnyhowError::from)?; let codegen_options = ast::CodegenOptions { target: Some(built.target), @@ -132,7 +131,7 @@ impl Loader for SwcLoader { inline_script: Some(false), keep_comments: Some(true), }; - let program = c.transform(built)?; + let program = c.transform(built).map_err(AnyhowError::from)?; let ast = c.into_js_ast(program); // If swc-loader is the latest loader available, @@ -152,7 +151,10 @@ impl Loader for SwcLoader { } else { let TransformOutput { code, map } = ast::stringify(&ast, codegen_options)?; loader_context.content = Some(code.into()); - loader_context.source_map = map.map(|m| SourceMap::from_json(&m)).transpose()?; + loader_context.source_map = map + .map(|m| SourceMap::from_json(&m)) + .transpose() + .map_err(|e| internal_error!(e.to_string()))?; } Ok(()) diff --git a/crates/rspack_napi_shared/src/errors.rs b/crates/rspack_napi_shared/src/errors.rs index f18bc4980f99..082d976f3ebc 100644 --- a/crates/rspack_napi_shared/src/errors.rs +++ b/crates/rspack_napi_shared/src/errors.rs @@ -23,11 +23,11 @@ pub trait NapiResultExt { impl NapiErrorExt for Error { fn into_rspack_error(self) -> rspack_error::Error { - rspack_error::Error::InternalError(NodeError(self.reason, "".to_string()).into()) + NodeError(self.reason, "".to_string()).into() } fn into_rspack_error_with_detail(self, env: &Env) -> rspack_error::Error { let (reason, backtrace) = extract_stack_or_message_from_napi_error(env, self); - rspack_error::Error::InternalError(NodeError(reason, backtrace.unwrap_or_default()).into()) + NodeError(reason, backtrace.unwrap_or_default()).into() } } diff --git a/crates/rspack_napi_shared/src/lib.rs b/crates/rspack_napi_shared/src/lib.rs index 36725baef1cc..f24e55aa3ecc 100644 --- a/crates/rspack_napi_shared/src/lib.rs +++ b/crates/rspack_napi_shared/src/lib.rs @@ -11,7 +11,20 @@ pub mod threadsafe_function; thread_local! { // Safety: A single node process always share the same napi_env, so it's safe to use a thread local - pub static NAPI_ENV: std::cell::RefCell> = Default::default(); + static NAPI_ENV: std::cell::RefCell> = Default::default(); +} + +/// Get [napi::sys::napi_env], only intended to be called on main thread. +/// # Panic +/// +/// Panics if is accessed from other thread. +pub unsafe fn get_napi_env() -> napi::sys::napi_env { + NAPI_ENV.with(|e| e.borrow().expect("NAPI ENV should be available")) +} + +/// Set [napi::sys::napi_env] +pub fn set_napi_env(napi_env: napi::sys::napi_env) { + NAPI_ENV.with(|e| *e.borrow_mut() = Some(napi_env)) } pub use crate::{ diff --git a/crates/rspack_plugin_copy/src/lib.rs b/crates/rspack_plugin_copy/src/lib.rs index fa1e584c62b6..a5205003aa37 100644 --- a/crates/rspack_plugin_copy/src/lib.rs +++ b/crates/rspack_plugin_copy/src/lib.rs @@ -15,7 +15,7 @@ use rspack_core::{ rspack_sources::RawSource, AssetInfo, AssetInfoRelated, Compilation, CompilationAsset, CompilationLogger, Filename, Logger, PathData, Plugin, }; -use rspack_error::Diagnostic; +use rspack_error::{Diagnostic, DiagnosticError, Error, ErrorExt}; use rspack_hash::{HashDigest, HashFunction, HashSalt, RspackHash, RspackHashDigest}; use sugar_path::{AsPath, SugarPath}; @@ -232,7 +232,8 @@ impl CopyRspackPlugin { RawSource::Buffer(data) } Err(e) => { - let rspack_err: Vec = rspack_error::Error::from(e).into(); + let e: Error = DiagnosticError::from(e.boxed()).into(); + let rspack_err: Vec = vec![e.into()]; for err in rspack_err { diagnostics.insert(err); } @@ -433,8 +434,6 @@ impl CopyRspackPlugin { diagnostics.insert(Diagnostic::error( "CopyRspackPlugin Error".into(), format!("unable to locate '{glob_query}' glob"), - 0, - 0, )); } @@ -467,8 +466,6 @@ impl CopyRspackPlugin { diagnostics.insert(Diagnostic::error( "CopyRspackPlugin Error".into(), format!("unable to locate '{glob_query}' glob"), - 0, - 0, )); return None; } @@ -487,12 +484,7 @@ impl CopyRspackPlugin { return None; } - diagnostics.insert(Diagnostic::error( - "Glob Error".into(), - e.msg.to_string(), - 0, - 0, - )); + diagnostics.insert(Diagnostic::error("Glob Error".into(), e.msg.to_string())); None } diff --git a/crates/rspack_plugin_css/src/plugin/mod.rs b/crates/rspack_plugin_css/src/plugin/mod.rs index 9c7ec84ef34a..b7c40c126722 100644 --- a/crates/rspack_plugin_css/src/plugin/mod.rs +++ b/crates/rspack_plugin_css/src/plugin/mod.rs @@ -4,12 +4,12 @@ use std::cmp::{self, Reverse}; use std::hash::Hash; use std::str::FromStr; -use anyhow::bail; use bitflags::bitflags; use once_cell::sync::Lazy; use regex::Regex; use rspack_core::Filename; use rspack_core::{Chunk, ChunkGraph, Compilation, Module, ModuleGraph, PathData, SourceType}; +use rspack_error::internal_error_bail; use rspack_identifier::IdentifierSet; static ESCAPE_LOCAL_IDENT_REGEX: Lazy = @@ -78,7 +78,7 @@ impl LocalsConvention { } impl FromStr for LocalsConvention { - type Err = anyhow::Error; + type Err = rspack_error::Error; fn from_str(s: &str) -> std::result::Result { Ok(match s { @@ -87,7 +87,7 @@ impl FromStr for LocalsConvention { "camelCaseOnly" => Self(LocalsConventionFlags::CAMELCASE), "dashes" => Self(LocalsConventionFlags::ASIS | LocalsConventionFlags::DASHES), "dashesOnly" => Self(LocalsConventionFlags::DASHES), - _ => bail!("css modules exportsLocalsConvention error"), + _ => internal_error_bail!("css modules exportsLocalsConvention error"), }) } } diff --git a/crates/rspack_plugin_css/src/visitors/mod.rs b/crates/rspack_plugin_css/src/visitors/mod.rs index 6ffc204bc57e..ab3f78553fd1 100644 --- a/crates/rspack_plugin_css/src/visitors/mod.rs +++ b/crates/rspack_plugin_css/src/visitors/mod.rs @@ -46,15 +46,10 @@ struct Analyzer<'a> { fn replace_module_request_prefix(specifier: String, diagnostics: &mut Vec) -> String { if IS_MODULE_REQUEST.is_match(&specifier) { - diagnostics.push( - Diagnostic::warn( - "Deprecated '~'".to_string(), - "'@import' or 'url()' with a request starts with '~' is deprecated.".to_string(), - 0, - 0, - ) - .with_kind(DiagnosticKind::Css), - ); + diagnostics.push(Diagnostic::warn( + "css: Deprecated '~'".to_string(), + "'@import' or 'url()' with a request starts with '~' is deprecated.".to_string(), + )); IS_MODULE_REQUEST.replace(&specifier, "").to_string() } else { specifier diff --git a/crates/rspack_plugin_devtool/src/lib.rs b/crates/rspack_plugin_devtool/src/lib.rs index 40f9122a9a90..84f7b35a8347 100644 --- a/crates/rspack_plugin_devtool/src/lib.rs +++ b/crates/rspack_plugin_devtool/src/lib.rs @@ -16,6 +16,7 @@ use rspack_core::{ PluginJsChunkHashHookOutput, PluginProcessAssetsOutput, PluginRenderModuleContentOutput, ProcessAssetsArgs, RenderModuleContentArgs, SourceType, }; +use rspack_error::miette::IntoDiagnostic; use rspack_error::{internal_error, Error, Result}; use rspack_util::swc::normalize_custom_filename; use rustc_hash::FxHashMap as HashMap; @@ -141,7 +142,7 @@ impl Plugin for DevtoolPlugin { }) .transpose()?; let mut code_buffer = Vec::new(); - source.to_writer(&mut code_buffer)?; + source.to_writer(&mut code_buffer).into_diagnostic()?; Ok((filename.to_owned(), (code_buffer, map))) }) .collect::>()?; diff --git a/crates/rspack_plugin_ensure_chunk_conditions/src/lib.rs b/crates/rspack_plugin_ensure_chunk_conditions/src/lib.rs index f7f6dc0b7dda..dd9a31e731c3 100644 --- a/crates/rspack_plugin_ensure_chunk_conditions/src/lib.rs +++ b/crates/rspack_plugin_ensure_chunk_conditions/src/lib.rs @@ -1,7 +1,6 @@ use std::collections::{HashMap, HashSet}; use rspack_core::{Logger, OptimizeChunksArgs, Plugin, PluginContext, PluginOptimizeChunksOutput}; -use rspack_error::Error; #[derive(Debug)] pub struct EnsureChunkConditionsPlugin; @@ -66,10 +65,13 @@ impl Plugin for EnsureChunkConditionsPlugin { } } if chunk_group.is_initial() { - return Err(Error::InternalError(rspack_error::InternalError::new( - format!("Cannot fulfil chunk condition of {}", module_id), - Default::default(), - ))); + return Err( + rspack_error::InternalError::new( + format!("Cannot fulfil chunk condition of {}", module_id), + Default::default(), + ) + .into(), + ); } let parent_chunks = chunk_group.parents_iterable(); diff --git a/crates/rspack_plugin_html/src/parser.rs b/crates/rspack_plugin_html/src/parser.rs index 6eaa410e361f..76588375788d 100644 --- a/crates/rspack_plugin_html/src/parser.rs +++ b/crates/rspack_plugin_html/src/parser.rs @@ -1,6 +1,7 @@ use rspack_core::ErrorSpan; use rspack_error::{ - Diagnostic, DiagnosticKind, IntoTWithDiagnosticArray, Result, TWithDiagnosticArray, + internal_error, Diagnostic, DiagnosticKind, IntoTWithDiagnosticArray, Result, + TWithDiagnosticArray, }; use swc_core::common::{sync::Lrc, FileName, FilePathMapping, SourceFile, SourceMap, GLOBALS}; use swc_html::{ @@ -33,14 +34,16 @@ impl<'a> HtmlCompiler<'a> { let document = parse_file_as_document(fm.as_ref(), ParserConfig::default(), &mut errors); let diagnostics: Vec = errors .into_iter() - .flat_map(|error| >::from(html_parse_error_to_traceable_error(error, &fm))) + .flat_map(|error| { + >::from(vec![html_parse_error_to_traceable_error(error, &fm).into()]) + }) .collect(); document .map(|doc| doc.with_diagnostic(diagnostics)) .map_err(|e| html_parse_error_to_traceable_error(e, &fm)) } - pub fn codegen(&self, ast: &mut Document) -> anyhow::Result { + pub fn codegen(&self, ast: &mut Document) -> Result { let writer_config = BasicHtmlWriterConfig::default(); let codegen_config = CodegenConfig { minify: self.config.minify, @@ -57,7 +60,7 @@ impl<'a> HtmlCompiler<'a> { let wr = BasicHtmlWriter::new(&mut output, None, writer_config); let mut gen = CodeGenerator::new(wr, codegen_config); - gen.emit(ast).map_err(|e| anyhow::format_err!(e))?; + gen.emit(ast).map_err(|e| internal_error!(e.to_string()))?; Ok(output) } } @@ -66,7 +69,7 @@ pub fn html_parse_error_to_traceable_error(error: Error, fm: &SourceFile) -> rsp let message = error.message(); let error = error.into_inner(); let span: ErrorSpan = error.0.into(); - let traceable_error = rspack_error::TraceableRspackError::from_source_file( + let traceable_error = rspack_error::TraceableError::from_source_file( fm, span.start as usize, span.end as usize, @@ -75,5 +78,5 @@ pub fn html_parse_error_to_traceable_error(error: Error, fm: &SourceFile) -> rsp ) .with_kind(DiagnosticKind::Html); //Use this `Error` conversion could avoid eagerly clone source file. - rspack_error::Error::TraceableRspackError(traceable_error) + traceable_error.into() } diff --git a/crates/rspack_plugin_html/src/plugin.rs b/crates/rspack_plugin_html/src/plugin.rs index 57dcbc3f22ee..7e6aba369a8e 100644 --- a/crates/rspack_plugin_html/src/plugin.rs +++ b/crates/rspack_plugin_html/src/plugin.rs @@ -14,6 +14,7 @@ use rspack_core::{ rspack_sources::{RawSource, SourceExt}, CompilationAsset, Filename, PathData, Plugin, }; +use rspack_error::AnyhowError; use serde::Deserialize; use swc_html::visit::VisitMutWith; @@ -74,11 +75,13 @@ impl Plugin for HtmlRspackPlugin { AsRef::::as_ref(&compilation.options.context).join(template.as_str()), ); - let content = fs::read_to_string(&resolved_template).context(format!( - "failed to read `{}` from `{}`", - resolved_template.display(), - &compilation.options.context - ))?; + let content = fs::read_to_string(&resolved_template) + .context(format!( + "failed to read `{}` from `{}`", + resolved_template.display(), + &compilation.options.context + )) + .map_err(AnyhowError::from)?; let url = resolved_template.to_string_lossy().to_string(); compilation.file_dependencies.insert(resolved_template); @@ -201,11 +204,13 @@ impl Plugin for HtmlRspackPlugin { let favicon_file_path = PathBuf::from(config.get_relative_path(compilation, favicon)); let resolved_favicon = AsRef::::as_ref(&compilation.options.context).join(url.path()); - let content = fs::read(resolved_favicon).context(format!( - "failed to read `{}` from `{}`", - url.path(), - &compilation.options.context - ))?; + let content = fs::read(resolved_favicon) + .context(format!( + "failed to read `{}` from `{}`", + url.path(), + &compilation.options.context + )) + .map_err(AnyhowError::from)?; compilation.emit_asset( favicon_file_path.to_string_lossy().to_string(), CompilationAsset::from(RawSource::from(content).boxed()), diff --git a/crates/rspack_plugin_javascript/src/ast/parse.rs b/crates/rspack_plugin_javascript/src/ast/parse.rs index d99aed908558..2a9d4f8c945a 100644 --- a/crates/rspack_plugin_javascript/src/ast/parse.rs +++ b/crates/rspack_plugin_javascript/src/ast/parse.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use rspack_ast::javascript::Ast; use rspack_core::ModuleType; -use rspack_error::Error; +use rspack_error::BatchErrors; use swc_core::common::comments::Comments; use swc_core::common::{FileName, SourceFile}; use swc_core::ecma::ast::{self, EsVersion, Program}; @@ -68,7 +68,7 @@ pub fn parse( syntax: Syntax, filename: &str, module_type: &ModuleType, -) -> Result { +) -> Result { let source_code = if syntax.dts() { // dts build result must be empty "".to_string() @@ -88,7 +88,7 @@ pub fn parse( Some(&comments), ) { Ok(program) => Ok(Ast::new(program, cm, Some(comments))), - Err(errs) => Err(Error::BatchErrors( + Err(errs) => Err(BatchErrors( errs .into_iter() .map(|err| ecma_parse_error_to_rspack_error(err, &fm, module_type)) diff --git a/crates/rspack_plugin_javascript/src/ast/stringify.rs b/crates/rspack_plugin_javascript/src/ast/stringify.rs index 708c4e6c9bc3..952b0a7163d9 100644 --- a/crates/rspack_plugin_javascript/src/ast/stringify.rs +++ b/crates/rspack_plugin_javascript/src/ast/stringify.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use rspack_ast::javascript::Ast; use rspack_core::Devtool; -use rspack_error::{internal_error, Result}; +use rspack_error::{internal_error, miette::IntoDiagnostic, Result}; use swc_core::base::config::JsMinifyFormatOptions; use swc_core::{ common::{ @@ -114,7 +114,7 @@ pub fn print( wr, }; - node.emit_with(&mut emitter)?; + node.emit_with(&mut emitter).into_diagnostic()?; } // SAFETY: SWC will emit valid utf8 for sure unsafe { String::from_utf8_unchecked(buf) } diff --git a/crates/rspack_plugin_javascript/src/utils/mod.rs b/crates/rspack_plugin_javascript/src/utils/mod.rs index 73abf6938a13..047911511512 100644 --- a/crates/rspack_plugin_javascript/src/utils/mod.rs +++ b/crates/rspack_plugin_javascript/src/utils/mod.rs @@ -104,7 +104,7 @@ pub fn ecma_parse_error_to_rspack_error( }; let message = error.kind().msg().to_string(); let span: ErrorSpan = error.span().into(); - let traceable_error = rspack_error::TraceableRspackError::from_source_file( + let traceable_error = rspack_error::TraceableError::from_source_file( fm, span.start as usize, span.end as usize, @@ -112,7 +112,7 @@ pub fn ecma_parse_error_to_rspack_error( message, ) .with_kind(diagnostic_kind); - Error::TraceableRspackError(traceable_error) + traceable_error.into() } pub fn join_jsword(arr: &[JsWord], separator: &str) -> String { diff --git a/crates/rspack_plugin_javascript/src/visitors/dependency/import_meta_scanner.rs b/crates/rspack_plugin_javascript/src/visitors/dependency/import_meta_scanner.rs index aef72465f715..757a20026adf 100644 --- a/crates/rspack_plugin_javascript/src/visitors/dependency/import_meta_scanner.rs +++ b/crates/rspack_plugin_javascript/src/visitors/dependency/import_meta_scanner.rs @@ -95,9 +95,9 @@ impl Visit for ImportMetaScanner<'_> { String::from("import.meta warning"), String::from( "Critical dependency: Accessing import.meta directly is unsupported (only property access or destructuring is supported)"), - expr.span().real_lo() as usize, - expr.span().real_hi()as usize) - ); + // expr.span().real_lo() as usize, + // expr.span().real_hi()as usize + )); self .presentational_dependencies .push(Box::new(ConstDependency::new( diff --git a/crates/rspack_plugin_javascript/src/visitors/dependency/mod.rs b/crates/rspack_plugin_javascript/src/visitors/dependency/mod.rs index d69e1958b4f6..c0be39799d6d 100644 --- a/crates/rspack_plugin_javascript/src/visitors/dependency/mod.rs +++ b/crates/rspack_plugin_javascript/src/visitors/dependency/mod.rs @@ -23,7 +23,7 @@ use rspack_core::{ AsyncDependenciesBlock, BoxDependency, BoxDependencyTemplate, BuildInfo, BuildMeta, CompilerOptions, ModuleIdentifier, ModuleType, ResourceData, }; -use rspack_error::{Diagnostic, Result}; +use rspack_error::{BatchErrors, Diagnostic}; use rustc_hash::FxHashMap as HashMap; use swc_core::common::Span; use swc_core::common::{comments::Comments, Mark, SyntaxContext}; @@ -75,7 +75,7 @@ pub fn scan_dependencies( build_info: &mut BuildInfo, build_meta: &mut BuildMeta, module_identifier: ModuleIdentifier, -) -> Result { +) -> Result { let mut warning_diagnostics: Vec = vec![]; let mut errors = vec![]; let mut dependencies = vec![]; @@ -225,6 +225,6 @@ pub fn scan_dependencies( warning_diagnostics, }) } else { - Err(rspack_error::Error::BatchErrors(errors)) + Err(rspack_error::BatchErrors(errors)) } } diff --git a/crates/rspack_plugin_javascript/src/visitors/mod.rs b/crates/rspack_plugin_javascript/src/visitors/mod.rs index 4969360b5e25..1eaf65cfc037 100644 --- a/crates/rspack_plugin_javascript/src/visitors/mod.rs +++ b/crates/rspack_plugin_javascript/src/visitors/mod.rs @@ -14,7 +14,7 @@ use swc_core::ecma::transforms::base::Assumptions; pub mod swc_visitor; use rspack_ast::javascript::Ast; use rspack_core::{CompilerOptions, ResourceData}; -use rspack_error::Result; +use rspack_error::{AnyhowError, Result}; use swc_core::common::{chain, Mark, SourceMap}; use swc_core::ecma::parser::Syntax; use swc_core::ecma::transforms::base::pass::{noop, Optional}; @@ -189,65 +189,67 @@ pub fn run_before_pass( source: &str, ) -> Result<()> { let cm = ast.get_context().source_map.clone(); - ast.transform_with_handler(cm.clone(), |_handler, program, context| { - let top_level_mark = context.top_level_mark; - let unresolved_mark = context.unresolved_mark; - let comments: Option<&dyn Comments> = None; + ast + .transform_with_handler(cm.clone(), |_handler, program, context| { + let top_level_mark = context.top_level_mark; + let unresolved_mark = context.unresolved_mark; + let comments: Option<&dyn Comments> = None; - let mut assumptions = Assumptions::default(); - if syntax.typescript() { - assumptions.set_class_methods = true; - assumptions.set_public_class_fields = true; - } + let mut assumptions = Assumptions::default(); + if syntax.typescript() { + assumptions.set_class_methods = true; + assumptions.set_public_class_fields = true; + } - let mut pass = chain!( - swc_visitor::resolver(unresolved_mark, top_level_mark, syntax.typescript()), - Optional::new( - swc_visitor::decorator(assumptions, &options.builtins.decorator), - // Decorator transformation varies from `ModuleType`, - // - TypeScript-like: decorators will be transformed by default, with legacy settings and will emit meta data. - // Since this is a default behavior with tsc. - // - JavaScript-like: decorators will not be transformed(if `disableTransformByDefault` is on), and the parse will fail. - (options.should_transform_by_default() || syntax.typescript()) && syntax.decorators() - ), - Optional::new( - swc_visitor::typescript(top_level_mark, comments, &cm), - options.should_transform_by_default() && syntax.typescript() - ), - Optional::new( - builtins_additional_feature_transforms( - resource_data, - options, - module_type, - source, - top_level_mark, - unresolved_mark, - cm + let mut pass = chain!( + swc_visitor::resolver(unresolved_mark, top_level_mark, syntax.typescript()), + Optional::new( + swc_visitor::decorator(assumptions, &options.builtins.decorator), + // Decorator transformation varies from `ModuleType`, + // - TypeScript-like: decorators will be transformed by default, with legacy settings and will emit meta data. + // Since this is a default behavior with tsc. + // - JavaScript-like: decorators will not be transformed(if `disableTransformByDefault` is on), and the parse will fail. + (options.should_transform_by_default() || syntax.typescript()) && syntax.decorators() ), - options.should_transform_by_default() - ), - Optional::new( - compat_transform( - resource_data, - options, - top_level_mark, - unresolved_mark, - assumptions, - syntax + Optional::new( + swc_visitor::typescript(top_level_mark, comments, &cm), + options.should_transform_by_default() && syntax.typescript() ), - options.should_transform_by_default() - ), - builtins_webpack_plugin(options, unresolved_mark), - // This will be deprecated in the future when TypeScript support and transform by default is dropped. - // These features are coupled with this. - swc_visitor::inject_helpers(unresolved_mark), - swc_visitor::hygiene(false, top_level_mark), - swc_visitor::fixer(comments.map(|v| v as &dyn Comments)), - ); - program.fold_with(&mut pass); + Optional::new( + builtins_additional_feature_transforms( + resource_data, + options, + module_type, + source, + top_level_mark, + unresolved_mark, + cm + ), + options.should_transform_by_default() + ), + Optional::new( + compat_transform( + resource_data, + options, + top_level_mark, + unresolved_mark, + assumptions, + syntax + ), + options.should_transform_by_default() + ), + builtins_webpack_plugin(options, unresolved_mark), + // This will be deprecated in the future when TypeScript support and transform by default is dropped. + // These features are coupled with this. + swc_visitor::inject_helpers(unresolved_mark), + swc_visitor::hygiene(false, top_level_mark), + swc_visitor::fixer(comments.map(|v| v as &dyn Comments)), + ); + program.fold_with(&mut pass); - Ok(()) - })?; + Ok(()) + }) + .map_err(AnyhowError::from)?; Ok(()) } diff --git a/crates/rspack_plugin_json/src/lib.rs b/crates/rspack_plugin_json/src/lib.rs index 83479b630378..128e52481576 100644 --- a/crates/rspack_plugin_json/src/lib.rs +++ b/crates/rspack_plugin_json/src/lib.rs @@ -7,8 +7,8 @@ use rspack_core::{ ParserAndGenerator, Plugin, RuntimeGlobals, SourceType, }; use rspack_error::{ - internal_error, DiagnosticKind, Error, IntoTWithDiagnosticArray, Result, TWithDiagnosticArray, - TraceableRspackError, + internal_error, DiagnosticKind, IntoTWithDiagnosticArray, Result, TWithDiagnosticArray, + TraceableError, }; mod utils; @@ -58,18 +58,17 @@ impl ParserAndGenerator for JsonParserAndGenerator { } else { start_offset }; - Error::TraceableRspackError( - TraceableRspackError::from_file( - resource_data.resource_path.to_string_lossy().to_string(), - source.into_owned(), - // one character offset - start_offset, - start_offset + 1, - "Json parsing error".to_string(), - format!("Unexpected character {ch}"), - ) - .with_kind(DiagnosticKind::Json), + TraceableError::from_file( + resource_data.resource_path.to_string_lossy().to_string(), + source.into_owned(), + // one character offset + start_offset, + start_offset + 1, + "Json parsing error".to_string(), + format!("Unexpected character {ch}"), ) + .with_kind(DiagnosticKind::Json) + .into() } ExceededDepthLimit | WrongType(_) | FailedUtf8Parsing => { internal_error!(format!("{e}")) @@ -77,23 +76,22 @@ impl ParserAndGenerator for JsonParserAndGenerator { UnexpectedEndOfJson => { // End offset of json file let offset = source.len(); - Error::TraceableRspackError( - TraceableRspackError::from_file( - resource_data.resource_path.to_string_lossy().to_string(), - source.into_owned(), - offset, - offset, - "Json parsing error".to_string(), - format!("{e}"), - ) - .with_kind(DiagnosticKind::Json), + TraceableError::from_file( + resource_data.resource_path.to_string_lossy().to_string(), + source.into_owned(), + offset, + offset, + "Json parsing error".to_string(), + format!("{e}"), ) + .with_kind(DiagnosticKind::Json) + .into() } } }); let diagnostics = if let Err(err) = parse_result { - err.into() + vec![err.into()] } else { vec![] }; diff --git a/crates/rspack_plugin_runtime/src/array_push_callback_chunk_format.rs b/crates/rspack_plugin_runtime/src/array_push_callback_chunk_format.rs index d1f41b083b1f..9f8c71b43b86 100644 --- a/crates/rspack_plugin_runtime/src/array_push_callback_chunk_format.rs +++ b/crates/rspack_plugin_runtime/src/array_push_callback_chunk_format.rs @@ -1,6 +1,5 @@ use std::hash::Hash; -use anyhow::anyhow; use async_trait::async_trait; use rspack_core::rspack_sources::{ConcatSource, RawSource, SourceExt}; use rspack_core::{ @@ -33,7 +32,7 @@ impl Plugin for ArrayPushCallbackChunkFormatPlugin { let chunk = compilation .chunk_by_ukey .get(chunk_ukey) - .ok_or_else(|| anyhow!("chunk not found"))?; + .ok_or_else(|| internal_error!("chunk not found"))?; if chunk.has_runtime(&compilation.chunk_group_by_ukey) { return Ok(()); diff --git a/crates/rspack_plugin_runtime/src/common_js_chunk_format.rs b/crates/rspack_plugin_runtime/src/common_js_chunk_format.rs index 7c924784c98a..1703dd35ac8b 100644 --- a/crates/rspack_plugin_runtime/src/common_js_chunk_format.rs +++ b/crates/rspack_plugin_runtime/src/common_js_chunk_format.rs @@ -1,6 +1,5 @@ use std::hash::Hash; -use anyhow::anyhow; use async_trait::async_trait; use rspack_core::rspack_sources::{ConcatSource, RawSource, SourceExt}; use rspack_core::{ @@ -8,6 +7,7 @@ use rspack_core::{ PluginAdditionalChunkRuntimeRequirementsOutput, PluginContext, PluginJsChunkHashHookOutput, PluginRenderChunkHookOutput, RenderChunkArgs, RenderStartupArgs, RuntimeGlobals, }; +use rspack_error::internal_error; use rspack_plugin_javascript::runtime::{render_chunk_runtime_modules, render_iife}; use crate::{ @@ -35,7 +35,7 @@ impl Plugin for CommonJsChunkFormatPlugin { let chunk = compilation .chunk_by_ukey .get(chunk_ukey) - .ok_or_else(|| anyhow!("chunk not found"))?; + .ok_or_else(|| internal_error!("chunk not found"))?; if chunk.has_runtime(&compilation.chunk_group_by_ukey) { return Ok(()); diff --git a/crates/rspack_plugin_runtime/src/helpers.rs b/crates/rspack_plugin_runtime/src/helpers.rs index 1a03940408d7..5ddd5dd2a422 100644 --- a/crates/rspack_plugin_runtime/src/helpers.rs +++ b/crates/rspack_plugin_runtime/src/helpers.rs @@ -1,12 +1,11 @@ use std::hash::Hash; -use anyhow::anyhow; use rspack_core::{ rspack_sources::{BoxSource, RawSource, SourceExt}, Chunk, ChunkGroupByUkey, ChunkGroupUkey, ChunkUkey, Compilation, PathData, RenderChunkArgs, RuntimeGlobals, }; -use rspack_error::Result; +use rspack_error::{internal_error, Result}; use rspack_hash::RspackHash; use rspack_identifier::IdentifierLinkedMap; use rspack_plugin_javascript::runtime::stringify_chunks_to_array; @@ -119,20 +118,20 @@ pub fn get_runtime_chunk_output_name(args: &RenderChunkArgs) -> Result { let (_, entry_point_ukey) = entry_points .iter() .next() - .ok_or_else(|| anyhow!("should has entry point ukey"))?; + .ok_or_else(|| internal_error!("should has entry point ukey"))?; args .compilation .chunk_group_by_ukey .get(entry_point_ukey) - .ok_or_else(|| anyhow!("should has entry point"))? + .ok_or_else(|| internal_error!("should has entry point"))? }; let runtime_chunk = args .compilation .chunk_by_ukey .get(&entry_point.get_runtime_chunk()) - .ok_or_else(|| anyhow!("should has runtime chunk"))?; + .ok_or_else(|| internal_error!("should has runtime chunk"))?; Ok(get_chunk_output_name(runtime_chunk, args.compilation)) } diff --git a/crates/rspack_plugin_runtime/src/module_chunk_format.rs b/crates/rspack_plugin_runtime/src/module_chunk_format.rs index 536267cbf489..a9d869a80621 100644 --- a/crates/rspack_plugin_runtime/src/module_chunk_format.rs +++ b/crates/rspack_plugin_runtime/src/module_chunk_format.rs @@ -1,6 +1,5 @@ use std::hash::Hash; -use anyhow::anyhow; use async_trait::async_trait; use rspack_core::rspack_sources::{ConcatSource, RawSource, SourceExt}; use rspack_core::{ @@ -37,7 +36,7 @@ impl Plugin for ModuleChunkFormatPlugin { let chunk = compilation .chunk_by_ukey .get(chunk_ukey) - .ok_or_else(|| anyhow!("chunk not found"))?; + .ok_or_else(|| internal_error!("chunk not found"))?; if chunk.has_runtime(&compilation.chunk_group_by_ukey) { return Ok(()); diff --git a/crates/rspack_plugin_swc_js_minimizer/src/lib.rs b/crates/rspack_plugin_swc_js_minimizer/src/lib.rs index a04a07fdcc76..5fa079bc4e3e 100644 --- a/crates/rspack_plugin_swc_js_minimizer/src/lib.rs +++ b/crates/rspack_plugin_swc_js_minimizer/src/lib.rs @@ -18,6 +18,7 @@ use rspack_core::{ AssetInfo, CompilationAsset, JsChunkHashArgs, Plugin, PluginContext, PluginJsChunkHashHookOutput, PluginProcessAssetsOutput, ProcessAssetsArgs, }; +use rspack_error::miette::IntoDiagnostic; use rspack_error::{internal_error, Diagnostic, Result}; use rspack_regex::RspackRegex; use rspack_util::try_any_sync; @@ -214,8 +215,7 @@ impl Plugin for SwcJsMinimizerRspackPlugin { ) { Ok(r) => r, Err(e) => { - tx.send(e.into()) - .map_err(|e| internal_error!(e.to_string()))?; + tx.send(e.into()).into_diagnostic()?; return Ok(()) } }; diff --git a/crates/rspack_plugin_swc_js_minimizer/src/minify.rs b/crates/rspack_plugin_swc_js_minimizer/src/minify.rs index aec0a91f66af..57c201d311e5 100644 --- a/crates/rspack_plugin_swc_js_minimizer/src/minify.rs +++ b/crates/rspack_plugin_swc_js_minimizer/src/minify.rs @@ -7,7 +7,7 @@ use rspack_core::{ rspack_sources::{RawSource, SourceExt}, ModuleType, }; -use rspack_error::{internal_error, DiagnosticKind, Error, Result, TraceableRspackError}; +use rspack_error::{internal_error, BatchErrors, DiagnosticKind, Result, TraceableError}; use rspack_plugin_javascript::ast::parse_js; use rspack_plugin_javascript::ast::{print, SourceMapConfig}; use rspack_plugin_javascript::{ @@ -102,203 +102,208 @@ pub fn minify( filename: &str, all_extract_comments: &Mutex>, extract_comments: &Option>, -) -> Result { +) -> std::result::Result { let cm: Arc = Default::default(); - GLOBALS.set(&Default::default(), || -> Result { - with_rspack_error_handler( - "Minify Error".to_string(), - DiagnosticKind::JavaScript, - cm.clone(), - |handler| { - let fm = cm.new_source_file(FileName::Custom(filename.to_string()), input); - let target = opts.ecma.clone().into(); - - let source_map = opts - .source_map - .as_ref() - .map(|_| SourceMapsConfig::Bool(true)) - .unwrap_as_option(|v| { - Some(match v { - Some(true) => SourceMapsConfig::Bool(true), - _ => SourceMapsConfig::Bool(false), + GLOBALS.set( + &Default::default(), + || -> std::result::Result { + with_rspack_error_handler( + "Minify Error".to_string(), + DiagnosticKind::JavaScript, + cm.clone(), + |handler| { + let fm = cm.new_source_file(FileName::Custom(filename.to_string()), input); + let target = opts.ecma.clone().into(); + + let source_map = opts + .source_map + .as_ref() + .map(|_| SourceMapsConfig::Bool(true)) + .unwrap_as_option(|v| { + Some(match v { + Some(true) => SourceMapsConfig::Bool(true), + _ => SourceMapsConfig::Bool(false), + }) }) - }) - .expect("TODO:"); - - let mut min_opts = MinifyOptions { - compress: opts - .compress - .clone() - .unwrap_as_option(|default| match default { - Some(true) | None => Some(Default::default()), - _ => None, - }) - .map(|v| v.into_config(cm.clone())), - mangle: opts - .mangle - .clone() - .unwrap_as_option(|default| match default { - Some(true) | None => Some(Default::default()), - _ => None, - }), - ..Default::default() - }; + .expect("TODO:"); + + let mut min_opts = MinifyOptions { + compress: opts + .compress + .clone() + .unwrap_as_option(|default| match default { + Some(true) | None => Some(Default::default()), + _ => None, + }) + .map(|v| v.into_config(cm.clone())), + mangle: opts + .mangle + .clone() + .unwrap_as_option(|default| match default { + Some(true) | None => Some(Default::default()), + _ => None, + }), + ..Default::default() + }; - // top_level defaults to true if module is true + // top_level defaults to true if module is true - // https://github.com/swc-project/swc/issues/2254 - if opts.module { - if let Some(opts) = &mut min_opts.compress { - if opts.top_level.is_none() { - opts.top_level = Some(TopLevelOptions { functions: true }); + // https://github.com/swc-project/swc/issues/2254 + if opts.module { + if let Some(opts) = &mut min_opts.compress { + if opts.top_level.is_none() { + opts.top_level = Some(TopLevelOptions { functions: true }); + } } - } - if let Some(opts) = &mut min_opts.mangle { - opts.top_level = Some(true); + if let Some(opts) = &mut min_opts.mangle { + opts.top_level = Some(true); + } } - } - let comments = SingleThreadedComments::default(); + let comments = SingleThreadedComments::default(); - let program = parse_js( - fm.clone(), - target, - Syntax::Es(EsConfig { - jsx: true, - decorators: true, - decorators_before_export: true, - ..Default::default() - }), - IsModule::Bool(opts.module), - Some(&comments), - ) - .map_err(|errs| { - Error::BatchErrors( - errs - .into_iter() - .map(|err| ecma_parse_error_to_rspack_error(err, &fm, &ModuleType::Js)) - .collect::>(), + let program = parse_js( + fm.clone(), + target, + Syntax::Es(EsConfig { + jsx: true, + decorators: true, + decorators_before_export: true, + ..Default::default() + }), + IsModule::Bool(opts.module), + Some(&comments), ) - })?; - - let source_map_names = if source_map.enabled() { - let mut v = IdentCollector { - names: Default::default(), + .map_err(|errs| { + BatchErrors( + errs + .into_iter() + .map(|err| ecma_parse_error_to_rspack_error(err, &fm, &ModuleType::Js)) + .collect::>(), + ) + })?; + + let source_map_names = if source_map.enabled() { + let mut v = IdentCollector { + names: Default::default(), + }; + + program.visit_with(&mut v); + + v.names + } else { + Default::default() }; - program.visit_with(&mut v); - - v.names - } else { - Default::default() - }; - - let unresolved_mark = Mark::new(); - let top_level_mark = Mark::new(); - - let is_mangler_enabled = min_opts.mangle.is_some(); - - let program = helpers::HELPERS.set(&Helpers::new(false), || { - HANDLER.set(handler, || { - let program = program.fold_with(&mut resolver(unresolved_mark, top_level_mark, false)); - - let mut program = swc_ecma_minifier::optimize( - program, - cm.clone(), - Some(&comments), - None, - &min_opts, - &swc_ecma_minifier::option::ExtraOptions { - unresolved_mark, - top_level_mark, - }, - ); + let unresolved_mark = Mark::new(); + let top_level_mark = Mark::new(); + + let is_mangler_enabled = min_opts.mangle.is_some(); + + let program = helpers::HELPERS.set(&Helpers::new(false), || { + HANDLER.set(handler, || { + let program = + program.fold_with(&mut resolver(unresolved_mark, top_level_mark, false)); + + let mut program = swc_ecma_minifier::optimize( + program, + cm.clone(), + Some(&comments), + None, + &min_opts, + &swc_ecma_minifier::option::ExtraOptions { + unresolved_mark, + top_level_mark, + }, + ); - if !is_mangler_enabled { - program.visit_mut_with(&mut hygiene()) - } - program.fold_with(&mut fixer(Some(&comments as &dyn Comments))) - }) - }); - - if let Some(extract_comments) = extract_comments { - let mut extracted_comments = vec![]; - // add all matched comments to source - - let (leading_trivial, trailing_trivial) = comments.borrow_all(); - - leading_trivial.iter().for_each(|(_, comments)| { - comments.iter().for_each(|c| { - if extract_comments.condition.is_match(&c.text) { - extracted_comments.push(match c.kind { - CommentKind::Line => { - format!("// {}", c.text) - } - CommentKind::Block => { - format!("/*{}*/", c.text) - } - }); + if !is_mangler_enabled { + program.visit_mut_with(&mut hygiene()) } - }); + program.fold_with(&mut fixer(Some(&comments as &dyn Comments))) + }) }); - trailing_trivial.iter().for_each(|(_, comments)| { - comments.iter().for_each(|c| { - if extract_comments.condition.is_match(&c.text) { - extracted_comments.push(match c.kind { - CommentKind::Line => { - format!("// {}", c.text) - } - CommentKind::Block => { - format!("/*{}*/", c.text) - } - }); - } + + if let Some(extract_comments) = extract_comments { + let mut extracted_comments = vec![]; + // add all matched comments to source + + let (leading_trivial, trailing_trivial) = comments.borrow_all(); + + leading_trivial.iter().for_each(|(_, comments)| { + comments.iter().for_each(|c| { + if extract_comments.condition.is_match(&c.text) { + extracted_comments.push(match c.kind { + CommentKind::Line => { + format!("// {}", c.text) + } + CommentKind::Block => { + format!("/*{}*/", c.text) + } + }); + } + }); + }); + trailing_trivial.iter().for_each(|(_, comments)| { + comments.iter().for_each(|c| { + if extract_comments.condition.is_match(&c.text) { + extracted_comments.push(match c.kind { + CommentKind::Line => { + format!("// {}", c.text) + } + CommentKind::Block => { + format!("/*{}*/", c.text) + } + }); + } + }); }); - }); - // if not matched comments, we don't need to emit .License.txt file - if !extracted_comments.is_empty() { - all_extract_comments - .lock() - .expect("all_extract_comments lock failed") - .insert( - filename.to_string(), - ExtractedCommentsInfo { - source: RawSource::Source(extracted_comments.join("\n\n")).boxed(), - comments_file_name: extract_comments.filename.to_string(), - }, - ); + // if not matched comments, we don't need to emit .License.txt file + if !extracted_comments.is_empty() { + all_extract_comments + .lock() + .expect("all_extract_comments lock failed") + .insert( + filename.to_string(), + ExtractedCommentsInfo { + source: RawSource::Source(extracted_comments.join("\n\n")).boxed(), + comments_file_name: extract_comments.filename.to_string(), + }, + ); + } } - } - - minify_file_comments( - &comments, - opts - .format - .comments - .clone() - .into_inner() - .unwrap_or(BoolOr::Data(JsMinifyCommentOption::PreserveSomeComments)), - ); - - print( - &program, - cm.clone(), - target, - SourceMapConfig { - enable: source_map.enabled(), - inline_sources_content: opts.inline_sources_content, - emit_columns: opts.emit_source_map_columns, - names: source_map_names, - }, - true, - Some(&comments), - &opts.format, - ) - }, - ) - }) + + minify_file_comments( + &comments, + opts + .format + .comments + .clone() + .into_inner() + .unwrap_or(BoolOr::Data(JsMinifyCommentOption::PreserveSomeComments)), + ); + + print( + &program, + cm.clone(), + target, + SourceMapConfig { + enable: source_map.enabled(), + inline_sources_content: opts.inline_sources_content, + emit_columns: opts.emit_source_map_columns, + names: source_map_names, + }, + true, + Some(&comments), + &opts.format, + ) + .map_err(BatchErrors::from) + }, + ) + }, + ) } pub struct IdentCollector { @@ -330,16 +335,17 @@ impl Emitter for RspackErrorEmitter { if let Some(source_file_and_byte_pos) = source_file_and_byte_pos { self .tx - .send(Error::TraceableRspackError( - TraceableRspackError::from_source_file( + .send( + TraceableError::from_source_file( &source_file_and_byte_pos.sf, source_file_and_byte_pos.pos.0 as usize, source_file_and_byte_pos.pos.0 as usize, self.title.to_string(), db.message(), ) - .with_kind(self.kind), - )) + .with_kind(self.kind) + .into(), + ) .expect("Sender should drop after emit called"); } else { self @@ -355,9 +361,9 @@ pub fn with_rspack_error_handler( kind: DiagnosticKind, cm: Arc, op: F, -) -> Result +) -> std::result::Result where - F: FnOnce(&Handler) -> Result, + F: FnOnce(&Handler) -> std::result::Result, { let (tx, rx) = mpsc::channel(); let emitter = RspackErrorEmitter { @@ -372,7 +378,7 @@ where if handler.has_errors() { drop(handler); - Err(rspack_error::Error::BatchErrors(rx.into_iter().collect())) + Err(BatchErrors(rx.into_iter().collect()).into()) } else { ret } diff --git a/crates/rspack_plugin_warn_sensitive_module/src/lib.rs b/crates/rspack_plugin_warn_sensitive_module/src/lib.rs index 89f647c4b2dc..219cf471acde 100644 --- a/crates/rspack_plugin_warn_sensitive_module/src/lib.rs +++ b/crates/rspack_plugin_warn_sensitive_module/src/lib.rs @@ -90,8 +90,6 @@ impl Plugin for WarnCaseSensitiveModulesPlugin { diagnostics.push(Diagnostic::warn( "Sensitive Modules Warn".to_string(), self.create_sensitive_modules_warning(&case_modules, &compilation.module_graph), - 0, - 0, )); } } diff --git a/crates/rspack_plugin_wasm/src/parser_and_generator.rs b/crates/rspack_plugin_wasm/src/parser_and_generator.rs index 86f8a6ec0fa4..56a641897166 100644 --- a/crates/rspack_plugin_wasm/src/parser_and_generator.rs +++ b/crates/rspack_plugin_wasm/src/parser_and_generator.rs @@ -50,8 +50,6 @@ impl ParserAndGenerator for AsyncWasmParserAndGenerator { Err(err) => diagnostic.push(Diagnostic::error( "Wasm Export Parse Error".into(), err.to_string(), - 0, - 0, )), }; } @@ -69,8 +67,6 @@ impl ParserAndGenerator for AsyncWasmParserAndGenerator { Err(err) => diagnostic.push(Diagnostic::error( "Wasm Import Parse Error".into(), err.to_string(), - 0, - 0, )), } } @@ -81,8 +77,6 @@ impl ParserAndGenerator for AsyncWasmParserAndGenerator { diagnostic.push(Diagnostic::error( "Wasm Parse Error".into(), err.to_string(), - 0, - 0, )); } } diff --git a/examples/basic/rspack.config.js b/examples/basic/rspack.config.js index c2001deb6935..43d3741bb6f6 100644 --- a/examples/basic/rspack.config.js +++ b/examples/basic/rspack.config.js @@ -6,9 +6,6 @@ const config = { new rspack.HtmlRspackPlugin({ template: "./index.html" }) - ], - builtins: { - noEmitAssets: true - } + ] }; module.exports = config;