From debd40611a9db400260b0cb028cb019bd315e6e1 Mon Sep 17 00:00:00 2001 From: Gengkun Date: Mon, 19 Aug 2024 15:30:35 +0800 Subject: [PATCH] perf: warn case sensitive plugin (#7606) --- Cargo.lock | 2 + .../Cargo.toml | 11 ++-- .../src/lib.rs | 53 +++++++++++-------- 3 files changed, 41 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 41e7ed739f7..9269e1614b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3824,9 +3824,11 @@ dependencies = [ name = "rspack_plugin_warn_sensitive_module" version = "0.1.0" dependencies = [ + "rspack_collections", "rspack_core", "rspack_error", "rspack_hook", + "rustc-hash 1.1.0", "tracing", ] diff --git a/crates/rspack_plugin_warn_sensitive_module/Cargo.toml b/crates/rspack_plugin_warn_sensitive_module/Cargo.toml index afa0bc8a824..a4359f1e87d 100644 --- a/crates/rspack_plugin_warn_sensitive_module/Cargo.toml +++ b/crates/rspack_plugin_warn_sensitive_module/Cargo.toml @@ -5,11 +5,14 @@ license = "MIT" name = "rspack_plugin_warn_sensitive_module" repository = "https://github.com/web-infra-dev/rspack" version = "0.1.0" + [dependencies] -rspack_core = { version = "0.1.0", path = "../rspack_core" } -rspack_error = { version = "0.1.0", path = "../rspack_error" } -rspack_hook = { version = "0.1.0", path = "../rspack_hook" } -tracing = { workspace = true } +rspack_collections = { path = "../rspack_collections" } +rspack_core = { version = "0.1.0", path = "../rspack_core" } +rspack_error = { version = "0.1.0", path = "../rspack_error" } +rspack_hook = { version = "0.1.0", path = "../rspack_hook" } +rustc-hash = { workspace = true } +tracing = { workspace = true } [package.metadata.cargo-shear] ignored = ["tracing"] diff --git a/crates/rspack_plugin_warn_sensitive_module/src/lib.rs b/crates/rspack_plugin_warn_sensitive_module/src/lib.rs index 49a64f55b02..b27e0398457 100644 --- a/crates/rspack_plugin_warn_sensitive_module/src/lib.rs +++ b/crates/rspack_plugin_warn_sensitive_module/src/lib.rs @@ -1,13 +1,15 @@ // https://github.com/webpack/webpack/blob/main/lib/WarnCaseSensitiveModulesPlugin.js -use std::collections::HashMap; +use std::{collections::HashMap, hash::BuildHasherDefault}; +use rspack_collections::{Identifier, IdentifierSet}; use rspack_core::{ - ApplyContext, Compilation, CompilationSeal, CompilerOptions, Logger, Module, ModuleGraph, Plugin, + ApplyContext, Compilation, CompilationSeal, CompilerOptions, Logger, ModuleGraph, Plugin, PluginContext, }; use rspack_error::{Diagnostic, Result}; use rspack_hook::{plugin, plugin_hook}; +use rustc_hash::{FxHashMap, FxHasher}; #[plugin] #[derive(Debug, Default)] @@ -16,15 +18,15 @@ pub struct WarnCaseSensitiveModulesPlugin; impl WarnCaseSensitiveModulesPlugin { pub fn create_sensitive_modules_warning( &self, - modules: &Vec<&dyn Module>, + modules: Vec, graph: &ModuleGraph, ) -> String { let mut message = String::from("There are multiple modules with names that only differ in casing.\n"); for m in modules { - if let Some(boxed_m) = graph.module_by_identifier(&m.identifier()) { - let mut module_msg = format!(" - {}\n", m.identifier()); + if let Some(boxed_m) = graph.module_by_identifier(&m) { + let mut module_msg = format!(" - {}\n", m); graph .get_incoming_connections(&boxed_m.identifier()) .iter() @@ -48,8 +50,11 @@ async fn seal(&self, compilation: &mut Compilation) -> Result<()> { let start = logger.time("check case sensitive modules"); let mut diagnostics: Vec = vec![]; let module_graph = compilation.get_module_graph(); - let mut module_without_case_map: HashMap>> = - HashMap::new(); + let mut not_conflect: FxHashMap = HashMap::with_capacity_and_hasher( + module_graph.modules().len(), + BuildHasherDefault::::default(), + ); + let mut conflict: FxHashMap = FxHashMap::default(); for module in module_graph.modules().values() { // Ignore `data:` URLs, because it's not a real path @@ -63,25 +68,31 @@ async fn seal(&self, compilation: &mut Compilation) -> Result<()> { } } - let identifier = module.identifier().to_string(); + let identifier = module.identifier(); let lower_identifier = identifier.to_lowercase(); - let lower_map = module_without_case_map.entry(lower_identifier).or_default(); - lower_map.insert(identifier, module); + if let Some(prev_identifier) = not_conflect.remove(&lower_identifier) { + conflict.insert( + lower_identifier, + IdentifierSet::from_iter([prev_identifier, identifier]), + ); + } else if let Some(set) = conflict.get_mut(&lower_identifier) { + set.insert(identifier); + } else { + not_conflect.insert(lower_identifier, identifier); + } } // sort by module identifier, guarantee the warning order - let mut case_map_vec = module_without_case_map.into_iter().collect::>(); - case_map_vec.sort_by(|a, b| a.0.cmp(&b.0)); + let mut case_map_vec = conflict.into_iter().collect::>(); + case_map_vec.sort_unstable_by(|a, b| a.0.cmp(&b.0)); - for (_, lower_map) in case_map_vec { - if lower_map.values().len() > 1 { - let mut case_modules = lower_map.values().map(|m| m.as_ref()).collect::>(); - case_modules.sort_by_key(|m| m.identifier()); - diagnostics.push(Diagnostic::warn( - "Sensitive Modules Warn".to_string(), - self.create_sensitive_modules_warning(&case_modules, &compilation.get_module_graph()), - )); - } + for (_, set) in case_map_vec { + let mut case_modules = set.iter().copied().collect::>(); + case_modules.sort_unstable(); + diagnostics.push(Diagnostic::warn( + "Sensitive Modules Warn".to_string(), + self.create_sensitive_modules_warning(case_modules, &compilation.get_module_graph()), + )); } compilation.extend_diagnostics(diagnostics);