From 746b8d2efd57b3a554f82d3f0a96f59d84d7f9b5 Mon Sep 17 00:00:00 2001 From: ClarkXia Date: Wed, 29 Nov 2023 15:30:55 +0800 Subject: [PATCH] fix: simplify loader config (#15) * fix: simplify loader config * chore: fix test case * fix: built-in options --- Cargo.lock | 1 + crates/loader_compilation/Cargo.toml | 1 + crates/loader_compilation/src/lib.rs | 46 +++++++++++++++++-- .../loader_compilation/src/transform/mod.rs | 25 +++------- crates/loader_compilation/tests/fixtures.rs | 5 +- 5 files changed, 54 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6133446..ba40dc5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1483,6 +1483,7 @@ dependencies = [ "rspack_error", "rspack_loader_runner", "rspack_plugin_javascript", + "rspack_regex", "rspack_testing", "serde", "serde_json", diff --git a/crates/loader_compilation/Cargo.toml b/crates/loader_compilation/Cargo.toml index c252936..46e8ced 100644 --- a/crates/loader_compilation/Cargo.toml +++ b/crates/loader_compilation/Cargo.toml @@ -18,6 +18,7 @@ rspack_core = { path = "../.rspack_crates/rspack_core" } rspack_error = { path = "../.rspack_crates/rspack_error" } rspack_loader_runner = { path = "../.rspack_crates/rspack_loader_runner" } rspack_plugin_javascript = { path = "../.rspack_crates/rspack_plugin_javascript" } +rspack_regex = { path = "../.rspack_crates/rspack_regex" } regex = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = "1.0.100" diff --git a/crates/loader_compilation/src/lib.rs b/crates/loader_compilation/src/lib.rs index ff2e4ce..5bcb3c9 100644 --- a/crates/loader_compilation/src/lib.rs +++ b/crates/loader_compilation/src/lib.rs @@ -6,12 +6,18 @@ use rspack_loader_runner::{Identifiable, Identifier, Loader, LoaderContext}; use rspack_error::{ internal_error, Result, Diagnostic, }; -use swc_core::{base::config::{InputSourceMap, Options, OutputCharset, Config, TransformConfig}, ecma::transforms::react::Runtime}; +use swc_core::{ + base::config::{InputSourceMap, Options, OutputCharset, Config, TransformConfig}, + ecma::parser::{Syntax, TsConfig}, +}; + +use swc_config::{config_types::MergingOption, merge::Merge}; use rspack_plugin_javascript::{ ast::{self, SourceMapConfig}, TransformOutput, }; use serde::Deserialize; +use rspack_regex::RspackRegex; mod compiler; mod transform; @@ -19,16 +25,25 @@ mod transform; use transform::*; use compiler::{SwcCompiler, IntoJsAst}; +#[derive(Debug, Default, Deserialize)] +#[serde(rename_all = "camelCase", default)] +pub struct CompileRules { + // Built-in rules to exclude files from compilation, such as react, react-dom, etc. + exclude: Option>, +} + #[derive(Debug, Default, Deserialize)] #[serde(rename_all = "camelCase", default)] pub struct LoaderOptions { pub swc_options: Config, pub transform_features: TransformFeatureOptions, + pub compile_rules: CompileRules, } pub struct CompilationOptions { swc_options: Options, transform_features: TransformFeatureOptions, + compile_rules: CompileRules, } pub struct CompilationLoader { identifier: Identifier, @@ -39,13 +54,15 @@ pub const COMPILATION_LOADER_IDENTIFIER: &str = "builtin:compilation-loader"; impl From for CompilationOptions { fn from(value: LoaderOptions) -> Self { - let transform_features = TransformFeatureOptions::default(); + let transform_features = value.transform_features; + let compile_rules = value.compile_rules; CompilationOptions { swc_options: Options { config: value.swc_options, ..Default::default() }, transform_features, + compile_rules, } } } @@ -74,6 +91,17 @@ lazy_static! { impl Loader for CompilationLoader { async fn run(&self, loader_context: &mut LoaderContext<'_, LoaderRunnerContext>) -> Result<()> { let resource_path = loader_context.resource_path.to_path_buf(); + + if self.loader_options.compile_rules.exclude.is_some() { + let exclude = self.loader_options.compile_rules.exclude.as_ref().unwrap(); + for pattern in exclude { + let pattern = RspackRegex::new(pattern).unwrap(); + if pattern.test(&resource_path.to_string_lossy()) { + return Ok(()); + } + } + } + let Some(content) = std::mem::take(&mut loader_context.content) else { return Err(internal_error!("No content found")); }; @@ -84,7 +112,17 @@ impl Loader for CompilationLoader { let mut transform = TransformConfig::default(); let default_development = matches!(loader_context.context.options.mode, Mode::Development); transform.react.development = Some(default_development); - transform.react.runtime = Some(Runtime::Automatic); + swc_options + .config + .jsc + .transform + .merge(MergingOption::from(Some(transform))); + } + + let file_extension = resource_path.extension().unwrap(); + let ts_extensions = vec!["tsx", "ts", "mts"]; + if ts_extensions.iter().any(|ext| ext == &file_extension) { + swc_options.config.jsc.syntax = Some(Syntax::Typescript(TsConfig { tsx: true, decorators: true, ..Default::default() })); } if let Some(pre_source_map) = std::mem::take(&mut loader_context.source_map) { @@ -133,7 +171,7 @@ impl Loader for CompilationLoader { } } file_access.insert(resource_path.to_string_lossy().to_string(), true); - + let built = compiler.parse(None, |_| { transform( &resource_path, diff --git a/crates/loader_compilation/src/transform/mod.rs b/crates/loader_compilation/src/transform/mod.rs index ff2a10b..9bc09dd 100644 --- a/crates/loader_compilation/src/transform/mod.rs +++ b/crates/loader_compilation/src/transform/mod.rs @@ -80,24 +80,11 @@ fn match_app_entry(resource_path: &Path) -> bool { regex_for_app.is_match(resource_path_str) } -#[derive(Default, Debug, Clone, Deserialize)] -#[serde(rename_all = "camelCase", default)] -pub struct KeepExportOptions { - pub export_names: Vec, -} - -#[derive(Default, Debug, Clone, Deserialize)] -#[serde(rename_all = "camelCase", default)] -pub struct RemoveExportOptions { - pub remove_names: Vec, -} - - #[derive(Debug, Default, Deserialize)] #[serde(rename_all = "camelCase", default)] pub struct TransformFeatureOptions { - pub keep_export: Option, - pub remove_export: Option, + pub keep_export: Option>, + pub remove_export: Option>, } pub(crate) fn transform<'a>( @@ -106,8 +93,8 @@ pub(crate) fn transform<'a>( feature_options: &TransformFeatureOptions, ) -> impl Fold + 'a { chain!( - either!(feature_options.keep_export, |options: &KeepExportOptions| { - let mut exports_name = options.export_names.clone(); + either!(feature_options.keep_export, |options: &Vec| { + let mut exports_name = options.clone(); // Special case for app entry. // When keep pageConfig, we should also keep the default export of app entry. if match_app_entry(resource_path) && exports_name.contains(&String::from("pageConfig")) { @@ -117,8 +104,8 @@ pub(crate) fn transform<'a>( }, || { match_app_entry(resource_path) || match_route_entry(resource_path, routes_config) }), - either!(feature_options.remove_export, |options: &RemoveExportOptions| { - remove_export(options.remove_names.clone()) + either!(feature_options.remove_export, |options: &Vec| { + remove_export(options.clone()) }, || { // Remove export only work for app entry and route entry. match_app_entry(resource_path) || match_route_entry(resource_path, routes_config) diff --git a/crates/loader_compilation/tests/fixtures.rs b/crates/loader_compilation/tests/fixtures.rs index 2a4597a..ae7386a 100644 --- a/crates/loader_compilation/tests/fixtures.rs +++ b/crates/loader_compilation/tests/fixtures.rs @@ -3,7 +3,7 @@ use loader_compilation::{CompilationLoader, LoaderOptions}; use rspack_core::{ run_loaders, CompilerContext, CompilerOptions, Loader, LoaderRunnerContext, ResourceData, SideEffectOption, }; -use swc_core::base::config::{PluginConfig, Config}; +use swc_core::base::config::Config; async fn loader_test(actual: impl AsRef, expected: impl AsRef) { let tests_path = PathBuf::from(concat!(env!("CARGO_MANIFEST_DIR"))).join("tests"); @@ -16,10 +16,13 @@ async fn loader_test(actual: impl AsRef, expected: impl AsRef) { &[Arc::new(CompilationLoader::new(LoaderOptions { swc_options: options, transform_features: Default::default(), + compile_rules: Default::default(), })) as Arc>], &ResourceData::new(actual_path.to_string_lossy().to_string(), actual_path), &[], CompilerContext { + module: None, + module_context: None, options: std::sync::Arc::new(CompilerOptions { context: rspack_core::Context::new(parent_path.to_string_lossy().to_string()), dev_server: rspack_core::DevServerOptions::default(),