From eefa9bfa91e8189a3a6864232c32a14cfa04ae7f Mon Sep 17 00:00:00 2001 From: LingyuCoder Date: Mon, 4 Nov 2024 19:45:14 +0800 Subject: [PATCH 1/3] fix: file dependencies lost when incremental compiling failed in css module --- crates/node_binding/binding.d.ts | 1 + .../src/plugins/js_loader/context.rs | 5 +- .../src/plugins/js_loader/scheduler.rs | 19 +- .../src/compilation/mod.rs | 59 +++--- .../src/compiler/module_executor/execute.rs | 79 ++++---- .../src/compiler/module_executor/mod.rs | 5 +- crates/rspack_core/src/diagnostics.rs | 92 +++++++++- crates/rspack_core/src/normal_module.rs | 59 ++++-- .../asset-module-build-failed/stats.err | 3 +- .../loader-emit-diagnostic/stats.err | 2 - .../loader-throw-error/stats.err | 3 +- packages/rspack/src/loader-runner/index.ts | 172 ++++++++++-------- 12 files changed, 324 insertions(+), 175 deletions(-) diff --git a/crates/node_binding/binding.d.ts b/crates/node_binding/binding.d.ts index 096f0b98b722..1abecb96ab19 100644 --- a/crates/node_binding/binding.d.ts +++ b/crates/node_binding/binding.d.ts @@ -659,6 +659,7 @@ export interface JsLoaderContext { loaderItems: Array loaderIndex: number loaderState: Readonly + __internal__error?: JsRspackError } export interface JsLoaderItem { diff --git a/crates/rspack_binding_options/src/plugins/js_loader/context.rs b/crates/rspack_binding_options/src/plugins/js_loader/context.rs index 1c0c8b9fe096..d5152432454b 100644 --- a/crates/rspack_binding_options/src/plugins/js_loader/context.rs +++ b/crates/rspack_binding_options/src/plugins/js_loader/context.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use napi::bindgen_prelude::*; use napi_derive::napi; -use rspack_binding_values::{JsModuleWrapper, JsResourceData}; +use rspack_binding_values::{JsModuleWrapper, JsResourceData, JsRspackError}; use rspack_core::{LoaderContext, RunnerContext}; use rspack_error::error; use rspack_loader_runner::{LoaderItem, State as LoaderState}; @@ -81,6 +81,8 @@ pub struct JsLoaderContext { pub loader_index: i32, #[napi(ts_type = "Readonly")] pub loader_state: JsLoaderState, + #[napi(js_name = "__internal__error")] + pub error: Option, } impl TryFrom<&mut LoaderContext> for JsLoaderContext { @@ -137,6 +139,7 @@ impl TryFrom<&mut LoaderContext> for JsLoaderContext { loader_items: cx.loader_items.iter().map(Into::into).collect(), loader_index: cx.loader_index, loader_state: cx.state().into(), + error: None, }) } } diff --git a/crates/rspack_binding_options/src/plugins/js_loader/scheduler.rs b/crates/rspack_binding_options/src/plugins/js_loader/scheduler.rs index 1a56d7643146..3d6acd3ab588 100644 --- a/crates/rspack_binding_options/src/plugins/js_loader/scheduler.rs +++ b/crates/rspack_binding_options/src/plugins/js_loader/scheduler.rs @@ -1,7 +1,7 @@ use napi::Either; use rspack_core::{ - AdditionalData, LoaderContext, NormalModuleLoaderShouldYield, NormalModuleLoaderStartYielding, - RunnerContext, BUILTIN_LOADER_PREFIX, + diagnostics::CapturedLoaderError, AdditionalData, LoaderContext, NormalModuleLoaderShouldYield, + NormalModuleLoaderStartYielding, RunnerContext, BUILTIN_LOADER_PREFIX, }; use rspack_error::{error, Result}; use rspack_hook::plugin_hook; @@ -46,6 +46,21 @@ pub(crate) fn merge_loader_context( to: &mut LoaderContext, mut from: JsLoaderContext, ) -> Result<()> { + if let Some(error) = from.error { + return Err( + CapturedLoaderError::new( + error.message, + error.stack, + error.hide_stack, + from.file_dependencies, + from.context_dependencies, + from.missing_dependencies, + from.build_dependencies, + ) + .into(), + ); + } + to.cacheable = from.cacheable; to.file_dependencies = from.file_dependencies.into_iter().map(Into::into).collect(); to.context_dependencies = from diff --git a/crates/rspack_binding_values/src/compilation/mod.rs b/crates/rspack_binding_values/src/compilation/mod.rs index 58e9935246ae..45312eab1e1b 100644 --- a/crates/rspack_binding_values/src/compilation/mod.rs +++ b/crates/rspack_binding_values/src/compilation/mod.rs @@ -548,7 +548,7 @@ impl JsCompilation { .module_executor .as_ref() .expect("should have module executor"); - let result = module_executor + let res = module_executor .import_module( request, layer, @@ -558,37 +558,32 @@ impl JsCompilation { original_module.map(ModuleIdentifier::from), ) .await; - match result { - Ok(res) => { - let js_result = JsExecuteModuleResult { - cacheable: res.cacheable, - file_dependencies: res - .file_dependencies - .into_iter() - .map(|d| d.to_string_lossy().to_string()) - .collect(), - context_dependencies: res - .context_dependencies - .into_iter() - .map(|d| d.to_string_lossy().to_string()) - .collect(), - build_dependencies: res - .build_dependencies - .into_iter() - .map(|d| d.to_string_lossy().to_string()) - .collect(), - missing_dependencies: res - .missing_dependencies - .into_iter() - .map(|d| d.to_string_lossy().to_string()) - .collect(), - assets: res.assets.into_iter().collect(), - id: res.id, - }; - Ok(js_result) - } - Err(e) => Err(Error::new(napi::Status::GenericFailure, format!("{e}"))), - } + let js_result = JsExecuteModuleResult { + cacheable: res.cacheable, + file_dependencies: res + .file_dependencies + .into_iter() + .map(|d| d.to_string_lossy().to_string()) + .collect(), + context_dependencies: res + .context_dependencies + .into_iter() + .map(|d| d.to_string_lossy().to_string()) + .collect(), + build_dependencies: res + .build_dependencies + .into_iter() + .map(|d| d.to_string_lossy().to_string()) + .collect(), + missing_dependencies: res + .missing_dependencies + .into_iter() + .map(|d| d.to_string_lossy().to_string()) + .collect(), + assets: res.assets.into_iter().collect(), + id: res.id, + }; + Ok(js_result) }) } diff --git a/crates/rspack_core/src/compiler/module_executor/execute.rs b/crates/rspack_core/src/compiler/module_executor/execute.rs index 997f5e1b7fba..f185a7c5ab2f 100644 --- a/crates/rspack_core/src/compiler/module_executor/execute.rs +++ b/crates/rspack_core/src/compiler/module_executor/execute.rs @@ -3,7 +3,6 @@ use std::{iter::once, sync::atomic::AtomicU32}; use itertools::Itertools; use rspack_collections::{Identifier, IdentifierSet}; -use rspack_error::Result; use rustc_hash::FxHashMap as HashMap; use rustc_hash::FxHashSet as HashSet; use tokio::sync::oneshot::Sender; @@ -31,6 +30,7 @@ pub type ExecuteModuleId = u32; #[derive(Debug, Default)] pub struct ExecuteModuleResult { + pub error: Option, pub cacheable: bool, pub file_dependencies: HashSet, pub context_dependencies: HashSet, @@ -48,7 +48,7 @@ pub struct ExecuteTask { pub public_path: Option, pub base_uri: Option, pub result_sender: Sender<( - Result, + ExecuteModuleResult, CompilationAssets, IdentifierSet, Vec, @@ -217,39 +217,37 @@ impl Task for ExecuteTask { ); let module_graph = compilation.get_module_graph(); - let mut execute_result = match exports { + let mut execute_result = modules.iter().fold( + ExecuteModuleResult { + cacheable: true, + id, + ..Default::default() + }, + |mut res, m| { + let module = module_graph.module_by_identifier(m).expect("unreachable"); + let build_info = &module.build_info(); + if let Some(info) = build_info { + res + .file_dependencies + .extend(info.file_dependencies.iter().cloned()); + res + .context_dependencies + .extend(info.context_dependencies.iter().cloned()); + res + .missing_dependencies + .extend(info.missing_dependencies.iter().cloned()); + res + .build_dependencies + .extend(info.build_dependencies.iter().cloned()); + if !info.cacheable { + res.cacheable = false; + } + } + res + }, + ); + match exports { Ok(_) => { - let mut result = modules.iter().fold( - ExecuteModuleResult { - cacheable: true, - ..Default::default() - }, - |mut res, m| { - let module = module_graph.module_by_identifier(m).expect("unreachable"); - let build_info = &module.build_info(); - if let Some(info) = build_info { - res - .file_dependencies - .extend(info.file_dependencies.iter().cloned()); - res - .context_dependencies - .extend(info.context_dependencies.iter().cloned()); - res - .missing_dependencies - .extend(info.missing_dependencies.iter().cloned()); - res - .build_dependencies - .extend(info.build_dependencies.iter().cloned()); - if !info.cacheable { - res.cacheable = false; - } - } - res - }, - ); - - result.id = id; - for m in modules.iter() { let codegen_result = codegen_results.get(m, Some(&runtime)); @@ -264,18 +262,19 @@ impl Task for ExecuteTask { ); } } - - Ok(result) } - Err(e) => Err(e), + Err(e) => { + execute_result.cacheable = false; + execute_result.error = Some(e.to_string()); + } }; let assets = std::mem::take(compilation.assets_mut()); let code_generated_modules = std::mem::take(&mut compilation.code_generated_modules); let module_assets = std::mem::take(&mut compilation.module_assets); - if let Ok(ref mut result) = execute_result { - result.assets = assets.keys().cloned().collect::>(); - result.assets.extend( + if execute_result.error.is_none() { + execute_result.assets = assets.keys().cloned().collect::>(); + execute_result.assets.extend( module_assets .values() .flat_map(|m| m.iter().map(|i| i.to_owned()).collect_vec()) diff --git a/crates/rspack_core/src/compiler/module_executor/mod.rs b/crates/rspack_core/src/compiler/module_executor/mod.rs index 8bcfc83c31b5..e9954aa685b4 100644 --- a/crates/rspack_core/src/compiler/module_executor/mod.rs +++ b/crates/rspack_core/src/compiler/module_executor/mod.rs @@ -8,7 +8,6 @@ use dashmap::{mapref::entry::Entry, DashSet}; pub use execute::ExecuteModuleId; pub use execute::ExecutedRuntimeModule; use rspack_collections::{Identifier, IdentifierDashMap, IdentifierDashSet}; -use rspack_error::Result; use tokio::sync::{ mpsc::{unbounded_channel, UnboundedSender}, oneshot, @@ -189,7 +188,7 @@ impl ModuleExecutor { base_uri: Option, original_module_context: Option, original_module_identifier: Option, - ) -> Result { + ) -> ExecuteModuleResult { let sender = self .event_sender .as_ref() @@ -226,7 +225,7 @@ impl ModuleExecutor { let (execute_result, assets, code_generated_modules, executed_runtime_modules) = rx.await.expect("should receiver success"); - if let Ok(execute_result) = &execute_result + if execute_result.error.is_none() && let Some(original_module_identifier) = original_module_identifier { self diff --git a/crates/rspack_core/src/diagnostics.rs b/crates/rspack_core/src/diagnostics.rs index b4588ec6c61e..7f6ae06fadce 100644 --- a/crates/rspack_core/src/diagnostics.rs +++ b/crates/rspack_core/src/diagnostics.rs @@ -1,13 +1,14 @@ -use std::fmt::Display; +use std::{fmt::Display, path::PathBuf}; use itertools::Itertools; use rspack_error::{ - impl_diagnostic_transparent, + error, impl_diagnostic_transparent, miette::{self, Diagnostic}, thiserror::{self, Error}, DiagnosticExt, Error, TraceableError, }; use rspack_util::ext::AsAny; +use rustc_hash::FxHashSet; use crate::{BoxLoader, RealDependencyLocation}; @@ -147,6 +148,93 @@ impl ModuleParseError { } } +#[derive(Debug)] +pub struct CapturedLoaderError { + pub message: String, + pub stack: Option, + pub hide_stack: Option, + pub file_dependencies: Vec, + pub context_dependencies: Vec, + pub missing_dependencies: Vec, + pub build_dependencies: Vec, +} + +impl CapturedLoaderError { + pub fn new( + message: String, + stack: Option, + hide_stack: Option, + file_dependencies: Vec, + context_dependencies: Vec, + missing_dependencies: Vec, + build_dependencies: Vec, + ) -> Self { + Self { + message, + stack, + hide_stack, + file_dependencies, + context_dependencies, + missing_dependencies, + build_dependencies, + } + } + + pub fn take_message(&mut self) -> String { + std::mem::take(&mut self.message) + } + + pub fn take_stack(&mut self) -> Option { + std::mem::take(&mut self.stack) + } + + pub fn take_file_dependencies(&mut self) -> FxHashSet { + std::mem::take(&mut self.file_dependencies) + .into_iter() + .map(Into::into) + .collect() + } + + pub fn take_context_dependencies(&mut self) -> FxHashSet { + std::mem::take(&mut self.context_dependencies) + .into_iter() + .map(Into::into) + .collect() + } + + pub fn take_missing_dependencies(&mut self) -> FxHashSet { + std::mem::take(&mut self.missing_dependencies) + .into_iter() + .map(Into::into) + .collect() + } + + pub fn take_build_dependencies(&mut self) -> FxHashSet { + std::mem::take(&mut self.build_dependencies) + .into_iter() + .map(Into::into) + .collect() + } +} + +impl std::error::Error for CapturedLoaderError { + fn source(&self) -> ::core::option::Option<&(dyn std::error::Error + 'static)> { + None + } +} + +impl std::fmt::Display for CapturedLoaderError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "CapturedLoaderError: {}", self.message) + } +} + +impl rspack_error::miette::Diagnostic for CapturedLoaderError { + fn code<'a>(&'a self) -> Option> { + Some(Box::new("CapturedLoaderError")) + } +} + /// Mark boxed errors as [crate::diagnostics::ModuleParseError], /// then, map it to diagnostics pub fn map_box_diagnostics_to_module_parse_diagnostics( diff --git a/crates/rspack_core/src/normal_module.rs b/crates/rspack_core/src/normal_module.rs index e3c801313113..e6a60e8f6cf3 100644 --- a/crates/rspack_core/src/normal_module.rs +++ b/crates/rspack_core/src/normal_module.rs @@ -29,14 +29,16 @@ use rustc_hash::FxHasher; use serde_json::json; use crate::{ - contextify, diagnostics::ModuleBuildError, get_context, impl_module_meta_info, - module_update_hash, AsyncDependenciesBlockIdentifier, BoxLoader, BoxModule, BuildContext, - BuildInfo, BuildMeta, BuildResult, ChunkGraph, CodeGenerationResult, Compilation, - ConcatenationScope, ConnectionState, Context, DependenciesBlock, DependencyId, - DependencyTemplate, FactoryMeta, GenerateContext, GeneratorOptions, LibIdentOptions, Module, - ModuleDependency, ModuleGraph, ModuleIdentifier, ModuleLayer, ModuleType, OutputOptions, - ParseContext, ParseResult, ParserAndGenerator, ParserOptions, Resolve, RspackLoaderRunnerPlugin, - RunnerContext, RuntimeGlobals, RuntimeSpec, SourceType, + contextify, + diagnostics::{CapturedLoaderError, ModuleBuildError}, + get_context, impl_module_meta_info, module_update_hash, AsyncDependenciesBlockIdentifier, + BoxLoader, BoxModule, BuildContext, BuildInfo, BuildMeta, BuildResult, ChunkGraph, + CodeGenerationResult, Compilation, ConcatenationScope, ConnectionState, Context, + DependenciesBlock, DependencyId, DependencyTemplate, FactoryMeta, GenerateContext, + GeneratorOptions, LibIdentOptions, Module, ModuleDependency, ModuleGraph, ModuleIdentifier, + ModuleLayer, ModuleType, OutputOptions, ParseContext, ParseResult, ParserAndGenerator, + ParserOptions, Resolve, RspackLoaderRunnerPlugin, RunnerContext, RuntimeGlobals, RuntimeSpec, + SourceType, }; #[derive(Debug, Clone)] @@ -434,16 +436,39 @@ impl Module for NormalModule { .await; let (mut loader_result, ds) = match loader_result { Ok(r) => r.split_into_parts(), - Err(r) => { - let node_error = r.downcast_ref::(); - let stack = node_error.and_then(|e| e.stack.clone()); - let hide_stack = node_error.and_then(|e| e.hide_stack); - let e = ModuleBuildError(r).boxed(); - let d = Diagnostic::from(e) + Err(mut r) => { + let diagnostic = if let Some(captured_error) = r.downcast_mut::() { + build_info.file_dependencies = captured_error.take_file_dependencies(); + build_info.context_dependencies = captured_error.take_context_dependencies(); + build_info.missing_dependencies = captured_error.take_missing_dependencies(); + build_info.build_dependencies = captured_error.take_build_dependencies(); + + let stack = captured_error.take_stack(); + Diagnostic::from( + ModuleBuildError(error!(if captured_error.hide_stack.unwrap_or_default() { + captured_error.take_message() + } else { + stack + .clone() + .unwrap_or_else(|| captured_error.take_message()) + })) + .boxed(), + ) .with_stack(stack) - .with_hide_stack(hide_stack); - self.source = NormalModuleSource::BuiltFailed(d.clone()); - self.add_diagnostic(d); + .with_hide_stack(captured_error.hide_stack) + } else { + let node_error = r.downcast_ref::(); + let stack = node_error.and_then(|e| e.stack.clone()); + let hide_stack = node_error.and_then(|e| e.hide_stack); + let e = ModuleBuildError(r).boxed(); + let d = Diagnostic::from(e) + .with_stack(stack) + .with_hide_stack(hide_stack); + d + }; + + self.source = NormalModuleSource::BuiltFailed(diagnostic.clone()); + self.add_diagnostic(diagnostic); build_info.hash = Some(self.init_build_hash(&build_context.compiler_options.output, &build_meta)); diff --git a/packages/rspack-test-tools/tests/diagnosticsCases/module-build-failed/asset-module-build-failed/stats.err b/packages/rspack-test-tools/tests/diagnosticsCases/module-build-failed/asset-module-build-failed/stats.err index f831c274beac..5b6c143e2f51 100644 --- a/packages/rspack-test-tools/tests/diagnosticsCases/module-build-failed/asset-module-build-failed/stats.err +++ b/packages/rspack-test-tools/tests/diagnosticsCases/module-build-failed/asset-module-build-failed/stats.err @@ -7,5 +7,4 @@ ERROR in ./logo.svg │ at xxx │ at xxx │ at xxx - │ at xxx - │ \ No newline at end of file + │ at xxx \ No newline at end of file diff --git a/packages/rspack-test-tools/tests/diagnosticsCases/module-build-failed/loader-emit-diagnostic/stats.err b/packages/rspack-test-tools/tests/diagnosticsCases/module-build-failed/loader-emit-diagnostic/stats.err index 3dda5456db11..a467b8bc1bab 100644 --- a/packages/rspack-test-tools/tests/diagnosticsCases/module-build-failed/loader-emit-diagnostic/stats.err +++ b/packages/rspack-test-tools/tests/diagnosticsCases/module-build-failed/loader-emit-diagnostic/stats.err @@ -59,7 +59,6 @@ ERROR in (./with-multi-byte-char.js!) │ at xxx │ at xxx │ at xxx - │ ERROR in (./with-multiple-line.js!) 1:0-2:4 × ModuleError: Multiple line error @@ -87,7 +86,6 @@ ERROR in (./with-multiple-line.js!) │ at xxx │ at xxx │ at xxx - │ ERROR in (./with-multiple-line.js!) 3:4 × ModuleError: Multiple line snippet diff --git a/packages/rspack-test-tools/tests/diagnosticsCases/module-build-failed/loader-throw-error/stats.err b/packages/rspack-test-tools/tests/diagnosticsCases/module-build-failed/loader-throw-error/stats.err index 7ca692e1000c..bd54b5a8c2e0 100644 --- a/packages/rspack-test-tools/tests/diagnosticsCases/module-build-failed/loader-throw-error/stats.err +++ b/packages/rspack-test-tools/tests/diagnosticsCases/module-build-failed/loader-throw-error/stats.err @@ -7,5 +7,4 @@ ERROR in ./lib.js │ at xxx │ at xxx │ at xxx - │ at xxx - │ \ No newline at end of file + │ at xxx \ No newline at end of file diff --git a/packages/rspack/src/loader-runner/index.ts b/packages/rspack/src/loader-runner/index.ts index c01d7aee0ed3..a6c72add8465 100644 --- a/packages/rspack/src/loader-runner/index.ts +++ b/packages/rspack/src/loader-runner/index.ts @@ -438,7 +438,13 @@ export async function runLoaders( this.cacheable(false); } - resolve(compiler.__internal__getModuleExecutionResult(res.id)); + if (res.error) { + reject(new Error(err)); + } else { + resolve( + compiler.__internal__getModuleExecutionResult(res.id) + ); + } } } ); @@ -473,10 +479,14 @@ export async function runLoaders( this.cacheable(false); } - callback( - undefined, - compiler.__internal__getModuleExecutionResult(res.id) - ); + if (res.error) { + callback(new Error(err), undefined); + } else { + callback( + undefined, + compiler.__internal__getModuleExecutionResult(res.id) + ); + } } } ); @@ -803,83 +813,101 @@ export async function runLoaders( get: () => context.__internal__parseMeta }); - switch (loaderState) { - case JsLoaderState.Pitching: { - while (loaderContext.loaderIndex < loaderContext.loaders.length) { - const currentLoaderObject = - loaderContext.loaders[loaderContext.loaderIndex]; + try { + switch (loaderState) { + case JsLoaderState.Pitching: { + while (loaderContext.loaderIndex < loaderContext.loaders.length) { + const currentLoaderObject = + loaderContext.loaders[loaderContext.loaderIndex]; + + if (currentLoaderObject.shouldYield()) break; + if (currentLoaderObject.pitchExecuted) { + loaderContext.loaderIndex += 1; + continue; + } - if (currentLoaderObject.shouldYield()) break; - if (currentLoaderObject.pitchExecuted) { - loaderContext.loaderIndex += 1; - continue; + await loadLoaderAsync(currentLoaderObject); + const fn = currentLoaderObject.pitch; + currentLoaderObject.pitchExecuted = true; + if (!fn) continue; + + const args = + (await runSyncOrAsync(fn, loaderContext, [ + loaderContext.remainingRequest, + loaderContext.previousRequest, + currentLoaderObject.data + ])) || []; + + const hasArg = args.some(value => value !== undefined); + + if (hasArg) { + const [content, sourceMap, additionalData] = args; + context.content = isNil(content) ? null : toBuffer(content); + context.sourceMap = serializeObject(sourceMap); + context.additionalData = additionalData; + break; + } } - await loadLoaderAsync(currentLoaderObject); - const fn = currentLoaderObject.pitch; - currentLoaderObject.pitchExecuted = true; - if (!fn) continue; - - const args = - (await runSyncOrAsync(fn, loaderContext, [ - loaderContext.remainingRequest, - loaderContext.previousRequest, - currentLoaderObject.data - ])) || []; - - const hasArg = args.some(value => value !== undefined); - - if (hasArg) { - const [content, sourceMap, additionalData] = args; - context.content = isNil(content) ? null : toBuffer(content); - context.sourceMap = serializeObject(sourceMap); - context.additionalData = additionalData; - break; - } + break; } + case JsLoaderState.Normal: { + let content = context.content; + let sourceMap = JsSourceMap.__from_binding(context.sourceMap); + let additionalData = context.additionalData; + + while (loaderContext.loaderIndex >= 0) { + const currentLoaderObject = + loaderContext.loaders[loaderContext.loaderIndex]; + + if (currentLoaderObject.shouldYield()) break; + if (currentLoaderObject.normalExecuted) { + loaderContext.loaderIndex--; + continue; + } - break; - } - case JsLoaderState.Normal: { - let content = context.content; - let sourceMap = JsSourceMap.__from_binding(context.sourceMap); - let additionalData = context.additionalData; - - while (loaderContext.loaderIndex >= 0) { - const currentLoaderObject = - loaderContext.loaders[loaderContext.loaderIndex]; - - if (currentLoaderObject.shouldYield()) break; - if (currentLoaderObject.normalExecuted) { - loaderContext.loaderIndex--; - continue; + await loadLoaderAsync(currentLoaderObject); + const fn = currentLoaderObject.normal; + currentLoaderObject.normalExecuted = true; + if (!fn) continue; + const args = [content, sourceMap, additionalData]; + convertArgs(args, !!currentLoaderObject.raw); + [content, sourceMap, additionalData] = + (await runSyncOrAsync(fn, loaderContext, args)) || []; } - await loadLoaderAsync(currentLoaderObject); - const fn = currentLoaderObject.normal; - currentLoaderObject.normalExecuted = true; - if (!fn) continue; - const args = [content, sourceMap, additionalData]; - convertArgs(args, !!currentLoaderObject.raw); - [content, sourceMap, additionalData] = - (await runSyncOrAsync(fn, loaderContext, args)) || []; - } + context.content = isNil(content) ? null : toBuffer(content); + context.sourceMap = JsSourceMap.__to_binding(sourceMap); + context.additionalData = additionalData; - context.content = isNil(content) ? null : toBuffer(content); - context.sourceMap = JsSourceMap.__to_binding(sourceMap); - context.additionalData = additionalData; - - break; + break; + } + default: + throw new Error(`Unexpected loader runner state: ${loaderState}`); } - default: - throw new Error(`Unexpected loader runner state: ${loaderState}`); - } - - // update loader state - context.loaderItems = loaderContext.loaders.map(item => - LoaderObject.__to_binding(item) - ); + // update loader state + context.loaderItems = loaderContext.loaders.map(item => + LoaderObject.__to_binding(item) + ); + } catch (e) { + const error = e as Error & { hideStack?: boolean | "true" }; + context.__internal__error = + typeof e === "string" + ? { + name: "ModuleBuildError", + message: e + } + : { + name: "ModuleBuildError", + message: error.message, + stack: typeof error.stack === "string" ? error.stack : undefined, + hideStack: + "hideStack" in error + ? error.hideStack === true || error.hideStack === "true" + : undefined + }; + } return context; } From d5c5508da5fca25104fc86ed1ff5049409a1de41 Mon Sep 17 00:00:00 2001 From: LingyuCoder Date: Mon, 4 Nov 2024 19:47:11 +0800 Subject: [PATCH 2/3] fix: file dependencies lost when incremental compiling failed in css module --- crates/rspack_core/src/normal_module.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/rspack_core/src/normal_module.rs b/crates/rspack_core/src/normal_module.rs index e6a60e8f6cf3..462e3c0a87af 100644 --- a/crates/rspack_core/src/normal_module.rs +++ b/crates/rspack_core/src/normal_module.rs @@ -461,10 +461,9 @@ impl Module for NormalModule { let stack = node_error.and_then(|e| e.stack.clone()); let hide_stack = node_error.and_then(|e| e.hide_stack); let e = ModuleBuildError(r).boxed(); - let d = Diagnostic::from(e) + Diagnostic::from(e) .with_stack(stack) - .with_hide_stack(hide_stack); - d + .with_hide_stack(hide_stack) }; self.source = NormalModuleSource::BuiltFailed(diagnostic.clone()); From d53c14e714aa65f998a460dcb0c5561a0de54c70 Mon Sep 17 00:00:00 2001 From: LingyuCoder Date: Tue, 5 Nov 2024 12:28:21 +0800 Subject: [PATCH 3/3] fix: file dependencies lost when incremental compiling failed in css module --- .../watch-loader-failed-css/0/dep.txt | 1 + .../watch-loader-failed-css/0/entry.txt | 2 + .../watch-loader-failed-css/0/index.js | 11 ++++++ .../watch-loader-failed-css/1/dep.txt | 1 + .../watch-loader-failed-css/1/errors.js | 1 + .../watch-loader-failed-css/2/dep.txt | 1 + .../watch-loader-failed-css/loader.js | 13 +++++++ .../watch-loader-failed-css/rspack.config.js | 37 +++++++++++++++++++ .../watch-loader-failed/0/dep.txt | 1 + .../watch-loader-failed/0/entry.txt | 1 + .../watch-loader-failed/0/index.js | 11 ++++++ .../watch-loader-failed/1/dep.txt | 1 + .../watch-loader-failed/1/errors.js | 1 + .../watch-loader-failed/2/dep.txt | 1 + .../watch-loader-failed/loader.js | 11 ++++++ .../watch-loader-failed/rspack.config.js | 14 +++++++ 16 files changed, 108 insertions(+) create mode 100644 packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed-css/0/dep.txt create mode 100644 packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed-css/0/entry.txt create mode 100644 packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed-css/0/index.js create mode 100644 packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed-css/1/dep.txt create mode 100644 packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed-css/1/errors.js create mode 100644 packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed-css/2/dep.txt create mode 100644 packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed-css/loader.js create mode 100644 packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed-css/rspack.config.js create mode 100644 packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed/0/dep.txt create mode 100644 packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed/0/entry.txt create mode 100644 packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed/0/index.js create mode 100644 packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed/1/dep.txt create mode 100644 packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed/1/errors.js create mode 100644 packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed/2/dep.txt create mode 100644 packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed/loader.js create mode 100644 packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed/rspack.config.js diff --git a/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed-css/0/dep.txt b/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed-css/0/dep.txt new file mode 100644 index 000000000000..a3ce69cbc736 --- /dev/null +++ b/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed-css/0/dep.txt @@ -0,0 +1 @@ +color: blue; \ No newline at end of file diff --git a/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed-css/0/entry.txt b/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed-css/0/entry.txt new file mode 100644 index 000000000000..b9802c908886 --- /dev/null +++ b/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed-css/0/entry.txt @@ -0,0 +1,2 @@ +background: red; +$dep$ \ No newline at end of file diff --git a/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed-css/0/index.js b/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed-css/0/index.js new file mode 100644 index 000000000000..3becb63ab553 --- /dev/null +++ b/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed-css/0/index.js @@ -0,0 +1,11 @@ +it("should have correct value", () => { + if (WATCH_STEP === "0") { + expect(require("./entry.txt").myClass).toBeTruthy(); + } else if (WATCH_STEP === "1") { + expect(() => { + require("./entry.txt") + }).toThrow(); + } else if (WATCH_STEP === "2") { + expect(require("./entry.txt").myClass).toBeTruthy(); + } +}); diff --git a/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed-css/1/dep.txt b/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed-css/1/dep.txt new file mode 100644 index 000000000000..f45d4b694dab --- /dev/null +++ b/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed-css/1/dep.txt @@ -0,0 +1 @@ +fail \ No newline at end of file diff --git a/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed-css/1/errors.js b/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed-css/1/errors.js new file mode 100644 index 000000000000..51dd9ce6f310 --- /dev/null +++ b/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed-css/1/errors.js @@ -0,0 +1 @@ +module.exports = [/Failed/, /Module build failed/]; diff --git a/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed-css/2/dep.txt b/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed-css/2/dep.txt new file mode 100644 index 000000000000..55a06ecb12ce --- /dev/null +++ b/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed-css/2/dep.txt @@ -0,0 +1 @@ +color: blueviolet; \ No newline at end of file diff --git a/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed-css/loader.js b/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed-css/loader.js new file mode 100644 index 000000000000..fd72ca2337fb --- /dev/null +++ b/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed-css/loader.js @@ -0,0 +1,13 @@ +const fs = require("fs"); + +module.exports = function (source) { + const depPath = this.resource.replace("entry.txt", "dep.txt"); + this.addDependency(depPath); + const depContent = fs.readFileSync(depPath, 'utf-8'); + if (depContent === "fail") { + throw new Error("Failed"); + } + return `.my-class { + ${source.replace("$dep$", depContent)} + }`; +}; \ No newline at end of file diff --git a/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed-css/rspack.config.js b/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed-css/rspack.config.js new file mode 100644 index 000000000000..faad443b5c59 --- /dev/null +++ b/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed-css/rspack.config.js @@ -0,0 +1,37 @@ +const path = require("path"); +const rspack = require('@rspack/core'); + +/** @type {import("@rspack/core").Configuration} */ +module.exports = { + module: { + rules: [{ + test: /.txt$/, + type: 'javascript/auto', + use: [ + { + loader: rspack.CssExtractRspackPlugin.loader, + }, + { + loader: "css-loader", + options: { + modules: { + namedExport: true + } + } + }, + { + loader: path.resolve(__dirname, './loader.js') + } + ] + }] + }, + plugins: [ + new rspack.CssExtractRspackPlugin(), + ], + experiments: { + css: false + }, + resolve: { + extensions: ["...", ".txt"] + } +}; diff --git a/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed/0/dep.txt b/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed/0/dep.txt new file mode 100644 index 000000000000..7b5c6cf2a3cc --- /dev/null +++ b/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed/0/dep.txt @@ -0,0 +1 @@ +dep0 \ No newline at end of file diff --git a/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed/0/entry.txt b/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed/0/entry.txt new file mode 100644 index 000000000000..9c2c833bd8c5 --- /dev/null +++ b/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed/0/entry.txt @@ -0,0 +1 @@ +entry for $dep$ \ No newline at end of file diff --git a/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed/0/index.js b/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed/0/index.js new file mode 100644 index 000000000000..7a42634ef378 --- /dev/null +++ b/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed/0/index.js @@ -0,0 +1,11 @@ +it("should have correct value", () => { + if (WATCH_STEP === "0") { + expect(require("./entry.txt")).toBe("entry for dep0"); + } else if (WATCH_STEP === "1") { + expect(() => { + require("./entry.txt") + }).toThrow(); + } else if (WATCH_STEP === "2") { + expect(require("./entry.txt")).toBe("entry for dep2"); + } +}); diff --git a/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed/1/dep.txt b/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed/1/dep.txt new file mode 100644 index 000000000000..f45d4b694dab --- /dev/null +++ b/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed/1/dep.txt @@ -0,0 +1 @@ +fail \ No newline at end of file diff --git a/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed/1/errors.js b/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed/1/errors.js new file mode 100644 index 000000000000..5e147e073e4e --- /dev/null +++ b/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed/1/errors.js @@ -0,0 +1 @@ +module.exports = [[/Failed/]]; diff --git a/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed/2/dep.txt b/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed/2/dep.txt new file mode 100644 index 000000000000..4f9934ee02b9 --- /dev/null +++ b/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed/2/dep.txt @@ -0,0 +1 @@ +dep2 \ No newline at end of file diff --git a/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed/loader.js b/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed/loader.js new file mode 100644 index 000000000000..731cee11d97e --- /dev/null +++ b/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed/loader.js @@ -0,0 +1,11 @@ +const fs = require("fs"); + +module.exports = function (source) { + const depPath = this.resource.replace("entry.txt", "dep.txt"); + this.addDependency(depPath); + const depContent = fs.readFileSync(depPath, 'utf-8'); + if (depContent === "fail") { + throw new Error("Failed"); + } + return `module.exports = "${source.replace("$dep$", depContent)}"`; +}; \ No newline at end of file diff --git a/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed/rspack.config.js b/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed/rspack.config.js new file mode 100644 index 000000000000..572256f09d4a --- /dev/null +++ b/packages/rspack-test-tools/tests/watchCases/build-failed/watch-loader-failed/rspack.config.js @@ -0,0 +1,14 @@ +const path = require("path"); + +/** @type {import("@rspack/core").Configuration} */ +module.exports = { + module: { + rules: [{ + test: /.txt$/, + loader: path.resolve(__dirname, './loader.js') + }] + }, + resolve: { + extensions: ["...", ".txt"] + } +};