diff --git a/Cargo.lock b/Cargo.lock index bd3f79ace16..72e5aa40d80 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1716,9 +1716,9 @@ checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" [[package]] name = "oxc_resolver" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0cba9c2dd86cc336814aa1b2fb2e3c1bdee5cbf411debb736ab582856f249db" +checksum = "9657cba6ac0894a8acf3aca5b9a4b7668ce8486042588cf2bf0f34eb5f37ebc6" dependencies = [ "dashmap", "dunce", @@ -1729,6 +1729,7 @@ dependencies = [ "serde_json", "thiserror", "tracing", + "tracing-subscriber", ] [[package]] @@ -2322,12 +2323,14 @@ dependencies = [ name = "rspack" version = "0.1.0" dependencies = [ + "cargo-rst", "criterion", "insta", "mimalloc-rust", "rspack_binding_options", "rspack_core", "rspack_fs", + "rspack_plugin_javascript", "rspack_testing", "rspack_tracing", "serde", @@ -2389,6 +2392,7 @@ dependencies = [ "rspack_error", "rspack_identifier", "rspack_ids", + "rspack_loader_react_refresh", "rspack_loader_runner", "rspack_loader_sass", "rspack_loader_swc", @@ -2441,7 +2445,6 @@ dependencies = [ "derivative", "dyn-clone", "futures", - "glob", "glob-match", "hashlink", "indexmap 1.9.3", @@ -2574,6 +2577,16 @@ dependencies = [ "rustc-hash", ] +[[package]] +name = "rspack_loader_react_refresh" +version = "0.1.0" +dependencies = [ + "async-trait", + "rspack_core", + "rspack_error", + "rspack_loader_runner", +] + [[package]] name = "rspack_loader_runner" version = "0.1.0" @@ -3018,6 +3031,7 @@ version = "0.1.0" dependencies = [ "async-recursion", "async-trait", + "rayon", "regex", "rspack_core", "rspack_error", @@ -3357,9 +3371,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.105" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" +checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" dependencies = [ "indexmap 2.0.0", "itoa", diff --git a/crates/cargo-rst/Cargo.toml b/crates/cargo-rst/Cargo.toml index 84ba6635d80..67cd6352433 100644 --- a/crates/cargo-rst/Cargo.toml +++ b/crates/cargo-rst/Cargo.toml @@ -18,4 +18,4 @@ serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } console = "0.15.7" -similar = { workspace = true, features = ["inline"] } +similar = { workspace = true, features = ["inline", "text", "bytes"] } diff --git a/crates/cargo-rst/src/lib.rs b/crates/cargo-rst/src/lib.rs index 1bb379f0af8..f3becb9bd2f 100644 --- a/crates/cargo-rst/src/lib.rs +++ b/crates/cargo-rst/src/lib.rs @@ -6,6 +6,7 @@ pub mod rst; mod terminal_inline; mod update; pub use rst::test; +pub use terminal_inline::*; pub use update::update; // #[derive(FromArgs)] diff --git a/crates/cargo-rst/src/terminal_inline.rs b/crates/cargo-rst/src/terminal_inline.rs index e3948c67eaf..de65b43593f 100644 --- a/crates/cargo-rst/src/terminal_inline.rs +++ b/crates/cargo-rst/src/terminal_inline.rs @@ -57,3 +57,8 @@ pub fn diff_and_print(expected: &str, actual: &str) -> String { let diff = TextDiff::from_lines(expected, actual); pretty_diff_printer(&diff) } + +pub fn git_diff(expected: &str, actual: &str) -> String { + let diff = TextDiff::from_lines(expected, actual); + diff.unified_diff().header("expected", "actual").to_string() +} diff --git a/crates/node_binding/binding.d.ts b/crates/node_binding/binding.d.ts index 12b701a0f3b..4eb70c19af1 100644 --- a/crates/node_binding/binding.d.ts +++ b/crates/node_binding/binding.d.ts @@ -110,24 +110,31 @@ export interface BeforeResolveData { } export interface BuiltinPlugin { - kind: BuiltinPluginKind + name: BuiltinPluginName options: unknown } -export const enum BuiltinPluginKind { - Define = 'Define', - Provide = 'Provide', - Banner = 'Banner', - Progress = 'Progress', - Copy = 'Copy', - Html = 'Html', - SwcJsMinimizer = 'SwcJsMinimizer', - SwcCssMinimizer = 'SwcCssMinimizer', - Entry = 'Entry', - Externals = 'Externals', - NodeTarget = 'NodeTarget', - ElectronTarget = 'ElectronTarget', - HttpExternals = 'HttpExternals' +export const enum BuiltinPluginName { + DefinePlugin = 'DefinePlugin', + ProvidePlugin = 'ProvidePlugin', + BannerPlugin = 'BannerPlugin', + ProgressPlugin = 'ProgressPlugin', + EntryPlugin = 'EntryPlugin', + ExternalsPlugin = 'ExternalsPlugin', + NodeTargetPlugin = 'NodeTargetPlugin', + ElectronTargetPlugin = 'ElectronTargetPlugin', + EnableChunkLoadingPlugin = 'EnableChunkLoadingPlugin', + EnableLibraryPlugin = 'EnableLibraryPlugin', + EnableWasmLoadingPlugin = 'EnableWasmLoadingPlugin', + CommonJsChunkFormatPlugin = 'CommonJsChunkFormatPlugin', + ArrayPushCallbackChunkFormatPlugin = 'ArrayPushCallbackChunkFormatPlugin', + ModuleChunkFormatPlugin = 'ModuleChunkFormatPlugin', + HotModuleReplacementPlugin = 'HotModuleReplacementPlugin', + HttpExternalsRspackPlugin = 'HttpExternalsRspackPlugin', + CopyRspackPlugin = 'CopyRspackPlugin', + HtmlRspackPlugin = 'HtmlRspackPlugin', + SwcJsMinimizerRspackPlugin = 'SwcJsMinimizerRspackPlugin', + SwcCssMinimizerRspackPlugin = 'SwcCssMinimizerRspackPlugin' } export function cleanupGlobalTrace(): void @@ -234,6 +241,7 @@ export interface JsHooks { afterEmit: (...args: any[]) => any make: (...args: any[]) => any optimizeModules: (...args: any[]) => any + optimizeTree: (...args: any[]) => any optimizeChunkModule: (...args: any[]) => any beforeCompile: (...args: any[]) => any afterCompile: (...args: any[]) => any @@ -492,39 +500,39 @@ export interface RawAssetResourceGeneratorOptions { publicPath?: string } -export interface RawBannerCondition { - type: "string" | "regexp" - stringMatcher?: string - regexpMatcher?: string +export interface RawBannerContent { + type: "string" | "function" + stringPayload?: string + fnPayload?: (...args: any[]) => any } -export interface RawBannerConditions { - type: "string" | "regexp" | "array" - stringMatcher?: string - regexpMatcher?: string - arrayMatcher?: Array +export interface RawBannerContentFnCtx { + hash: string + chunk: JsChunk + filename: string } -export interface RawBannerConfig { +export interface RawBannerPluginOptions { banner: RawBannerContent entryOnly?: boolean footer?: boolean raw?: boolean - test?: RawBannerConditions - include?: RawBannerConditions - exclude?: RawBannerConditions + test?: RawBannerRules + include?: RawBannerRules + exclude?: RawBannerRules } -export interface RawBannerContent { - type: "string" | "function" - stringPayload?: string - fnPayload?: (...args: any[]) => any +export interface RawBannerRule { + type: "string" | "regexp" + stringMatcher?: string + regexpMatcher?: string } -export interface RawBannerContentFnCtx { - hash: string - chunk: JsChunk - filename: string +export interface RawBannerRules { + type: "string" | "regexp" | "array" + stringMatcher?: string + regexpMatcher?: string + arrayMatcher?: Array } export interface RawBuiltins { @@ -569,8 +577,25 @@ export interface RawCacheOptions { version: string } -export interface RawCopyConfig { - patterns: Array +export interface RawCopyGlobOptions { + caseSensitiveMatch?: boolean + dot?: boolean + ignore?: Array +} + +export interface RawCopyPattern { + from: string + to?: string + context?: string + toType?: string + noErrorOnMissing: boolean + force: boolean + priority: number + globOptions: RawCopyGlobOptions +} + +export interface RawCopyRspackPluginOptions { + patterns: Array } export interface RawCrossOriginLoading { @@ -643,10 +668,11 @@ export interface RawExternalItemFnResult { } export interface RawExternalItemValue { - type: "string" | "bool" | "array" + type: "string" | "bool" | "array" | "object" stringPayload?: string boolPayload?: boolean arrayPayload?: Array + objectPayload?: Record> } export interface RawExternalsPluginOptions { @@ -685,25 +711,19 @@ export interface RawGeneratorOptions { assetResource?: RawAssetResourceGeneratorOptions } -export interface RawGlobOptions { - caseSensitiveMatch?: boolean - dot?: boolean - ignore?: Array -} - -export interface RawHtmlPluginConfig { +export interface RawHtmlRspackPluginOptions { /** emitted file name in output path */ filename?: string /** template html file */ template?: string templateContent?: string templateParameters?: Record - /** `head`, `body` or None */ - inject?: "head" | "body" + /** "head", "body" or "false" */ + inject: "head" | "body" | "false" /** path or `auto` */ publicPath?: string /** `blocking`, `defer`, or `module` */ - scriptLoading?: "blocking" | "defer" | "module" + scriptLoading: "blocking" | "defer" | "module" /** entry_chunk_name (only entry chunks are supported) */ chunks?: Array excludedChunks?: Array @@ -714,8 +734,9 @@ export interface RawHtmlPluginConfig { meta?: Record> } -export interface RawHttpExternalsPluginOptions { +export interface RawHttpExternalsRspackPluginOptions { css: boolean + webAsync: boolean } export interface RawIncrementalRebuild { @@ -744,33 +765,6 @@ export interface RawLibraryOptions { auxiliaryComment?: RawLibraryAuxiliaryComment } -export interface RawMinification { - passes: number - dropConsole: boolean - keepClassNames: boolean - keepFnNames: boolean - comments: "all" | "some" | "false" - asciiOnly: boolean - pureFuncs: Array - extractComments?: string - test?: RawMinificationConditions - include?: RawMinificationConditions - exclude?: RawMinificationConditions -} - -export interface RawMinificationCondition { - type: "string" | "regexp" - stringMatcher?: string - regexpMatcher?: string -} - -export interface RawMinificationConditions { - type: "string" | "regexp" | "array" - stringMatcher?: string - regexpMatcher?: string - arrayMatcher?: Array -} - export interface RawModuleOptions { rules: Array parser?: Record @@ -844,6 +838,8 @@ export interface RawOptimizationOptions { removeAvailableModules: boolean removeEmptyChunks: boolean sideEffects: string + usedExports: string + providedExports: boolean realContentHash: boolean } @@ -882,6 +878,7 @@ export interface RawOutputOptions { cssChunkFilename: string hotUpdateMainFilename: string hotUpdateChunkFilename: string + hotUpdateGlobal: string uniqueName: string chunkLoadingGlobal: string library?: RawLibraryOptions @@ -891,7 +888,6 @@ export interface RawOutputOptions { importFunctionName: string iife: boolean module: boolean - chunkFormat: string chunkLoading: string enabledChunkLoadingTypes?: Array trustedTypes?: RawTrustedTypes @@ -911,17 +907,6 @@ export interface RawParserOptions { asset?: RawAssetParserOptions } -export interface RawPattern { - from: string - to?: string - context?: string - toType?: string - noErrorOnMissing: boolean - force: boolean - priority: number - globOptions: RawGlobOptions -} - export interface RawPluginImportConfig { libraryName: string libraryDirectory?: string @@ -940,7 +925,7 @@ export interface RawPresetEnv { coreJs?: string } -export interface RawProgressPluginConfig { +export interface RawProgressPluginOptions { prefix?: string } @@ -981,6 +966,8 @@ export interface RawResolveOptions { export interface RawRspackFuture { newResolver: boolean + newTreeshaking: boolean + disableTransformByDefault: boolean } export interface RawRuleSetCondition { @@ -1036,6 +1023,33 @@ export interface RawStyleConfig { bool?: boolean } +export interface RawSwcJsMinimizerRspackPluginOptions { + passes: number + dropConsole: boolean + keepClassNames: boolean + keepFnNames: boolean + comments: "all" | "some" | "false" + asciiOnly: boolean + pureFuncs: Array + extractComments?: string + test?: RawSwcJsMinimizerRules + include?: RawSwcJsMinimizerRules + exclude?: RawSwcJsMinimizerRules +} + +export interface RawSwcJsMinimizerRule { + type: "string" | "regexp" + stringMatcher?: string + regexpMatcher?: string +} + +export interface RawSwcJsMinimizerRules { + type: "string" | "regexp" | "array" + stringMatcher?: string + regexpMatcher?: string + arrayMatcher?: Array +} + export interface RawTrustedTypes { policyName?: string } diff --git a/crates/node_binding/package.json b/crates/node_binding/package.json index 21cff575349..d6a9c8d0de2 100644 --- a/crates/node_binding/package.json +++ b/crates/node_binding/package.json @@ -1,6 +1,6 @@ { "name": "@rspack/binding", - "version": "0.3.2", + "version": "0.3.4", "license": "MIT", "description": "Node binding for rspack", "main": "binding.js", diff --git a/crates/node_binding/src/hook.rs b/crates/node_binding/src/hook.rs index 0fdcd4f6a87..38c56496b58 100644 --- a/crates/node_binding/src/hook.rs +++ b/crates/node_binding/src/hook.rs @@ -32,6 +32,7 @@ pub enum Hook { AfterCompile, FinishModules, OptimizeModules, + OptimizeTree, /// webpack `compilation.hooks.chunkAsset` ChunkAsset, NormalModuleFactoryResolveForScheme, @@ -73,6 +74,7 @@ impl From for Hook { "afterCompile" => Hook::AfterCompile, "finishModules" => Hook::FinishModules, "optimizeModules" => Hook::OptimizeModules, + "optimizeTree" => Hook::OptimizeTree, "chunkAsset" => Hook::ChunkAsset, "normalModuleFactoryResolveForScheme" => Hook::NormalModuleFactoryResolveForScheme, "afterResolve" => Hook::AfterResolve, diff --git a/crates/node_binding/src/js_values/hooks.rs b/crates/node_binding/src/js_values/hooks.rs index 64e178e9b2a..3a401a52603 100644 --- a/crates/node_binding/src/js_values/hooks.rs +++ b/crates/node_binding/src/js_values/hooks.rs @@ -25,6 +25,7 @@ pub struct JsHooks { pub after_emit: JsFunction, pub make: JsFunction, pub optimize_modules: JsFunction, + pub optimize_tree: JsFunction, pub optimize_chunk_module: JsFunction, pub before_compile: JsFunction, pub after_compile: JsFunction, diff --git a/crates/node_binding/src/plugins/mod.rs b/crates/node_binding/src/plugins/mod.rs index e70ce25eb36..619404e227f 100644 --- a/crates/node_binding/src/plugins/mod.rs +++ b/crates/node_binding/src/plugins/mod.rs @@ -46,6 +46,7 @@ pub struct JsHooksAdapter { pub asset_emitted_tsfn: ThreadsafeFunction, pub after_emit_tsfn: ThreadsafeFunction<(), ()>, pub optimize_modules_tsfn: ThreadsafeFunction, + pub optimize_tree_tsfn: ThreadsafeFunction<(), ()>, pub optimize_chunk_modules_tsfn: ThreadsafeFunction, pub before_compile_tsfn: ThreadsafeFunction<(), ()>, pub after_compile_tsfn: ThreadsafeFunction, @@ -534,6 +535,21 @@ impl rspack_core::Plugin for JsHooksAdapter { .map_err(|err| internal_error!("Failed to call optimize modules: {err}"))? } + async fn optimize_tree( + &self, + _compilation: &mut rspack_core::Compilation, + ) -> rspack_error::Result<()> { + if self.is_hook_disabled(&Hook::OptimizeTree) { + return Ok(()); + } + self + .optimize_tree_tsfn + .call((), ThreadsafeFunctionCallMode::NonBlocking) + .into_rspack_result()? + .await + .map_err(|err| internal_error!("Failed to call optimize tree: {err}",))? + } + async fn optimize_chunk_modules( &self, args: rspack_core::OptimizeChunksArgs<'_>, @@ -753,6 +769,7 @@ impl JsHooksAdapter { asset_emitted, after_emit, optimize_modules, + optimize_tree, optimize_chunk_module, before_resolve, after_resolve, @@ -811,6 +828,8 @@ impl JsHooksAdapter { let make_tsfn: ThreadsafeFunction<(), ()> = js_fn_into_threadsafe_fn!(make, env); let optimize_modules_tsfn: ThreadsafeFunction = js_fn_into_threadsafe_fn!(optimize_modules, env); + let optimize_tree_tsfn: ThreadsafeFunction<(), ()> = + js_fn_into_threadsafe_fn!(optimize_tree, env); let optimize_chunk_modules_tsfn: ThreadsafeFunction = js_fn_into_threadsafe_fn!(optimize_chunk_module, env); let before_compile_tsfn: ThreadsafeFunction<(), ()> = @@ -865,6 +884,7 @@ impl JsHooksAdapter { asset_emitted_tsfn, after_emit_tsfn, optimize_modules_tsfn, + optimize_tree_tsfn, optimize_chunk_modules_tsfn, before_compile_tsfn, after_compile_tsfn, diff --git a/crates/rspack/Cargo.toml b/crates/rspack/Cargo.toml index 9c91dbf77b7..b3ee6d46af7 100644 --- a/crates/rspack/Cargo.toml +++ b/crates/rspack/Cargo.toml @@ -15,10 +15,13 @@ rspack_fs = { path = "../rspack_fs", features = ["async", "rspack-error"] } tokio = { workspace = true, features = ["rt", "rt-multi-thread", "macros"] } [dev-dependencies] -rspack_binding_options = { path = "../rspack_binding_options" } -rspack_testing = { path = "../rspack_testing" } -rspack_tracing = { path = "../rspack_tracing" } +rspack_binding_options = { path = "../rspack_binding_options" } +rspack_plugin_javascript = { path = "../rspack_plugin_javascript" } +rspack_testing = { path = "../rspack_testing" } +rspack_tracing = { path = "../rspack_tracing" } + +cargo-rst = { path = "../cargo-rst" } criterion = { version = "0.3.6", features = ["async_tokio", "async_futures"] } insta = { workspace = true } serde = { workspace = true, features = ["derive"] } diff --git a/crates/rspack/tests/check.js b/crates/rspack/tests/check.js new file mode 100644 index 00000000000..622be8493bd --- /dev/null +++ b/crates/rspack/tests/check.js @@ -0,0 +1,35 @@ +const path = require("path"); +const fs = require("fs"); + +const currentDir = path.resolve(__dirname, "./tree-shaking"); +const dirList = fs.readdirSync(currentDir); +const excludeList = ["node_modules"] + + +const filteredList = dirList.filter((dir) => { + if (dir.startsWith(".")) { + return false; + } + if (excludeList.includes(dir)) { + return false; + } + + return true; +}); + +console.log(`total: ${filteredList.length}`) + +const falsePositiveList = [ + 'cjs-export-computed-property', // This one is false positive because webpack will not counted a esm export as unsed in an entry module, the previous implementation follows the esbuild behavior , see https://gist.github.com/IWANABETHATGUY/b41d0f80a558580010276a44b310a473 +] +const failedList = filteredList.filter(item => { + if (falsePositiveList.includes(item)) { + return false; + } + const abPath = path.join(currentDir, item, "snapshot", "snap.diff") + return fs.existsSync(abPath) +}) + +console.log(`failed: ${failedList.length}`) +console.log(`passed: ${filteredList.length - failedList.length}`) +console.log('failed list:\n', failedList) diff --git a/crates/rspack/tests/fixtures.rs b/crates/rspack/tests/fixtures.rs index e20408501bf..b5df1152582 100644 --- a/crates/rspack/tests/fixtures.rs +++ b/crates/rspack/tests/fixtures.rs @@ -1,19 +1,62 @@ use std::path::PathBuf; +use std::sync::atomic::Ordering; +use cargo_rst::git_diff; +use rspack_core::{BoxPlugin, CompilerOptions, TreeShaking, UsedExportsOption, IS_NEW_TREESHAKING}; +use rspack_plugin_javascript::{FlagDependencyExportsPlugin, FlagDependencyUsagePlugin}; use rspack_testing::test_fixture; use testing_macros::fixture; #[fixture("tests/fixtures/*")] fn rspack(fixture_path: PathBuf) { - test_fixture(&fixture_path); + test_fixture(&fixture_path, Box::new(|_, _| {}), None); } #[fixture("tests/samples/**/test.config.json")] fn samples(fixture_path: PathBuf) { - test_fixture(fixture_path.parent().expect("should exist")); + test_fixture( + fixture_path.parent().expect("should exist"), + Box::new(|_, _| {}), + None, + ); } #[fixture("tests/tree-shaking/*", exclude("node_modules"))] fn tree_shaking(fixture_path: PathBuf) { - test_fixture(&fixture_path); + // For each test case + // First test is old version tree shaking snapshot test + // test_fixture(&fixture_path, Box::new(|_, _| {}), None); + // second test is webpack based tree shaking + IS_NEW_TREESHAKING.store(true, Ordering::SeqCst); + test_fixture( + &fixture_path, + Box::new( + |plugins: &mut Vec, options: &mut CompilerOptions| { + options.experiments.rspack_future.new_treeshaking = true; + options.optimization.provided_exports = true; + options.optimization.used_exports = UsedExportsOption::True; + options.builtins.tree_shaking = TreeShaking::False; + + plugins.push(Box::::default()); + plugins.push(Box::::default()); + }, + ), + Some("new_treeshaking".to_string()), + ); + + // then we generate a diff file, the less diff generated the more we are closed to our + // target + let old_snapshot_path = fixture_path.join("snapshot/output.snap"); + let old_snapshot = std::fs::read_to_string(old_snapshot_path).expect("should have snapshot"); + let new_treeshaking_snapshot_path = fixture_path.join("snapshot/new_treeshaking.snap"); + let new_treeshaking_snapshot = + std::fs::read_to_string(new_treeshaking_snapshot_path).expect("should have snapshot"); + let diff = git_diff(&old_snapshot, &new_treeshaking_snapshot); + let diff_path = fixture_path.join("snapshot/snap.diff"); + if diff_path.exists() { + std::fs::remove_file(diff_path.clone()).expect("remove file failed"); + } + if !diff.is_empty() { + std::fs::write(diff_path, diff).expect("should write successfully"); + } } diff --git a/crates/rspack/tests/fixtures/code-splitting/expected/a_js.js b/crates/rspack/tests/fixtures/code-splitting/expected/a_js.js deleted file mode 100644 index a36675cb253..00000000000 --- a/crates/rspack/tests/fixtures/code-splitting/expected/a_js.js +++ /dev/null @@ -1,6 +0,0 @@ -(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["a_js"], { -"./a.js": function (__unused_webpack_module, exports, __webpack_require__) { -console.log('a'); -}, - -}]); \ No newline at end of file diff --git a/crates/rspack/tests/fixtures/code-splitting/expected/b_js.js b/crates/rspack/tests/fixtures/code-splitting/expected/b_js.js deleted file mode 100644 index 9b2dc743503..00000000000 --- a/crates/rspack/tests/fixtures/code-splitting/expected/b_js.js +++ /dev/null @@ -1,6 +0,0 @@ -(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["b_js"], { -"./b.js": function (__unused_webpack_module, exports, __webpack_require__) { -console.log('b'); -}, - -}]); \ No newline at end of file diff --git a/crates/rspack/tests/fixtures/code-splitting/expected/main.js b/crates/rspack/tests/fixtures/code-splitting/expected/main.js deleted file mode 100644 index 1e457442034..00000000000 --- a/crates/rspack/tests/fixtures/code-splitting/expected/main.js +++ /dev/null @@ -1,13 +0,0 @@ -(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { -"./index.js": function (__unused_webpack_module, exports, __webpack_require__) { -console.log('hello, world'); -__webpack_require__.el(/* ./a */"./a.js").then(__webpack_require__.t.bind(__webpack_require__, /* ./a */"./a.js", 21)); -__webpack_require__.el(/* ./b */"./b.js").then(__webpack_require__.t.bind(__webpack_require__, /* ./b */"./b.js", 21)); -}, - -},function(__webpack_require__) { -var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } -var __webpack_exports__ = (__webpack_exec__("./index.js")); - -} -]); \ No newline at end of file diff --git a/crates/rspack/tests/fixtures/dynamic-import/expected/main.js b/crates/rspack/tests/fixtures/dynamic-import/expected/main.js deleted file mode 100644 index 28921a7709a..00000000000 --- a/crates/rspack/tests/fixtures/dynamic-import/expected/main.js +++ /dev/null @@ -1,38 +0,0 @@ -(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { -"./child Lazy recursive ^\\.\\/.*\\.js$": function (module, exports, __webpack_require__) { -var map = {"./a.js": "./child/a.js","./b.js": "./child/b.js",}; - - function webpackAsyncContext(req) { - if(!__webpack_require__.o(map, req)) { - return Promise.resolve().then(function() { - var e = new Error("Cannot find module '" + req + "'"); - e.code = 'MODULE_NOT_FOUND'; - throw e; - }); - } - var id = map[req]; - return __webpack_require__.el(id).then(function() { - return __webpack_require__(id); - }); - } - webpackAsyncContext.keys = function() { - return Object.keys(map); - }; - webpackAsyncContext.id = "./child Lazy recursive ^\\.\\/.*\\.js$"; - module.exports = webpackAsyncContext; - }, -"./index.js": function (__unused_webpack_module, exports, __webpack_require__) { -const request = 'a'; -__webpack_require__.el(/* ./child/a.js */"./child/a.js").then(__webpack_require__.bind(__webpack_require__, /* ./child/a.js */"./child/a.js")).then(({ a })=>console.log("Literal", a)); -__webpack_require__.el(/* ./child/b.js */"./child/b.js").then(__webpack_require__.bind(__webpack_require__, /* ./child/b.js */"./child/b.js")).then(({ b })=>console.log("Template Literal", b)); -__webpack_require__(/* ./child */"./child Lazy recursive ^\\.\\/.*\\.js$")((`./child/${request}.js`).replace('./child/', './')).then(({ a })=>console.log("context_module_tpl", a)); -__webpack_require__(/* ./child */"./child Lazy recursive ^\\.\\/.*\\.js$")(('./child/' + request + '.js').replace('./child/', './')).then(({ a })=>console.log("context_module_bin", a)); -__webpack_require__(/* ./child */"./child Lazy recursive ^\\.\\/.*\\.js$")(("./child/".concat(request, ".js")).replace('./child/', './')).then(({ a })=>console.log("context_module_concat", a)); -}, - -},function(__webpack_require__) { -var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } -var __webpack_exports__ = (__webpack_exec__("./index.js")); - -} -]); \ No newline at end of file diff --git a/crates/rspack/tests/fixtures/simple-with-query/expected/main.js b/crates/rspack/tests/fixtures/simple-with-query/expected/main.js deleted file mode 100644 index 1bb744ca0fb..00000000000 --- a/crates/rspack/tests/fixtures/simple-with-query/expected/main.js +++ /dev/null @@ -1,35 +0,0 @@ -(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { -"./b.js?x": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'a': function() { return a; } -}); - const a = 3; -}, -"./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -/* harmony import */var _b_jsx__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./b.jsx */"./b.jsx"); -/* harmony import */var _b_js_x__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./b.js?x */"./b.js?x"); - - -_b_js_x__WEBPACK_IMPORTED_MODULE_1_.a; -_b_jsx__WEBPACK_IMPORTED_MODULE_0_.a; -console.log("hello, world"); -}, -"./b.jsx": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'a': function() { return a; } -}); - const a = 3; -}, - -},function(__webpack_require__) { -var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } -var __webpack_exports__ = (__webpack_exec__("./index.js")); - -} -]); \ No newline at end of file diff --git a/crates/rspack/tests/fixtures/static-import/expected/main.js b/crates/rspack/tests/fixtures/static-import/expected/main.js deleted file mode 100644 index 150227dcaaf..00000000000 --- a/crates/rspack/tests/fixtures/static-import/expected/main.js +++ /dev/null @@ -1,26 +0,0 @@ -(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { -"./a.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -/* harmony import */var _b__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./b */"./b.js"); -/* harmony import */var _b__WEBPACK_IMPORTED_MODULE_0__default = /*#__PURE__*/__webpack_require__.n(_b__WEBPACK_IMPORTED_MODULE_0_); - -console.log('a'); -}, -"./b.js": function (__unused_webpack_module, exports, __webpack_require__) { -console.log('b'); -}, -"./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -/* harmony import */var _a__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./a */"./a.js"); - -console.log('hello, world'); -}, - -},function(__webpack_require__) { -var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } -var __webpack_exports__ = (__webpack_exec__("./index.js")); - -} -]); \ No newline at end of file diff --git a/crates/rspack/tests/samples/remove-parent-modules/cycle-dynamic-entry/expected/dynamic-1_js.js b/crates/rspack/tests/samples/remove-parent-modules/cycle-dynamic-entry/expected/dynamic-1_js.js deleted file mode 100644 index d8689eb1e54..00000000000 --- a/crates/rspack/tests/samples/remove-parent-modules/cycle-dynamic-entry/expected/dynamic-1_js.js +++ /dev/null @@ -1,15 +0,0 @@ -(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["dynamic-1_js"], { -"./dynamic-1.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -/* harmony import */var _shared__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./shared */"./shared.js"); -/* harmony import */var _shared__WEBPACK_IMPORTED_MODULE_0__default = /*#__PURE__*/__webpack_require__.n(_shared__WEBPACK_IMPORTED_MODULE_0_); - -__webpack_require__.el(/* ./dynamic-2 */"./dynamic-2.js").then(__webpack_require__.bind(__webpack_require__, /* ./dynamic-2 */"./dynamic-2.js")); -console.log('dynamic-1'); -}, -"./shared.js": function (__unused_webpack_module, exports, __webpack_require__) { -console.log('shared'); -}, - -}]); \ No newline at end of file diff --git a/crates/rspack/tests/samples/remove-parent-modules/cycle-dynamic-entry/expected/dynamic-2_js.js b/crates/rspack/tests/samples/remove-parent-modules/cycle-dynamic-entry/expected/dynamic-2_js.js deleted file mode 100644 index b388b58aecb..00000000000 --- a/crates/rspack/tests/samples/remove-parent-modules/cycle-dynamic-entry/expected/dynamic-2_js.js +++ /dev/null @@ -1,15 +0,0 @@ -(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["dynamic-2_js"], { -"./dynamic-2.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -/* harmony import */var _shared__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./shared */"./shared.js"); -/* harmony import */var _shared__WEBPACK_IMPORTED_MODULE_0__default = /*#__PURE__*/__webpack_require__.n(_shared__WEBPACK_IMPORTED_MODULE_0_); - -__webpack_require__.el(/* ./dynamic-1 */"./dynamic-1.js").then(__webpack_require__.bind(__webpack_require__, /* ./dynamic-1 */"./dynamic-1.js")); -console.log('dynamic-2'); -}, -"./shared.js": function (__unused_webpack_module, exports, __webpack_require__) { -console.log('shared'); -}, - -}]); \ No newline at end of file diff --git a/crates/rspack/tests/samples/remove-parent-modules/cycle-dynamic-entry/expected/main.js b/crates/rspack/tests/samples/remove-parent-modules/cycle-dynamic-entry/expected/main.js deleted file mode 100644 index 0bcd1cc8c81..00000000000 --- a/crates/rspack/tests/samples/remove-parent-modules/cycle-dynamic-entry/expected/main.js +++ /dev/null @@ -1,13 +0,0 @@ -(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { -"./index.js": function (__unused_webpack_module, exports, __webpack_require__) { -__webpack_require__.el(/* ./dynamic-1 */"./dynamic-1.js").then(__webpack_require__.bind(__webpack_require__, /* ./dynamic-1 */"./dynamic-1.js")); -__webpack_require__.el(/* ./dynamic-2 */"./dynamic-2.js").then(__webpack_require__.bind(__webpack_require__, /* ./dynamic-2 */"./dynamic-2.js")); -console.log('index'); -}, - -},function(__webpack_require__) { -var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } -var __webpack_exports__ = (__webpack_exec__("./index.js")); - -} -]); \ No newline at end of file diff --git a/crates/rspack/tests/samples/remove-parent-modules/cycle-entry/expected/index.js b/crates/rspack/tests/samples/remove-parent-modules/cycle-entry/expected/index.js deleted file mode 100644 index 84f1d0732be..00000000000 --- a/crates/rspack/tests/samples/remove-parent-modules/cycle-entry/expected/index.js +++ /dev/null @@ -1,20 +0,0 @@ -(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["index"], { -"./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -/* harmony import */var _shared__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./shared */"./shared.js"); -/* harmony import */var _shared__WEBPACK_IMPORTED_MODULE_0__default = /*#__PURE__*/__webpack_require__.n(_shared__WEBPACK_IMPORTED_MODULE_0_); -__webpack_require__.el(/* ./index */"./index.js").then(__webpack_require__.bind(__webpack_require__, /* ./index */"./index.js")); - -console.log('index1'); -}, -"./shared.js": function (__unused_webpack_module, exports, __webpack_require__) { -console.log('shared'); -}, - -},function(__webpack_require__) { -var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } -var __webpack_exports__ = (__webpack_exec__("./index.js")); - -} -]); \ No newline at end of file diff --git a/crates/rspack/tests/samples/remove-parent-modules/cycle-entry/expected/index2.js b/crates/rspack/tests/samples/remove-parent-modules/cycle-entry/expected/index2.js deleted file mode 100644 index 8b8d912c2bc..00000000000 --- a/crates/rspack/tests/samples/remove-parent-modules/cycle-entry/expected/index2.js +++ /dev/null @@ -1,20 +0,0 @@ -(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["index2"], { -"./index2.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -/* harmony import */var _shared__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./shared */"./shared.js"); -/* harmony import */var _shared__WEBPACK_IMPORTED_MODULE_0__default = /*#__PURE__*/__webpack_require__.n(_shared__WEBPACK_IMPORTED_MODULE_0_); -__webpack_require__.el(/* ./index */"./index.js").then(__webpack_require__.bind(__webpack_require__, /* ./index */"./index.js")); - -console.log('index2'); -}, -"./shared.js": function (__unused_webpack_module, exports, __webpack_require__) { -console.log('shared'); -}, - -},function(__webpack_require__) { -var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } -var __webpack_exports__ = (__webpack_exec__("./index2.js")); - -} -]); \ No newline at end of file diff --git a/crates/rspack/tests/samples/remove-parent-modules/cycle-entry/expected/index_js.js b/crates/rspack/tests/samples/remove-parent-modules/cycle-entry/expected/index_js.js deleted file mode 100644 index 530dab7987c..00000000000 --- a/crates/rspack/tests/samples/remove-parent-modules/cycle-entry/expected/index_js.js +++ /dev/null @@ -1,12 +0,0 @@ -(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["index_js"], { -"./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -/* harmony import */var _shared__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./shared */"./shared.js"); -/* harmony import */var _shared__WEBPACK_IMPORTED_MODULE_0__default = /*#__PURE__*/__webpack_require__.n(_shared__WEBPACK_IMPORTED_MODULE_0_); -__webpack_require__.el(/* ./index */"./index.js").then(__webpack_require__.bind(__webpack_require__, /* ./index */"./index.js")); - -console.log('index1'); -}, - -}]); \ No newline at end of file diff --git a/crates/rspack/tests/samples/remove-parent-modules/intersection/expected/a_js.js b/crates/rspack/tests/samples/remove-parent-modules/intersection/expected/a_js.js deleted file mode 100644 index c123399cfce..00000000000 --- a/crates/rspack/tests/samples/remove-parent-modules/intersection/expected/a_js.js +++ /dev/null @@ -1,23 +0,0 @@ -(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["a_js"], { -"./a.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -/* harmony import */var _shared__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./shared */"./shared.js"); -/* harmony import */var _shared__WEBPACK_IMPORTED_MODULE_0__default = /*#__PURE__*/__webpack_require__.n(_shared__WEBPACK_IMPORTED_MODULE_0_); -/* harmony import */var _i_1__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./i-1 */"./i-1.js"); -/* harmony import */var _i_1__WEBPACK_IMPORTED_MODULE_1__default = /*#__PURE__*/__webpack_require__.n(_i_1__WEBPACK_IMPORTED_MODULE_1_); -/* harmony import */var _i_2__WEBPACK_IMPORTED_MODULE_2_ = __webpack_require__(/* ./i-2 */"./i-2.js"); -/* harmony import */var _i_2__WEBPACK_IMPORTED_MODULE_2__default = /*#__PURE__*/__webpack_require__.n(_i_2__WEBPACK_IMPORTED_MODULE_2_); - - - -console.log('a'); -}, -"./i-1.js": function (__unused_webpack_module, exports, __webpack_require__) { -console.log('i-1'); -}, -"./i-2.js": function (__unused_webpack_module, exports, __webpack_require__) { -console.log('i-2'); -}, - -}]); \ No newline at end of file diff --git a/crates/rspack/tests/samples/remove-parent-modules/intersection/expected/index.js b/crates/rspack/tests/samples/remove-parent-modules/intersection/expected/index.js deleted file mode 100644 index d9c78962157..00000000000 --- a/crates/rspack/tests/samples/remove-parent-modules/intersection/expected/index.js +++ /dev/null @@ -1,26 +0,0 @@ -(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["index"], { -"./i-1.js": function (__unused_webpack_module, exports, __webpack_require__) { -console.log('i-1'); -}, -"./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -/* harmony import */var _shared__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./shared */"./shared.js"); -/* harmony import */var _shared__WEBPACK_IMPORTED_MODULE_0__default = /*#__PURE__*/__webpack_require__.n(_shared__WEBPACK_IMPORTED_MODULE_0_); -/* harmony import */var _i_1__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./i-1 */"./i-1.js"); -/* harmony import */var _i_1__WEBPACK_IMPORTED_MODULE_1__default = /*#__PURE__*/__webpack_require__.n(_i_1__WEBPACK_IMPORTED_MODULE_1_); - - -__webpack_require__.el(/* ./a */"./a.js").then(__webpack_require__.bind(__webpack_require__, /* ./a */"./a.js")); -console.log('index'); -}, -"./shared.js": function (__unused_webpack_module, exports, __webpack_require__) { -console.log('shared'); -}, - -},function(__webpack_require__) { -var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } -var __webpack_exports__ = (__webpack_exec__("./index.js")); - -} -]); \ No newline at end of file diff --git a/crates/rspack/tests/samples/remove-parent-modules/intersection/expected/index2.js b/crates/rspack/tests/samples/remove-parent-modules/intersection/expected/index2.js deleted file mode 100644 index 95640273581..00000000000 --- a/crates/rspack/tests/samples/remove-parent-modules/intersection/expected/index2.js +++ /dev/null @@ -1,26 +0,0 @@ -(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["index2"], { -"./i-2.js": function (__unused_webpack_module, exports, __webpack_require__) { -console.log('i-2'); -}, -"./index2.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -/* harmony import */var _shared__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./shared */"./shared.js"); -/* harmony import */var _shared__WEBPACK_IMPORTED_MODULE_0__default = /*#__PURE__*/__webpack_require__.n(_shared__WEBPACK_IMPORTED_MODULE_0_); -/* harmony import */var _i_2__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./i-2 */"./i-2.js"); -/* harmony import */var _i_2__WEBPACK_IMPORTED_MODULE_1__default = /*#__PURE__*/__webpack_require__.n(_i_2__WEBPACK_IMPORTED_MODULE_1_); - - -__webpack_require__.el(/* ./a */"./a.js").then(__webpack_require__.bind(__webpack_require__, /* ./a */"./a.js")); -console.log('index'); -}, -"./shared.js": function (__unused_webpack_module, exports, __webpack_require__) { -console.log('shared'); -}, - -},function(__webpack_require__) { -var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } -var __webpack_exports__ = (__webpack_exec__("./index2.js")); - -} -]); \ No newline at end of file diff --git a/crates/rspack/tests/samples/remove-parent-modules/self-import/expected/main.js b/crates/rspack/tests/samples/remove-parent-modules/self-import/expected/main.js deleted file mode 100644 index 0112289f07d..00000000000 --- a/crates/rspack/tests/samples/remove-parent-modules/self-import/expected/main.js +++ /dev/null @@ -1,12 +0,0 @@ -(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { -"./index.js": function (__unused_webpack_module, exports, __webpack_require__) { -__webpack_require__.el(/* ./index */"./index.js").then(__webpack_require__.t.bind(__webpack_require__, /* ./index */"./index.js", 21)); -console.log('index'); -}, - -},function(__webpack_require__) { -var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } -var __webpack_exports__ = (__webpack_exec__("./index.js")); - -} -]); \ No newline at end of file diff --git a/crates/rspack/tests/samples/remove-parent-modules/simple/expected/a_js.js b/crates/rspack/tests/samples/remove-parent-modules/simple/expected/a_js.js deleted file mode 100644 index 9f96e228983..00000000000 --- a/crates/rspack/tests/samples/remove-parent-modules/simple/expected/a_js.js +++ /dev/null @@ -1,11 +0,0 @@ -(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["a_js"], { -"./a.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -/* harmony import */var _shared__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./shared */"./shared.js"); -/* harmony import */var _shared__WEBPACK_IMPORTED_MODULE_0__default = /*#__PURE__*/__webpack_require__.n(_shared__WEBPACK_IMPORTED_MODULE_0_); - -console.log('a'); -}, - -}]); \ No newline at end of file diff --git a/crates/rspack/tests/samples/remove-parent-modules/simple/expected/main.js b/crates/rspack/tests/samples/remove-parent-modules/simple/expected/main.js deleted file mode 100644 index e5f21528a9f..00000000000 --- a/crates/rspack/tests/samples/remove-parent-modules/simple/expected/main.js +++ /dev/null @@ -1,20 +0,0 @@ -(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { -"./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -/* harmony import */var _shared__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./shared */"./shared.js"); -/* harmony import */var _shared__WEBPACK_IMPORTED_MODULE_0__default = /*#__PURE__*/__webpack_require__.n(_shared__WEBPACK_IMPORTED_MODULE_0_); - -__webpack_require__.el(/* ./a */"./a.js").then(__webpack_require__.bind(__webpack_require__, /* ./a */"./a.js")); -console.log('index'); -}, -"./shared.js": function (__unused_webpack_module, exports, __webpack_require__) { -console.log('shared'); -}, - -},function(__webpack_require__) { -var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } -var __webpack_exports__ = (__webpack_exec__("./index.js")); - -} -]); \ No newline at end of file diff --git a/crates/rspack/tests/tree-shaking/array-side-effects/expected/main.js b/crates/rspack/tests/tree-shaking/array-side-effects/snapshot/new_treeshaking.snap similarity index 94% rename from crates/rspack/tests/tree-shaking/array-side-effects/expected/main.js rename to crates/rspack/tests/tree-shaking/array-side-effects/snapshot/new_treeshaking.snap index 9c2a921d8ff..949dbc6c732 100644 --- a/crates/rspack/tests/tree-shaking/array-side-effects/expected/main.js +++ b/crates/rspack/tests/tree-shaking/array-side-effects/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./app.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -40,4 +44,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/assign-with-side-effects/expected/main.js b/crates/rspack/tests/tree-shaking/assign-with-side-effects/snapshot/new_treeshaking.snap similarity index 94% rename from crates/rspack/tests/tree-shaking/assign-with-side-effects/expected/main.js rename to crates/rspack/tests/tree-shaking/assign-with-side-effects/snapshot/new_treeshaking.snap index 5f8f27c33e3..407bc677e6e 100644 --- a/crates/rspack/tests/tree-shaking/assign-with-side-effects/expected/main.js +++ b/crates/rspack/tests/tree-shaking/assign-with-side-effects/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./app.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -33,4 +37,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/basic/expected/main.js b/crates/rspack/tests/tree-shaking/basic/snapshot/new_treeshaking.snap similarity index 87% rename from crates/rspack/tests/tree-shaking/basic/expected/main.js rename to crates/rspack/tests/tree-shaking/basic/snapshot/new_treeshaking.snap index c30b097d79f..5525f1dd5d2 100644 --- a/crates/rspack/tests/tree-shaking/basic/expected/main.js +++ b/crates/rspack/tests/tree-shaking/basic/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./answer.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -18,7 +22,7 @@ setTimeout(()=>{ function render() { function test() { const container = document.getElementById("root"); - container.innerHTML = `adddd333:${/* "./lib" unused */null}:${_lib__WEBPACK_IMPORTED_MODULE_0_.myanswer}`; + container.innerHTML = `adddd333:${_lib__WEBPACK_IMPORTED_MODULE_0_.secret}:${_lib__WEBPACK_IMPORTED_MODULE_0_.myanswer}`; } } if (module.hot?.accept) module.hot.accept((module1)=>{ @@ -35,6 +39,7 @@ __webpack_require__.r(__webpack_exports__); 'use strict'; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { + 'secret': function() { return secret; }, 'myanswer': function() { return myanswer; } }); /* harmony import */var _answer__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./answer */"./answer.js"); @@ -48,4 +53,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/basic/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/basic/snapshot/snap.diff new file mode 100644 index 00000000000..88332af7f14 --- /dev/null +++ b/crates/rspack/tests/tree-shaking/basic/snapshot/snap.diff @@ -0,0 +1,19 @@ +--- expected ++++ actual +@@ -22,7 +22,7 @@ + function render() { + function test() { + const container = document.getElementById("root"); +- container.innerHTML = `adddd333:${/* "./lib" unused */null}:${_lib__WEBPACK_IMPORTED_MODULE_0_.myanswer}`; ++ container.innerHTML = `adddd333:${_lib__WEBPACK_IMPORTED_MODULE_0_.secret}:${_lib__WEBPACK_IMPORTED_MODULE_0_.myanswer}`; + } + } + if (module.hot?.accept) module.hot.accept((module1)=>{ +@@ -39,6 +39,7 @@ + 'use strict'; + __webpack_require__.r(__webpack_exports__); + __webpack_require__.d(__webpack_exports__, { ++ 'secret': function() { return secret; }, + 'myanswer': function() { return myanswer; } + }); + /* harmony import */var _answer__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./answer */"./answer.js"); diff --git a/crates/rspack/tests/tree-shaking/bb/expected/main.js b/crates/rspack/tests/tree-shaking/bb/snapshot/new_treeshaking.snap similarity index 94% rename from crates/rspack/tests/tree-shaking/bb/expected/main.js rename to crates/rspack/tests/tree-shaking/bb/snapshot/new_treeshaking.snap index 3bb5bbed62a..e0582015ed7 100644 --- a/crates/rspack/tests/tree-shaking/bb/expected/main.js +++ b/crates/rspack/tests/tree-shaking/bb/snapshot/new_treeshaking.snap @@ -1,10 +1,14 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./a.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); -/* harmony import */var _b_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./b.js */"./b.js"); /* harmony import */var _c_js__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./c.js */"./c.js"); __webpack_require__.es(_c_js__WEBPACK_IMPORTED_MODULE_1_, __webpack_exports__); +/* harmony import */var _b_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./b.js */"./b.js"); const a = 3; @@ -41,4 +45,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/bb/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/bb/snapshot/snap.diff new file mode 100644 index 00000000000..8500dbdd2cb --- /dev/null +++ b/crates/rspack/tests/tree-shaking/bb/snapshot/snap.diff @@ -0,0 +1,13 @@ +--- expected ++++ actual +@@ -6,9 +6,9 @@ + "./a.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); +-/* harmony import */var _b_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./b.js */"./b.js"); + /* harmony import */var _c_js__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./c.js */"./c.js"); + __webpack_require__.es(_c_js__WEBPACK_IMPORTED_MODULE_1_, __webpack_exports__); ++/* harmony import */var _b_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./b.js */"./b.js"); + + + const a = 3; diff --git a/crates/rspack/tests/tree-shaking/cjs-export-computed-property/expected/main.js b/crates/rspack/tests/tree-shaking/cjs-export-computed-property/snapshot/new_treeshaking.snap similarity index 95% rename from crates/rspack/tests/tree-shaking/cjs-export-computed-property/expected/main.js rename to crates/rspack/tests/tree-shaking/cjs-export-computed-property/snapshot/new_treeshaking.snap index e7c20a1a9a2..d5ebf30e9ee 100644 --- a/crates/rspack/tests/tree-shaking/cjs-export-computed-property/expected/main.js +++ b/crates/rspack/tests/tree-shaking/cjs-export-computed-property/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./zh_locale.js": function (__unused_webpack_module, exports, __webpack_require__) { "use strict"; @@ -24,9 +28,6 @@ const locales = { "./index.ts": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'test': function() { return test; } -}); /* harmony import */var _antd_index__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./antd/index */"./antd/index.ts"); _antd_index__WEBPACK_IMPORTED_MODULE_0_.locales.zh_CN; @@ -48,4 +49,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.ts")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/cjs-export-computed-property/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/cjs-export-computed-property/snapshot/snap.diff new file mode 100644 index 00000000000..184e438e452 --- /dev/null +++ b/crates/rspack/tests/tree-shaking/cjs-export-computed-property/snapshot/snap.diff @@ -0,0 +1,12 @@ +--- expected ++++ actual +@@ -28,9 +28,6 @@ + "./index.ts": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'test': function() { return test; } +-}); + /* harmony import */var _antd_index__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./antd/index */"./antd/index.ts"); + + _antd_index__WEBPACK_IMPORTED_MODULE_0_.locales.zh_CN; diff --git a/crates/rspack/tests/tree-shaking/cjs-tree-shaking-basic/expected/main.js b/crates/rspack/tests/tree-shaking/cjs-tree-shaking-basic/snapshot/new_treeshaking.snap similarity index 94% rename from crates/rspack/tests/tree-shaking/cjs-tree-shaking-basic/expected/main.js rename to crates/rspack/tests/tree-shaking/cjs-tree-shaking-basic/snapshot/new_treeshaking.snap index d7d11798498..12f11d33c3e 100644 --- a/crates/rspack/tests/tree-shaking/cjs-tree-shaking-basic/expected/main.js +++ b/crates/rspack/tests/tree-shaking/cjs-tree-shaking-basic/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./answer.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -39,4 +43,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/class-extend/expected/main.js b/crates/rspack/tests/tree-shaking/class-extend/snapshot/new_treeshaking.snap similarity index 84% rename from crates/rspack/tests/tree-shaking/class-extend/expected/main.js rename to crates/rspack/tests/tree-shaking/class-extend/snapshot/new_treeshaking.snap index 2417366efe4..af784057aa7 100644 --- a/crates/rspack/tests/tree-shaking/class-extend/expected/main.js +++ b/crates/rspack/tests/tree-shaking/class-extend/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./app.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -7,11 +11,11 @@ __webpack_require__.d(__webpack_exports__, { }); /* harmony import */var _lib__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./lib */"./lib.js"); - class Lib extends /* "./lib" unused */null { + class Lib extends _lib__WEBPACK_IMPORTED_MODULE_0_.Lib { } function foo() { return { - OriginLib: /* "./lib" unused */null + OriginLib: _lib__WEBPACK_IMPORTED_MODULE_0_.Lib }; } const v = _lib__WEBPACK_IMPORTED_MODULE_0_.value; @@ -27,6 +31,7 @@ _app__WEBPACK_IMPORTED_MODULE_0_.v; 'use strict'; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { + 'Lib': function() { return Lib; }, 'value': function() { return value; } }); class Lib { @@ -39,4 +44,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/class-extend/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/class-extend/snapshot/snap.diff new file mode 100644 index 00000000000..1665d4d4074 --- /dev/null +++ b/crates/rspack/tests/tree-shaking/class-extend/snapshot/snap.diff @@ -0,0 +1,24 @@ +--- expected ++++ actual +@@ -11,11 +11,11 @@ + }); + /* harmony import */var _lib__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./lib */"./lib.js"); + +- class Lib extends /* "./lib" unused */null { ++ class Lib extends _lib__WEBPACK_IMPORTED_MODULE_0_.Lib { + } + function foo() { + return { +- OriginLib: /* "./lib" unused */null ++ OriginLib: _lib__WEBPACK_IMPORTED_MODULE_0_.Lib + }; + } + const v = _lib__WEBPACK_IMPORTED_MODULE_0_.value; +@@ -31,6 +31,7 @@ + 'use strict'; + __webpack_require__.r(__webpack_exports__); + __webpack_require__.d(__webpack_exports__, { ++ 'Lib': function() { return Lib; }, + 'value': function() { return value; } + }); + class Lib { diff --git a/crates/rspack/tests/tree-shaking/conflicted_name_by_re_export_all_should_be_hidden/expected/main.js b/crates/rspack/tests/tree-shaking/conflicted_name_by_re_export_all_should_be_hidden/snapshot/new_treeshaking.snap similarity index 93% rename from crates/rspack/tests/tree-shaking/conflicted_name_by_re_export_all_should_be_hidden/expected/main.js rename to crates/rspack/tests/tree-shaking/conflicted_name_by_re_export_all_should_be_hidden/snapshot/new_treeshaking.snap index 3b69bc78141..46f2a271fc8 100644 --- a/crates/rspack/tests/tree-shaking/conflicted_name_by_re_export_all_should_be_hidden/expected/main.js +++ b/crates/rspack/tests/tree-shaking/conflicted_name_by_re_export_all_should_be_hidden/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./bar.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -26,4 +30,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/context-module-elimated/expected/main.js b/crates/rspack/tests/tree-shaking/context-module-elimated/expected/main.js deleted file mode 100644 index 899475de62c..00000000000 --- a/crates/rspack/tests/tree-shaking/context-module-elimated/expected/main.js +++ /dev/null @@ -1,16 +0,0 @@ -(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { -"./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); - -function test() { - /* "./lib.js" unused */null; -} -}, - -},function(__webpack_require__) { -var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } -var __webpack_exports__ = (__webpack_exec__("./index.js")); - -} -]); \ No newline at end of file diff --git a/crates/rspack/tests/tree-shaking/context-module-elimated/snapshot/new_treeshaking.snap b/crates/rspack/tests/tree-shaking/context-module-elimated/snapshot/new_treeshaking.snap new file mode 100644 index 00000000000..4bc90088ccb --- /dev/null +++ b/crates/rspack/tests/tree-shaking/context-module-elimated/snapshot/new_treeshaking.snap @@ -0,0 +1,73 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js +(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { +"./child/child/index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +'use strict'; +__webpack_require__.r(__webpack_exports__); +__webpack_require__.d(__webpack_exports__, { + 'value': function() { return value; } +}); + const value = "dynamic"; +}, +"./child/index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +'use strict'; +__webpack_require__.r(__webpack_exports__); +__webpack_require__.d(__webpack_exports__, { + 'value': function() { return value; } +}); + const value = "dynamic"; +}, +"./child Sync recursive ^\\.\\/.*\\.js$": function (module, exports, __webpack_require__) { +var map = {"./child/index.js": "./child/child/index.js","./index.js": "./child/index.js",}; +function webpackContext(req) { +var id = webpackContextResolve(req); + +return __webpack_require__(id); + +} +function webpackContextResolve(req) { + + if(!__webpack_require__.o(map, req)) { + var e = new Error("Cannot find module '" + req + "'"); + e.code = 'MODULE_NOT_FOUND'; + throw e; + } + return map[req]; + +} +webpackContext.id = '"./child Sync recursive ^\\.\\/.*\\.js$"'; + + webpackContext.keys = function webpackContextKeys() { + return Object.keys(map); + }; + webpackContext.resolve = webpackContextResolve; + module.exports = webpackContext; + }, +"./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +'use strict'; +__webpack_require__.r(__webpack_exports__); +/* harmony import */var _lib_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./lib.js */"./lib.js"); + +function test() { + _lib_js__WEBPACK_IMPORTED_MODULE_0_.a; +} +}, +"./lib.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +'use strict'; +__webpack_require__.r(__webpack_exports__); +__webpack_require__.d(__webpack_exports__, { + 'a': function() { return a; } +}); + const a = ""; +__webpack_require__(/* ./child */"./child Sync recursive ^\\.\\/.*\\.js$")((`./child/${a}.js`).replace('./child/', './')); +}, + +},function(__webpack_require__) { +var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } +var __webpack_exports__ = (__webpack_exec__("./index.js")); + +} +]); +``` diff --git a/crates/rspack/tests/tree-shaking/context-module-elimated/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/context-module-elimated/snapshot/snap.diff new file mode 100644 index 00000000000..8e9dcf8147d --- /dev/null +++ b/crates/rspack/tests/tree-shaking/context-module-elimated/snapshot/snap.diff @@ -0,0 +1,70 @@ +--- expected ++++ actual +@@ -3,14 +3,66 @@ + --- + ```js title=main.js + (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { ++"./child/child/index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { ++'use strict'; ++__webpack_require__.r(__webpack_exports__); ++__webpack_require__.d(__webpack_exports__, { ++ 'value': function() { return value; } ++}); ++ const value = "dynamic"; ++}, ++"./child/index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { ++'use strict'; ++__webpack_require__.r(__webpack_exports__); ++__webpack_require__.d(__webpack_exports__, { ++ 'value': function() { return value; } ++}); ++ const value = "dynamic"; ++}, ++"./child Sync recursive ^\\.\\/.*\\.js$": function (module, exports, __webpack_require__) { ++var map = {"./child/index.js": "./child/child/index.js","./index.js": "./child/index.js",}; ++function webpackContext(req) { ++var id = webpackContextResolve(req); ++ ++return __webpack_require__(id); ++ ++} ++function webpackContextResolve(req) { ++ ++ if(!__webpack_require__.o(map, req)) { ++ var e = new Error("Cannot find module '" + req + "'"); ++ e.code = 'MODULE_NOT_FOUND'; ++ throw e; ++ } ++ return map[req]; ++ ++} ++webpackContext.id = '"./child Sync recursive ^\\.\\/.*\\.js$"'; ++ ++ webpackContext.keys = function webpackContextKeys() { ++ return Object.keys(map); ++ }; ++ webpackContext.resolve = webpackContextResolve; ++ module.exports = webpackContext; ++ }, + "./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); ++/* harmony import */var _lib_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./lib.js */"./lib.js"); + + function test() { +- /* "./lib.js" unused */null; ++ _lib_js__WEBPACK_IMPORTED_MODULE_0_.a; + } + }, ++"./lib.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { ++'use strict'; ++__webpack_require__.r(__webpack_exports__); ++__webpack_require__.d(__webpack_exports__, { ++ 'a': function() { return a; } ++}); ++ const a = ""; ++__webpack_require__(/* ./child */"./child Sync recursive ^\\.\\/.*\\.js$")((`./child/${a}.js`).replace('./child/', './')); ++}, + + },function(__webpack_require__) { + var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } diff --git a/crates/rspack/tests/tree-shaking/context-module/expected/main.js b/crates/rspack/tests/tree-shaking/context-module/snapshot/new_treeshaking.snap similarity index 95% rename from crates/rspack/tests/tree-shaking/context-module/expected/main.js rename to crates/rspack/tests/tree-shaking/context-module/snapshot/new_treeshaking.snap index 2420a88eef3..a817c6cb389 100644 --- a/crates/rspack/tests/tree-shaking/context-module/expected/main.js +++ b/crates/rspack/tests/tree-shaking/context-module/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./child/child/index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -51,4 +55,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/cyclic-reference-export-all/expected/main.js b/crates/rspack/tests/tree-shaking/cyclic-reference-export-all/snapshot/new_treeshaking.snap similarity index 73% rename from crates/rspack/tests/tree-shaking/cyclic-reference-export-all/expected/main.js rename to crates/rspack/tests/tree-shaking/cyclic-reference-export-all/snapshot/new_treeshaking.snap index 31abe01bf38..1c7809ea70f 100644 --- a/crates/rspack/tests/tree-shaking/cyclic-reference-export-all/expected/main.js +++ b/crates/rspack/tests/tree-shaking/cyclic-reference-export-all/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./src/App.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -17,8 +21,6 @@ var __WEBPACK_DEFAULT_EXPORT__ = Index; "./src/containers/containers.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); -/* harmony import */var _platform_container__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./platform-container */"./src/containers/platform-container/index.js"); -__webpack_require__.es(_platform_container__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); }, @@ -31,16 +33,6 @@ __webpack_require__.d(__webpack_exports__, { /* harmony import */var _containers__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./containers */"./src/containers/containers.js"); -}, -"./src/containers/platform-container/index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'usePlatform': function() { return usePlatform; }, - 'PlatformProvider': function() { return PlatformProvider; } -}); - const usePlatform = 3; - const PlatformProvider = 1000; }, "./src/index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -55,4 +47,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./src/index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/cyclic-reference-export-all/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/cyclic-reference-export-all/snapshot/snap.diff new file mode 100644 index 00000000000..c51c472cb18 --- /dev/null +++ b/crates/rspack/tests/tree-shaking/cyclic-reference-export-all/snapshot/snap.diff @@ -0,0 +1,28 @@ +--- expected ++++ actual +@@ -21,8 +21,6 @@ + "./src/containers/containers.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); +-/* harmony import */var _platform_container__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./platform-container */"./src/containers/platform-container/index.js"); +-__webpack_require__.es(_platform_container__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); + + + }, +@@ -35,16 +33,6 @@ + /* harmony import */var _containers__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./containers */"./src/containers/containers.js"); + + +-}, +-"./src/containers/platform-container/index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +-'use strict'; +-__webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'usePlatform': function() { return usePlatform; }, +- 'PlatformProvider': function() { return PlatformProvider; } +-}); +- const usePlatform = 3; +- const PlatformProvider = 1000; + }, + "./src/index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; diff --git a/crates/rspack/tests/tree-shaking/default_export/expected/main.js b/crates/rspack/tests/tree-shaking/default_export/snapshot/new_treeshaking.snap similarity index 96% rename from crates/rspack/tests/tree-shaking/default_export/expected/main.js rename to crates/rspack/tests/tree-shaking/default_export/snapshot/new_treeshaking.snap index 76bffe6eb92..cd892fcd8fb 100644 --- a/crates/rspack/tests/tree-shaking/default_export/expected/main.js +++ b/crates/rspack/tests/tree-shaking/default_export/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./answer.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -49,4 +53,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/explicit_named_export_higher_priority_1/expected/main.js b/crates/rspack/tests/tree-shaking/explicit_named_export_higher_priority_1/snapshot/new_treeshaking.snap similarity index 93% rename from crates/rspack/tests/tree-shaking/explicit_named_export_higher_priority_1/expected/main.js rename to crates/rspack/tests/tree-shaking/explicit_named_export_higher_priority_1/snapshot/new_treeshaking.snap index e51ef185893..51599a002db 100644 --- a/crates/rspack/tests/tree-shaking/explicit_named_export_higher_priority_1/expected/main.js +++ b/crates/rspack/tests/tree-shaking/explicit_named_export_higher_priority_1/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./bar.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -28,4 +32,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/explicit_named_export_higher_priority_2/expected/main.js b/crates/rspack/tests/tree-shaking/explicit_named_export_higher_priority_2/snapshot/new_treeshaking.snap similarity index 94% rename from crates/rspack/tests/tree-shaking/explicit_named_export_higher_priority_2/expected/main.js rename to crates/rspack/tests/tree-shaking/explicit_named_export_higher_priority_2/snapshot/new_treeshaking.snap index 30905d6282e..bd579c58e56 100644 --- a/crates/rspack/tests/tree-shaking/explicit_named_export_higher_priority_2/expected/main.js +++ b/crates/rspack/tests/tree-shaking/explicit_named_export_higher_priority_2/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./bar.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -37,4 +41,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/export-all-from-side-effects-free-commonjs/expected/main.js b/crates/rspack/tests/tree-shaking/export-all-from-side-effects-free-commonjs/snapshot/new_treeshaking.snap similarity index 91% rename from crates/rspack/tests/tree-shaking/export-all-from-side-effects-free-commonjs/expected/main.js rename to crates/rspack/tests/tree-shaking/export-all-from-side-effects-free-commonjs/snapshot/new_treeshaking.snap index 0bb858e3111..65b7aa562ff 100644 --- a/crates/rspack/tests/tree-shaking/export-all-from-side-effects-free-commonjs/expected/main.js +++ b/crates/rspack/tests/tree-shaking/export-all-from-side-effects-free-commonjs/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -16,4 +20,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/export-imported-import-all-as/expected/main.js b/crates/rspack/tests/tree-shaking/export-imported-import-all-as/expected/main.js deleted file mode 100644 index 1c20d5ccfde..00000000000 --- a/crates/rspack/tests/tree-shaking/export-imported-import-all-as/expected/main.js +++ /dev/null @@ -1,41 +0,0 @@ -(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { -"./answer.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -/* harmony import */var _lib__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./lib */"./lib.js"); -__webpack_require__.es(_lib__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); - -}, -"./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -/* harmony import */var _answer__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./answer */"./answer.js"); - -_answer__WEBPACK_IMPORTED_MODULE_0_.filter; -}, -"./lib.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'filter': function() { return _test_js__WEBPACK_IMPORTED_MODULE_0_; } -}); -/* harmony import */var _test_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./test.js */"./test.js"); - const a = 3; - - -}, -"./test.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'result': function() { return result; } -}); - const result = ""; -}, - -},function(__webpack_require__) { -var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } -var __webpack_exports__ = (__webpack_exec__("./index.js")); - -} -]); \ No newline at end of file diff --git a/crates/rspack/tests/tree-shaking/export-imported-import-all-as/snapshot/new_treeshaking.snap b/crates/rspack/tests/tree-shaking/export-imported-import-all-as/snapshot/new_treeshaking.snap new file mode 100644 index 00000000000..9df20f537de --- /dev/null +++ b/crates/rspack/tests/tree-shaking/export-imported-import-all-as/snapshot/new_treeshaking.snap @@ -0,0 +1,25 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js +(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { +"./answer.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +'use strict'; +__webpack_require__.r(__webpack_exports__); + +}, +"./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +'use strict'; +__webpack_require__.r(__webpack_exports__); +/* harmony import */var _answer__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./answer */"./answer.js"); + +_answer__WEBPACK_IMPORTED_MODULE_0_.filter; +}, + +},function(__webpack_require__) { +var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } +var __webpack_exports__ = (__webpack_exec__("./index.js")); + +} +]); +``` diff --git a/crates/rspack/tests/tree-shaking/export-imported-import-all-as/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/export-imported-import-all-as/snapshot/snap.diff new file mode 100644 index 00000000000..659e4b07807 --- /dev/null +++ b/crates/rspack/tests/tree-shaking/export-imported-import-all-as/snapshot/snap.diff @@ -0,0 +1,37 @@ +--- expected ++++ actual +@@ -6,8 +6,6 @@ + "./answer.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); +-/* harmony import */var _lib__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./lib */"./lib.js"); +-__webpack_require__.es(_lib__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); + + }, + "./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +@@ -16,25 +14,6 @@ + /* harmony import */var _answer__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./answer */"./answer.js"); + + _answer__WEBPACK_IMPORTED_MODULE_0_.filter; +-}, +-"./lib.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +-'use strict'; +-__webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'filter': function() { return _test_js__WEBPACK_IMPORTED_MODULE_0_; } +-}); +-/* harmony import */var _test_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./test.js */"./test.js"); +- const a = 3; +- +- +-}, +-"./test.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +-'use strict'; +-__webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'result': function() { return result; } +-}); +- const result = ""; + }, + + },function(__webpack_require__) { diff --git a/crates/rspack/tests/tree-shaking/export-named-decl-as/expected/main.js b/crates/rspack/tests/tree-shaking/export-named-decl-as/snapshot/new_treeshaking.snap similarity index 92% rename from crates/rspack/tests/tree-shaking/export-named-decl-as/expected/main.js rename to crates/rspack/tests/tree-shaking/export-named-decl-as/snapshot/new_treeshaking.snap index 3a09eee5f44..0810f183395 100644 --- a/crates/rspack/tests/tree-shaking/export-named-decl-as/expected/main.js +++ b/crates/rspack/tests/tree-shaking/export-named-decl-as/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./src/answer.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -19,9 +23,6 @@ console.log(_answer__WEBPACK_IMPORTED_MODULE_0_); "./src/plugin/formatNumber.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'default': function() { return formatNumber_default; } -}); function formatNumber(config) {} const plugin = (cls)=>{ cls.prototype.formatNumber = formatNumber; @@ -35,4 +36,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./src/index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/export-named-decl-as/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/export-named-decl-as/snapshot/snap.diff new file mode 100644 index 00000000000..932aea79560 --- /dev/null +++ b/crates/rspack/tests/tree-shaking/export-named-decl-as/snapshot/snap.diff @@ -0,0 +1,12 @@ +--- expected ++++ actual +@@ -23,9 +23,6 @@ + "./src/plugin/formatNumber.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'default': function() { return formatNumber_default; } +-}); + function formatNumber(config) {} + const plugin = (cls)=>{ + cls.prototype.formatNumber = formatNumber; diff --git a/crates/rspack/tests/tree-shaking/export-star-chain/expected/main.js b/crates/rspack/tests/tree-shaking/export-star-chain/expected/main.js deleted file mode 100644 index 9c2c40c78e8..00000000000 --- a/crates/rspack/tests/tree-shaking/export-star-chain/expected/main.js +++ /dev/null @@ -1,97 +0,0 @@ -(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { -"./Layout.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -/* harmony import */var _something__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./something */"./something/index.js"); -__webpack_require__.es(_something__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); - - -}, -"./colors/a.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'red': function() { return red; } -}); - const red = 'red'; -}, -"./colors/b.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'blue': function() { return blue; } -}); - const blue = 'blue'; -}, -"./colors/c.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -/* harmony import */var _result__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./result */"./colors/result.js"); -__webpack_require__.es(_result__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); - -}, -"./colors/index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -/* harmony import */var _a__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./a */"./colors/a.js"); -__webpack_require__.es(_a__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); -/* harmony import */var _b__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./b */"./colors/b.js"); -__webpack_require__.es(_b__WEBPACK_IMPORTED_MODULE_1_, __webpack_exports__); -/* harmony import */var _c__WEBPACK_IMPORTED_MODULE_2_ = __webpack_require__(/* ./c */"./colors/c.js"); -__webpack_require__.es(_c__WEBPACK_IMPORTED_MODULE_2_, __webpack_exports__); - - - -}, -"./colors/result.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'result': function() { return result; } -}); - const result = 'ssss'; -}, -"./export.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -/* harmony import */var _Layout__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./Layout */"./Layout.js"); -__webpack_require__.es(_Layout__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); - -}, -"./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -/* harmony import */var _export__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./export */"./export.js"); - -_export__WEBPACK_IMPORTED_MODULE_0_.Colors; -_export__WEBPACK_IMPORTED_MODULE_0_.Something; -}, -"./something/Something.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'Something': function() { return Something; } -}); - class Something { -} -}, -"./something/index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'Colors': function() { return _colors_index__WEBPACK_IMPORTED_MODULE_0_; } -}); -/* harmony import */var _colors_index__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ../colors/index */"./colors/index.js"); -/* harmony import */var _Something__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./Something */"./something/Something.js"); -__webpack_require__.es(_Something__WEBPACK_IMPORTED_MODULE_1_, __webpack_exports__); - - - -}, - -},function(__webpack_require__) { -var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } -var __webpack_exports__ = (__webpack_exec__("./index.js")); - -} -]); \ No newline at end of file diff --git a/crates/rspack/tests/tree-shaking/export-star-chain/snapshot/new_treeshaking.snap b/crates/rspack/tests/tree-shaking/export-star-chain/snapshot/new_treeshaking.snap new file mode 100644 index 00000000000..1ced53d3c04 --- /dev/null +++ b/crates/rspack/tests/tree-shaking/export-star-chain/snapshot/new_treeshaking.snap @@ -0,0 +1,26 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js +(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { +"./export.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +'use strict'; +__webpack_require__.r(__webpack_exports__); + +}, +"./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +'use strict'; +__webpack_require__.r(__webpack_exports__); +/* harmony import */var _export__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./export */"./export.js"); + +_export__WEBPACK_IMPORTED_MODULE_0_.Colors; +_export__WEBPACK_IMPORTED_MODULE_0_.Something; +}, + +},function(__webpack_require__) { +var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } +var __webpack_exports__ = (__webpack_exec__("./index.js")); + +} +]); +``` diff --git a/crates/rspack/tests/tree-shaking/export-star-chain/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/export-star-chain/snapshot/snap.diff new file mode 100644 index 00000000000..6c1903f2dda --- /dev/null +++ b/crates/rspack/tests/tree-shaking/export-star-chain/snapshot/snap.diff @@ -0,0 +1,95 @@ +--- expected ++++ actual +@@ -3,63 +3,9 @@ + --- + ```js title=main.js + (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { +-"./Layout.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +-'use strict'; +-__webpack_require__.r(__webpack_exports__); +-/* harmony import */var _something__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./something */"./something/index.js"); +-__webpack_require__.es(_something__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); +- +- +-}, +-"./colors/a.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +-'use strict'; +-__webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'red': function() { return red; } +-}); +- const red = 'red'; +-}, +-"./colors/b.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +-'use strict'; +-__webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'blue': function() { return blue; } +-}); +- const blue = 'blue'; +-}, +-"./colors/c.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +-'use strict'; +-__webpack_require__.r(__webpack_exports__); +-/* harmony import */var _result__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./result */"./colors/result.js"); +-__webpack_require__.es(_result__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); +- +-}, +-"./colors/index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +-'use strict'; +-__webpack_require__.r(__webpack_exports__); +-/* harmony import */var _a__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./a */"./colors/a.js"); +-__webpack_require__.es(_a__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); +-/* harmony import */var _b__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./b */"./colors/b.js"); +-__webpack_require__.es(_b__WEBPACK_IMPORTED_MODULE_1_, __webpack_exports__); +-/* harmony import */var _c__WEBPACK_IMPORTED_MODULE_2_ = __webpack_require__(/* ./c */"./colors/c.js"); +-__webpack_require__.es(_c__WEBPACK_IMPORTED_MODULE_2_, __webpack_exports__); +- +- +- +-}, +-"./colors/result.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +-'use strict'; +-__webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'result': function() { return result; } +-}); +- const result = 'ssss'; +-}, + "./export.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); +-/* harmony import */var _Layout__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./Layout */"./Layout.js"); +-__webpack_require__.es(_Layout__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); + + }, + "./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +@@ -69,28 +15,6 @@ + + _export__WEBPACK_IMPORTED_MODULE_0_.Colors; + _export__WEBPACK_IMPORTED_MODULE_0_.Something; +-}, +-"./something/Something.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +-'use strict'; +-__webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'Something': function() { return Something; } +-}); +- class Something { +-} +-}, +-"./something/index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +-'use strict'; +-__webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'Colors': function() { return _colors_index__WEBPACK_IMPORTED_MODULE_0_; } +-}); +-/* harmony import */var _colors_index__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ../colors/index */"./colors/index.js"); +-/* harmony import */var _Something__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./Something */"./something/Something.js"); +-__webpack_require__.es(_Something__WEBPACK_IMPORTED_MODULE_1_, __webpack_exports__); +- +- +- + }, + + },function(__webpack_require__) { diff --git a/crates/rspack/tests/tree-shaking/export_star/expected/main.js b/crates/rspack/tests/tree-shaking/export_star/snapshot/new_treeshaking.snap similarity index 88% rename from crates/rspack/tests/tree-shaking/export_star/expected/main.js rename to crates/rspack/tests/tree-shaking/export_star/snapshot/new_treeshaking.snap index 0a956b1c104..c1d1ab86524 100644 --- a/crates/rspack/tests/tree-shaking/export_star/expected/main.js +++ b/crates/rspack/tests/tree-shaking/export_star/snapshot/new_treeshaking.snap @@ -1,10 +1,11 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./bar.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'bar': function() { return _foo__WEBPACK_IMPORTED_MODULE_0_; } -}); /* harmony import */var _foo__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./foo */"./foo.js"); /* harmony import */var _result__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./result */"./result.js"); __webpack_require__.es(_result__WEBPACK_IMPORTED_MODULE_1_, __webpack_exports__); @@ -15,9 +16,6 @@ __webpack_require__.es(_result__WEBPACK_IMPORTED_MODULE_1_, __webpack_exports__) "./foo.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'a': function() { return a; } -}); /* harmony import */var _bar__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./bar */"./bar.js"); __webpack_require__.es(_bar__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); /* harmony import */var _result__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./result */"./result.js"); @@ -38,9 +36,6 @@ _foo__WEBPACK_IMPORTED_MODULE_0_.bar.a; "./result.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'c': function() { return c; } -}); /* harmony import */var _foo__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./foo */"./foo.js"); __webpack_require__.es(_foo__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); /* harmony import */var _bar__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./bar */"./bar.js"); @@ -55,4 +50,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/export_star/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/export_star/snapshot/snap.diff new file mode 100644 index 00000000000..388d75dd7cd --- /dev/null +++ b/crates/rspack/tests/tree-shaking/export_star/snapshot/snap.diff @@ -0,0 +1,32 @@ +--- expected ++++ actual +@@ -6,9 +6,6 @@ + "./bar.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'bar': function() { return _foo__WEBPACK_IMPORTED_MODULE_0_; } +-}); + /* harmony import */var _foo__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./foo */"./foo.js"); + /* harmony import */var _result__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./result */"./result.js"); + __webpack_require__.es(_result__WEBPACK_IMPORTED_MODULE_1_, __webpack_exports__); +@@ -19,9 +16,6 @@ + "./foo.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'a': function() { return a; } +-}); + /* harmony import */var _bar__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./bar */"./bar.js"); + __webpack_require__.es(_bar__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); + /* harmony import */var _result__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./result */"./result.js"); +@@ -42,9 +36,6 @@ + "./result.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'c': function() { return c; } +-}); + /* harmony import */var _foo__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./foo */"./foo.js"); + __webpack_require__.es(_foo__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); + /* harmony import */var _bar__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./bar */"./bar.js"); diff --git a/crates/rspack/tests/tree-shaking/export_star2/expected/main.js b/crates/rspack/tests/tree-shaking/export_star2/snapshot/new_treeshaking.snap similarity index 96% rename from crates/rspack/tests/tree-shaking/export_star2/expected/main.js rename to crates/rspack/tests/tree-shaking/export_star2/snapshot/new_treeshaking.snap index 23ad4db46ca..6c118c52652 100644 --- a/crates/rspack/tests/tree-shaking/export_star2/expected/main.js +++ b/crates/rspack/tests/tree-shaking/export_star2/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./bar.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -51,4 +55,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/export_star_conflict_export_no_error/expected/main.js b/crates/rspack/tests/tree-shaking/export_star_conflict_export_no_error/snapshot/new_treeshaking.snap similarity index 96% rename from crates/rspack/tests/tree-shaking/export_star_conflict_export_no_error/expected/main.js rename to crates/rspack/tests/tree-shaking/export_star_conflict_export_no_error/snapshot/new_treeshaking.snap index 7ef071b08df..312f1ee2784 100644 --- a/crates/rspack/tests/tree-shaking/export_star_conflict_export_no_error/expected/main.js +++ b/crates/rspack/tests/tree-shaking/export_star_conflict_export_no_error/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./bar.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -50,4 +54,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/handle-side-effects-commonjs-imported-unused/expected/main.js b/crates/rspack/tests/tree-shaking/handle-side-effects-commonjs-imported-unused/snapshot/new_treeshaking.snap similarity index 84% rename from crates/rspack/tests/tree-shaking/handle-side-effects-commonjs-imported-unused/expected/main.js rename to crates/rspack/tests/tree-shaking/handle-side-effects-commonjs-imported-unused/snapshot/new_treeshaking.snap index ee575edea66..623d8dcb582 100644 --- a/crates/rspack/tests/tree-shaking/handle-side-effects-commonjs-imported-unused/expected/main.js +++ b/crates/rspack/tests/tree-shaking/handle-side-effects-commonjs-imported-unused/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -11,4 +15,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/handle-side-effects-commonjs-required/expected/main.js b/crates/rspack/tests/tree-shaking/handle-side-effects-commonjs-required/snapshot/new_treeshaking.snap similarity index 97% rename from crates/rspack/tests/tree-shaking/handle-side-effects-commonjs-required/expected/main.js rename to crates/rspack/tests/tree-shaking/handle-side-effects-commonjs-required/snapshot/new_treeshaking.snap index 1102ae68cbc..dd4ea4e8a6c 100644 --- a/crates/rspack/tests/tree-shaking/handle-side-effects-commonjs-required/expected/main.js +++ b/crates/rspack/tests/tree-shaking/handle-side-effects-commonjs-required/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./index.js": function (__unused_webpack_module, exports, __webpack_require__) { __webpack_require__(/* ./source */"./source/index.js"); @@ -73,4 +77,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/import-as-default/expected/main.js b/crates/rspack/tests/tree-shaking/import-as-default/snapshot/new_treeshaking.snap similarity index 91% rename from crates/rspack/tests/tree-shaking/import-as-default/expected/main.js rename to crates/rspack/tests/tree-shaking/import-as-default/snapshot/new_treeshaking.snap index 6a53cc37b5f..ec93b1bae78 100644 --- a/crates/rspack/tests/tree-shaking/import-as-default/expected/main.js +++ b/crates/rspack/tests/tree-shaking/import-as-default/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./app.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -21,4 +25,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/import-export-all-as-a-empty-module/expected/main.js b/crates/rspack/tests/tree-shaking/import-export-all-as-a-empty-module/snapshot/new_treeshaking.snap similarity index 95% rename from crates/rspack/tests/tree-shaking/import-export-all-as-a-empty-module/expected/main.js rename to crates/rspack/tests/tree-shaking/import-export-all-as-a-empty-module/snapshot/new_treeshaking.snap index 2e8f9b1c1bb..7b5f2134a03 100644 --- a/crates/rspack/tests/tree-shaking/import-export-all-as-a-empty-module/expected/main.js +++ b/crates/rspack/tests/tree-shaking/import-export-all-as-a-empty-module/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./a.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -6,10 +10,10 @@ __webpack_require__.d(__webpack_exports__, { 'aaa': function() { return _app__WEBPACK_IMPORTED_MODULE_1_; }, 'routes': function() { return routes; } }); -/* harmony import */var _answer__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./answer */"./answer.js"); -/* harmony import */var _answer__WEBPACK_IMPORTED_MODULE_0__default = /*#__PURE__*/__webpack_require__.n(_answer__WEBPACK_IMPORTED_MODULE_0_); /* harmony import */var _app__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./app */"./app.js"); /* harmony import */var _app__WEBPACK_IMPORTED_MODULE_1__default = /*#__PURE__*/__webpack_require__.n(_app__WEBPACK_IMPORTED_MODULE_1_); +/* harmony import */var _answer__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./answer */"./answer.js"); +/* harmony import */var _answer__WEBPACK_IMPORTED_MODULE_0__default = /*#__PURE__*/__webpack_require__.n(_answer__WEBPACK_IMPORTED_MODULE_0_); const routes = { @@ -34,4 +38,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/import-export-all-as-a-empty-module/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/import-export-all-as-a-empty-module/snapshot/snap.diff new file mode 100644 index 00000000000..4349dd3f8a0 --- /dev/null +++ b/crates/rspack/tests/tree-shaking/import-export-all-as-a-empty-module/snapshot/snap.diff @@ -0,0 +1,15 @@ +--- expected ++++ actual +@@ -10,10 +10,10 @@ + 'aaa': function() { return _app__WEBPACK_IMPORTED_MODULE_1_; }, + 'routes': function() { return routes; } + }); ++/* harmony import */var _app__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./app */"./app.js"); ++/* harmony import */var _app__WEBPACK_IMPORTED_MODULE_1__default = /*#__PURE__*/__webpack_require__.n(_app__WEBPACK_IMPORTED_MODULE_1_); + /* harmony import */var _answer__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./answer */"./answer.js"); + /* harmony import */var _answer__WEBPACK_IMPORTED_MODULE_0__default = /*#__PURE__*/__webpack_require__.n(_answer__WEBPACK_IMPORTED_MODULE_0_); +-/* harmony import */var _app__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./app */"./app.js"); +-/* harmony import */var _app__WEBPACK_IMPORTED_MODULE_1__default = /*#__PURE__*/__webpack_require__.n(_app__WEBPACK_IMPORTED_MODULE_1_); + + + const routes = { diff --git a/crates/rspack/tests/tree-shaking/import-star-as-and-export/expected/main.js b/crates/rspack/tests/tree-shaking/import-star-as-and-export/snapshot/new_treeshaking.snap similarity index 93% rename from crates/rspack/tests/tree-shaking/import-star-as-and-export/expected/main.js rename to crates/rspack/tests/tree-shaking/import-star-as-and-export/snapshot/new_treeshaking.snap index b8a860a638c..f6e653b7e11 100644 --- a/crates/rspack/tests/tree-shaking/import-star-as-and-export/expected/main.js +++ b/crates/rspack/tests/tree-shaking/import-star-as-and-export/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./app.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -30,4 +34,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/import-var-assign-side-effects/expected/main.js b/crates/rspack/tests/tree-shaking/import-var-assign-side-effects/snapshot/new_treeshaking.snap similarity index 51% rename from crates/rspack/tests/tree-shaking/import-var-assign-side-effects/expected/main.js rename to crates/rspack/tests/tree-shaking/import-var-assign-side-effects/snapshot/new_treeshaking.snap index cf30bb3f166..c0a468c61d1 100644 --- a/crates/rspack/tests/tree-shaking/import-var-assign-side-effects/expected/main.js +++ b/crates/rspack/tests/tree-shaking/import-var-assign-side-effects/snapshot/new_treeshaking.snap @@ -1,10 +1,16 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { +"./Layout.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +'use strict'; +__webpack_require__.r(__webpack_exports__); +function Layout() {} +}, "./Something.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'default': function() { return Something; } -}); class Something { } }, @@ -14,6 +20,7 @@ __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { 'Sider': function() { return _Something__WEBPACK_IMPORTED_MODULE_1_["default"]; } }); +/* harmony import */var _layout_export__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./layout_export */"./layout_export.js"); /* harmony import */var _Something__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./Something */"./Something.js"); @@ -26,10 +33,22 @@ __webpack_require__.r(__webpack_exports__); (0, _export__WEBPACK_IMPORTED_MODULE_0_.Sider)(); }, +"./layout_export.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +'use strict'; +__webpack_require__.r(__webpack_exports__); +/* harmony import */var _Layout_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./Layout.js */"./Layout.js"); +/* harmony import */var _Something_js__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./Something.js */"./Something.js"); +/* harmony import */var _Layout_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./Layout.js */"./Layout.js"); + + +_Layout_js__WEBPACK_IMPORTED_MODULE_0_["default"].sider = _Something_js__WEBPACK_IMPORTED_MODULE_1_["default"]; +var __WEBPACK_DEFAULT_EXPORT__ = _Layout_js__WEBPACK_IMPORTED_MODULE_0_["default"]; +}, },function(__webpack_require__) { var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/import-var-assign-side-effects/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/import-var-assign-side-effects/snapshot/snap.diff new file mode 100644 index 00000000000..d620f3725f4 --- /dev/null +++ b/crates/rspack/tests/tree-shaking/import-var-assign-side-effects/snapshot/snap.diff @@ -0,0 +1,46 @@ +--- expected ++++ actual +@@ -3,12 +3,14 @@ + --- + ```js title=main.js + (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { ++"./Layout.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { ++'use strict'; ++__webpack_require__.r(__webpack_exports__); ++function Layout() {} ++}, + "./Something.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'default': function() { return Something; } +-}); + class Something { + } + }, +@@ -18,6 +20,7 @@ + __webpack_require__.d(__webpack_exports__, { + 'Sider': function() { return _Something__WEBPACK_IMPORTED_MODULE_1_["default"]; } + }); ++/* harmony import */var _layout_export__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./layout_export */"./layout_export.js"); + /* harmony import */var _Something__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./Something */"./Something.js"); + + +@@ -30,6 +33,17 @@ + + (0, _export__WEBPACK_IMPORTED_MODULE_0_.Sider)(); + }, ++"./layout_export.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { ++'use strict'; ++__webpack_require__.r(__webpack_exports__); ++/* harmony import */var _Layout_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./Layout.js */"./Layout.js"); ++/* harmony import */var _Something_js__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./Something.js */"./Something.js"); ++/* harmony import */var _Layout_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./Layout.js */"./Layout.js"); ++ ++ ++_Layout_js__WEBPACK_IMPORTED_MODULE_0_["default"].sider = _Something_js__WEBPACK_IMPORTED_MODULE_1_["default"]; ++var __WEBPACK_DEFAULT_EXPORT__ = _Layout_js__WEBPACK_IMPORTED_MODULE_0_["default"]; ++}, + + },function(__webpack_require__) { + var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } diff --git a/crates/rspack/tests/tree-shaking/inherit_export_map_should_lookup_in_dfs_order/expected/main.js b/crates/rspack/tests/tree-shaking/inherit_export_map_should_lookup_in_dfs_order/snapshot/new_treeshaking.snap similarity index 88% rename from crates/rspack/tests/tree-shaking/inherit_export_map_should_lookup_in_dfs_order/expected/main.js rename to crates/rspack/tests/tree-shaking/inherit_export_map_should_lookup_in_dfs_order/snapshot/new_treeshaking.snap index a4bc8805daf..c057f772376 100644 --- a/crates/rspack/tests/tree-shaking/inherit_export_map_should_lookup_in_dfs_order/expected/main.js +++ b/crates/rspack/tests/tree-shaking/inherit_export_map_should_lookup_in_dfs_order/snapshot/new_treeshaking.snap @@ -1,15 +1,19 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./a.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'c': function() { return c; } -}); const c = 'a'; }, "./bar.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); +__webpack_require__.d(__webpack_exports__, { + 'c': function() { return c; } +}); const a = 'bar'; const c = 'bar'; }, @@ -22,6 +26,8 @@ __webpack_require__.d(__webpack_exports__, { /* harmony import */var _foo__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./foo */"./foo.js"); __webpack_require__.es(_foo__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); /* harmony import */var _bar__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./bar */"./bar.js"); +__webpack_require__.es(_bar__WEBPACK_IMPORTED_MODULE_1_, __webpack_exports__); +/* harmony import */var _bar__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./bar */"./bar.js"); __webpack_require__.es(_bar__WEBPACK_IMPORTED_MODULE_1_, __webpack_exports__); @@ -30,9 +36,6 @@ __webpack_require__.es(_bar__WEBPACK_IMPORTED_MODULE_1_, __webpack_exports__); "./foo.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'b': function() { return b; } -}); /* harmony import */var _a_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./a.js */"./a.js"); __webpack_require__.es(_a_js__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); @@ -55,4 +58,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/inherit_export_map_should_lookup_in_dfs_order/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/inherit_export_map_should_lookup_in_dfs_order/snapshot/snap.diff new file mode 100644 index 00000000000..8b862e0c4c5 --- /dev/null +++ b/crates/rspack/tests/tree-shaking/inherit_export_map_should_lookup_in_dfs_order/snapshot/snap.diff @@ -0,0 +1,39 @@ +--- expected ++++ actual +@@ -6,14 +6,14 @@ + "./a.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'c': function() { return c; } +-}); + const c = 'a'; + }, + "./bar.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); ++__webpack_require__.d(__webpack_exports__, { ++ 'c': function() { return c; } ++}); + const a = 'bar'; + const c = 'bar'; + }, +@@ -27,6 +27,8 @@ + __webpack_require__.es(_foo__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); + /* harmony import */var _bar__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./bar */"./bar.js"); + __webpack_require__.es(_bar__WEBPACK_IMPORTED_MODULE_1_, __webpack_exports__); ++/* harmony import */var _bar__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./bar */"./bar.js"); ++__webpack_require__.es(_bar__WEBPACK_IMPORTED_MODULE_1_, __webpack_exports__); + + + const a = 3; +@@ -34,9 +36,6 @@ + "./foo.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'b': function() { return b; } +-}); + /* harmony import */var _a_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./a.js */"./a.js"); + __webpack_require__.es(_a_js__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); + diff --git a/crates/rspack/tests/tree-shaking/issues_3198/expected/main.js b/crates/rspack/tests/tree-shaking/issues_3198/snapshot/new_treeshaking.snap similarity index 90% rename from crates/rspack/tests/tree-shaking/issues_3198/expected/main.js rename to crates/rspack/tests/tree-shaking/issues_3198/snapshot/new_treeshaking.snap index b0480b0bd82..ca1988145fb 100644 --- a/crates/rspack/tests/tree-shaking/issues_3198/expected/main.js +++ b/crates/rspack/tests/tree-shaking/issues_3198/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -20,4 +24,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/local-binding-reachable1/expected/main.js b/crates/rspack/tests/tree-shaking/local-binding-reachable1/snapshot/new_treeshaking.snap similarity index 94% rename from crates/rspack/tests/tree-shaking/local-binding-reachable1/expected/main.js rename to crates/rspack/tests/tree-shaking/local-binding-reachable1/snapshot/new_treeshaking.snap index 786404aff93..2554928597f 100644 --- a/crates/rspack/tests/tree-shaking/local-binding-reachable1/expected/main.js +++ b/crates/rspack/tests/tree-shaking/local-binding-reachable1/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./Layout.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -36,4 +40,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/local-binding-reachable2/expected/main.js b/crates/rspack/tests/tree-shaking/local-binding-reachable2/snapshot/new_treeshaking.snap similarity index 94% rename from crates/rspack/tests/tree-shaking/local-binding-reachable2/expected/main.js rename to crates/rspack/tests/tree-shaking/local-binding-reachable2/snapshot/new_treeshaking.snap index 3609e070745..ee52c108f58 100644 --- a/crates/rspack/tests/tree-shaking/local-binding-reachable2/expected/main.js +++ b/crates/rspack/tests/tree-shaking/local-binding-reachable2/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./Layout.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -36,4 +40,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/module-rule-side-effects1/expected/main.js b/crates/rspack/tests/tree-shaking/module-rule-side-effects1/snapshot/new_treeshaking.snap similarity index 85% rename from crates/rspack/tests/tree-shaking/module-rule-side-effects1/expected/main.js rename to crates/rspack/tests/tree-shaking/module-rule-side-effects1/snapshot/new_treeshaking.snap index c8af6ca1701..cb5608646ad 100644 --- a/crates/rspack/tests/tree-shaking/module-rule-side-effects1/expected/main.js +++ b/crates/rspack/tests/tree-shaking/module-rule-side-effects1/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./a.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -17,6 +21,7 @@ __webpack_require__.r(__webpack_exports__); __webpack_require__.r(__webpack_exports__); /* harmony import */var _a_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./a.js */"./a.js"); /* harmony import */var _c_js__WEBPACK_IMPORTED_MODULE_2_ = __webpack_require__(/* ./c.js */"./c.js"); +/* harmony import */var _a_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./a.js */"./a.js"); @@ -28,4 +33,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/module-rule-side-effects1/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/module-rule-side-effects1/snapshot/snap.diff new file mode 100644 index 00000000000..9fe31842991 --- /dev/null +++ b/crates/rspack/tests/tree-shaking/module-rule-side-effects1/snapshot/snap.diff @@ -0,0 +1,10 @@ +--- expected ++++ actual +@@ -21,6 +21,7 @@ + __webpack_require__.r(__webpack_exports__); + /* harmony import */var _a_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./a.js */"./a.js"); + /* harmony import */var _c_js__WEBPACK_IMPORTED_MODULE_2_ = __webpack_require__(/* ./c.js */"./c.js"); ++/* harmony import */var _a_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./a.js */"./a.js"); + + + diff --git a/crates/rspack/tests/tree-shaking/module-rule-side-effects2/expected/main.js b/crates/rspack/tests/tree-shaking/module-rule-side-effects2/snapshot/new_treeshaking.snap similarity index 92% rename from crates/rspack/tests/tree-shaking/module-rule-side-effects2/expected/main.js rename to crates/rspack/tests/tree-shaking/module-rule-side-effects2/snapshot/new_treeshaking.snap index cace7db086d..36737b8a3c9 100644 --- a/crates/rspack/tests/tree-shaking/module-rule-side-effects2/expected/main.js +++ b/crates/rspack/tests/tree-shaking/module-rule-side-effects2/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./a.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -15,8 +19,8 @@ __webpack_require__.r(__webpack_exports__); "./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); -/* harmony import */var _a_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./a.js */"./a.js"); /* harmony import */var _b_js__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./b.js */"./b.js"); +/* harmony import */var _a_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./a.js */"./a.js"); @@ -28,4 +32,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/module-rule-side-effects2/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/module-rule-side-effects2/snapshot/snap.diff new file mode 100644 index 00000000000..55e32f1068d --- /dev/null +++ b/crates/rspack/tests/tree-shaking/module-rule-side-effects2/snapshot/snap.diff @@ -0,0 +1,12 @@ +--- expected ++++ actual +@@ -19,8 +19,8 @@ + "./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); ++/* harmony import */var _b_js__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./b.js */"./b.js"); + /* harmony import */var _a_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./a.js */"./a.js"); +-/* harmony import */var _b_js__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./b.js */"./b.js"); + + + diff --git a/crates/rspack/tests/tree-shaking/named-export-decl-with-src-eval/expected/main.js b/crates/rspack/tests/tree-shaking/named-export-decl-with-src-eval/snapshot/new_treeshaking.snap similarity index 96% rename from crates/rspack/tests/tree-shaking/named-export-decl-with-src-eval/expected/main.js rename to crates/rspack/tests/tree-shaking/named-export-decl-with-src-eval/snapshot/new_treeshaking.snap index 94328ad69b3..39af57dac5b 100644 --- a/crates/rspack/tests/tree-shaking/named-export-decl-with-src-eval/expected/main.js +++ b/crates/rspack/tests/tree-shaking/named-export-decl-with-src-eval/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./Layout.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -29,9 +33,9 @@ __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { 'cccc': function() { return _c__WEBPACK_IMPORTED_MODULE_2_.cccc; } }); +/* harmony import */var _c__WEBPACK_IMPORTED_MODULE_2_ = __webpack_require__(/* ./c */"./c.js"); /* harmony import */var _Layout__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./Layout */"./Layout.js"); /* harmony import */var _Something__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./Something */"./Something.js"); -/* harmony import */var _c__WEBPACK_IMPORTED_MODULE_2_ = __webpack_require__(/* ./c */"./c.js"); var L = _Layout__WEBPACK_IMPORTED_MODULE_0_["default"]; @@ -52,4 +56,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/named-export-decl-with-src-eval/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/named-export-decl-with-src-eval/snapshot/snap.diff new file mode 100644 index 00000000000..2cee3bc15f1 --- /dev/null +++ b/crates/rspack/tests/tree-shaking/named-export-decl-with-src-eval/snapshot/snap.diff @@ -0,0 +1,13 @@ +--- expected ++++ actual +@@ -33,9 +33,9 @@ + __webpack_require__.d(__webpack_exports__, { + 'cccc': function() { return _c__WEBPACK_IMPORTED_MODULE_2_.cccc; } + }); ++/* harmony import */var _c__WEBPACK_IMPORTED_MODULE_2_ = __webpack_require__(/* ./c */"./c.js"); + /* harmony import */var _Layout__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./Layout */"./Layout.js"); + /* harmony import */var _Something__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./Something */"./Something.js"); +-/* harmony import */var _c__WEBPACK_IMPORTED_MODULE_2_ = __webpack_require__(/* ./c */"./c.js"); + + + var L = _Layout__WEBPACK_IMPORTED_MODULE_0_["default"]; diff --git a/crates/rspack/tests/tree-shaking/named_export_alias/expected/main.js b/crates/rspack/tests/tree-shaking/named_export_alias/snapshot/new_treeshaking.snap similarity index 94% rename from crates/rspack/tests/tree-shaking/named_export_alias/expected/main.js rename to crates/rspack/tests/tree-shaking/named_export_alias/snapshot/new_treeshaking.snap index 4b39da4c7a0..5bd4a8e79d8 100644 --- a/crates/rspack/tests/tree-shaking/named_export_alias/expected/main.js +++ b/crates/rspack/tests/tree-shaking/named_export_alias/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./Something.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -34,4 +38,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/namespace-access-var-decl-rhs/expected/main.js b/crates/rspack/tests/tree-shaking/namespace-access-var-decl-rhs/snapshot/new_treeshaking.snap similarity index 54% rename from crates/rspack/tests/tree-shaking/namespace-access-var-decl-rhs/expected/main.js rename to crates/rspack/tests/tree-shaking/namespace-access-var-decl-rhs/snapshot/new_treeshaking.snap index 2a5ec0321c1..77519700c76 100644 --- a/crates/rspack/tests/tree-shaking/namespace-access-var-decl-rhs/expected/main.js +++ b/crates/rspack/tests/tree-shaking/namespace-access-var-decl-rhs/snapshot/new_treeshaking.snap @@ -1,41 +1,11 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { -"./a.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'a': function() { return a; } -}); - const a = { - a: '' -}; -}, -"./b.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'b': function() { return b; } -}); - const b = { - b: "" -}; -}, -"./enum-old.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'a': function() { return _a__WEBPACK_IMPORTED_MODULE_0_.a; }, - 'b': function() { return _b__WEBPACK_IMPORTED_MODULE_1_.b; } -}); -/* harmony import */var _a__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./a */"./a.js"); -/* harmony import */var _b__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./b */"./b.js"); - - -}, "./enum.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); -/* harmony import */var _enum_old__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./enum-old */"./enum-old.js"); -__webpack_require__.es(_enum_old__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); }, "./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { @@ -71,4 +41,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/namespace-access-var-decl-rhs/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/namespace-access-var-decl-rhs/snapshot/snap.diff new file mode 100644 index 00000000000..faf2a25b2df --- /dev/null +++ b/crates/rspack/tests/tree-shaking/namespace-access-var-decl-rhs/snapshot/snap.diff @@ -0,0 +1,46 @@ +--- expected ++++ actual +@@ -3,43 +3,9 @@ + --- + ```js title=main.js + (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { +-"./a.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +-'use strict'; +-__webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'a': function() { return a; } +-}); +- const a = { +- a: '' +-}; +-}, +-"./b.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +-'use strict'; +-__webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'b': function() { return b; } +-}); +- const b = { +- b: "" +-}; +-}, +-"./enum-old.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +-'use strict'; +-__webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'a': function() { return _a__WEBPACK_IMPORTED_MODULE_0_.a; }, +- 'b': function() { return _b__WEBPACK_IMPORTED_MODULE_1_.b; } +-}); +-/* harmony import */var _a__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./a */"./a.js"); +-/* harmony import */var _b__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./b */"./b.js"); +- +- +-}, + "./enum.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); +-/* harmony import */var _enum_old__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./enum-old */"./enum-old.js"); +-__webpack_require__.es(_enum_old__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); + + }, + "./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { diff --git a/crates/rspack/tests/tree-shaking/nested-import-3/expected/main.js b/crates/rspack/tests/tree-shaking/nested-import-3/expected/main.js deleted file mode 100644 index 5b7f0285404..00000000000 --- a/crates/rspack/tests/tree-shaking/nested-import-3/expected/main.js +++ /dev/null @@ -1,38 +0,0 @@ -(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { -"./answer.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'a': function() { return a; } -}); - const a = 103330; - const b = 103330; -}, -"./app.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -/* harmony import */var _answer__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./answer */"./answer.js"); -__webpack_require__.es(_answer__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); - -}, -"./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -/* harmony import */var _lib__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./lib */"./lib.js"); - -_lib__WEBPACK_IMPORTED_MODULE_0_.a; -}, -"./lib.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -/* harmony import */var _app__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./app */"./app.js"); -__webpack_require__.es(_app__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); - -}, - -},function(__webpack_require__) { -var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } -var __webpack_exports__ = (__webpack_exec__("./index.js")); - -} -]); \ No newline at end of file diff --git a/crates/rspack/tests/tree-shaking/side-effects-export-default-expr/expected/main.js b/crates/rspack/tests/tree-shaking/nested-import-3/snapshot/new_treeshaking.snap similarity index 59% rename from crates/rspack/tests/tree-shaking/side-effects-export-default-expr/expected/main.js rename to crates/rspack/tests/tree-shaking/nested-import-3/snapshot/new_treeshaking.snap index 8c9450a0238..c6d4c72f355 100644 --- a/crates/rspack/tests/tree-shaking/side-effects-export-default-expr/expected/main.js +++ b/crates/rspack/tests/tree-shaking/nested-import-3/snapshot/new_treeshaking.snap @@ -1,20 +1,19 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { -"./app.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +"./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'b': function() { return b; } -}); +/* harmony import */var _lib__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./lib */"./lib.js"); -var __WEBPACK_DEFAULT_EXPORT__ = /* "./lib" unused */null; - const b = 1; +_lib__WEBPACK_IMPORTED_MODULE_0_.a; }, -"./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +"./lib.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); -/* harmony import */var _app__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./app */"./app.js"); -_app__WEBPACK_IMPORTED_MODULE_0_.b; }, },function(__webpack_require__) { @@ -22,4 +21,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/nested-import-3/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/nested-import-3/snapshot/snap.diff new file mode 100644 index 00000000000..ce140b712ca --- /dev/null +++ b/crates/rspack/tests/tree-shaking/nested-import-3/snapshot/snap.diff @@ -0,0 +1,34 @@ +--- expected ++++ actual +@@ -3,22 +3,6 @@ + --- + ```js title=main.js + (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { +-"./answer.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +-'use strict'; +-__webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'a': function() { return a; } +-}); +- const a = 103330; +- const b = 103330; +-}, +-"./app.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +-'use strict'; +-__webpack_require__.r(__webpack_exports__); +-/* harmony import */var _answer__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./answer */"./answer.js"); +-__webpack_require__.es(_answer__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); +- +-}, + "./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); +@@ -29,8 +13,6 @@ + "./lib.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); +-/* harmony import */var _app__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./app */"./app.js"); +-__webpack_require__.es(_app__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); + + }, + diff --git a/crates/rspack/tests/tree-shaking/nested-import-4/expected/main.js b/crates/rspack/tests/tree-shaking/nested-import-4/snapshot/new_treeshaking.snap similarity index 88% rename from crates/rspack/tests/tree-shaking/nested-import-4/expected/main.js rename to crates/rspack/tests/tree-shaking/nested-import-4/snapshot/new_treeshaking.snap index e2fb9567007..0f88efb840a 100644 --- a/crates/rspack/tests/tree-shaking/nested-import-4/expected/main.js +++ b/crates/rspack/tests/tree-shaking/nested-import-4/snapshot/new_treeshaking.snap @@ -1,9 +1,14 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./answer.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { - 'a': function() { return a; } + 'a': function() { return a; }, + 'b': function() { return b; } }); const a = 103330; const b = 103330; @@ -31,4 +36,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/nested-import-4/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/nested-import-4/snapshot/snap.diff new file mode 100644 index 00000000000..091fa6afd83 --- /dev/null +++ b/crates/rspack/tests/tree-shaking/nested-import-4/snapshot/snap.diff @@ -0,0 +1,12 @@ +--- expected ++++ actual +@@ -7,7 +7,8 @@ + 'use strict'; + __webpack_require__.r(__webpack_exports__); + __webpack_require__.d(__webpack_exports__, { +- 'a': function() { return a; } ++ 'a': function() { return a; }, ++ 'b': function() { return b; } + }); + const a = 103330; + const b = 103330; diff --git a/crates/rspack/tests/tree-shaking/prune-bailout-module/expected/main.js b/crates/rspack/tests/tree-shaking/prune-bailout-module/snapshot/new_treeshaking.snap similarity index 65% rename from crates/rspack/tests/tree-shaking/prune-bailout-module/expected/main.js rename to crates/rspack/tests/tree-shaking/prune-bailout-module/snapshot/new_treeshaking.snap index ea63856c835..6ecff837ed4 100644 --- a/crates/rspack/tests/tree-shaking/prune-bailout-module/expected/main.js +++ b/crates/rspack/tests/tree-shaking/prune-bailout-module/snapshot/new_treeshaking.snap @@ -1,12 +1,25 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./a.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } -}); var __WEBPACK_DEFAULT_EXPORT__ = 300; }, +"./app.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +'use strict'; +__webpack_require__.r(__webpack_exports__); + function app() {} + function test() {} +}, +"./b.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +'use strict'; +__webpack_require__.r(__webpack_exports__); +__webpack_require__(/* ./app.js */"./app.js"); +var __WEBPACK_DEFAULT_EXPORT__ = 200; +}, "./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); @@ -21,6 +34,7 @@ __webpack_require__.d(__webpack_exports__, { 'a': function() { return _a_js__WEBPACK_IMPORTED_MODULE_0_["default"]; } }); /* harmony import */var _a_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./a.js */"./a.js"); +/* harmony import */var _b_js__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./b.js */"./b.js"); }, @@ -30,4 +44,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/prune-bailout-module/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/prune-bailout-module/snapshot/snap.diff new file mode 100644 index 00000000000..8859c05281b --- /dev/null +++ b/crates/rspack/tests/tree-shaking/prune-bailout-module/snapshot/snap.diff @@ -0,0 +1,34 @@ +--- expected ++++ actual +@@ -6,11 +6,20 @@ + "./a.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } +-}); + var __WEBPACK_DEFAULT_EXPORT__ = 300; + }, ++"./app.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { ++'use strict'; ++__webpack_require__.r(__webpack_exports__); ++ function app() {} ++ function test() {} ++}, ++"./b.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { ++'use strict'; ++__webpack_require__.r(__webpack_exports__); ++__webpack_require__(/* ./app.js */"./app.js"); ++var __WEBPACK_DEFAULT_EXPORT__ = 200; ++}, + "./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); +@@ -25,6 +34,7 @@ + 'a': function() { return _a_js__WEBPACK_IMPORTED_MODULE_0_["default"]; } + }); + /* harmony import */var _a_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./a.js */"./a.js"); ++/* harmony import */var _b_js__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./b.js */"./b.js"); + + + }, diff --git a/crates/rspack/tests/tree-shaking/react-redux-like/snapshot/new_treeshaking.snap b/crates/rspack/tests/tree-shaking/react-redux-like/snapshot/new_treeshaking.snap new file mode 100644 index 00000000000..4ae6be842f6 --- /dev/null +++ b/crates/rspack/tests/tree-shaking/react-redux-like/snapshot/new_treeshaking.snap @@ -0,0 +1,28 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js +(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { +"./foo.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +'use strict'; +__webpack_require__.r(__webpack_exports__); + +function batch() {} + +}, +"./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +'use strict'; +__webpack_require__.r(__webpack_exports__); +/* harmony import */var _foo__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./foo */"./foo.js"); + +_foo__WEBPACK_IMPORTED_MODULE_0_.Provider; +_foo__WEBPACK_IMPORTED_MODULE_0_.useSelector; +}, + +},function(__webpack_require__) { +var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } +var __webpack_exports__ = (__webpack_exec__("./index.js")); + +} +]); +``` diff --git a/crates/rspack/tests/tree-shaking/react-redux-like/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/react-redux-like/snapshot/snap.diff new file mode 100644 index 00000000000..dcd2732b443 --- /dev/null +++ b/crates/rspack/tests/tree-shaking/react-redux-like/snapshot/snap.diff @@ -0,0 +1,53 @@ +--- expected ++++ actual +@@ -3,24 +3,9 @@ + --- + ```js title=main.js + (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { +-"./app.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +-'use strict'; +-__webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'Provider': function() { return _lib__WEBPACK_IMPORTED_MODULE_0_["default"]; }, +- 'useSelector': function() { return _selector_js__WEBPACK_IMPORTED_MODULE_1_["default"]; } +-}); +-/* harmony import */var _lib__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./lib */"./lib.js"); +-/* harmony import */var _selector_js__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./selector.js */"./selector.js"); +- +- +- +-}, + "./foo.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); +-/* harmony import */var _app__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./app */"./app.js"); +-__webpack_require__.es(_app__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); + + function batch() {} + +@@ -32,25 +17,6 @@ + + _foo__WEBPACK_IMPORTED_MODULE_0_.Provider; + _foo__WEBPACK_IMPORTED_MODULE_0_.useSelector; +-}, +-"./lib.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +-'use strict'; +-__webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } +-}); +-function Provider() {} +-var __WEBPACK_DEFAULT_EXPORT__ = Provider; +-}, +-"./selector.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +-'use strict'; +-__webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'default': function() { return useSelector; } +-}); +-function useSelector() { +- return ""; +-} + }, + + },function(__webpack_require__) { diff --git a/crates/rspack/tests/tree-shaking/reexport-all-as-multi-level-nested/expected/main.js b/crates/rspack/tests/tree-shaking/reexport-all-as-multi-level-nested/expected/main.js deleted file mode 100644 index 2fb691dca03..00000000000 --- a/crates/rspack/tests/tree-shaking/reexport-all-as-multi-level-nested/expected/main.js +++ /dev/null @@ -1,56 +0,0 @@ -(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { -"./package/autogen/a.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'a': function() { return a; }, - 'aa': function() { return _aa__WEBPACK_IMPORTED_MODULE_0_; } -}); -/* harmony import */var _aa__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./aa */"./package/autogen/aa.js"); - - function a() {} - function dddd() {} - -}, -"./package/autogen/aa.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'aa': function() { return aa; } -}); - const aa = 3; - const cc = 3; -}, -"./package/autogen/index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'a': function() { return _a__WEBPACK_IMPORTED_MODULE_0_; } -}); -/* harmony import */var _a__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./a */"./package/autogen/a.js"); - - - -}, -"./package/src/index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -/* harmony import */var _autogen_index__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ../autogen/index */"./package/autogen/index.js"); -__webpack_require__.es(_autogen_index__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); - -}, -"./src/index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -/* harmony import */var _package_src_index_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ../package/src/index.js */"./package/src/index.js"); - -_package_src_index_js__WEBPACK_IMPORTED_MODULE_0_.a.a; -_package_src_index_js__WEBPACK_IMPORTED_MODULE_0_.a.aa.aa; -}, - -},function(__webpack_require__) { -var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } -var __webpack_exports__ = (__webpack_exec__("./src/index.js")); - -} -]); \ No newline at end of file diff --git a/crates/rspack/tests/tree-shaking/reexport-all-as-multi-level-nested/snapshot/new_treeshaking.snap b/crates/rspack/tests/tree-shaking/reexport-all-as-multi-level-nested/snapshot/new_treeshaking.snap new file mode 100644 index 00000000000..39289772fce --- /dev/null +++ b/crates/rspack/tests/tree-shaking/reexport-all-as-multi-level-nested/snapshot/new_treeshaking.snap @@ -0,0 +1,26 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js +(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { +"./package/src/index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +'use strict'; +__webpack_require__.r(__webpack_exports__); + +}, +"./src/index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +'use strict'; +__webpack_require__.r(__webpack_exports__); +/* harmony import */var _package_src_index_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ../package/src/index.js */"./package/src/index.js"); + +_package_src_index_js__WEBPACK_IMPORTED_MODULE_0_.a.a; +_package_src_index_js__WEBPACK_IMPORTED_MODULE_0_.a.aa.aa; +}, + +},function(__webpack_require__) { +var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } +var __webpack_exports__ = (__webpack_exec__("./src/index.js")); + +} +]); +``` diff --git a/crates/rspack/tests/tree-shaking/reexport-all-as-multi-level-nested/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/reexport-all-as-multi-level-nested/snapshot/snap.diff new file mode 100644 index 00000000000..89a21e1ef53 --- /dev/null +++ b/crates/rspack/tests/tree-shaking/reexport-all-as-multi-level-nested/snapshot/snap.diff @@ -0,0 +1,47 @@ +--- expected ++++ actual +@@ -3,44 +3,9 @@ + --- + ```js title=main.js + (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { +-"./package/autogen/a.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +-'use strict'; +-__webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'a': function() { return a; }, +- 'aa': function() { return _aa__WEBPACK_IMPORTED_MODULE_0_; } +-}); +-/* harmony import */var _aa__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./aa */"./package/autogen/aa.js"); +- +- function a() {} +- function dddd() {} +- +-}, +-"./package/autogen/aa.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +-'use strict'; +-__webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'aa': function() { return aa; } +-}); +- const aa = 3; +- const cc = 3; +-}, +-"./package/autogen/index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +-'use strict'; +-__webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'a': function() { return _a__WEBPACK_IMPORTED_MODULE_0_; } +-}); +-/* harmony import */var _a__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./a */"./package/autogen/a.js"); +- +- +- +-}, + "./package/src/index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); +-/* harmony import */var _autogen_index__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ../autogen/index */"./package/autogen/index.js"); +-__webpack_require__.es(_autogen_index__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); + + }, + "./src/index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { diff --git a/crates/rspack/tests/tree-shaking/reexport-all-as/expected/main.js b/crates/rspack/tests/tree-shaking/reexport-all-as/expected/main.js deleted file mode 100644 index 60000a022b1..00000000000 --- a/crates/rspack/tests/tree-shaking/reexport-all-as/expected/main.js +++ /dev/null @@ -1,42 +0,0 @@ -(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { -"./package/autogen/a.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'a': function() { return a; } -}); - function a() {} - function dddd() {} -}, -"./package/autogen/index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'a': function() { return _a__WEBPACK_IMPORTED_MODULE_0_; } -}); -/* harmony import */var _a__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./a */"./package/autogen/a.js"); - - - -}, -"./package/src/index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -/* harmony import */var _autogen_index__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ../autogen/index */"./package/autogen/index.js"); -__webpack_require__.es(_autogen_index__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); - -}, -"./src/index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -/* harmony import */var _package_src_index_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ../package/src/index.js */"./package/src/index.js"); - -_package_src_index_js__WEBPACK_IMPORTED_MODULE_0_.a.a; -}, - -},function(__webpack_require__) { -var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } -var __webpack_exports__ = (__webpack_exec__("./src/index.js")); - -} -]); \ No newline at end of file diff --git a/crates/rspack/tests/tree-shaking/reexport-all-as/snapshot/new_treeshaking.snap b/crates/rspack/tests/tree-shaking/reexport-all-as/snapshot/new_treeshaking.snap new file mode 100644 index 00000000000..a2ad74f8e90 --- /dev/null +++ b/crates/rspack/tests/tree-shaking/reexport-all-as/snapshot/new_treeshaking.snap @@ -0,0 +1,25 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js +(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { +"./package/src/index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +'use strict'; +__webpack_require__.r(__webpack_exports__); + +}, +"./src/index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +'use strict'; +__webpack_require__.r(__webpack_exports__); +/* harmony import */var _package_src_index_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ../package/src/index.js */"./package/src/index.js"); + +_package_src_index_js__WEBPACK_IMPORTED_MODULE_0_.a.a; +}, + +},function(__webpack_require__) { +var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } +var __webpack_exports__ = (__webpack_exec__("./src/index.js")); + +} +]); +``` diff --git a/crates/rspack/tests/tree-shaking/reexport-all-as/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/reexport-all-as/snapshot/snap.diff new file mode 100644 index 00000000000..ad61b5daf55 --- /dev/null +++ b/crates/rspack/tests/tree-shaking/reexport-all-as/snapshot/snap.diff @@ -0,0 +1,34 @@ +--- expected ++++ actual +@@ -3,31 +3,9 @@ + --- + ```js title=main.js + (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { +-"./package/autogen/a.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +-'use strict'; +-__webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'a': function() { return a; } +-}); +- function a() {} +- function dddd() {} +-}, +-"./package/autogen/index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +-'use strict'; +-__webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'a': function() { return _a__WEBPACK_IMPORTED_MODULE_0_; } +-}); +-/* harmony import */var _a__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./a */"./package/autogen/a.js"); +- +- +- +-}, + "./package/src/index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); +-/* harmony import */var _autogen_index__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ../autogen/index */"./package/autogen/index.js"); +-__webpack_require__.es(_autogen_index__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); + + }, + "./src/index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { diff --git a/crates/rspack/tests/tree-shaking/reexport_default_as/expected/main.js b/crates/rspack/tests/tree-shaking/reexport_default_as/snapshot/new_treeshaking.snap similarity index 92% rename from crates/rspack/tests/tree-shaking/reexport_default_as/expected/main.js rename to crates/rspack/tests/tree-shaking/reexport_default_as/snapshot/new_treeshaking.snap index e82a1b13a20..66e8b084535 100644 --- a/crates/rspack/tests/tree-shaking/reexport_default_as/expected/main.js +++ b/crates/rspack/tests/tree-shaking/reexport_default_as/snapshot/new_treeshaking.snap @@ -1,10 +1,11 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./bar.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'default': function() { return test; } -}); function test() {} }, "./foo.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { @@ -29,4 +30,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/reexport_default_as/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/reexport_default_as/snapshot/snap.diff new file mode 100644 index 00000000000..7cc41478805 --- /dev/null +++ b/crates/rspack/tests/tree-shaking/reexport_default_as/snapshot/snap.diff @@ -0,0 +1,12 @@ +--- expected ++++ actual +@@ -6,9 +6,6 @@ + "./bar.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'default': function() { return test; } +-}); + function test() {} + }, + "./foo.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { diff --git a/crates/rspack/tests/tree-shaking/reexport_entry_elimination/expected/main.js b/crates/rspack/tests/tree-shaking/reexport_entry_elimination/snapshot/new_treeshaking.snap similarity index 89% rename from crates/rspack/tests/tree-shaking/reexport_entry_elimination/expected/main.js rename to crates/rspack/tests/tree-shaking/reexport_entry_elimination/snapshot/new_treeshaking.snap index 205a254e0cf..e23d57f53ab 100644 --- a/crates/rspack/tests/tree-shaking/reexport_entry_elimination/expected/main.js +++ b/crates/rspack/tests/tree-shaking/reexport_entry_elimination/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./a.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -6,15 +10,13 @@ __webpack_require__.d(__webpack_exports__, { 'b': function() { return _b_js__WEBPACK_IMPORTED_MODULE_0_["default"]; } }); /* harmony import */var _b_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./b.js */"./b.js"); +/* harmony import */var _c_js__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./c.js */"./c.js"); }, "./b.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } -}); /* harmony import */var _c_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./c.js */"./c.js"); var __WEBPACK_DEFAULT_EXPORT__ = 2000 + _c_js__WEBPACK_IMPORTED_MODULE_0_["default"]; @@ -40,4 +42,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/reexport_entry_elimination/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/reexport_entry_elimination/snapshot/snap.diff new file mode 100644 index 00000000000..c918505b027 --- /dev/null +++ b/crates/rspack/tests/tree-shaking/reexport_entry_elimination/snapshot/snap.diff @@ -0,0 +1,19 @@ +--- expected ++++ actual +@@ -10,15 +10,13 @@ + 'b': function() { return _b_js__WEBPACK_IMPORTED_MODULE_0_["default"]; } + }); + /* harmony import */var _b_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./b.js */"./b.js"); ++/* harmony import */var _c_js__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./c.js */"./c.js"); + + + }, + "./b.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } +-}); + /* harmony import */var _c_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./c.js */"./c.js"); + + var __WEBPACK_DEFAULT_EXPORT__ = 2000 + _c_js__WEBPACK_IMPORTED_MODULE_0_["default"]; diff --git a/crates/rspack/tests/tree-shaking/rename-export-from-import/expected/main.js b/crates/rspack/tests/tree-shaking/rename-export-from-import/snapshot/new_treeshaking.snap similarity index 92% rename from crates/rspack/tests/tree-shaking/rename-export-from-import/expected/main.js rename to crates/rspack/tests/tree-shaking/rename-export-from-import/snapshot/new_treeshaking.snap index ec083c2f8cd..f166c73a967 100644 --- a/crates/rspack/tests/tree-shaking/rename-export-from-import/expected/main.js +++ b/crates/rspack/tests/tree-shaking/rename-export-from-import/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./app.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -19,9 +23,6 @@ _app__WEBPACK_IMPORTED_MODULE_0_.q; "./lib.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'question': function() { return question; } -}); const answer = "1"; const question = "2"; }, @@ -31,4 +32,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/rename-export-from-import/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/rename-export-from-import/snapshot/snap.diff new file mode 100644 index 00000000000..b84c7524799 --- /dev/null +++ b/crates/rspack/tests/tree-shaking/rename-export-from-import/snapshot/snap.diff @@ -0,0 +1,12 @@ +--- expected ++++ actual +@@ -23,9 +23,6 @@ + "./lib.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'question': function() { return question; } +-}); + const answer = "1"; + const question = "2"; + }, diff --git a/crates/rspack/tests/tree-shaking/rollup-unmodified-default-exports-function-argument/expected/main.js b/crates/rspack/tests/tree-shaking/rollup-unmodified-default-exports-function-argument/snapshot/new_treeshaking.snap similarity index 93% rename from crates/rspack/tests/tree-shaking/rollup-unmodified-default-exports-function-argument/expected/main.js rename to crates/rspack/tests/tree-shaking/rollup-unmodified-default-exports-function-argument/snapshot/new_treeshaking.snap index e7494d84e39..487917f3289 100644 --- a/crates/rspack/tests/tree-shaking/rollup-unmodified-default-exports-function-argument/expected/main.js +++ b/crates/rspack/tests/tree-shaking/rollup-unmodified-default-exports-function-argument/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./foo.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -29,4 +33,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/rollup-unmodified-default-exports/expected/main.js b/crates/rspack/tests/tree-shaking/rollup-unmodified-default-exports/snapshot/new_treeshaking.snap similarity index 92% rename from crates/rspack/tests/tree-shaking/rollup-unmodified-default-exports/expected/main.js rename to crates/rspack/tests/tree-shaking/rollup-unmodified-default-exports/snapshot/new_treeshaking.snap index 654f1ddec4f..64cb2243ae9 100644 --- a/crates/rspack/tests/tree-shaking/rollup-unmodified-default-exports/expected/main.js +++ b/crates/rspack/tests/tree-shaking/rollup-unmodified-default-exports/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./foo.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -29,4 +33,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/rollup-unused-called-import/expected/main.js b/crates/rspack/tests/tree-shaking/rollup-unused-called-import/snapshot/new_treeshaking.snap similarity index 82% rename from crates/rspack/tests/tree-shaking/rollup-unused-called-import/expected/main.js rename to crates/rspack/tests/tree-shaking/rollup-unused-called-import/snapshot/new_treeshaking.snap index b8bd01004b7..efd6bf481f5 100644 --- a/crates/rspack/tests/tree-shaking/rollup-unused-called-import/expected/main.js +++ b/crates/rspack/tests/tree-shaking/rollup-unused-called-import/snapshot/new_treeshaking.snap @@ -1,7 +1,14 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./dead.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); +__webpack_require__.d(__webpack_exports__, { + 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } +}); function __WEBPACK_DEFAULT_EXPORT__(){ return "dead"; } @@ -18,7 +25,7 @@ function __WEBPACK_DEFAULT_EXPORT__(){ return "foo"; } function foodead() { - return "foo" + /* "./dead" unused */null(); + return "foo" + (0, _dead__WEBPACK_IMPORTED_MODULE_0_["default"])(); } }, "./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { @@ -34,4 +41,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/rollup-unused-called-import/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/rollup-unused-called-import/snapshot/snap.diff new file mode 100644 index 00000000000..ea0a1343b8d --- /dev/null +++ b/crates/rspack/tests/tree-shaking/rollup-unused-called-import/snapshot/snap.diff @@ -0,0 +1,21 @@ +--- expected ++++ actual +@@ -6,6 +6,9 @@ + "./dead.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); ++__webpack_require__.d(__webpack_exports__, { ++ 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } ++}); + function __WEBPACK_DEFAULT_EXPORT__(){ + return "dead"; + } +@@ -22,7 +25,7 @@ + return "foo"; + } + function foodead() { +- return "foo" + /* "./dead" unused */null(); ++ return "foo" + (0, _dead__WEBPACK_IMPORTED_MODULE_0_["default"])(); + } + }, + "./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { diff --git a/crates/rspack/tests/tree-shaking/rollup-unused-default-exports/expected/main.js b/crates/rspack/tests/tree-shaking/rollup-unused-default-exports/snapshot/new_treeshaking.snap similarity index 92% rename from crates/rspack/tests/tree-shaking/rollup-unused-default-exports/expected/main.js rename to crates/rspack/tests/tree-shaking/rollup-unused-default-exports/snapshot/new_treeshaking.snap index 67be18f12e4..779a255cc84 100644 --- a/crates/rspack/tests/tree-shaking/rollup-unused-default-exports/expected/main.js +++ b/crates/rspack/tests/tree-shaking/rollup-unused-default-exports/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./foo.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -27,4 +31,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/rollup-unused-inner-functions-and-classes/expected/main.js b/crates/rspack/tests/tree-shaking/rollup-unused-inner-functions-and-classes/snapshot/new_treeshaking.snap similarity index 94% rename from crates/rspack/tests/tree-shaking/rollup-unused-inner-functions-and-classes/expected/main.js rename to crates/rspack/tests/tree-shaking/rollup-unused-inner-functions-and-classes/snapshot/new_treeshaking.snap index 3b6dd7ba881..a6bd608acf6 100644 --- a/crates/rspack/tests/tree-shaking/rollup-unused-inner-functions-and-classes/expected/main.js +++ b/crates/rspack/tests/tree-shaking/rollup-unused-inner-functions-and-classes/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -60,4 +64,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/rollup-unused-var/expected/main.js b/crates/rspack/tests/tree-shaking/rollup-unused-var/snapshot/new_treeshaking.snap similarity index 91% rename from crates/rspack/tests/tree-shaking/rollup-unused-var/expected/main.js rename to crates/rspack/tests/tree-shaking/rollup-unused-var/snapshot/new_treeshaking.snap index af94a25bd4c..e315d90931f 100644 --- a/crates/rspack/tests/tree-shaking/rollup-unused-var/expected/main.js +++ b/crates/rspack/tests/tree-shaking/rollup-unused-var/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./foo.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -23,4 +27,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/side-effects-flagged-only/expected/main.js b/crates/rspack/tests/tree-shaking/side-effects-analyzed/snapshot/new_treeshaking.snap similarity index 92% rename from crates/rspack/tests/tree-shaking/side-effects-flagged-only/expected/main.js rename to crates/rspack/tests/tree-shaking/side-effects-analyzed/snapshot/new_treeshaking.snap index fa7a74d9293..afc1386b762 100644 --- a/crates/rspack/tests/tree-shaking/side-effects-flagged-only/expected/main.js +++ b/crates/rspack/tests/tree-shaking/side-effects-analyzed/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./app.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -21,7 +25,7 @@ __webpack_require__.r(__webpack_exports__); 'use strict'; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { - 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } + 'something': function() { return something; } }); const secret = "888"; const result = 20000; @@ -41,4 +45,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/side-effects-analyzed/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/side-effects-analyzed/snapshot/snap.diff new file mode 100644 index 00000000000..ea4909df0e0 --- /dev/null +++ b/crates/rspack/tests/tree-shaking/side-effects-analyzed/snapshot/snap.diff @@ -0,0 +1,32 @@ +--- expected ++++ actual +@@ -10,6 +10,7 @@ + 'something': function() { return _lib__WEBPACK_IMPORTED_MODULE_0_["default"]; } + }); + /* harmony import */var _lib__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./lib */"./lib.js"); ++/* harmony import */var _src_a__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./src/a */"./src/a.js"); + + + }, +@@ -24,13 +25,20 @@ + 'use strict'; + __webpack_require__.r(__webpack_exports__); + __webpack_require__.d(__webpack_exports__, { +- 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } ++ 'something': function() { return something; } + }); + const secret = "888"; + const result = 20000; + const something = function() {}; + function __WEBPACK_DEFAULT_EXPORT__(){} + }, ++"./src/a.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { ++'use strict'; ++__webpack_require__.r(__webpack_exports__); ++var __WEBPACK_DEFAULT_EXPORT__ = (()=>{ ++ console.log(""); ++}); ++}, + + },function(__webpack_require__) { + var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } diff --git a/crates/rspack/tests/tree-shaking/side-effects-analyzed/expected/main.js b/crates/rspack/tests/tree-shaking/side-effects-export-default-expr/snapshot/new_treeshaking.snap similarity index 76% rename from crates/rspack/tests/tree-shaking/side-effects-analyzed/expected/main.js rename to crates/rspack/tests/tree-shaking/side-effects-export-default-expr/snapshot/new_treeshaking.snap index e84908372f3..2ee7d7a2e9d 100644 --- a/crates/rspack/tests/tree-shaking/side-effects-analyzed/expected/main.js +++ b/crates/rspack/tests/tree-shaking/side-effects-export-default-expr/snapshot/new_treeshaking.snap @@ -1,31 +1,33 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./app.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { - 'something': function() { return _lib__WEBPACK_IMPORTED_MODULE_0_["default"]; } + 'b': function() { return b; } }); /* harmony import */var _lib__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./lib */"./lib.js"); - +var __WEBPACK_DEFAULT_EXPORT__ = _lib__WEBPACK_IMPORTED_MODULE_0_.a; + const b = 1; }, "./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); /* harmony import */var _app__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./app */"./app.js"); -(0, _app__WEBPACK_IMPORTED_MODULE_0_.something)(); +_app__WEBPACK_IMPORTED_MODULE_0_.b; }, "./lib.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { - 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } + 'a': function() { return a; } }); - const secret = "888"; - const result = 20000; - const something = function() {}; -function __WEBPACK_DEFAULT_EXPORT__(){} + const a = 20000; }, },function(__webpack_require__) { @@ -33,4 +35,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/side-effects-export-default-expr/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/side-effects-export-default-expr/snapshot/snap.diff new file mode 100644 index 00000000000..667caf9856a --- /dev/null +++ b/crates/rspack/tests/tree-shaking/side-effects-export-default-expr/snapshot/snap.diff @@ -0,0 +1,28 @@ +--- expected ++++ actual +@@ -9,8 +9,9 @@ + __webpack_require__.d(__webpack_exports__, { + 'b': function() { return b; } + }); ++/* harmony import */var _lib__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./lib */"./lib.js"); + +-var __WEBPACK_DEFAULT_EXPORT__ = /* "./lib" unused */null; ++var __WEBPACK_DEFAULT_EXPORT__ = _lib__WEBPACK_IMPORTED_MODULE_0_.a; + const b = 1; + }, + "./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +@@ -20,6 +21,14 @@ + + _app__WEBPACK_IMPORTED_MODULE_0_.b; + }, ++"./lib.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { ++'use strict'; ++__webpack_require__.r(__webpack_exports__); ++__webpack_require__.d(__webpack_exports__, { ++ 'a': function() { return a; } ++}); ++ const a = 20000; ++}, + + },function(__webpack_require__) { + var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } diff --git a/crates/rspack/tests/tree-shaking/side-effects-flagged-only/snapshot/new_treeshaking.snap b/crates/rspack/tests/tree-shaking/side-effects-flagged-only/snapshot/new_treeshaking.snap new file mode 100644 index 00000000000..afc1386b762 --- /dev/null +++ b/crates/rspack/tests/tree-shaking/side-effects-flagged-only/snapshot/new_treeshaking.snap @@ -0,0 +1,49 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js +(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { +"./app.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +'use strict'; +__webpack_require__.r(__webpack_exports__); +__webpack_require__.d(__webpack_exports__, { + 'something': function() { return _lib__WEBPACK_IMPORTED_MODULE_0_["default"]; } +}); +/* harmony import */var _lib__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./lib */"./lib.js"); +/* harmony import */var _src_a__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./src/a */"./src/a.js"); + + +}, +"./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +'use strict'; +__webpack_require__.r(__webpack_exports__); +/* harmony import */var _app__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./app */"./app.js"); + +(0, _app__WEBPACK_IMPORTED_MODULE_0_.something)(); +}, +"./lib.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +'use strict'; +__webpack_require__.r(__webpack_exports__); +__webpack_require__.d(__webpack_exports__, { + 'something': function() { return something; } +}); + const secret = "888"; + const result = 20000; + const something = function() {}; +function __WEBPACK_DEFAULT_EXPORT__(){} +}, +"./src/a.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +'use strict'; +__webpack_require__.r(__webpack_exports__); +var __WEBPACK_DEFAULT_EXPORT__ = (()=>{ + console.log(""); +}); +}, + +},function(__webpack_require__) { +var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } +var __webpack_exports__ = (__webpack_exec__("./index.js")); + +} +]); +``` diff --git a/crates/rspack/tests/tree-shaking/side-effects-flagged-only/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/side-effects-flagged-only/snapshot/snap.diff new file mode 100644 index 00000000000..e04feddfff2 --- /dev/null +++ b/crates/rspack/tests/tree-shaking/side-effects-flagged-only/snapshot/snap.diff @@ -0,0 +1,11 @@ +--- expected ++++ actual +@@ -25,7 +25,7 @@ + 'use strict'; + __webpack_require__.r(__webpack_exports__); + __webpack_require__.d(__webpack_exports__, { +- 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } ++ 'something': function() { return something; } + }); + const secret = "888"; + const result = 20000; diff --git a/crates/rspack/tests/tree-shaking/side-effects-prune/expected/main.js b/crates/rspack/tests/tree-shaking/side-effects-prune/snapshot/new_treeshaking.snap similarity index 93% rename from crates/rspack/tests/tree-shaking/side-effects-prune/expected/main.js rename to crates/rspack/tests/tree-shaking/side-effects-prune/snapshot/new_treeshaking.snap index 13767f2ed52..1faa6134b14 100644 --- a/crates/rspack/tests/tree-shaking/side-effects-prune/expected/main.js +++ b/crates/rspack/tests/tree-shaking/side-effects-prune/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./app.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -32,4 +36,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/side-effects-two/expected/main.js b/crates/rspack/tests/tree-shaking/side-effects-two/snapshot/new_treeshaking.snap similarity index 74% rename from crates/rspack/tests/tree-shaking/side-effects-two/expected/main.js rename to crates/rspack/tests/tree-shaking/side-effects-two/snapshot/new_treeshaking.snap index add9fa6ab4a..7fca6a907a9 100644 --- a/crates/rspack/tests/tree-shaking/side-effects-two/expected/main.js +++ b/crates/rspack/tests/tree-shaking/side-effects-two/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./app.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -6,6 +10,7 @@ __webpack_require__.d(__webpack_exports__, { 'something': function() { return _lib__WEBPACK_IMPORTED_MODULE_0_["default"]; } }); /* harmony import */var _lib__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./lib */"./lib.js"); +/* harmony import */var _src_a__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./src/a */"./src/a.js"); // export { // result as test @@ -22,17 +27,25 @@ __webpack_require__.r(__webpack_exports__); 'use strict'; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { - 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } + 'something': function() { return something; } }); const secret = "888"; const result = 20000; const something = function() {}; function __WEBPACK_DEFAULT_EXPORT__(){} }, +"./src/a.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +'use strict'; +__webpack_require__.r(__webpack_exports__); +var __WEBPACK_DEFAULT_EXPORT__ = (()=>{ + console.log(''); +}); +}, },function(__webpack_require__) { var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/side-effects-two/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/side-effects-two/snapshot/snap.diff new file mode 100644 index 00000000000..4953c035f97 --- /dev/null +++ b/crates/rspack/tests/tree-shaking/side-effects-two/snapshot/snap.diff @@ -0,0 +1,32 @@ +--- expected ++++ actual +@@ -10,6 +10,7 @@ + 'something': function() { return _lib__WEBPACK_IMPORTED_MODULE_0_["default"]; } + }); + /* harmony import */var _lib__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./lib */"./lib.js"); ++/* harmony import */var _src_a__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./src/a */"./src/a.js"); + + // export { + // result as test +@@ -26,13 +27,20 @@ + 'use strict'; + __webpack_require__.r(__webpack_exports__); + __webpack_require__.d(__webpack_exports__, { +- 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } ++ 'something': function() { return something; } + }); + const secret = "888"; + const result = 20000; + const something = function() {}; + function __WEBPACK_DEFAULT_EXPORT__(){} + }, ++"./src/a.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { ++'use strict'; ++__webpack_require__.r(__webpack_exports__); ++var __WEBPACK_DEFAULT_EXPORT__ = (()=>{ ++ console.log(''); ++}); ++}, + + },function(__webpack_require__) { + var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } diff --git a/crates/rspack/tests/tree-shaking/simple-namespace-access/expected/main.js b/crates/rspack/tests/tree-shaking/simple-namespace-access/snapshot/new_treeshaking.snap similarity index 94% rename from crates/rspack/tests/tree-shaking/simple-namespace-access/expected/main.js rename to crates/rspack/tests/tree-shaking/simple-namespace-access/snapshot/new_treeshaking.snap index d705eb5b99a..d114893021c 100644 --- a/crates/rspack/tests/tree-shaking/simple-namespace-access/expected/main.js +++ b/crates/rspack/tests/tree-shaking/simple-namespace-access/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -32,9 +36,6 @@ __webpack_require__.d(__webpack_exports__, { "./test.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'test': function() { return test; } -}); function test() {} function ccc() {} }, @@ -44,4 +45,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/simple-namespace-access/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/simple-namespace-access/snapshot/snap.diff new file mode 100644 index 00000000000..abbd04f63d0 --- /dev/null +++ b/crates/rspack/tests/tree-shaking/simple-namespace-access/snapshot/snap.diff @@ -0,0 +1,12 @@ +--- expected ++++ actual +@@ -36,9 +36,6 @@ + "./test.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'test': function() { return test; } +-}); + function test() {} + function ccc() {} + }, diff --git a/crates/rspack/tests/tree-shaking/static-class/expected/main.js b/crates/rspack/tests/tree-shaking/static-class/snapshot/new_treeshaking.snap similarity index 87% rename from crates/rspack/tests/tree-shaking/static-class/expected/main.js rename to crates/rspack/tests/tree-shaking/static-class/snapshot/new_treeshaking.snap index d7d7c639418..ac9525a6ba2 100644 --- a/crates/rspack/tests/tree-shaking/static-class/expected/main.js +++ b/crates/rspack/tests/tree-shaking/static-class/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./a.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -15,7 +19,7 @@ __webpack_require__.d(__webpack_exports__, { } class Result { static test() { - /* "./b.js" unused */null; + _b_js__WEBPACK_IMPORTED_MODULE_0_.cc; } } const a = 3; @@ -24,7 +28,8 @@ class Result { 'use strict'; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { - 'bb': function() { return bb; } + 'bb': function() { return bb; }, + 'cc': function() { return cc; } }); const bb = 2; const cc = 3; @@ -42,4 +47,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/static-class/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/static-class/snapshot/snap.diff new file mode 100644 index 00000000000..f22ddcfe0ed --- /dev/null +++ b/crates/rspack/tests/tree-shaking/static-class/snapshot/snap.diff @@ -0,0 +1,21 @@ +--- expected ++++ actual +@@ -19,7 +19,7 @@ + } + class Result { + static test() { +- /* "./b.js" unused */null; ++ _b_js__WEBPACK_IMPORTED_MODULE_0_.cc; + } + } + const a = 3; +@@ -28,7 +28,8 @@ + 'use strict'; + __webpack_require__.r(__webpack_exports__); + __webpack_require__.d(__webpack_exports__, { +- 'bb': function() { return bb; } ++ 'bb': function() { return bb; }, ++ 'cc': function() { return cc; } + }); + const bb = 2; + const cc = 3; diff --git a/crates/rspack/tests/tree-shaking/transitive-bailout/expected/main.js b/crates/rspack/tests/tree-shaking/transitive-bailout/snapshot/new_treeshaking.snap similarity index 66% rename from crates/rspack/tests/tree-shaking/transitive-bailout/expected/main.js rename to crates/rspack/tests/tree-shaking/transitive-bailout/snapshot/new_treeshaking.snap index 8fbb394c1c4..0b02c69b9bf 100644 --- a/crates/rspack/tests/tree-shaking/transitive-bailout/expected/main.js +++ b/crates/rspack/tests/tree-shaking/transitive-bailout/snapshot/new_treeshaking.snap @@ -1,14 +1,8 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { -"./a.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'a': function() { return a; }, - 'b': function() { return b; } -}); - const a = 3; - const b = 3; -}, "./answer.js": function (__unused_webpack_module, exports, __webpack_require__) { const res = __webpack_require__(/* ./lib.js */"./lib.js"); exports.test = function() { @@ -25,8 +19,6 @@ _answer__WEBPACK_IMPORTED_MODULE_0_.test; "./lib.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); -/* harmony import */var _a_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./a.js */"./a.js"); -__webpack_require__.es(_a_js__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); }, @@ -35,4 +27,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/transitive-bailout/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/transitive-bailout/snapshot/snap.diff new file mode 100644 index 00000000000..819f7f7eb2b --- /dev/null +++ b/crates/rspack/tests/tree-shaking/transitive-bailout/snapshot/snap.diff @@ -0,0 +1,28 @@ +--- expected ++++ actual +@@ -3,16 +3,6 @@ + --- + ```js title=main.js + (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { +-"./a.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +-'use strict'; +-__webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'a': function() { return a; }, +- 'b': function() { return b; } +-}); +- const a = 3; +- const b = 3; +-}, + "./answer.js": function (__unused_webpack_module, exports, __webpack_require__) { + const res = __webpack_require__(/* ./lib.js */"./lib.js"); + exports.test = function() { +@@ -29,8 +19,6 @@ + "./lib.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); +-/* harmony import */var _a_js__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./a.js */"./a.js"); +-__webpack_require__.es(_a_js__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); + + }, + diff --git a/crates/rspack/tests/tree-shaking/transitive_side_effects_when_analyze/expected/main.js b/crates/rspack/tests/tree-shaking/transitive_side_effects_when_analyze/snapshot/new_treeshaking.snap similarity index 93% rename from crates/rspack/tests/tree-shaking/transitive_side_effects_when_analyze/expected/main.js rename to crates/rspack/tests/tree-shaking/transitive_side_effects_when_analyze/snapshot/new_treeshaking.snap index ebe16a1792f..a753df8b2db 100644 --- a/crates/rspack/tests/tree-shaking/transitive_side_effects_when_analyze/expected/main.js +++ b/crates/rspack/tests/tree-shaking/transitive_side_effects_when_analyze/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./app.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -27,4 +31,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/tree-shaking-false-with-side-effect-true/expected/main.js b/crates/rspack/tests/tree-shaking/tree-shaking-false-with-side-effect-true/snapshot/new_treeshaking.snap similarity index 93% rename from crates/rspack/tests/tree-shaking/tree-shaking-false-with-side-effect-true/expected/main.js rename to crates/rspack/tests/tree-shaking/tree-shaking-false-with-side-effect-true/snapshot/new_treeshaking.snap index f43c9d80720..ed71fa5a81e 100644 --- a/crates/rspack/tests/tree-shaking/tree-shaking-false-with-side-effect-true/expected/main.js +++ b/crates/rspack/tests/tree-shaking/tree-shaking-false-with-side-effect-true/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./ b.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -31,4 +35,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/tree-shaking-interop/expected/bar_js.js b/crates/rspack/tests/tree-shaking/tree-shaking-interop/expected/bar_js.js deleted file mode 100644 index 603a7efc37b..00000000000 --- a/crates/rspack/tests/tree-shaking/tree-shaking-interop/expected/bar_js.js +++ /dev/null @@ -1,11 +0,0 @@ -(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["bar_js"], { -"./bar.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'default': function() { return test; } -}); -function test() {} -}, - -}]); \ No newline at end of file diff --git a/crates/rspack/tests/tree-shaking/tree-shaking-interop/expected/main.js b/crates/rspack/tests/tree-shaking/tree-shaking-interop/snapshot/new_treeshaking.snap similarity index 74% rename from crates/rspack/tests/tree-shaking/tree-shaking-interop/expected/main.js rename to crates/rspack/tests/tree-shaking/tree-shaking-interop/snapshot/new_treeshaking.snap index f6d11786f2a..5fe767c457c 100644 --- a/crates/rspack/tests/tree-shaking/tree-shaking-interop/expected/main.js +++ b/crates/rspack/tests/tree-shaking/tree-shaking-interop/snapshot/new_treeshaking.snap @@ -1,3 +1,21 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=bar_js.js +(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["bar_js"], { +"./bar.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +'use strict'; +__webpack_require__.r(__webpack_exports__); +__webpack_require__.d(__webpack_exports__, { + 'default': function() { return test; } +}); +function test() {} +}, + +}]); +``` + +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./a.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -31,4 +49,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/tree-shaking-lazy-import/expected/lib_js.js b/crates/rspack/tests/tree-shaking/tree-shaking-lazy-import/expected/lib_js.js deleted file mode 100644 index 192e05cd7d7..00000000000 --- a/crates/rspack/tests/tree-shaking/tree-shaking-lazy-import/expected/lib_js.js +++ /dev/null @@ -1,25 +0,0 @@ -(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["lib_js"], { -"./lib.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } -}); -/* harmony import */var _test__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./test */"./test.js"); - -function myanswer() { - _test__WEBPACK_IMPORTED_MODULE_0_["default"]; -} -var __WEBPACK_DEFAULT_EXPORT__ = myanswer; -}, -"./test.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } -}); -function test() {} -var __WEBPACK_DEFAULT_EXPORT__ = test; -}, - -}]); \ No newline at end of file diff --git a/crates/rspack/tests/tree-shaking/tree-shaking-lazy-import/expected/main.js b/crates/rspack/tests/tree-shaking/tree-shaking-lazy-import/expected/main.js deleted file mode 100644 index 0e23e0d1639..00000000000 --- a/crates/rspack/tests/tree-shaking/tree-shaking-lazy-import/expected/main.js +++ /dev/null @@ -1,25 +0,0 @@ -(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { -"./app.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'answer': function() { return answer; } -}); - const answer = 30; -}, -"./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -/* harmony import */var _app__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./app */"./app.js"); - -const a = test(()=>__webpack_require__.el(/* ./lib */"./lib.js").then(__webpack_require__.bind(__webpack_require__, /* ./lib */"./lib.js"))); -(0, _app__WEBPACK_IMPORTED_MODULE_0_.answer)(); -a; -}, - -},function(__webpack_require__) { -var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } -var __webpack_exports__ = (__webpack_exec__("./index.js")); - -} -]); \ No newline at end of file diff --git a/crates/rspack/tests/tree-shaking/react-redux-like/expected/main.js b/crates/rspack/tests/tree-shaking/tree-shaking-lazy-import/snapshot/new_treeshaking.snap similarity index 50% rename from crates/rspack/tests/tree-shaking/react-redux-like/expected/main.js rename to crates/rspack/tests/tree-shaking/tree-shaking-lazy-import/snapshot/new_treeshaking.snap index a4dcf2265e4..67734803efd 100644 --- a/crates/rspack/tests/tree-shaking/react-redux-like/expected/main.js +++ b/crates/rspack/tests/tree-shaking/tree-shaking-lazy-import/snapshot/new_treeshaking.snap @@ -1,52 +1,52 @@ -(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { -"./app.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=lib_js.js +(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["lib_js"], { +"./lib.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { - 'Provider': function() { return _lib__WEBPACK_IMPORTED_MODULE_0_["default"]; }, - 'useSelector': function() { return _selector_js__WEBPACK_IMPORTED_MODULE_1_["default"]; } + 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } }); -/* harmony import */var _lib__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./lib */"./lib.js"); -/* harmony import */var _selector_js__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./selector.js */"./selector.js"); - - +/* harmony import */var _test__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./test */"./test.js"); +function myanswer() { + _test__WEBPACK_IMPORTED_MODULE_0_["default"]; +} +var __WEBPACK_DEFAULT_EXPORT__ = myanswer; }, -"./foo.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +"./test.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); -/* harmony import */var _app__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./app */"./app.js"); -__webpack_require__.es(_app__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); - -function batch() {} - +__webpack_require__.d(__webpack_exports__, { + 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } +}); +function test() {} +var __WEBPACK_DEFAULT_EXPORT__ = test; }, -"./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -/* harmony import */var _foo__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./foo */"./foo.js"); -_foo__WEBPACK_IMPORTED_MODULE_0_.Provider; -_foo__WEBPACK_IMPORTED_MODULE_0_.useSelector; -}, -"./lib.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +}]); +``` + +```js title=main.js +(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { +"./app.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { - 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } + 'answer': function() { return answer; } }); -function Provider() {} -var __WEBPACK_DEFAULT_EXPORT__ = Provider; + const answer = 30; }, -"./selector.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +"./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'default': function() { return useSelector; } -}); -function useSelector() { - return ""; -} +/* harmony import */var _app__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./app */"./app.js"); + +const a = test(()=>__webpack_require__.el(/* ./lib */"./lib.js").then(__webpack_require__.bind(__webpack_require__, /* ./lib */"./lib.js"))); +(0, _app__WEBPACK_IMPORTED_MODULE_0_.answer)(); +a; }, },function(__webpack_require__) { @@ -54,4 +54,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/ts-target-es5/expected/main.js b/crates/rspack/tests/tree-shaking/ts-target-es5/snapshot/new_treeshaking.snap similarity index 99% rename from crates/rspack/tests/tree-shaking/ts-target-es5/expected/main.js rename to crates/rspack/tests/tree-shaking/ts-target-es5/snapshot/new_treeshaking.snap index 064a397f006..1e2d5450a5b 100644 --- a/crates/rspack/tests/tree-shaking/ts-target-es5/expected/main.js +++ b/crates/rspack/tests/tree-shaking/ts-target-es5/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "../../../../../node_modules/@swc/helpers/esm/_async_to_generator.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -45,9 +49,6 @@ __webpack_require__.d(__webpack_exports__, { "../../../../../node_modules/tslib/tslib.es6.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - '__generator': function() { return __generator; } -}); /****************************************************************************** Copyright (c) Microsoft Corporation. @@ -478,9 +479,6 @@ var __setModuleDefault = Object.create ? function(o, v) { "./index.ts": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); -__webpack_require__.d(__webpack_exports__, { - 'test': function() { return test; } -}); /* harmony import */var _swc_helpers_async_to_generator__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* @swc/helpers/_/_async_to_generator */"../../../../../node_modules/@swc/helpers/esm/_async_to_generator.js"); /* harmony import */var _swc_helpers_ts_generator__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* @swc/helpers/_/_ts_generator */"../../../../../node_modules/@swc/helpers/esm/_ts_generator.js"); @@ -505,4 +503,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.ts")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/ts-target-es5/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/ts-target-es5/snapshot/snap.diff new file mode 100644 index 00000000000..bc740092764 --- /dev/null +++ b/crates/rspack/tests/tree-shaking/ts-target-es5/snapshot/snap.diff @@ -0,0 +1,22 @@ +--- expected ++++ actual +@@ -49,9 +49,6 @@ + "../../../../../node_modules/tslib/tslib.es6.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- '__generator': function() { return __generator; } +-}); + /****************************************************************************** + Copyright (c) Microsoft Corporation. + +@@ -482,9 +479,6 @@ + "./index.ts": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); +-__webpack_require__.d(__webpack_exports__, { +- 'test': function() { return test; } +-}); + /* harmony import */var _swc_helpers_async_to_generator__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* @swc/helpers/_/_async_to_generator */"../../../../../node_modules/@swc/helpers/esm/_async_to_generator.js"); + /* harmony import */var _swc_helpers_ts_generator__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* @swc/helpers/_/_ts_generator */"../../../../../node_modules/@swc/helpers/esm/_ts_generator.js"); + diff --git a/crates/rspack/tests/tree-shaking/var-function-expr/expected/main.js b/crates/rspack/tests/tree-shaking/var-function-expr/snapshot/new_treeshaking.snap similarity index 89% rename from crates/rspack/tests/tree-shaking/var-function-expr/expected/main.js rename to crates/rspack/tests/tree-shaking/var-function-expr/snapshot/new_treeshaking.snap index ad5af26e97c..1198b349d2a 100644 --- a/crates/rspack/tests/tree-shaking/var-function-expr/expected/main.js +++ b/crates/rspack/tests/tree-shaking/var-function-expr/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./app.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -11,7 +15,7 @@ __webpack_require__.d(__webpack_exports__, { _lib__WEBPACK_IMPORTED_MODULE_0_.result; }; var app2 = ()=>{ - /* "./lib" unused */null; + _lib__WEBPACK_IMPORTED_MODULE_0_.secret; }; var app4 = (0, _lib__WEBPACK_IMPORTED_MODULE_0_.something)('app4'), app5 = 10000; var app3 = (0, _lib__WEBPACK_IMPORTED_MODULE_0_.something)('app3'); @@ -27,6 +31,7 @@ __webpack_require__.r(__webpack_exports__); 'use strict'; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { + 'secret': function() { return secret; }, 'result': function() { return result; }, 'something': function() { return something; } }); @@ -40,4 +45,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/var-function-expr/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/var-function-expr/snapshot/snap.diff new file mode 100644 index 00000000000..07a1eb82343 --- /dev/null +++ b/crates/rspack/tests/tree-shaking/var-function-expr/snapshot/snap.diff @@ -0,0 +1,19 @@ +--- expected ++++ actual +@@ -15,7 +15,7 @@ + _lib__WEBPACK_IMPORTED_MODULE_0_.result; + }; + var app2 = ()=>{ +- /* "./lib" unused */null; ++ _lib__WEBPACK_IMPORTED_MODULE_0_.secret; + }; + var app4 = (0, _lib__WEBPACK_IMPORTED_MODULE_0_.something)('app4'), app5 = 10000; + var app3 = (0, _lib__WEBPACK_IMPORTED_MODULE_0_.something)('app3'); +@@ -31,6 +31,7 @@ + 'use strict'; + __webpack_require__.r(__webpack_exports__); + __webpack_require__.d(__webpack_exports__, { ++ 'secret': function() { return secret; }, + 'result': function() { return result; }, + 'something': function() { return something; } + }); diff --git a/crates/rspack/tests/tree-shaking/webpack-inner-graph-export-default-named/expected/main.js b/crates/rspack/tests/tree-shaking/webpack-inner-graph-export-default-named/snapshot/new_treeshaking.snap similarity index 85% rename from crates/rspack/tests/tree-shaking/webpack-inner-graph-export-default-named/expected/main.js rename to crates/rspack/tests/tree-shaking/webpack-inner-graph-export-default-named/snapshot/new_treeshaking.snap index e2a1c3cdae8..651c4b2a56a 100644 --- a/crates/rspack/tests/tree-shaking/webpack-inner-graph-export-default-named/expected/main.js +++ b/crates/rspack/tests/tree-shaking/webpack-inner-graph-export-default-named/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./a.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -11,15 +15,6 @@ function abc() { return _dep_a__WEBPACK_IMPORTED_MODULE_0_.x; } }, -"./b.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -/* harmony import */var _dep_b__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./dep?b */"./dep.js?b"); - -function abc() { - return /* "./dep?b" unused */null; -} -}, "./c.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); @@ -52,7 +47,7 @@ __webpack_require__.d(__webpack_exports__, { 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } }); const x = "x"; -var __WEBPACK_DEFAULT_EXPORT__ = true; +var __WEBPACK_DEFAULT_EXPORT__ = false; }, "./dep.js?b": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -71,7 +66,7 @@ __webpack_require__.d(__webpack_exports__, { 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } }); const x = "x"; -var __WEBPACK_DEFAULT_EXPORT__ = true; +var __WEBPACK_DEFAULT_EXPORT__ = false; }, "./dep.js?d": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -81,7 +76,7 @@ __webpack_require__.d(__webpack_exports__, { 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } }); const x = "x"; -var __WEBPACK_DEFAULT_EXPORT__ = true; +var __WEBPACK_DEFAULT_EXPORT__ = false; }, "./dep.js?e": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -100,18 +95,7 @@ __webpack_require__.d(__webpack_exports__, { 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } }); const x = "x"; -var __WEBPACK_DEFAULT_EXPORT__ = true; -}, -"./e.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -/* harmony import */var _dep_e__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./dep?e */"./dep.js?e"); - -class def { - method() { - return /* "./dep?e" unused */null; - } -} +var __WEBPACK_DEFAULT_EXPORT__ = false; }, "./f.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -128,12 +112,10 @@ new def().method(); "./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); -/* harmony import */var _a__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./a */"./a.js"); -/* harmony import */var _b__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./b */"./b.js"); /* harmony import */var _c__WEBPACK_IMPORTED_MODULE_2_ = __webpack_require__(/* ./c */"./c.js"); -/* harmony import */var _d__WEBPACK_IMPORTED_MODULE_3_ = __webpack_require__(/* ./d */"./d.js"); -/* harmony import */var _e__WEBPACK_IMPORTED_MODULE_4_ = __webpack_require__(/* ./e */"./e.js"); /* harmony import */var _f__WEBPACK_IMPORTED_MODULE_5_ = __webpack_require__(/* ./f */"./f.js"); +/* harmony import */var _a__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./a */"./a.js"); +/* harmony import */var _d__WEBPACK_IMPORTED_MODULE_3_ = __webpack_require__(/* ./d */"./d.js"); /* harmony import */var _dep_a__WEBPACK_IMPORTED_MODULE_6_ = __webpack_require__(/* ./dep?a */"./dep.js?a"); /* harmony import */var _dep_b__WEBPACK_IMPORTED_MODULE_7_ = __webpack_require__(/* ./dep?b */"./dep.js?b"); /* harmony import */var _dep_c__WEBPACK_IMPORTED_MODULE_8_ = __webpack_require__(/* ./dep?c */"./dep.js?c"); @@ -181,4 +163,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/webpack-inner-graph-export-default-named/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/webpack-inner-graph-export-default-named/snapshot/snap.diff new file mode 100644 index 00000000000..53808cb9b40 --- /dev/null +++ b/crates/rspack/tests/tree-shaking/webpack-inner-graph-export-default-named/snapshot/snap.diff @@ -0,0 +1,81 @@ +--- expected ++++ actual +@@ -15,15 +15,6 @@ + return _dep_a__WEBPACK_IMPORTED_MODULE_0_.x; + } + }, +-"./b.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +-'use strict'; +-__webpack_require__.r(__webpack_exports__); +-/* harmony import */var _dep_b__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./dep?b */"./dep.js?b"); +- +-function abc() { +- return /* "./dep?b" unused */null; +-} +-}, + "./c.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); +@@ -56,7 +47,7 @@ + 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } + }); + const x = "x"; +-var __WEBPACK_DEFAULT_EXPORT__ = true; ++var __WEBPACK_DEFAULT_EXPORT__ = false; + }, + "./dep.js?b": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; +@@ -75,7 +66,7 @@ + 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } + }); + const x = "x"; +-var __WEBPACK_DEFAULT_EXPORT__ = true; ++var __WEBPACK_DEFAULT_EXPORT__ = false; + }, + "./dep.js?d": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; +@@ -85,7 +76,7 @@ + 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } + }); + const x = "x"; +-var __WEBPACK_DEFAULT_EXPORT__ = true; ++var __WEBPACK_DEFAULT_EXPORT__ = false; + }, + "./dep.js?e": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; +@@ -104,19 +95,8 @@ + 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } + }); + const x = "x"; +-var __WEBPACK_DEFAULT_EXPORT__ = true; ++var __WEBPACK_DEFAULT_EXPORT__ = false; + }, +-"./e.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +-'use strict'; +-__webpack_require__.r(__webpack_exports__); +-/* harmony import */var _dep_e__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./dep?e */"./dep.js?e"); +- +-class def { +- method() { +- return /* "./dep?e" unused */null; +- } +-} +-}, + "./f.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); +@@ -132,12 +112,10 @@ + "./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); ++/* harmony import */var _c__WEBPACK_IMPORTED_MODULE_2_ = __webpack_require__(/* ./c */"./c.js"); ++/* harmony import */var _f__WEBPACK_IMPORTED_MODULE_5_ = __webpack_require__(/* ./f */"./f.js"); + /* harmony import */var _a__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./a */"./a.js"); +-/* harmony import */var _b__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./b */"./b.js"); +-/* harmony import */var _c__WEBPACK_IMPORTED_MODULE_2_ = __webpack_require__(/* ./c */"./c.js"); + /* harmony import */var _d__WEBPACK_IMPORTED_MODULE_3_ = __webpack_require__(/* ./d */"./d.js"); +-/* harmony import */var _e__WEBPACK_IMPORTED_MODULE_4_ = __webpack_require__(/* ./e */"./e.js"); +-/* harmony import */var _f__WEBPACK_IMPORTED_MODULE_5_ = __webpack_require__(/* ./f */"./f.js"); + /* harmony import */var _dep_a__WEBPACK_IMPORTED_MODULE_6_ = __webpack_require__(/* ./dep?a */"./dep.js?a"); + /* harmony import */var _dep_b__WEBPACK_IMPORTED_MODULE_7_ = __webpack_require__(/* ./dep?b */"./dep.js?b"); + /* harmony import */var _dep_c__WEBPACK_IMPORTED_MODULE_8_ = __webpack_require__(/* ./dep?c */"./dep.js?c"); diff --git a/crates/rspack/tests/tree-shaking/webpack-inner-graph-switch/expected/main.js b/crates/rspack/tests/tree-shaking/webpack-inner-graph-switch/snapshot/new_treeshaking.snap similarity index 89% rename from crates/rspack/tests/tree-shaking/webpack-inner-graph-switch/expected/main.js rename to crates/rspack/tests/tree-shaking/webpack-inner-graph-switch/snapshot/new_treeshaking.snap index 3d5ff8dd7f9..3e7c731cd70 100644 --- a/crates/rspack/tests/tree-shaking/webpack-inner-graph-switch/expected/main.js +++ b/crates/rspack/tests/tree-shaking/webpack-inner-graph-switch/snapshot/new_treeshaking.snap @@ -1,3 +1,18 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=chunk_js.js +(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["chunk_js"], { +"./chunk.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +'use strict'; +__webpack_require__.r(__webpack_exports__); + +}, + +}]); +``` + +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./import-module.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -88,4 +103,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/webpack-innergraph-circular/expected/chunk_js.js b/crates/rspack/tests/tree-shaking/webpack-innergraph-circular/expected/chunk_js.js deleted file mode 100644 index 4628f86d19b..00000000000 --- a/crates/rspack/tests/tree-shaking/webpack-innergraph-circular/expected/chunk_js.js +++ /dev/null @@ -1,9 +0,0 @@ -(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["chunk_js"], { -"./chunk.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { -'use strict'; -__webpack_require__.r(__webpack_exports__); -/* harmony import */var _inner__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./inner */"./inner.js"); - -}, - -}]); \ No newline at end of file diff --git a/crates/rspack/tests/tree-shaking/webpack-innergraph-circular/expected/main.js b/crates/rspack/tests/tree-shaking/webpack-innergraph-circular/snapshot/new_treeshaking.snap similarity index 77% rename from crates/rspack/tests/tree-shaking/webpack-innergraph-circular/expected/main.js rename to crates/rspack/tests/tree-shaking/webpack-innergraph-circular/snapshot/new_treeshaking.snap index 832e9674944..c9baf210b57 100644 --- a/crates/rspack/tests/tree-shaking/webpack-innergraph-circular/expected/main.js +++ b/crates/rspack/tests/tree-shaking/webpack-innergraph-circular/snapshot/new_treeshaking.snap @@ -1,9 +1,26 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=chunk_js.js +(self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["chunk_js"], { +"./chunk.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +'use strict'; +__webpack_require__.r(__webpack_exports__); +/* harmony import */var _inner__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./inner */"./inner.js"); + +}, + +}]); +``` + +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); /* harmony import */var _inner__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./inner */"./inner.js"); /* harmony import */var _module__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./module */"./module.js"); +/* harmony import */var _inner__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./inner */"./inner.js"); it("export should be unused when only unused functions use it", ()=>{ @@ -20,6 +37,7 @@ __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { 'A': function() { return A; }, 'B': function() { return B; }, + 'C': function() { return C; }, 'exportAUsed': function() { return exportAUsed; }, 'exportBUsed': function() { return exportBUsed; }, 'exportCUsed': function() { return exportCUsed; } @@ -33,8 +51,8 @@ __webpack_require__.d(__webpack_exports__, { function C(s) { return s + "C"; } - const exportAUsed = true; - const exportBUsed = true; + const exportAUsed = false; + const exportBUsed = false; const exportCUsed = false; }, "./module.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { @@ -68,7 +86,7 @@ function withB(v) { } function withC(v) { const value = x(v); - return /* "./inner" unused */null(value); + return (0, _inner__WEBPACK_IMPORTED_MODULE_0_.C)(value); } }, @@ -78,4 +96,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/webpack-innergraph-circular/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/webpack-innergraph-circular/snapshot/snap.diff new file mode 100644 index 00000000000..adbe03b50f5 --- /dev/null +++ b/crates/rspack/tests/tree-shaking/webpack-innergraph-circular/snapshot/snap.diff @@ -0,0 +1,38 @@ +--- expected ++++ actual +@@ -20,6 +20,7 @@ + __webpack_require__.r(__webpack_exports__); + /* harmony import */var _inner__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./inner */"./inner.js"); + /* harmony import */var _module__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./module */"./module.js"); ++/* harmony import */var _inner__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./inner */"./inner.js"); + + + it("export should be unused when only unused functions use it", ()=>{ +@@ -36,6 +37,7 @@ + __webpack_require__.d(__webpack_exports__, { + 'A': function() { return A; }, + 'B': function() { return B; }, ++ 'C': function() { return C; }, + 'exportAUsed': function() { return exportAUsed; }, + 'exportBUsed': function() { return exportBUsed; }, + 'exportCUsed': function() { return exportCUsed; } +@@ -49,8 +51,8 @@ + function C(s) { + return s + "C"; + } +- const exportAUsed = true; +- const exportBUsed = true; ++ const exportAUsed = false; ++ const exportBUsed = false; + const exportCUsed = false; + }, + "./module.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +@@ -84,7 +86,7 @@ + } + function withC(v) { + const value = x(v); +- return /* "./inner" unused */null(value); ++ return (0, _inner__WEBPACK_IMPORTED_MODULE_0_.C)(value); + } + + }, diff --git a/crates/rspack/tests/tree-shaking/webpack-innergraph-circular2/expected/main.js b/crates/rspack/tests/tree-shaking/webpack-innergraph-circular2/snapshot/new_treeshaking.snap similarity index 96% rename from crates/rspack/tests/tree-shaking/webpack-innergraph-circular2/expected/main.js rename to crates/rspack/tests/tree-shaking/webpack-innergraph-circular2/snapshot/new_treeshaking.snap index c26a7a91a7c..f559cdb5154 100644 --- a/crates/rspack/tests/tree-shaking/webpack-innergraph-circular2/expected/main.js +++ b/crates/rspack/tests/tree-shaking/webpack-innergraph-circular2/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -129,4 +133,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/webpack-innergraph-no-side-effects/expected/main.js b/crates/rspack/tests/tree-shaking/webpack-innergraph-no-side-effects/snapshot/new_treeshaking.snap similarity index 68% rename from crates/rspack/tests/tree-shaking/webpack-innergraph-no-side-effects/expected/main.js rename to crates/rspack/tests/tree-shaking/webpack-innergraph-no-side-effects/snapshot/new_treeshaking.snap index 181a50214a9..a205ad5ae0d 100644 --- a/crates/rspack/tests/tree-shaking/webpack-innergraph-no-side-effects/expected/main.js +++ b/crates/rspack/tests/tree-shaking/webpack-innergraph-no-side-effects/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./index.js": function (__unused_webpack_module, exports, __webpack_require__) { it("should be able to load package without side effects where modules are unused", ()=>{ @@ -22,18 +26,28 @@ __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { 'a': function() { return a; } }); +/* harmony import */var _unusedModule__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./unusedModule */"./package/unusedModule.js"); function a() { return 42; } function b() { - return /* "./unusedModule" unused */null; + return _unusedModule__WEBPACK_IMPORTED_MODULE_0_["default"]; } }, +"./package/unusedModule.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +'use strict'; +__webpack_require__.r(__webpack_exports__); +__webpack_require__.d(__webpack_exports__, { + 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } +}); +var __WEBPACK_DEFAULT_EXPORT__ = 42; +}, },function(__webpack_require__) { var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/webpack-innergraph-no-side-effects/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/webpack-innergraph-no-side-effects/snapshot/snap.diff new file mode 100644 index 00000000000..fdc2abc2f26 --- /dev/null +++ b/crates/rspack/tests/tree-shaking/webpack-innergraph-no-side-effects/snapshot/snap.diff @@ -0,0 +1,27 @@ +--- expected ++++ actual +@@ -26,14 +26,23 @@ + __webpack_require__.d(__webpack_exports__, { + 'a': function() { return a; } + }); ++/* harmony import */var _unusedModule__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./unusedModule */"./package/unusedModule.js"); + + function a() { + return 42; + } + function b() { +- return /* "./unusedModule" unused */null; ++ return _unusedModule__WEBPACK_IMPORTED_MODULE_0_["default"]; + } + }, ++"./package/unusedModule.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { ++'use strict'; ++__webpack_require__.r(__webpack_exports__); ++__webpack_require__.d(__webpack_exports__, { ++ 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } ++}); ++var __WEBPACK_DEFAULT_EXPORT__ = 42; ++}, + + },function(__webpack_require__) { + var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId) } diff --git a/crates/rspack/tests/tree-shaking/webpack-innergraph-try-globals/expected/main.js b/crates/rspack/tests/tree-shaking/webpack-innergraph-try-globals/snapshot/new_treeshaking.snap similarity index 94% rename from crates/rspack/tests/tree-shaking/webpack-innergraph-try-globals/expected/main.js rename to crates/rspack/tests/tree-shaking/webpack-innergraph-try-globals/snapshot/new_treeshaking.snap index 221c30e5dfb..1926f323acf 100644 --- a/crates/rspack/tests/tree-shaking/webpack-innergraph-try-globals/expected/main.js +++ b/crates/rspack/tests/tree-shaking/webpack-innergraph-try-globals/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./import-module.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -44,4 +48,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/webpack-reexport-namespace-and-default/expected/main.js b/crates/rspack/tests/tree-shaking/webpack-reexport-namespace-and-default/snapshot/new_treeshaking.snap similarity index 81% rename from crates/rspack/tests/tree-shaking/webpack-reexport-namespace-and-default/expected/main.js rename to crates/rspack/tests/tree-shaking/webpack-reexport-namespace-and-default/snapshot/new_treeshaking.snap index 7609fa8b653..52f81d4ac55 100644 --- a/crates/rspack/tests/tree-shaking/webpack-reexport-namespace-and-default/expected/main.js +++ b/crates/rspack/tests/tree-shaking/webpack-reexport-namespace-and-default/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -27,7 +31,6 @@ __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { 'mod': function() { return mod; } }); -/* harmony import */var _package1_script__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./package1/script */"./package1/script.js"); /* harmony import */var _package2_script__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./package2/script */"./package2/script.js"); @@ -40,17 +43,17 @@ __webpack_require__.d(__webpack_exports__, { 'exportDefaultUsed': function() { return exportDefaultUsed; } }); /* harmony import */var _script1__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./script1 */"./package1/script1.js"); -__webpack_require__.es(_script1__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); -var __WEBPACK_DEFAULT_EXPORT__ = /* "./script1" unused */null; +var __WEBPACK_DEFAULT_EXPORT__ = _script1__WEBPACK_IMPORTED_MODULE_0_["default"]; const exportDefaultUsed = false; }, "./package1/script1.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); -/* harmony import */var _script2__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./script2 */"./package1/script2.js"); -__webpack_require__.es(_script2__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); +__webpack_require__.d(__webpack_exports__, { + 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } +}); var __WEBPACK_DEFAULT_EXPORT__ = 1; }, @@ -60,13 +63,22 @@ __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { 'exportDefaultUsed': function() { return exportDefaultUsed; } }); +/* harmony import */var _script3__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./script3 */"./package1/script3.js"); function __WEBPACK_DEFAULT_EXPORT__(){ - return /* "./script3" unused */null; + return _script3__WEBPACK_IMPORTED_MODULE_0_["default"]; } const exportDefaultUsed = false; }, +"./package1/script3.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { +'use strict'; +__webpack_require__.r(__webpack_exports__); +__webpack_require__.d(__webpack_exports__, { + 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } +}); +var __WEBPACK_DEFAULT_EXPORT__ = 1; +}, "./package2/script.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); @@ -75,11 +87,10 @@ __webpack_require__.d(__webpack_exports__, { 'exportDefaultUsed': function() { return exportDefaultUsed; } }); /* harmony import */var _script1__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./script1 */"./package2/script1.js"); -__webpack_require__.es(_script1__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); var __WEBPACK_DEFAULT_EXPORT__ = _script1__WEBPACK_IMPORTED_MODULE_0_["default"]; - const exportDefaultUsed = true; + const exportDefaultUsed = false; }, "./package2/script1.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -95,4 +106,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/webpack-reexport-namespace-and-default/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/webpack-reexport-namespace-and-default/snapshot/snap.diff new file mode 100644 index 00000000000..78a8cf05d69 --- /dev/null +++ b/crates/rspack/tests/tree-shaking/webpack-reexport-namespace-and-default/snapshot/snap.diff @@ -0,0 +1,69 @@ +--- expected ++++ actual +@@ -31,7 +31,6 @@ + __webpack_require__.d(__webpack_exports__, { + 'mod': function() { return mod; } + }); +-/* harmony import */var _package1_script__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./package1/script */"./package1/script.js"); + /* harmony import */var _package2_script__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* ./package2/script */"./package2/script.js"); + + +@@ -44,17 +43,17 @@ + 'exportDefaultUsed': function() { return exportDefaultUsed; } + }); + /* harmony import */var _script1__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./script1 */"./package1/script1.js"); +-__webpack_require__.es(_script1__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); + +-var __WEBPACK_DEFAULT_EXPORT__ = /* "./script1" unused */null; ++var __WEBPACK_DEFAULT_EXPORT__ = _script1__WEBPACK_IMPORTED_MODULE_0_["default"]; + + const exportDefaultUsed = false; + }, + "./package1/script1.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); +-/* harmony import */var _script2__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./script2 */"./package1/script2.js"); +-__webpack_require__.es(_script2__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); ++__webpack_require__.d(__webpack_exports__, { ++ 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } ++}); + + var __WEBPACK_DEFAULT_EXPORT__ = 1; + }, +@@ -64,13 +63,22 @@ + __webpack_require__.d(__webpack_exports__, { + 'exportDefaultUsed': function() { return exportDefaultUsed; } + }); ++/* harmony import */var _script3__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./script3 */"./package1/script3.js"); + + function __WEBPACK_DEFAULT_EXPORT__(){ +- return /* "./script3" unused */null; ++ return _script3__WEBPACK_IMPORTED_MODULE_0_["default"]; + } + + const exportDefaultUsed = false; + }, ++"./package1/script3.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { ++'use strict'; ++__webpack_require__.r(__webpack_exports__); ++__webpack_require__.d(__webpack_exports__, { ++ 'default': function() { return __WEBPACK_DEFAULT_EXPORT__; } ++}); ++var __WEBPACK_DEFAULT_EXPORT__ = 1; ++}, + "./package2/script.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); +@@ -79,11 +87,10 @@ + 'exportDefaultUsed': function() { return exportDefaultUsed; } + }); + /* harmony import */var _script1__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* ./script1 */"./package2/script1.js"); +-__webpack_require__.es(_script1__WEBPACK_IMPORTED_MODULE_0_, __webpack_exports__); + + var __WEBPACK_DEFAULT_EXPORT__ = _script1__WEBPACK_IMPORTED_MODULE_0_["default"]; + +- const exportDefaultUsed = true; ++ const exportDefaultUsed = false; + }, + "./package2/script1.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; diff --git a/crates/rspack/tests/tree-shaking/webpack-side-effects-all-used/expected/main.js b/crates/rspack/tests/tree-shaking/webpack-side-effects-all-used/snapshot/new_treeshaking.snap similarity index 97% rename from crates/rspack/tests/tree-shaking/webpack-side-effects-all-used/expected/main.js rename to crates/rspack/tests/tree-shaking/webpack-side-effects-all-used/snapshot/new_treeshaking.snap index 802bdbec4b0..3cf8df94141 100644 --- a/crates/rspack/tests/tree-shaking/webpack-side-effects-all-used/expected/main.js +++ b/crates/rspack/tests/tree-shaking/webpack-side-effects-all-used/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "../node_modules/pmodule/a.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -78,8 +82,8 @@ __webpack_require__.d(__webpack_exports__, { "./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); -/* harmony import */var pmodule_tracker__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* pmodule/tracker */"../node_modules/pmodule/tracker.js"); /* harmony import */var pmodule__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* pmodule */"../node_modules/pmodule/index.js"); +/* harmony import */var pmodule_tracker__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* pmodule/tracker */"../node_modules/pmodule/tracker.js"); @@ -100,4 +104,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/webpack-side-effects-all-used/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/webpack-side-effects-all-used/snapshot/snap.diff new file mode 100644 index 00000000000..a4a9c3d8af5 --- /dev/null +++ b/crates/rspack/tests/tree-shaking/webpack-side-effects-all-used/snapshot/snap.diff @@ -0,0 +1,12 @@ +--- expected ++++ actual +@@ -82,8 +82,8 @@ + "./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); ++/* harmony import */var pmodule__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* pmodule */"../node_modules/pmodule/index.js"); + /* harmony import */var pmodule_tracker__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* pmodule/tracker */"../node_modules/pmodule/tracker.js"); +-/* harmony import */var pmodule__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* pmodule */"../node_modules/pmodule/index.js"); + + + diff --git a/crates/rspack/tests/tree-shaking/webpack-side-effects-simple-unused/expected/main.js b/crates/rspack/tests/tree-shaking/webpack-side-effects-simple-unused/snapshot/new_treeshaking.snap similarity index 97% rename from crates/rspack/tests/tree-shaking/webpack-side-effects-simple-unused/expected/main.js rename to crates/rspack/tests/tree-shaking/webpack-side-effects-simple-unused/snapshot/new_treeshaking.snap index c209f3164ec..97bb9b0f6c0 100644 --- a/crates/rspack/tests/tree-shaking/webpack-side-effects-simple-unused/expected/main.js +++ b/crates/rspack/tests/tree-shaking/webpack-side-effects-simple-unused/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "../node_modules/pmodule/b.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -62,8 +66,8 @@ __webpack_require__.d(__webpack_exports__, { "./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); -/* harmony import */var pmodule_tracker__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* pmodule/tracker */"../node_modules/pmodule/tracker.js"); /* harmony import */var pmodule__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* pmodule */"../node_modules/pmodule/index.js"); +/* harmony import */var pmodule_tracker__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* pmodule/tracker */"../node_modules/pmodule/tracker.js"); @@ -82,4 +86,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack/tests/tree-shaking/webpack-side-effects-simple-unused/snapshot/snap.diff b/crates/rspack/tests/tree-shaking/webpack-side-effects-simple-unused/snapshot/snap.diff new file mode 100644 index 00000000000..315398d9f1d --- /dev/null +++ b/crates/rspack/tests/tree-shaking/webpack-side-effects-simple-unused/snapshot/snap.diff @@ -0,0 +1,12 @@ +--- expected ++++ actual +@@ -66,8 +66,8 @@ + "./index.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { + 'use strict'; + __webpack_require__.r(__webpack_exports__); ++/* harmony import */var pmodule__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* pmodule */"../node_modules/pmodule/index.js"); + /* harmony import */var pmodule_tracker__WEBPACK_IMPORTED_MODULE_0_ = __webpack_require__(/* pmodule/tracker */"../node_modules/pmodule/tracker.js"); +-/* harmony import */var pmodule__WEBPACK_IMPORTED_MODULE_1_ = __webpack_require__(/* pmodule */"../node_modules/pmodule/index.js"); + + + diff --git a/crates/rspack/tests/tree-shaking/with-assets/expected/main.js b/crates/rspack/tests/tree-shaking/with-assets/snapshot/new_treeshaking.snap similarity index 92% rename from crates/rspack/tests/tree-shaking/with-assets/expected/main.js rename to crates/rspack/tests/tree-shaking/with-assets/snapshot/new_treeshaking.snap index b96b64788cc..09c144491ad 100644 --- a/crates/rspack/tests/tree-shaking/with-assets/expected/main.js +++ b/crates/rspack/tests/tree-shaking/with-assets/snapshot/new_treeshaking.snap @@ -1,3 +1,7 @@ +--- +source: crates/rspack_testing/src/run_fixture.rs +--- +```js title=main.js (self['webpackChunkwebpack'] = self['webpackChunkwebpack'] || []).push([["main"], { "./a.js": function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; @@ -25,4 +29,5 @@ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack var __webpack_exports__ = (__webpack_exec__("./index.js")); } -]); \ No newline at end of file +]); +``` diff --git a/crates/rspack_binding_options/Cargo.toml b/crates/rspack_binding_options/Cargo.toml index 9c9bd76b1a1..ce947b8f301 100644 --- a/crates/rspack_binding_options/Cargo.toml +++ b/crates/rspack_binding_options/Cargo.toml @@ -11,6 +11,7 @@ rspack_core = { path = "../rspack_core" } rspack_error = { path = "../rspack_error" } rspack_identifier = { path = "../rspack_identifier" } rspack_ids = { path = "../rspack_ids" } +rspack_loader_react_refresh = { path = "../rspack_loader_react_refresh" } rspack_loader_runner = { path = "../rspack_loader_runner" } rspack_loader_sass = { path = "../rspack_loader_sass" } rspack_loader_swc = { path = "../rspack_loader_swc" } diff --git a/crates/rspack_binding_options/src/options/mod.rs b/crates/rspack_binding_options/src/options/mod.rs index f52d70be30b..e7e1810497b 100644 --- a/crates/rspack_binding_options/src/options/mod.rs +++ b/crates/rspack_binding_options/src/options/mod.rs @@ -3,6 +3,7 @@ use rspack_core::{ BoxPlugin, CompilerOptions, Context, DevServerOptions, Devtool, Experiments, IncrementalRebuild, IncrementalRebuildMakeState, ModuleOptions, ModuleType, OutputOptions, PluginExt, }; +use rspack_plugin_javascript::{FlagDependencyExportsPlugin, FlagDependencyUsagePlugin}; use serde::Deserialize; mod raw_builtins; @@ -124,9 +125,6 @@ impl RawOptionsApply for RawOptions { .boxed(), ); plugins.push(rspack_plugin_json::JsonPlugin {}.boxed()); - if dev_server.hot { - plugins.push(rspack_plugin_hmr::HotModuleReplacementPlugin {}.boxed()); - } plugins.push(rspack_plugin_runtime::RuntimePlugin {}.boxed()); if experiments.lazy_compilation { plugins.push(rspack_plugin_runtime::LazyCompilationPlugin {}.boxed()); @@ -158,6 +156,15 @@ impl RawOptionsApply for RawOptions { plugins.push(rspack_ids::NamedChunkIdsPlugin::new(None, None).boxed()); + if experiments.rspack_future.new_treeshaking { + if optimization.provided_exports { + plugins.push(FlagDependencyExportsPlugin::default().boxed()); + } + if optimization.used_exports.is_enable() { + plugins.push(FlagDependencyUsagePlugin::default().boxed()); + } + } + // Notice the plugin need to be placed after SplitChunksPlugin if optimization.remove_empty_chunks { plugins.push(rspack_plugin_remove_empty_chunks::RemoveEmptyChunksPlugin.boxed()); diff --git a/crates/rspack_binding_options/src/options/raw_builtins/mod.rs b/crates/rspack_binding_options/src/options/raw_builtins/mod.rs index 47005a64ff2..dc028bb5bea 100644 --- a/crates/rspack_binding_options/src/options/raw_builtins/mod.rs +++ b/crates/rspack_binding_options/src/options/raw_builtins/mod.rs @@ -10,51 +10,68 @@ use napi::{ JsUnknown, }; use napi_derive::napi; -use rspack_core::{ - BoxPlugin, CopyPluginConfig, Define, DefinePlugin, PluginExt, Provide, ProvidePlugin, -}; +use rspack_core::{BoxPlugin, Define, DefinePlugin, PluginExt, Provide, ProvidePlugin}; use rspack_error::Result; use rspack_napi_shared::NapiResultExt; use rspack_plugin_banner::BannerPlugin; -use rspack_plugin_copy::CopyPlugin; +use rspack_plugin_copy::{CopyRspackPlugin, CopyRspackPluginOptions}; use rspack_plugin_entry::EntryPlugin; use rspack_plugin_externals::{ - electron_target_plugin, http_externals_plugin, node_target_plugin, ExternalsPlugin, + electron_target_plugin, http_externals_rspack_plugin, node_target_plugin, ExternalsPlugin, }; -use rspack_plugin_html::HtmlPlugin; +use rspack_plugin_hmr::HotModuleReplacementPlugin; +use rspack_plugin_html::HtmlRspackPlugin; +use rspack_plugin_library::enable_library_plugin; use rspack_plugin_progress::ProgressPlugin; -use rspack_plugin_swc_css_minimizer::SwcCssMinimizerPlugin; -use rspack_plugin_swc_js_minimizer::SwcJsMinimizerPlugin; +use rspack_plugin_runtime::{ + enable_chunk_loading_plugin, ArrayPushCallbackChunkFormatPlugin, CommonJsChunkFormatPlugin, + ModuleChunkFormatPlugin, +}; +use rspack_plugin_swc_css_minimizer::SwcCssMinimizerRspackPlugin; +use rspack_plugin_swc_js_minimizer::SwcJsMinimizerRspackPlugin; +use rspack_plugin_wasm::enable_wasm_loading_plugin; pub use self::{ - raw_banner::RawBannerConfig, raw_copy::RawCopyConfig, raw_html::RawHtmlPluginConfig, - raw_progress::RawProgressPluginConfig, raw_swc_js_minimizer::RawMinification, + raw_banner::RawBannerPluginOptions, raw_copy::RawCopyRspackPluginOptions, + raw_html::RawHtmlRspackPluginOptions, raw_progress::RawProgressPluginOptions, + raw_swc_js_minimizer::RawSwcJsMinimizerRspackPluginOptions, }; use crate::{ - RawEntryPluginOptions, RawExternalsPluginOptions, RawHttpExternalsPluginOptions, RawOptionsApply, + RawEntryPluginOptions, RawExternalsPluginOptions, RawHttpExternalsRspackPluginOptions, + RawOptionsApply, }; #[napi(string_enum)] #[derive(Debug)] -pub enum BuiltinPluginKind { - Define, - Provide, - Banner, - Progress, - Copy, - Html, - SwcJsMinimizer, - SwcCssMinimizer, - Entry, - Externals, - NodeTarget, - ElectronTarget, - HttpExternals, +pub enum BuiltinPluginName { + // webpack also have these plugins + DefinePlugin, + ProvidePlugin, + BannerPlugin, + ProgressPlugin, + EntryPlugin, + ExternalsPlugin, + NodeTargetPlugin, + ElectronTargetPlugin, + EnableChunkLoadingPlugin, + EnableLibraryPlugin, + EnableWasmLoadingPlugin, + CommonJsChunkFormatPlugin, + ArrayPushCallbackChunkFormatPlugin, + ModuleChunkFormatPlugin, + HotModuleReplacementPlugin, + + // rspack specific plugins + HttpExternalsRspackPlugin, + CopyRspackPlugin, + HtmlRspackPlugin, + SwcJsMinimizerRspackPlugin, + SwcCssMinimizerRspackPlugin, } #[napi(object)] pub struct BuiltinPlugin { - pub kind: BuiltinPluginKind, + pub name: BuiltinPluginName, pub options: JsUnknown, } @@ -65,46 +82,29 @@ impl RawOptionsApply for BuiltinPlugin { self, plugins: &mut Vec, ) -> std::result::Result { - match self.kind { - BuiltinPluginKind::Define => { + match self.name { + // webpack also have these plugins + BuiltinPluginName::DefinePlugin => { let plugin = DefinePlugin::new(downcast_into::(self.options)?).boxed(); plugins.push(plugin); } - BuiltinPluginKind::Provide => { + BuiltinPluginName::ProvidePlugin => { let plugin = ProvidePlugin::new(downcast_into::(self.options)?).boxed(); plugins.push(plugin); } - BuiltinPluginKind::Banner => { + BuiltinPluginName::BannerPlugin => { let plugin = - BannerPlugin::new(downcast_into::(self.options)?.try_into()?).boxed(); - plugins.push(plugin); - } - BuiltinPluginKind::SwcJsMinimizer => { - let plugin = - SwcJsMinimizerPlugin::new(downcast_into::(self.options)?.try_into()?) + BannerPlugin::new(downcast_into::(self.options)?.try_into()?) .boxed(); plugins.push(plugin); } - BuiltinPluginKind::SwcCssMinimizer => plugins.push(SwcCssMinimizerPlugin {}.boxed()), - BuiltinPluginKind::Progress => { + BuiltinPluginName::ProgressPlugin => { let plugin = - ProgressPlugin::new(downcast_into::(self.options)?.into()) + ProgressPlugin::new(downcast_into::(self.options)?.into()) .boxed(); plugins.push(plugin); } - BuiltinPluginKind::Copy => { - let plugin = CopyPlugin::new( - CopyPluginConfig::from(downcast_into::(self.options)?).patterns, - ) - .boxed(); - plugins.push(plugin); - } - BuiltinPluginKind::Html => { - let plugin = - HtmlPlugin::new(downcast_into::(self.options)?.into()).boxed(); - plugins.push(plugin); - } - BuiltinPluginKind::Entry => { + BuiltinPluginName::EntryPlugin => { let plugin_options = downcast_into::(self.options)?; let context = plugin_options.context.into(); let entry_request = plugin_options.entry; @@ -112,7 +112,7 @@ impl RawOptionsApply for BuiltinPlugin { let plugin = EntryPlugin::new(context, entry_request, options).boxed(); plugins.push(plugin); } - BuiltinPluginKind::Externals => { + BuiltinPluginName::ExternalsPlugin => { let plugin_options = downcast_into::(self.options)?; let externals = plugin_options .externals @@ -122,14 +122,66 @@ impl RawOptionsApply for BuiltinPlugin { let plugin = ExternalsPlugin::new(plugin_options.r#type, externals).boxed(); plugins.push(plugin); } - BuiltinPluginKind::NodeTarget => plugins.push(node_target_plugin()), - BuiltinPluginKind::ElectronTarget => { + BuiltinPluginName::NodeTargetPlugin => plugins.push(node_target_plugin()), + BuiltinPluginName::ElectronTargetPlugin => { let context = downcast_into::(self.options)?; - electron_target_plugin(context.into(), plugins) + electron_target_plugin(context.into(), plugins); + } + BuiltinPluginName::EnableChunkLoadingPlugin => { + let chunk_loading_type = downcast_into::(self.options)?; + enable_chunk_loading_plugin(chunk_loading_type.as_str().into(), plugins); + } + BuiltinPluginName::EnableLibraryPlugin => { + let library_type = downcast_into::(self.options)?; + enable_library_plugin(library_type, plugins); + } + BuiltinPluginName::EnableWasmLoadingPlugin => { + let wasm_loading_type = downcast_into::(self.options)?; + plugins.push(enable_wasm_loading_plugin( + wasm_loading_type.as_str().into(), + )); + } + BuiltinPluginName::CommonJsChunkFormatPlugin => { + plugins.push(CommonJsChunkFormatPlugin.boxed()); } - BuiltinPluginKind::HttpExternals => { - let plugin_options = downcast_into::(self.options)?; - let plugin = http_externals_plugin(plugin_options.css); + BuiltinPluginName::ArrayPushCallbackChunkFormatPlugin => { + plugins.push(ArrayPushCallbackChunkFormatPlugin.boxed()); + } + BuiltinPluginName::ModuleChunkFormatPlugin => { + plugins.push(ModuleChunkFormatPlugin.boxed()); + } + BuiltinPluginName::HotModuleReplacementPlugin => { + plugins.push(HotModuleReplacementPlugin.boxed()); + } + + // rspack specific plugins + BuiltinPluginName::HttpExternalsRspackPlugin => { + let plugin_options = downcast_into::(self.options)?; + let plugin = http_externals_rspack_plugin(plugin_options.css, plugin_options.web_async); + plugins.push(plugin); + } + BuiltinPluginName::SwcJsMinimizerRspackPlugin => { + let plugin = SwcJsMinimizerRspackPlugin::new( + downcast_into::(self.options)?.try_into()?, + ) + .boxed(); + plugins.push(plugin); + } + BuiltinPluginName::SwcCssMinimizerRspackPlugin => { + plugins.push(SwcCssMinimizerRspackPlugin {}.boxed()) + } + BuiltinPluginName::CopyRspackPlugin => { + let plugin = CopyRspackPlugin::new( + CopyRspackPluginOptions::from(downcast_into::(self.options)?) + .patterns, + ) + .boxed(); + plugins.push(plugin); + } + BuiltinPluginName::HtmlRspackPlugin => { + let plugin = + HtmlRspackPlugin::new(downcast_into::(self.options)?.into()) + .boxed(); plugins.push(plugin); } } 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 88bdfd82a2a..5767c5cb949 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 @@ -9,7 +9,7 @@ use rspack_napi_shared::{ NapiResultExt, NAPI_ENV, }; use rspack_plugin_banner::{ - BannerCondition, BannerConditions, BannerConfig, BannerContent, BannerContentFnCtx, + BannerContent, BannerContentFnCtx, BannerPluginOptions, BannerRule, BannerRules, }; use serde::Deserialize; @@ -18,7 +18,7 @@ use crate::chunk::JsChunk; #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] #[napi(object)] -pub struct RawBannerCondition { +pub struct RawBannerRule { #[napi(ts_type = r#""string" | "regexp""#)] pub r#type: String, pub string_matcher: Option, @@ -28,12 +28,12 @@ pub struct RawBannerCondition { #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] #[napi(object)] -pub struct RawBannerConditions { +pub struct RawBannerRules { #[napi(ts_type = r#""string" | "regexp" | "array""#)] pub r#type: String, pub string_matcher: Option, pub regexp_matcher: Option, - pub array_matcher: Option>, + pub array_matcher: Option>, } #[napi(object)] @@ -109,20 +109,20 @@ impl TryFrom for BannerContent { #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] #[napi(object)] -pub struct RawBannerConfig { +pub struct RawBannerPluginOptions { pub banner: RawBannerContent, pub entry_only: Option, pub footer: Option, pub raw: Option, - pub test: Option, - pub include: Option, - pub exclude: Option, + pub test: Option, + pub include: Option, + pub exclude: Option, } -impl TryFrom for BannerCondition { +impl TryFrom for BannerRule { type Error = rspack_error::Error; - fn try_from(x: RawBannerCondition) -> rspack_error::Result { + fn try_from(x: RawBannerRule) -> rspack_error::Result { let result = match x.r#type.as_str() { "string" => Self::String(x.string_matcher.ok_or_else(|| { internal_error!("should have a string_matcher when BannerConditions.type is \"string\"") @@ -144,11 +144,11 @@ impl TryFrom for BannerCondition { } } -impl TryFrom for BannerConditions { +impl TryFrom for BannerRules { type Error = rspack_error::Error; - fn try_from(x: RawBannerConditions) -> rspack_error::Result { - let result: BannerConditions = match x.r#type.as_str() { + fn try_from(x: RawBannerRules) -> rspack_error::Result { + let result: BannerRules = match x.r#type.as_str() { "string" => Self::String(x.string_matcher.ok_or_else(|| { internal_error!("should have a string_matcher when BannerConditions.type is \"string\"") })?), @@ -180,14 +180,14 @@ impl TryFrom for BannerConditions { } } -impl TryFrom for BannerConfig { +impl TryFrom for BannerPluginOptions { type Error = rspack_error::Error; - fn try_from(value: RawBannerConfig) -> std::result::Result { + fn try_from(value: RawBannerPluginOptions) -> std::result::Result { fn try_condition( - raw_condition: Option, - ) -> Result, rspack_error::Error> { - let condition: Option = if let Some(test) = raw_condition { + raw_condition: Option, + ) -> Result, rspack_error::Error> { + let condition: Option = if let Some(test) = raw_condition { Some(test.try_into()?) } else { None @@ -196,7 +196,7 @@ impl TryFrom for BannerConfig { Ok(condition) } - Ok(BannerConfig { + Ok(BannerPluginOptions { banner: value.banner.try_into()?, entry_only: value.entry_only, footer: value.footer, diff --git a/crates/rspack_binding_options/src/options/raw_builtins/raw_copy.rs b/crates/rspack_binding_options/src/options/raw_builtins/raw_copy.rs index af050483e24..2f077d72367 100644 --- a/crates/rspack_binding_options/src/options/raw_builtins/raw_copy.rs +++ b/crates/rspack_binding_options/src/options/raw_builtins/raw_copy.rs @@ -1,13 +1,13 @@ use std::path::PathBuf; use napi_derive::napi; -use rspack_core::{CopyPluginConfig, GlobOptions, Pattern, ToType}; +use rspack_plugin_copy::{CopyGlobOptions, CopyPattern, CopyRspackPluginOptions, ToType}; use serde::Deserialize; #[derive(Debug, Deserialize, Clone)] #[serde(rename_all = "camelCase")] #[napi(object)] -pub struct RawPattern { +pub struct RawCopyPattern { pub from: String, pub to: Option, pub context: Option, @@ -15,13 +15,13 @@ pub struct RawPattern { pub no_error_on_missing: bool, pub force: bool, pub priority: i32, - pub glob_options: RawGlobOptions, + pub glob_options: RawCopyGlobOptions, } #[derive(Debug, Deserialize, Clone)] #[serde(rename_all = "camelCase")] #[napi(object)] -pub struct RawGlobOptions { +pub struct RawCopyGlobOptions { pub case_sensitive_match: Option, pub dot: Option, pub ignore: Option>, @@ -30,13 +30,13 @@ pub struct RawGlobOptions { #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] #[napi(object)] -pub struct RawCopyConfig { - pub patterns: Vec, +pub struct RawCopyRspackPluginOptions { + pub patterns: Vec, } -impl From for Pattern { - fn from(value: RawPattern) -> Self { - let RawPattern { +impl From for CopyPattern { + fn from(value: RawCopyPattern) -> Self { + let RawCopyPattern { from, to, context, @@ -68,7 +68,7 @@ impl From for Pattern { info: None, force, priority, - glob_options: GlobOptions { + glob_options: CopyGlobOptions { case_sensitive_match: glob_options.case_sensitive_match, dot: glob_options.dot, ignore: glob_options.ignore.map(|ignore| { @@ -82,8 +82,8 @@ impl From for Pattern { } } -impl From for CopyPluginConfig { - fn from(val: RawCopyConfig) -> Self { +impl From for CopyRspackPluginOptions { + fn from(val: RawCopyRspackPluginOptions) -> Self { Self { patterns: val.patterns.into_iter().map(Into::into).collect(), } diff --git a/crates/rspack_binding_options/src/options/raw_builtins/raw_html.rs b/crates/rspack_binding_options/src/options/raw_builtins/raw_html.rs index 12d216207bd..ac9ed5e4aec 100644 --- a/crates/rspack_binding_options/src/options/raw_builtins/raw_html.rs +++ b/crates/rspack_binding_options/src/options/raw_builtins/raw_html.rs @@ -2,22 +2,22 @@ use std::collections::HashMap; use std::str::FromStr; use napi_derive::napi; -use rspack_plugin_html::config::HtmlPluginConfig; -use rspack_plugin_html::config::HtmlPluginConfigInject; -use rspack_plugin_html::config::HtmlPluginConfigScriptLoading; +use rspack_plugin_html::config::HtmlInject; +use rspack_plugin_html::config::HtmlRspackPluginOptions; +use rspack_plugin_html::config::HtmlScriptLoading; use rspack_plugin_html::sri::HtmlSriHashFunction; use serde::Deserialize; use serde::Serialize; -pub type RawHtmlPluginConfigScriptLoading = String; -pub type RawHtmlPluginConfigInject = String; +pub type RawHtmlScriptLoading = String; +pub type RawHtmlInject = String; pub type RawHtmlSriHashFunction = String; pub type RawHtmlFilename = String; #[derive(Deserialize, Debug, Serialize)] #[serde(rename_all = "camelCase")] #[napi(object)] -pub struct RawHtmlPluginConfig { +pub struct RawHtmlRspackPluginOptions { /// emitted file name in output path #[napi(ts_type = "string")] pub filename: Option, @@ -25,14 +25,14 @@ pub struct RawHtmlPluginConfig { pub template: Option, pub template_content: Option, pub template_parameters: Option>, - /// `head`, `body` or None - #[napi(ts_type = "\"head\" | \"body\"")] - pub inject: Option, + /// "head", "body" or "false" + #[napi(ts_type = "\"head\" | \"body\" | \"false\"")] + pub inject: RawHtmlInject, /// path or `auto` pub public_path: Option, /// `blocking`, `defer`, or `module` #[napi(ts_type = "\"blocking\" | \"defer\" | \"module\"")] - pub script_loading: Option, + pub script_loading: RawHtmlScriptLoading, /// entry_chunk_name (only entry chunks are supported) pub chunks: Option>, @@ -45,24 +45,18 @@ pub struct RawHtmlPluginConfig { pub meta: Option>>, } -impl From for HtmlPluginConfig { - fn from(value: RawHtmlPluginConfig) -> Self { - let inject = value.inject.as_ref().map(|s| { - HtmlPluginConfigInject::from_str(s).unwrap_or_else(|_| panic!("Invalid inject value: {s}")) - }); +impl From for HtmlRspackPluginOptions { + fn from(value: RawHtmlRspackPluginOptions) -> Self { + let inject = HtmlInject::from_str(&value.inject).expect("Invalid inject value"); - let script_loading = HtmlPluginConfigScriptLoading::from_str( - &value - .script_loading - .unwrap_or_else(|| String::from("defer")), - ) - .expect("value.script_loading has unwrap_or_else so this will never happen"); + let script_loading = + HtmlScriptLoading::from_str(&value.script_loading).expect("Invalid script_loading value"); let sri = value.sri.as_ref().map(|s| { HtmlSriHashFunction::from_str(s).unwrap_or_else(|_| panic!("Invalid sri value: {s}")) }); - HtmlPluginConfig { + HtmlRspackPluginOptions { filename: value.filename.unwrap_or_else(|| String::from("index.html")), template: value.template, template_content: value.template_content, diff --git a/crates/rspack_binding_options/src/options/raw_builtins/raw_progress.rs b/crates/rspack_binding_options/src/options/raw_builtins/raw_progress.rs index b263d8a920b..e8585fef0f3 100644 --- a/crates/rspack_binding_options/src/options/raw_builtins/raw_progress.rs +++ b/crates/rspack_binding_options/src/options/raw_builtins/raw_progress.rs @@ -1,16 +1,16 @@ use napi_derive::napi; -use rspack_plugin_progress::ProgressPluginConfig; +use rspack_plugin_progress::ProgressPluginOptions; use serde::{Deserialize, Serialize}; #[derive(Deserialize, Debug, Serialize, Clone)] #[serde(rename_all = "camelCase")] #[napi(object)] -pub struct RawProgressPluginConfig { +pub struct RawProgressPluginOptions { pub prefix: Option, } -impl From for ProgressPluginConfig { - fn from(value: RawProgressPluginConfig) -> Self { +impl From for ProgressPluginOptions { + fn from(value: RawProgressPluginOptions) -> Self { Self { prefix: value.prefix, } 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 f834e6aeb80..6b93a97bdc4 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,12 +1,14 @@ use napi_derive::napi; use rspack_error::internal_error; -use rspack_plugin_swc_js_minimizer::{Minification, MinificationCondition, MinificationConditions}; +use rspack_plugin_swc_js_minimizer::{ + SwcJsMinimizerRspackPluginOptions, SwcJsMinimizerRule, SwcJsMinimizerRules, +}; use serde::Deserialize; #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] #[napi(object)] -pub struct RawMinificationCondition { +pub struct RawSwcJsMinimizerRule { #[napi(ts_type = r#""string" | "regexp""#)] pub r#type: String, pub string_matcher: Option, @@ -16,18 +18,18 @@ pub struct RawMinificationCondition { #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] #[napi(object)] -pub struct RawMinificationConditions { +pub struct RawSwcJsMinimizerRules { #[napi(ts_type = r#""string" | "regexp" | "array""#)] pub r#type: String, pub string_matcher: Option, pub regexp_matcher: Option, - pub array_matcher: Option>, + pub array_matcher: Option>, } #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] #[napi(object)] -pub struct RawMinification { +pub struct RawSwcJsMinimizerRspackPluginOptions { pub passes: u32, pub drop_console: bool, pub keep_class_names: bool, @@ -37,19 +39,19 @@ pub struct RawMinification { pub ascii_only: bool, pub pure_funcs: Vec, pub extract_comments: Option, - pub test: Option, - pub include: Option, - pub exclude: Option, + pub test: Option, + pub include: Option, + pub exclude: Option, } -impl TryFrom for Minification { +impl TryFrom for SwcJsMinimizerRspackPluginOptions { type Error = rspack_error::Error; - fn try_from(value: RawMinification) -> rspack_error::Result { + fn try_from(value: RawSwcJsMinimizerRspackPluginOptions) -> rspack_error::Result { fn try_condition( - raw_condition: Option, - ) -> Result, rspack_error::Error> { - let condition: Option = if let Some(test) = raw_condition { + raw_condition: Option, + ) -> Result, rspack_error::Error> { + let condition: Option = if let Some(test) = raw_condition { Some(test.try_into()?) } else { None @@ -74,10 +76,10 @@ impl TryFrom for Minification { } } -impl TryFrom for MinificationCondition { +impl TryFrom for SwcJsMinimizerRule { type Error = rspack_error::Error; - fn try_from(x: RawMinificationCondition) -> rspack_error::Result { + fn try_from(x: RawSwcJsMinimizerRule) -> rspack_error::Result { let result = match x.r#type.as_str() { "string" => Self::String(x.string_matcher.ok_or_else(|| { internal_error!( @@ -101,11 +103,11 @@ impl TryFrom for MinificationCondition { } } -impl TryFrom for MinificationConditions { +impl TryFrom for SwcJsMinimizerRules { type Error = rspack_error::Error; - fn try_from(value: RawMinificationConditions) -> rspack_error::Result { - let result: MinificationConditions = match value.r#type.as_str() { + fn try_from(value: RawSwcJsMinimizerRules) -> rspack_error::Result { + let result = match value.r#type.as_str() { "string" => Self::String(value.string_matcher.ok_or_else(|| { internal_error!("should have a string_matcher when MinificationConditions.type is \"string\"") })?), diff --git a/crates/rspack_binding_options/src/options/raw_experiments.rs b/crates/rspack_binding_options/src/options/raw_experiments.rs index aab912c8761..d5a5a738822 100644 --- a/crates/rspack_binding_options/src/options/raw_experiments.rs +++ b/crates/rspack_binding_options/src/options/raw_experiments.rs @@ -15,6 +15,8 @@ pub struct RawIncrementalRebuild { #[napi(object)] pub struct RawRspackFuture { pub new_resolver: bool, + pub new_treeshaking: bool, + pub disable_transform_by_default: bool, } #[derive(Deserialize, Debug, Default)] @@ -33,6 +35,8 @@ impl From for RspackFuture { fn from(value: RawRspackFuture) -> Self { Self { new_resolver: value.new_resolver, + new_treeshaking: value.new_treeshaking, + disable_transform_by_default: value.disable_transform_by_default, } } } diff --git a/crates/rspack_binding_options/src/options/raw_external.rs b/crates/rspack_binding_options/src/options/raw_external.rs index 5d2e5af36b3..23c0a09b8a8 100644 --- a/crates/rspack_binding_options/src/options/raw_external.rs +++ b/crates/rspack_binding_options/src/options/raw_external.rs @@ -19,8 +19,9 @@ use { #[derive(Deserialize)] #[serde(rename_all = "camelCase")] #[napi(object)] -pub struct RawHttpExternalsPluginOptions { +pub struct RawHttpExternalsRspackPluginOptions { pub css: bool, + pub web_async: bool, } #[derive(Deserialize)] @@ -61,11 +62,12 @@ impl Debug for RawExternalItem { #[serde(rename_all = "camelCase")] #[napi(object)] pub struct RawExternalItemValue { - #[napi(ts_type = r#""string" | "bool" | "array""#)] + #[napi(ts_type = r#""string" | "bool" | "array" | "object""#)] pub r#type: String, pub string_payload: Option, pub bool_payload: Option, pub array_payload: Option>, + pub object_payload: Option>>, } impl From for ExternalItemValue { @@ -86,6 +88,13 @@ impl From for ExternalItemValue { .array_payload .expect("should have a array_payload when RawExternalItemValue.type is \"array\""), ), + "object" => Self::Object( + value + .object_payload + .expect("should have a object_payload when RawExternalItemValue.type is \"object\"") + .into_iter() + .collect(), + ), _ => unreachable!(), } } 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 60024b410ad..4bb450a7127 100644 --- a/crates/rspack_binding_options/src/options/raw_module/mod.rs +++ b/crates/rspack_binding_options/src/options/raw_module/mod.rs @@ -15,6 +15,7 @@ use rspack_core::{ ModuleRuleUseLoader, ModuleType, ParserOptions, ParserOptionsByModuleType, }; use rspack_error::internal_error; +use rspack_loader_react_refresh::REACT_REFRESH_LOADER_IDENTIFIER; use rspack_loader_sass::SASS_LOADER_IDENTIFIER; use rspack_loader_swc::SWC_LOADER_IDENTIFIER; use serde::Deserialize; @@ -44,6 +45,11 @@ pub fn get_builtin_loader(builtin: &str, options: Option<&str>) -> BoxLoader { .with_identifier(builtin.into()), ); } + if builtin.starts_with(REACT_REFRESH_LOADER_IDENTIFIER) { + return Arc::new( + rspack_loader_react_refresh::ReactRefreshLoader::default().with_identifier(builtin.into()), + ); + } unreachable!("Unexpected builtin loader: {builtin}") } diff --git a/crates/rspack_binding_options/src/options/raw_optimization.rs b/crates/rspack_binding_options/src/options/raw_optimization.rs index e7af9e67e61..f42496fb2d0 100644 --- a/crates/rspack_binding_options/src/options/raw_optimization.rs +++ b/crates/rspack_binding_options/src/options/raw_optimization.rs @@ -1,6 +1,6 @@ use better_scoped_tls::scoped_tls; use napi_derive::napi; -use rspack_core::{Optimization, PluginExt, SideEffectOption}; +use rspack_core::{Optimization, PluginExt, SideEffectOption, UsedExportsOption}; use rspack_error::internal_error; use rspack_ids::{ DeterministicChunkIdsPlugin, DeterministicModuleIdsPlugin, NamedChunkIdsPlugin, @@ -23,6 +23,8 @@ pub struct RawOptimizationOptions { pub remove_available_modules: bool, pub remove_empty_chunks: bool, pub side_effects: String, + pub used_exports: String, + pub provided_exports: bool, pub real_content_hash: bool, } @@ -71,6 +73,8 @@ impl RawOptionsApply for RawOptimizationOptions { remove_available_modules: self.remove_available_modules, remove_empty_chunks: self.remove_empty_chunks, side_effects: SideEffectOption::from(self.side_effects.as_str()), + provided_exports: self.provided_exports, + used_exports: UsedExportsOption::from(self.used_exports.as_str()), }) } } diff --git a/crates/rspack_binding_options/src/options/raw_output.rs b/crates/rspack_binding_options/src/options/raw_output.rs index fb4a28834da..003f2fcb833 100644 --- a/crates/rspack_binding_options/src/options/raw_output.rs +++ b/crates/rspack_binding_options/src/options/raw_output.rs @@ -1,9 +1,8 @@ use napi_derive::napi; use rspack_core::{ to_identifier, BoxPlugin, CrossOriginLoading, LibraryAuxiliaryComment, LibraryName, - LibraryOptions, OutputOptions, PluginExt, TrustedTypes, + LibraryOptions, OutputOptions, TrustedTypes, }; -use rspack_error::internal_error; use serde::Deserialize; use crate::RawOptionsApply; @@ -129,6 +128,7 @@ pub struct RawOutputOptions { pub css_chunk_filename: String, pub hot_update_main_filename: String, pub hot_update_chunk_filename: String, + pub hot_update_global: String, pub unique_name: String, pub chunk_loading_global: String, pub library: Option, @@ -138,7 +138,6 @@ pub struct RawOutputOptions { pub import_function_name: String, pub iife: bool, pub module: bool, - pub chunk_format: String, pub chunk_loading: String, pub enabled_chunk_loading_types: Option>, pub trusted_types: Option, @@ -155,23 +154,7 @@ pub struct RawOutputOptions { impl RawOptionsApply for RawOutputOptions { type Options = OutputOptions; - fn apply(self, plugins: &mut Vec) -> Result { - self.apply_chunk_format_plugin(plugins)?; - if let Some(chunk_loading_types) = self.enabled_chunk_loading_types.as_ref() { - for chunk_loading_type in chunk_loading_types { - rspack_plugin_runtime::enable_chunk_loading_plugin( - chunk_loading_type.as_str().into(), - plugins, - ); - } - } - self.apply_library_plugin(plugins); - for wasm_loading_type in self.enabled_wasm_loading_types { - plugins.push(rspack_plugin_wasm::enable_wasm_loading_plugin( - wasm_loading_type.as_str().into(), - )); - } - + fn apply(self, _: &mut Vec) -> Result { Ok(OutputOptions { path: self.path.into(), clean: self.clean, @@ -189,6 +172,7 @@ impl RawOptionsApply for RawOutputOptions { css_chunk_filename: self.css_chunk_filename.into(), hot_update_main_filename: self.hot_update_main_filename.into(), hot_update_chunk_filename: self.hot_update_chunk_filename.into(), + hot_update_global: self.hot_update_global, library: self.library.map(Into::into), strict_module_error_handling: self.strict_module_error_handling, enabled_library_types: self.enabled_library_types, @@ -209,165 +193,3 @@ impl RawOptionsApply for RawOutputOptions { }) } } - -impl RawOutputOptions { - fn apply_chunk_format_plugin( - &self, - plugins: &mut Vec, - ) -> Result<(), rspack_error::Error> { - match self.chunk_format.as_str() { - "array-push" => { - plugins.push(rspack_plugin_runtime::ArrayPushCallbackChunkFormatPlugin {}.boxed()); - } - "commonjs" => plugins.push(rspack_plugin_runtime::CommonJsChunkFormatPlugin {}.boxed()), - "module" => { - plugins.push(rspack_plugin_runtime::ModuleChunkFormatPlugin {}.boxed()); - } - "false" => {} - _ => { - return Err(internal_error!( - "Unsupported chunk format '{}'", - self.chunk_format - )) - } - } - Ok(()) - } - - fn apply_library_plugin(&self, plugins: &mut Vec) { - if let Some(enabled_library_types) = &self.enabled_library_types { - for library in enabled_library_types { - match library.as_str() { - "var" => { - plugins.push( - rspack_plugin_library::AssignLibraryPlugin::new( - rspack_plugin_library::AssignLibraryPluginOptions { - library_type: library.clone(), - prefix: vec![], - declare: true, - unnamed: rspack_plugin_library::Unnamed::Error, - named: None, - }, - ) - .boxed(), - ); - } - "assign-properties" => { - plugins.push( - rspack_plugin_library::AssignLibraryPlugin::new( - rspack_plugin_library::AssignLibraryPluginOptions { - library_type: library.clone(), - prefix: vec![], - declare: false, - unnamed: rspack_plugin_library::Unnamed::Error, - named: Some(rspack_plugin_library::Named::Copy), - }, - ) - .boxed(), - ); - } - "assign" => { - plugins.push( - rspack_plugin_library::AssignLibraryPlugin::new( - rspack_plugin_library::AssignLibraryPluginOptions { - library_type: library.clone(), - prefix: vec![], - declare: false, - unnamed: rspack_plugin_library::Unnamed::Error, - named: None, - }, - ) - .boxed(), - ); - } - "this" | "window" | "self" => { - plugins.push( - rspack_plugin_library::AssignLibraryPlugin::new( - rspack_plugin_library::AssignLibraryPluginOptions { - library_type: library.clone(), - prefix: vec![library.to_string()], - declare: false, - unnamed: rspack_plugin_library::Unnamed::Copy, - named: None, - }, - ) - .boxed(), - ); - } - "global" => { - plugins.push( - rspack_plugin_library::AssignLibraryPlugin::new( - rspack_plugin_library::AssignLibraryPluginOptions { - library_type: library.clone(), - prefix: vec![self.global_object.clone()], - declare: false, - unnamed: rspack_plugin_library::Unnamed::Copy, - named: None, - }, - ) - .boxed(), - ); - } - "commonjs" => { - plugins.push( - rspack_plugin_library::AssignLibraryPlugin::new( - rspack_plugin_library::AssignLibraryPluginOptions { - library_type: library.clone(), - prefix: vec!["exports".to_string()], - declare: false, - unnamed: rspack_plugin_library::Unnamed::Copy, - named: None, - }, - ) - .boxed(), - ); - } - "commonjs-static" => { - plugins.push( - rspack_plugin_library::AssignLibraryPlugin::new( - rspack_plugin_library::AssignLibraryPluginOptions { - library_type: library.clone(), - prefix: vec!["exports".to_string()], - declare: false, - unnamed: rspack_plugin_library::Unnamed::Static, - named: None, - }, - ) - .boxed(), - ); - } - "commonjs2" | "commonjs-module" => { - plugins.push( - rspack_plugin_library::AssignLibraryPlugin::new( - rspack_plugin_library::AssignLibraryPluginOptions { - library_type: library.clone(), - prefix: vec!["module".to_string(), "exports".to_string()], - declare: false, - unnamed: rspack_plugin_library::Unnamed::Assign, - named: None, - }, - ) - .boxed(), - ); - } - "umd" | "umd2" => { - plugins.push(rspack_plugin_library::ExportPropertyLibraryPlugin::default().boxed()); - plugins.push(rspack_plugin_library::UmdLibraryPlugin::new("umd2".eq(library)).boxed()); - } - "amd" | "amd-require" => { - plugins.push(rspack_plugin_library::ExportPropertyLibraryPlugin::default().boxed()); - plugins.push( - rspack_plugin_library::AmdLibraryPlugin::new("amd-require".eq(library)).boxed(), - ); - } - "module" => { - plugins.push(rspack_plugin_library::ExportPropertyLibraryPlugin::default().boxed()); - plugins.push(rspack_plugin_library::ModuleLibraryPlugin::default().boxed()); - } - "system" => plugins.push(rspack_plugin_library::SystemLibraryPlugin::default().boxed()), - _ => {} - } - } - } - } -} diff --git a/crates/rspack_core/Cargo.toml b/crates/rspack_core/Cargo.toml index 4ca90bfb2a2..dc786538fc6 100644 --- a/crates/rspack_core/Cargo.toml +++ b/crates/rspack_core/Cargo.toml @@ -15,7 +15,6 @@ dashmap = { workspace = true } derivative = { workspace = true } dyn-clone = "1.0.11" futures = { workspace = true } -glob = "0.3.1" glob-match = "0.2.1" hashlink = { workspace = true } indexmap = { workspace = true } @@ -23,7 +22,7 @@ itertools = { workspace = true } mime_guess = { workspace = true } nodejs-resolver = { version = "0.1.0" } once_cell = { workspace = true } -oxc_resolver = { version = "0.1.0" } +oxc_resolver = { version = "0.2.0", features = ["tracing-subscriber"] } paste = { workspace = true } petgraph = { version = "0.6.3", features = ["serde-1"] } rayon = { workspace = true } diff --git a/crates/rspack_core/src/chunk_graph/chunk_graph_chunk.rs b/crates/rspack_core/src/chunk_graph/chunk_graph_chunk.rs index 04ca683d74a..8c749485f2e 100644 --- a/crates/rspack_core/src/chunk_graph/chunk_graph_chunk.rs +++ b/crates/rspack_core/src/chunk_graph/chunk_graph_chunk.rs @@ -297,11 +297,18 @@ impl ChunkGraph { .module_by_identifier(&module) .expect("should exist"); for connection in module_graph.get_outgoing_connections(module) { - // TODO: consider activeState - // if (activeState === ModuleGraphConnection.TRANSITIVE_ONLY) { - // add_dependencies(connection.module_identifier, set, module_graph); - // continue; - // } + // TODO: add runtime after runtime opt + let active_state = connection.get_active_state(module_graph, None); + match active_state { + crate::ConnectionState::Bool(false) => { + continue; + } + crate::ConnectionState::TransitiveOnly => { + add_dependencies(connection.module_identifier, set, module_graph); + continue; + } + _ => {} + } set.insert(connection.module_identifier); } } diff --git a/crates/rspack_core/src/chunk_graph/chunk_graph_module.rs b/crates/rspack_core/src/chunk_graph/chunk_graph_module.rs index b7df2d255e8..e285f6da95d 100644 --- a/crates/rspack_core/src/chunk_graph/chunk_graph_module.rs +++ b/crates/rspack_core/src/chunk_graph/chunk_graph_module.rs @@ -151,14 +151,11 @@ impl ChunkGraph { &self, block: &ModuleIdentifier, chunk_group_by_ukey: &'a ChunkGroupByUkey, - ) -> &'a ChunkGroup { - let ukey = self + ) -> Option<&'a ChunkGroup> { + self .block_to_chunk_group_ukey .get(block) - .unwrap_or_else(|| panic!("Block({block:?}) doesn't have corresponding ChunkGroup")); - chunk_group_by_ukey - .get(ukey) - .unwrap_or_else(|| panic!("ChunkGroup({ukey:?}) doesn't exist")) + .and_then(|ukey| chunk_group_by_ukey.get(ukey)) } pub fn connect_block_and_chunk_group( diff --git a/crates/rspack_core/src/compiler/compilation.rs b/crates/rspack_core/src/compiler/compilation.rs index 8476e0f0bf2..151b1f3f8d9 100644 --- a/crates/rspack_core/src/compiler/compilation.rs +++ b/crates/rspack_core/src/compiler/compilation.rs @@ -359,6 +359,7 @@ impl Compilation { MakeParam::ForceBuildModules(std::mem::take(&mut self.make_failed_module)); let make_failed_dependencies = MakeParam::ForceBuildDeps(std::mem::take(&mut self.make_failed_dependencies)); + self .update_module_graph(vec![param, make_failed_module, make_failed_dependencies]) .await @@ -1144,12 +1145,29 @@ impl Compilation { let start = logger.time("finish modules"); plugin_driver.finish_modules(self).await?; logger.time_end(start); + Ok(()) } #[instrument(name = "compilation:seal", skip_all)] pub async fn seal(&mut self, plugin_driver: SharedPluginDriver) -> Result<()> { let logger = self.get_logger("rspack.Compilation"); + + let start = logger.time("optimize dependencies"); + // https://github.com/webpack/webpack/blob/d15c73469fd71cf98734685225250148b68ddc79/lib/Compilation.js#L2812-L2814 + while plugin_driver.optimize_dependencies(self).await?.is_some() {} + logger.time_end(start); + + // if self.options.is_new_tree_shaking() { + // // for module in self.module_graph.module_graph_modules().values() {} + // // self + // // .module_graph + // // .module_graph_modules() + // // .values() + // // .foreach(|item| {}); + // debug_exports_info(&self.module_graph); + // } + let start = logger.time("create chunks"); use_code_splitting_cache(self, |compilation| async { build_chunk_graph(compilation)?; @@ -1161,6 +1179,7 @@ impl Compilation { logger.time_end(start); let start = logger.time("optimize"); + plugin_driver.optimize_tree(self).await?; plugin_driver.optimize_chunk_modules(self).await?; logger.time_end(start); diff --git a/crates/rspack_core/src/compiler/mod.rs b/crates/rspack_core/src/compiler/mod.rs index 60a8b2b8c02..8b74168a32b 100644 --- a/crates/rspack_core/src/compiler/mod.rs +++ b/crates/rspack_core/src/compiler/mod.rs @@ -197,12 +197,12 @@ where }; match exports_info_map.entry(importer) { Entry::Occupied(mut occ) => { - let export_info = ExportInfo::new(name.clone(), UsageState::Used, None); + let export_info = ExportInfo::new(Some(name.clone()), UsageState::Used, None); occ.get_mut().insert(name.clone(), export_info); } Entry::Vacant(vac) => { let mut map = HashMap::default(); - let export_info = ExportInfo::new(name.clone(), UsageState::Used, None); + let export_info = ExportInfo::new(Some(name.clone()), UsageState::Used, None); map.insert(name.clone(), export_info); vac.insert(map); } diff --git a/crates/rspack_core/src/compiler/queue.rs b/crates/rspack_core/src/compiler/queue.rs index bcdd48157c0..01ab9ace47c 100644 --- a/crates/rspack_core/src/compiler/queue.rs +++ b/crates/rspack_core/src/compiler/queue.rs @@ -118,9 +118,12 @@ impl WorkerTask for FactorizeTask { } }; - let other_exports_info = ExportInfo::new("null".into(), UsageState::Unknown, None); - let side_effects_only_info = - ExportInfo::new("*side effects only*".into(), UsageState::Unknown, None); + let other_exports_info = ExportInfo::new(None, UsageState::Unknown, None); + let side_effects_only_info = ExportInfo::new( + Some("*side effects only*".into()), + UsageState::Unknown, + None, + ); let exports_info = ExportsInfo::new(other_exports_info.id, side_effects_only_info.id); let mgm = ModuleGraphModule::new( result.module.identifier(), diff --git a/crates/rspack_core/src/dependency/context_element_dependency.rs b/crates/rspack_core/src/dependency/context_element_dependency.rs index 5c05084d12d..45074be4ee7 100644 --- a/crates/rspack_core/src/dependency/context_element_dependency.rs +++ b/crates/rspack_core/src/dependency/context_element_dependency.rs @@ -80,6 +80,10 @@ impl ModuleDependency for ContextElementDependency { vec![ExtendedReferencedExport::Array(vec![])] } } + + fn dependency_debug_name(&self) -> &'static str { + "ContextElementDependency" + } } impl AsDependencyTemplate for ContextElementDependency {} diff --git a/crates/rspack_core/src/dependency/entry.rs b/crates/rspack_core/src/dependency/entry.rs index d8379b2649d..81ea7345cb1 100644 --- a/crates/rspack_core/src/dependency/entry.rs +++ b/crates/rspack_core/src/dependency/entry.rs @@ -54,6 +54,10 @@ impl ModuleDependency for EntryDependency { fn set_request(&mut self, request: String) { self.request = request; } + + fn dependency_debug_name(&self) -> &'static str { + "EntryDependency" + } } impl AsDependencyTemplate for EntryDependency {} diff --git a/crates/rspack_core/src/dependency/mod.rs b/crates/rspack_core/src/dependency/mod.rs index eee0e88aefc..eea740777c5 100644 --- a/crates/rspack_core/src/dependency/mod.rs +++ b/crates/rspack_core/src/dependency/mod.rs @@ -190,6 +190,14 @@ pub trait Dependency: fn get_exports(&self) -> Option { None } + + fn get_module_evaluation_side_effects_state( + &self, + _module_graph: &ModuleGraph, + _module_chain: &mut HashSet, + ) -> ConnectionState { + ConnectionState::Bool(true) + } } #[derive(Debug, Default)] @@ -343,6 +351,8 @@ impl Debug for DependencyCondition { } pub trait ModuleDependency: Dependency { + /// name of the original struct or enum + fn dependency_debug_name(&self) -> &'static str; fn request(&self) -> &str; fn user_request(&self) -> &str; fn span(&self) -> Option<&ErrorSpan>; @@ -364,18 +374,10 @@ pub trait ModuleDependency: Dependency { None } - fn get_condition(&self, _module_graph: &ModuleGraph) -> Option { + fn get_condition(&self) -> Option { None } - fn get_module_evaluation_side_effects_state( - &self, - _module_graph: &ModuleGraph, - _module_chain: &mut HashSet, - ) -> ConnectionState { - ConnectionState::Bool(true) - } - fn get_referenced_exports( &self, _module_graph: &ModuleGraph, @@ -388,6 +390,10 @@ pub trait ModuleDependency: Dependency { fn resource_identifier(&self) -> Option<&str> { None } + + fn is_export_all(&self) -> Option { + None + } } impl dyn Dependency + '_ { diff --git a/crates/rspack_core/src/dependency/runtime_template.rs b/crates/rspack_core/src/dependency/runtime_template.rs index 054934c503a..fa9a9efd394 100644 --- a/crates/rspack_core/src/dependency/runtime_template.rs +++ b/crates/rspack_core/src/dependency/runtime_template.rs @@ -1,10 +1,9 @@ -use once_cell::sync::Lazy; -use regex::Regex; use swc_core::ecma::atoms::JsWord; use crate::{ - Compilation, DependencyId, ExportsType, FakeNamespaceObjectMode, InitFragmentStage, ModuleGraph, - ModuleIdentifier, NormalInitFragment, RuntimeGlobals, TemplateContext, + property_access, Compilation, DependencyId, ExportsType, FakeNamespaceObjectMode, + InitFragmentStage, ModuleGraph, ModuleIdentifier, NormalInitFragment, RuntimeGlobals, + TemplateContext, }; pub fn export_from_import( @@ -32,7 +31,7 @@ pub fn export_from_import( { match exports_type { ExportsType::Dynamic => { - return format!("{import_var}_default{}", property_access(&export_name, 1)); + return format!("{import_var}_default{}", property_access(export_name, 1)); } ExportsType::DefaultOnly | ExportsType::DefaultWithNamed => { export_name = export_name[1..].to_vec(); @@ -41,7 +40,7 @@ pub fn export_from_import( } } else if !export_name.is_empty() { if matches!(exports_type, ExportsType::DefaultOnly) { - return format!("/* non-default import from non-esm module */undefined\n{}", property_access(&export_name, 1)); + return format!("/* non-default import from non-esm module */undefined\n{}", property_access(export_name, 1)); } else if !matches!(exports_type, ExportsType::Namespace) && let Some(first_export_name) = export_name.get(0) && first_export_name == "__esModule" { return "/* __esModule */true".to_string(); } @@ -102,69 +101,6 @@ pub fn get_exports_type_with_strict( .get_exports_type(strict) } -static SAFE_IDENTIFIER_REGEX: Lazy = - Lazy::new(|| Regex::new(r"^[_a-zA-Z$][_a-zA-Z$0-9]*$").expect("should init regex")); -const RESERVED_IDENTIFIER: [&str; 37] = [ - "break", - "case", - "catch", - "class", - "const", - "continue", - "debugger", - "default", - "delete", - "do", - "else", - "enum", - "export", - "extends", - "false", - "finally", - "for", - "function", - "if", - "import", - "in", - "instanceof", - "new", - "null", - "package", - "return", - "super", - "switch", - "this", - "throw", - "true", - "try", - "typeof", - "var", - "void", - "while", - "with", -]; - -fn property_access(o: &Vec, mut start: usize) -> String { - let mut str = String::default(); - while start < o.len() { - let property = &o[start]; - if SAFE_IDENTIFIER_REGEX.is_match(property) && !RESERVED_IDENTIFIER.contains(&property.as_ref()) - { - str.push_str(format!(".{property}").as_str()); - } else { - str.push_str( - format!( - "[{}]", - serde_json::to_string(property).expect("should render property") - ) - .as_str(), - ); - } - start += 1; - } - str -} - pub fn module_id_expr(request: &str, module_id: &str) -> String { format!( "/* {} */{}", diff --git a/crates/rspack_core/src/exports_info.rs b/crates/rspack_core/src/exports_info.rs index 8630eb0f6a6..3bb674d37b0 100644 --- a/crates/rspack_core/src/exports_info.rs +++ b/crates/rspack_core/src/exports_info.rs @@ -1,4 +1,3 @@ -use std::collections::VecDeque; use std::hash::Hasher; use std::sync::atomic::AtomicU32; use std::sync::atomic::Ordering::Relaxed; @@ -42,45 +41,27 @@ impl ExportsInfoId { /// it will panic if you provide a export info that does not exists in the module graph pub fn set_has_provide_info(&self, mg: &mut ModuleGraph) { let exports_info = mg.get_exports_info_by_id(self); - let mut cur = exports_info; - // get redirect chain, because you can't pass a mut ref into a recursive call - let mut chain = VecDeque::new(); - chain.push_back(cur.id); - while let Some(id) = cur.redirect_to { - chain.push_back(id); - cur = mg.get_exports_info_by_id(&id); - } - let len = chain.len(); - for (i, id) in chain.into_iter().enumerate() { - let is_last = i == len - 1; - - let exports_info = mg.get_exports_info_by_id(&id); - - let export_id_list = exports_info.exports.values().cloned().collect::>(); - let other_export_info = exports_info.other_exports_info; - for id in export_id_list { - let export_info = mg - .export_info_map - .get_mut(&id) - .expect("should have export info"); - if export_info.provided.is_none() { - export_info.provided = Some(ExportInfoProvided::False); - } - if export_info.can_mangle_provide.is_none() { - export_info.can_mangle_provide = Some(true); - } + let redirect_id = exports_info.redirect_to; + let other_exports_info_id = exports_info.other_exports_info; + let export_id_list = exports_info.exports.values().cloned().collect::>(); + for export_info_id in export_id_list { + let export_info = mg.get_export_info_mut_by_id(&export_info_id); + if export_info.provided.is_none() { + export_info.provided = Some(ExportInfoProvided::False); } - if is_last { - let other_export_info = mg - .export_info_map - .get_mut(&other_export_info) - .expect("should have export info"); - if other_export_info.provided.is_none() { - other_export_info.provided = Some(ExportInfoProvided::False); - } - if other_export_info.can_mangle_provide.is_none() { - other_export_info.can_mangle_provide = Some(true); - } + if export_info.can_mangle_provide.is_none() { + export_info.can_mangle_provide = Some(true); + } + } + if let Some(redirect) = redirect_id { + redirect.set_has_provide_info(mg); + } else { + let other_exports_info = mg.get_export_info_mut_by_id(&other_exports_info_id); + if other_exports_info.provided.is_none() { + other_exports_info.provided = Some(ExportInfoProvided::False); + } + if other_exports_info.can_mangle_provide.is_none() { + other_exports_info.can_mangle_provide = Some(true); } } } @@ -126,7 +107,7 @@ impl ExportsInfoId { changed = true; } if let Some(ref exclude_exports) = exclude_exports { - if exclude_exports.contains(&export_info.name) { + if let Some(ref export_name) = export_info.name && exclude_exports.contains(export_name) { continue; } } @@ -140,8 +121,8 @@ impl ExportsInfoId { if let Some(target_key) = target_key { export_info.set_target( &target_key, - target_module.clone(), - Some(&vec![export_info.name.clone()]), + target_module, + export_info.name.clone().map(|name| vec![name]).as_ref(), priority, ); } @@ -190,74 +171,44 @@ impl ExportsInfoId { mg: &'a ModuleGraph, ) -> &'a ExportInfo { let exports_info = mg.get_exports_info_by_id(self); - let mut cur = exports_info; - // get redirect chain, because you can't pass a mut ref into a recursive call - let mut chain = VecDeque::new(); - chain.push_back(cur.id); - while let Some(id) = cur.redirect_to { - chain.push_back(id); - cur = mg.get_exports_info_by_id(&id); - } - - let len = chain.len(); - for (i, id) in chain.into_iter().enumerate() { - let exports_info = mg.get_exports_info_by_id(&id); - let is_last = i == len - 1; - - if let Some(info) = exports_info.exports.get(name) { - let info = mg - .export_info_map - .get(info) - .expect("should have export info"); - return info; - } - if is_last { - let info = mg - .export_info_map - .get(&exports_info.other_exports_info) - .expect("should have export info"); - return info; - } + let redirect_id = exports_info.redirect_to; + let other_exports_info_id = exports_info.other_exports_info; + let export_info_id = exports_info.exports.get(name); + if let Some(export_info_id) = export_info_id { + let export_info = mg.get_export_info_by_id(export_info_id); + return export_info; + } + if let Some(redirect_id) = redirect_id { + return redirect_id.get_read_only_export_info(name, mg); } - unreachable!() + mg.get_export_info_by_id(&other_exports_info_id) } pub fn get_export_info(&self, name: &JsWord, mg: &mut ModuleGraph) -> ExportInfoId { let exports_info = mg.get_exports_info_by_id(self); - let mut cur = exports_info; - // get redirect chain, because you can't pass a mut ref into a recursive call - let mut chain = VecDeque::new(); - chain.push_back(cur.id); - while let Some(id) = cur.redirect_to { - chain.push_back(id); - cur = mg.get_exports_info_by_id(&id); - } - - let len = chain.len(); - - for (i, id) in chain.into_iter().enumerate() { - let is_last = i == len - 1; - let exports_info = mg.get_exports_info_by_id(&id); - let other_exports_info = exports_info.other_exports_info; - if let Some(export_info_id) = exports_info.exports.get(name) { - return *export_info_id; - } - if is_last { - let other_export_info = mg - .export_info_map - .get(&other_exports_info) - .expect("should have export_info"); - let new_info = ExportInfo::new(name.clone(), UsageState::Unknown, Some(other_export_info)); - let new_info_id = new_info.id; - mg.export_info_map.insert(new_info_id, new_info); - - let exports_info = mg.get_exports_info_mut_by_id(&id); - exports_info._exports_are_ordered = false; - exports_info.exports.insert(name.clone(), new_info_id); - return new_info_id; - } + let redirect_id = exports_info.redirect_to; + let other_exports_info_id = exports_info.other_exports_info; + let export_info_id = exports_info.exports.get(name); + if let Some(export_info_id) = export_info_id { + return *export_info_id; + } + if let Some(redirect_id) = redirect_id { + return redirect_id.get_export_info(name, mg); } - unreachable!() + + let other_export_info = mg.get_export_info_by_id(&other_exports_info_id); + let new_info = ExportInfo::new( + Some(name.clone()), + UsageState::Unknown, + Some(other_export_info), + ); + let new_info_id = new_info.id; + mg.export_info_map.insert(new_info_id, new_info); + + let exports_info = mg.get_exports_info_mut_by_id(self); + exports_info._exports_are_ordered = false; + exports_info.exports.insert(name.clone(), new_info_id); + new_info_id } pub fn get_nested_exports_info( @@ -324,10 +275,39 @@ impl ExportsInfoId { pub fn set_used_in_unknown_way( &self, - _mg: &mut ModuleGraph, - _runtime: Option<&RuntimeSpec>, + mg: &mut ModuleGraph, + runtime: Option<&RuntimeSpec>, ) -> bool { - todo!() + let mut changed = false; + let exports_info = mg.get_exports_info_by_id(self); + let export_info_id_list = exports_info.exports.values().cloned().collect::>(); + let redirect_to_id = exports_info.redirect_to; + let other_exports_info_id = exports_info.other_exports_info; + for export_info_id in export_info_id_list { + if export_info_id.set_used_in_unknown_way(mg, runtime) { + changed = true; + } + } + if let Some(redirect_to) = redirect_to_id { + if redirect_to.set_used_in_unknown_way(mg, runtime) { + changed = true; + } + } else { + if other_exports_info_id.set_used_conditionally( + mg, + Box::new(|value| value < &UsageState::Unknown), + UsageState::Unknown, + runtime, + ) { + changed = true; + } + let other_exports_info = mg.get_export_info_mut_by_id(&other_exports_info_id); + if other_exports_info.can_mangle_use != Some(false) { + other_exports_info.can_mangle_use = Some(false); + changed = true; + } + } + changed } pub fn set_used_for_side_effects_only( @@ -344,6 +324,21 @@ impl ExportsInfoId { runtime, ) } + + pub fn get_used_name( + &self, + mg: &ModuleGraph, + runtime: Option<&RuntimeSpec>, + name: UsedName, + ) -> Option { + match name { + UsedName::Str(name) => { + let info = self.get_read_only_export_info(&name, mg); + info.get_used_name(&name, runtime).map(UsedName::Str) + } + UsedName::Vec(_) => todo!(), + } + } } impl Default for ExportsInfoId { @@ -408,8 +403,9 @@ impl ExportsInfo { } } - pub fn get_used_exports(&self) -> HashSet<&JsWord> { - self.exports.keys().collect::>() + /// only used for old version tree shaking + pub fn old_get_used_exports(&self) -> HashSet { + self.exports.keys().cloned().collect::>() } pub fn get_used( @@ -480,6 +476,7 @@ impl ExportsInfo { } } +#[derive(Debug)] pub enum UsedName { Str(JsWord), Vec(Vec), @@ -583,6 +580,25 @@ impl ExportInfoId { let export_info = mg.get_export_info_by_id(self); export_info.exports_info } + + fn set_used_in_unknown_way(&self, mg: &mut ModuleGraph, runtime: Option<&RuntimeSpec>) -> bool { + let mut changed = false; + + if self.set_used_conditionally( + mg, + Box::new(|value| value < &UsageState::Unknown), + UsageState::Unknown, + runtime, + ) { + changed = true; + } + let export_info = mg.get_export_info_mut_by_id(self); + if export_info.can_mangle_use != Some(false) { + export_info.can_mangle_use = Some(false); + changed = true; + } + changed + } } impl Default for ExportInfoId { fn default() -> Self { @@ -607,10 +623,11 @@ impl From for ExportInfoId { #[derive(Debug, Clone, Default)] #[allow(unused)] pub struct ExportInfo { - pub name: JsWord, + pub name: Option, module_identifier: Option, pub usage_state: UsageState, - used_name: Option, + /// this is mangled name,https://github.com/webpack/webpack/blob/1f99ad6367f2b8a6ef17cce0e058f7a67fb7db18/lib/ExportsInfo.js#L1181-L1188 + used_name: Option, target: HashMap, max_target: HashMap, pub provided: Option, @@ -625,6 +642,7 @@ pub struct ExportInfo { pub has_use_in_runtime_info: bool, pub can_mangle_use: Option, pub global_used: Option, + pub used_in_runtime: Option>, } impl ExportsHash for ExportInfo { @@ -704,19 +722,25 @@ impl Clone for Box> { impl ExportInfo { // TODO: remove usage_state in the future - pub fn new(name: JsWord, usage_state: UsageState, init_from: Option<&ExportInfo>) -> Self { + pub fn new( + name: Option, + usage_state: UsageState, + init_from: Option<&ExportInfo>, + ) -> Self { let has_use_in_runtime_info = if let Some(init_from) = init_from { init_from.has_use_in_runtime_info } else { false }; let can_mangle_use = init_from.and_then(|init_from| init_from.can_mangle_use); + let used_in_runtime = init_from.and_then(|init_from| init_from.used_in_runtime.clone()); Self { name, module_identifier: None, usage_state, used_name: None, + used_in_runtime, // TODO: init this target: HashMap::default(), provided: None, @@ -734,9 +758,46 @@ impl ExportInfo { } } - // TODO pub fn get_used(&self, _runtime: Option<&RuntimeSpec>) -> UsageState { - UsageState::Unused + if !self.has_use_in_runtime_info { + return UsageState::NoInfo; + } + if let Some(global_used) = self.global_used { + return global_used; + } + if self.used_in_runtime.is_none() { + UsageState::Unused + } else { + // TODO: runtime optimization + todo!() + } + } + + /// Webpack returns `false | string`, we use `Option` to avoid declare a redundant enum + /// type + pub fn get_used_name( + &self, + fallback_name: &JsWord, + _runtime: Option<&RuntimeSpec>, + ) -> Option { + if self.has_use_in_runtime_info { + if let Some(usage) = self.global_used { + if matches!(usage, UsageState::Unused) { + return None; + } + } else { + self.used_in_runtime.as_ref()?; + // TODO: runtime optimization + } + } + if let Some(used_name) = self.used_name.as_ref() { + return Some(used_name.clone()); + } + if let Some(name) = self.name.as_ref() { + Some(name.clone()) + } else { + Some(fallback_name.clone()) + } } pub fn get_exports_info<'a>(&self, module_graph: &'a ModuleGraph) -> Option<&'a ExportsInfo> { @@ -914,7 +975,7 @@ impl ExportInfo { .get_max_target() .values() .map(|item| UnResolvedExportInfoTarget { - connection: item.connection.clone(), + connection: item.connection, exports: item.exports.clone(), }) .clone(); @@ -947,7 +1008,6 @@ impl ExportInfo { } } - // TODO: change connection to option pub fn set_target( &mut self, key: &DependencyId, @@ -1005,9 +1065,12 @@ impl ExportInfo { .expect("should have exports_info when exports_info is true"); } - let other_exports_info = ExportInfo::new("null".into(), UsageState::Unknown, None); - let side_effects_only_info = - ExportInfo::new("*side effects only*".into(), UsageState::Unknown, None); + let other_exports_info = ExportInfo::new(None, UsageState::Unknown, None); + let side_effects_only_info = ExportInfo::new( + Some("*side effects only*".into()), + UsageState::Unknown, + None, + ); let new_exports_info = ExportsInfo::new(other_exports_info.id, side_effects_only_info.id); let new_exports_info_id = new_exports_info.id; @@ -1028,12 +1091,20 @@ impl ExportInfo { } } -#[derive(Debug, PartialEq, Copy, Clone, Default, Hash)] +#[derive(Debug, PartialEq, Copy, Clone, Default, Hash, PartialOrd)] pub enum UsageState { - Unused, + Unused = 0, + OnlyPropertiesUsed = 1, + NoInfo = 2, + #[default] + Unknown = 3, + Used = 4, +} + +#[derive(Debug, PartialEq, Copy, Clone, Hash)] +pub enum RuntimeUsageStateType { OnlyPropertiesUsed, NoInfo, - #[default] Unknown, Used, } @@ -1048,18 +1119,17 @@ pub enum UsedByExports { // https://github.com/webpack/webpack/blob/1f99ad6367f2b8a6ef17cce0e058f7a67fb7db18/lib/optimize/InnerGraph.js#L319-L338 pub fn get_dependency_used_by_exports_condition( - dependency_id: &DependencyId, + dependency_id: DependencyId, used_by_exports: &UsedByExports, - module_graph: &ModuleGraph, ) -> Option { match used_by_exports { UsedByExports::Set(used_by_exports) => { - let module_identifier = module_graph - .parent_module_by_dependency_id(dependency_id) - .expect("should have parent module"); let used_by_exports = Arc::new(used_by_exports.clone()); Some(DependencyCondition::Fn(Box::new( - move |_, runtime, module_graph| { + move |_, runtime, module_graph: &ModuleGraph| { + let module_identifier = module_graph + .parent_module_by_dependency_id(&dependency_id) + .expect("should have parent module"); let exports_info = module_graph.get_exports_info(&module_identifier); for export_name in used_by_exports.iter() { if exports_info.get_used(UsedName::Str(export_name.clone()), runtime, module_graph) @@ -1084,7 +1154,7 @@ pub fn get_dependency_used_by_exports_condition( } /// refer https://github.com/webpack/webpack/blob/d15c73469fd71cf98734685225250148b68ddc79/lib/FlagDependencyUsagePlugin.js#L64 -#[derive(Clone)] +#[derive(Clone, Debug)] pub enum ExtendedReferencedExport { Array(Vec), Export(ReferencedExport), @@ -1117,7 +1187,7 @@ impl From for ExtendedReferencedExport { } } -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct ReferencedExport { pub name: Vec, pub can_mangle: bool, @@ -1182,11 +1252,19 @@ pub fn process_export_info( module_graph, runtime, referenced_export, - if default_points_to_self && &export_info.name == "default" { + if default_points_to_self + && export_info + .name + .as_ref() + .map(|name| name == "default") + .unwrap_or_default() + { prefix.clone() } else { let mut value = prefix.clone(); - value.push(export_info.name.clone()); + if let Some(name) = export_info.name.as_ref() { + value.push(name.clone()); + } value }, Some(export_info.id), @@ -1200,3 +1278,17 @@ pub fn process_export_info( referenced_export.push(prefix); } } + +#[allow(clippy::dbg_macro)] +pub fn debug_exports_info(module_graph: &ModuleGraph) { + for mgm in module_graph.module_graph_modules().values() { + dbg!(&mgm.module_identifier); + let exports_info_id = mgm.exports; + let exports_info = module_graph.get_exports_info_by_id(&exports_info_id); + dbg!(&exports_info); + for id in exports_info.exports.values() { + let export_info = module_graph.get_export_info_by_id(id); + dbg!(&export_info); + } + } +} diff --git a/crates/rspack_core/src/external_module.rs b/crates/rspack_core/src/external_module.rs index 6173ed53a26..3f5515d0487 100644 --- a/crates/rspack_core/src/external_module.rs +++ b/crates/rspack_core/src/external_module.rs @@ -1,12 +1,15 @@ use std::borrow::Cow; use std::hash::Hash; +use std::iter; use rspack_error::{internal_error, IntoTWithDiagnosticArray, Result, TWithDiagnosticArray}; use rspack_hash::RspackHash; use rspack_identifier::{Identifiable, Identifier}; -use serde::{Serialize, Serializer}; +use rustc_hash::FxHashMap as HashMap; +use serde::Serialize; use crate::{ + property_access, rspack_sources::{BoxSource, RawSource, Source, SourceExt}, to_identifier, BuildContext, BuildInfo, BuildMetaExportsType, BuildResult, ChunkInitFragments, ChunkUkey, CodeGenerationDataUrl, CodeGenerationResult, Compilation, Context, ExternalType, @@ -17,46 +20,61 @@ use crate::{ static EXTERNAL_MODULE_JS_SOURCE_TYPES: &[SourceType] = &[SourceType::JavaScript]; static EXTERNAL_MODULE_CSS_SOURCE_TYPES: &[SourceType] = &[SourceType::Css]; +#[derive(Debug, Clone, Serialize)] +#[serde(untagged)] +pub enum ExternalRequest { + Single(ExternalRequestValue), + Map(HashMap), +} + #[derive(Debug, Clone)] -pub struct ExternalRequest(pub Vec); +pub struct ExternalRequestValue { + primary: String, + rest: Option>, +} -impl Serialize for ExternalRequest { - fn serialize(&self, serializer: S) -> std::result::Result { - self.0.serialize(serializer) +impl Serialize for ExternalRequestValue { + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + self.iter().collect::>().serialize(serializer) } } -impl ExternalRequest { - pub fn as_str(&self) -> &str { - // we're sure array have more than one element,because it is valid in js side - self.0.get(0).expect("should have at least element") +impl ExternalRequestValue { + pub fn new(primary: String, rest: Option>) -> Self { + Self { primary, rest } } - pub fn as_array(&self) -> &Vec { - &self.0 + + pub fn primary(&self) -> &str { + &self.primary } -} -pub fn property_access(o: &Vec, mut start: usize) -> String { - let mut str = String::default(); - while start < o.len() { - let property = &o[start]; - str.push_str(format!(r#"["{property}"]"#).as_str()); - start += 1; + + pub fn rest(&self) -> Option<&[String]> { + self.rest.as_deref() + } + + pub fn iter(&self) -> impl Iterator { + if let Some(rest) = &self.rest { + iter::once(&self.primary).chain(rest) + } else { + iter::once(&self.primary).chain(&[]) + } } - str } fn get_source_for_global_variable_external( - request: &ExternalRequest, + variable_names: &ExternalRequestValue, external_type: &ExternalType, ) -> String { - let object_lookup = property_access(request.as_array(), 0); + let object_lookup = property_access(variable_names.iter(), 0); format!("{external_type}{object_lookup}") } -fn get_source_for_default_case(_optional: bool, request: &ExternalRequest) -> String { - let request = request.as_array(); - let variable_name = request.get(0).expect("should have at least one element"); - let object_lookup = property_access(request, 1); +fn get_source_for_default_case(_optional: bool, request: &ExternalRequestValue) -> String { + let variable_name = request.primary(); + let object_lookup = property_access(request.iter(), 1); format!("{variable_name}{object_lookup}") } @@ -70,10 +88,10 @@ pub struct ExternalModule { } impl ExternalModule { - pub fn new(request: Vec, external_type: ExternalType, user_request: String) -> Self { + pub fn new(request: ExternalRequest, external_type: ExternalType, user_request: String) -> Self { Self { id: Identifier::from(format!("external {external_type} {request:?}")), - request: ExternalRequest(request), + request, external_type, user_request, } @@ -83,50 +101,59 @@ impl ExternalModule { &self.external_type } - fn get_source_for_commonjs(&self) -> String { - let request = &self.request.as_array(); - let module_name = request.get(0).expect("should have at least one element"); + fn get_request_and_external_type(&self) -> (Option<&ExternalRequestValue>, &ExternalType) { + match &self.request { + ExternalRequest::Single(request) => (Some(request), &self.external_type), + ExternalRequest::Map(map) => (map.get(&self.external_type), &self.external_type), + } + } + + fn get_source_for_commonjs(&self, module_and_specifiers: &ExternalRequestValue) -> String { + let module_name = module_and_specifiers.primary(); format!( "module.exports = require('{}'){}", module_name, - property_access(request, 1) + property_access(module_and_specifiers.iter(), 1) ) } - fn get_source_for_import(&self, compilation: &Compilation) -> String { + fn get_source_for_import( + &self, + module_and_specifiers: &ExternalRequestValue, + compilation: &Compilation, + ) -> String { format!( "module.exports = {}({})", compilation.options.output.import_function_name, - serde_json::to_string(&self.request).expect("invalid json to_string") + serde_json::to_string(module_and_specifiers.primary()).expect("invalid json to_string") ) } - pub fn get_source( + fn get_source( &self, compilation: &Compilation, + request: Option<&ExternalRequestValue>, + external_type: &ExternalType, ) -> (BoxSource, ChunkInitFragments, RuntimeGlobals) { let mut chunk_init_fragments: ChunkInitFragments = Default::default(); let mut runtime_requirements: RuntimeGlobals = Default::default(); let source = match self.external_type.as_str() { - "this" => format!( + "this" if let Some(request) = request => format!( "module.exports = (function() {{ return {}; }}())", - get_source_for_global_variable_external(&self.request, &self.external_type) + get_source_for_global_variable_external(request, external_type) ), - "window" | "self" => format!( + "window" | "self" if let Some(request) = request => format!( "module.exports = {}", - get_source_for_global_variable_external(&self.request, &self.external_type) + get_source_for_global_variable_external(request, external_type) ), - "global" => format!( + "global" if let Some(request) = request=> format!( "module.exports ={} ", - get_source_for_global_variable_external( - &self.request, - &compilation.options.output.global_object - ) + get_source_for_global_variable_external(request, &compilation.options.output.global_object) ), - "commonjs" | "commonjs2" | "commonjs-module" | "commonjs-static" => { - self.get_source_for_commonjs() + "commonjs" | "commonjs2" | "commonjs-module" | "commonjs-static" if let Some(request) = request => { + self.get_source_for_commonjs(request) } - "node-commonjs" => { + "node-commonjs" if let Some(request) = request => { if compilation.options.output.module { chunk_init_fragments .entry("external module node-commonjs".to_string()) @@ -138,10 +165,10 @@ impl ExternalModule { )); format!( "__WEBPACK_EXTERNAL_createRequire(import.meta.url)('{}')", - self.request.as_str() + request.primary() ) } else { - self.get_source_for_commonjs() + self.get_source_for_commonjs(request) } } "amd" | "amd-require" | "umd" | "umd2" | "system" | "jsonp" => { @@ -155,14 +182,14 @@ impl ExternalModule { to_identifier(id) ) } - "import" => self.get_source_for_import(compilation), - "var" | "promise" | "const" | "let" | "assign" => { + "import" if let Some(request) = request => self.get_source_for_import(request, compilation), + "var" | "promise" | "const" | "let" | "assign" if let Some(request) = request => { format!( "module.exports = {}", - get_source_for_default_case(false, &self.request) + get_source_for_default_case(false, request) ) } - "module" => { + "module" if let Some(request) = request => { if compilation.options.output.module { let id = compilation .module_graph @@ -175,7 +202,7 @@ impl ExternalModule { .or_insert(NormalInitFragment::new( format!( "import * as __WEBPACK_EXTERNAL_MODULE_{identifier}__ from '{}';\n", - self.request.as_str() + request.primary() ), InitFragmentStage::StageHarmonyImports, None, @@ -188,7 +215,7 @@ impl ExternalModule { RuntimeGlobals::DEFINE_PROPERTY_GETTERS, ) } else { - self.get_source_for_import(compilation) + self.get_source_for_import(request, compilation) } } // TODO "script" @@ -289,34 +316,34 @@ impl Module for ExternalModule { fn code_generation(&self, compilation: &Compilation) -> Result { let mut cgr = CodeGenerationResult::default(); + let (request, external_type) = self.get_request_and_external_type(); match self.external_type.as_str() { - "asset" => { + "asset" if let Some(request) = request => { cgr.add( SourceType::JavaScript, RawSource::from(format!( "module.exports = {};", - serde_json::to_string(&self.request.as_str()) - .map_err(|e| internal_error!(e.to_string()))? + serde_json::to_string(request.primary()).map_err(|e| internal_error!(e.to_string()))? )) .boxed(), ); - cgr.data.insert(CodeGenerationDataUrl::new( - self.request.as_str().to_string(), - )); + cgr + .data + .insert(CodeGenerationDataUrl::new(request.primary().to_string())); } - "css-import" => { + "css-import" if let Some(request) = request => { cgr.add( SourceType::Css, RawSource::from(format!( "@import url({});", - serde_json::to_string(&self.request.as_str()) - .map_err(|e| internal_error!(e.to_string()))? + serde_json::to_string(request.primary()).map_err(|e| internal_error!(e.to_string()))? )) .boxed(), ); } _ => { - let (source, chunk_init_fragments, runtime_requirements) = self.get_source(compilation); + let (source, chunk_init_fragments, runtime_requirements) = + self.get_source(compilation, request, external_type); cgr.add(SourceType::JavaScript, source); cgr.chunk_init_fragments = chunk_init_fragments; cgr.runtime_requirements.insert(runtime_requirements); diff --git a/crates/rspack_core/src/lib.rs b/crates/rspack_core/src/lib.rs index 1d175b0c02c..cc1ae13c6f2 100644 --- a/crates/rspack_core/src/lib.rs +++ b/crates/rspack_core/src/lib.rs @@ -1,8 +1,10 @@ #![feature(let_chains)] +#![feature(if_let_guard)] #![feature(iter_intersperse)] #![feature(box_patterns)] #![feature(anonymous_lifetime_in_impl_trait)] +use std::sync::atomic::AtomicBool; use std::{fmt, sync::Arc}; mod fake_namespace_object; pub use fake_namespace_object::*; @@ -217,10 +219,12 @@ impl TryFrom<&str> for ModuleType { "js/dynamic" | "javascript/dynamic" => Ok(Self::JsDynamic), "js/esm" | "javascript/esm" => Ok(Self::JsEsm), + // TODO: remove in 0.5.0 "jsx" | "javascriptx" | "jsx/auto" | "javascriptx/auto" => Ok(Self::Jsx), "jsx/dynamic" | "javascriptx/dynamic" => Ok(Self::JsxDynamic), "jsx/esm" | "javascriptx/esm" => Ok(Self::JsxEsm), + // TODO: remove in 0.5.0 "ts" | "typescript" => Ok(Self::Ts), "tsx" | "typescriptx" => Ok(Self::Tsx), @@ -249,3 +253,5 @@ impl TryFrom<&str> for ModuleType { pub type ChunkByUkey = Database; pub type ChunkGroupByUkey = Database; pub(crate) type SharedPluginDriver = Arc; + +pub static IS_NEW_TREESHAKING: AtomicBool = AtomicBool::new(false); diff --git a/crates/rspack_core/src/module.rs b/crates/rspack_core/src/module.rs index a7418582e98..8223c032e7e 100644 --- a/crates/rspack_core/src/module.rs +++ b/crates/rspack_core/src/module.rs @@ -46,9 +46,10 @@ pub struct BuildInfo { pub asset_filenames: HashSet, pub harmony_named_exports: HashSet, pub all_star_exports: Vec, + pub need_create_require: bool, } -#[derive(Debug, Default, Clone, Hash)] +#[derive(Debug, Default, Clone, Hash, PartialEq, Eq)] pub enum BuildMetaExportsType { #[default] Unset, diff --git a/crates/rspack_core/src/module_graph/connection.rs b/crates/rspack_core/src/module_graph/connection.rs index f2b84606def..7009a3110c1 100644 --- a/crates/rspack_core/src/module_graph/connection.rs +++ b/crates/rspack_core/src/module_graph/connection.rs @@ -19,7 +19,7 @@ impl From for ConnectionId { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub struct ModuleGraphConnection { /// The referencing module identifier pub original_module_identifier: Option, @@ -31,7 +31,6 @@ pub struct ModuleGraphConnection { pub dependency_id: DependencyId, active: bool, conditional: bool, - condition: Option, } /// implementing hash by hand because condition maybe a function, which can't be hash @@ -65,17 +64,15 @@ impl ModuleGraphConnection { original_module_identifier: Option, dependency_id: DependencyId, module_identifier: ModuleIdentifier, - condition: Option, + active: bool, + conditional: bool, ) -> Self { - let active = !matches!(condition, Some(DependencyCondition::False)); - let conditional = condition.is_some(); Self { original_module_identifier, module_identifier, dependency_id, active, conditional, - condition, } } @@ -123,13 +120,18 @@ impl ModuleGraphConnection { module_graph: &ModuleGraph, runtime: Option<&RuntimeSpec>, ) -> ConnectionState { - match self.condition.as_ref().expect("should have condition") { + match module_graph + .connection_to_condition + .get(self) + .expect("should have condition") + { DependencyCondition::False => ConnectionState::Bool(false), DependencyCondition::Fn(f) => f(self, runtime, module_graph), } } } +#[derive(Debug)] pub enum ConnectionState { Bool(bool), CircularConnection, diff --git a/crates/rspack_core/src/module_graph/mod.rs b/crates/rspack_core/src/module_graph/mod.rs index 73614dc3552..181089e26dc 100644 --- a/crates/rspack_core/src/module_graph/mod.rs +++ b/crates/rspack_core/src/module_graph/mod.rs @@ -7,6 +7,7 @@ use rspack_hash::RspackHashDigest; use rspack_identifier::IdentifierMap; use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet}; +use crate::IS_NEW_TREESHAKING; mod connection; pub use connection::*; @@ -42,11 +43,11 @@ pub struct ModuleGraph { /// Module graph connections table index for `ConnectionId` connections_map: HashMap, - connection_to_condition: HashMap, import_var_map: IdentifierMap, pub exports_info_map: HashMap, pub export_info_map: HashMap, + connection_to_condition: HashMap, } impl ModuleGraph { @@ -82,13 +83,6 @@ impl ModuleGraph { self.dependencies.insert(*dependency.id(), dependency); } - pub fn get_condition_by_connection_id( - &self, - connection_id: &ConnectionId, - ) -> Option<&DependencyCondition> { - self.connection_to_condition.get(connection_id) - } - pub fn dependency_by_id(&self, dependency_id: &DependencyId) -> Option<&BoxDependency> { self.dependencies.get(dependency_id) } @@ -122,35 +116,49 @@ impl ModuleGraph { dependency: BoxDependency, module_identifier: ModuleIdentifier, ) -> Result<()> { - let module_dependency = dependency.as_module_dependency().is_some(); + let is_module_dependency = dependency.as_module_dependency().is_some(); let dependency_id = *dependency.id(); + let condition = if IS_NEW_TREESHAKING.load(std::sync::atomic::Ordering::Relaxed) { + dependency + .as_module_dependency() + .and_then(|dep| dep.get_condition()) + } else { + None + }; self.add_dependency(dependency); self .dependency_id_to_module_identifier .insert(dependency_id, module_identifier); - if !module_dependency { + if !is_module_dependency { return Ok(()); } + let active = !matches!(condition, Some(DependencyCondition::False)); + let conditional = condition.is_some(); // TODO: just a placeholder here, finish this when we have basic `getCondition` logic - let condition: Option = None; let new_connection = ModuleGraphConnection::new( original_module_identifier, dependency_id, module_identifier, - condition, + active, + conditional, ); let connection_id = if let Some(connection_id) = self.connections_map.get(&new_connection) { *connection_id } else { let new_connection_id = ConnectionId::from(self.connections.len()); - self.connections.push(Some(new_connection.clone())); + self.connections.push(Some(new_connection)); self .connections_map .insert(new_connection, new_connection_id); new_connection_id }; + if let Some(condition) = condition { + self + .connection_to_condition + .insert(new_connection, condition); + } self .dependency_id_to_connection_id @@ -657,6 +665,10 @@ mod test { } impl ModuleDependency for $ident { + fn dependency_debug_name(&self) -> &'static str { + stringify!($ident) + } + fn request(&self) -> &str { &*self.1 } @@ -681,9 +693,12 @@ mod test { impl_noop_trait_dep_type!(Edge); fn add_module_to_graph(mg: &mut ModuleGraph, m: Box) { - let other_exports_info = ExportInfo::new("null".into(), UsageState::Unknown, None); - let side_effects_only_info = - ExportInfo::new("*side effects only*".into(), UsageState::Unknown, None); + let other_exports_info = ExportInfo::new(None, UsageState::Unknown, None); + let side_effects_only_info = ExportInfo::new( + Some("*side effects only*".into()), + UsageState::Unknown, + None, + ); let exports_info = ExportsInfo::new(other_exports_info.id, side_effects_only_info.id); let mgm = ModuleGraphModule::new(m.identifier(), ModuleType::Js, exports_info.id); mg.add_module_graph_module(mgm); diff --git a/crates/rspack_core/src/module_graph_module.rs b/crates/rspack_core/src/module_graph_module.rs index a1bbfb89290..0c70b42bb90 100644 --- a/crates/rspack_core/src/module_graph_module.rs +++ b/crates/rspack_core/src/module_graph_module.rs @@ -1,13 +1,13 @@ use rspack_error::{internal_error, Result}; use rustc_hash::FxHashSet as HashSet; -use crate::ExportsInfoId; use crate::{ is_async_dependency, module_graph::ConnectionId, BuildInfo, BuildMeta, BuildMetaDefaultObject, BuildMetaExportsType, ChunkGraph, ChunkGroupOptionsKindRef, DependencyId, ExportsArgument, ExportsType, FactoryMeta, ModuleArgument, ModuleGraph, ModuleGraphConnection, ModuleIdentifier, ModuleIssuer, ModuleProfile, ModuleSyntax, ModuleType, }; +use crate::{ExportsInfoId, IS_NEW_TREESHAKING}; #[derive(Debug)] pub struct ModuleGraphModule { @@ -123,21 +123,54 @@ impl ModuleGraphModule { // } pub fn depended_modules<'a>(&self, module_graph: &'a ModuleGraph) -> Vec<&'a ModuleIdentifier> { - self - .dependencies - .iter() - .filter(|id| { - if let Some(dep) = module_graph - .dependency_by_id(id) - .expect("should have id") - .as_module_dependency() - { - return !is_async_dependency(dep) && !dep.weak(); - } - false - }) - .filter_map(|id| module_graph.module_identifier_by_dependency_id(id)) - .collect() + if IS_NEW_TREESHAKING.load(std::sync::atomic::Ordering::Relaxed) { + self + .outgoing_connections_unordered(module_graph) + .expect("should have outgoing connections") + .filter_map(|con: &ModuleGraphConnection| { + // TODO: runtime opt + let active_state = con.get_active_state(module_graph, None); + // dbg!(&con, &active_state,); + // dbg!(&module_graph + // .dependency_by_id(&con.dependency_id) + // .and_then(|dep| dep + // .as_module_dependency() + // .map(|item| item.dependency_debug_name()))); + match active_state { + crate::ConnectionState::Bool(false) => None, + _ => Some(con.dependency_id), + } + }) + .filter(|id| { + if let Some(dep) = module_graph + .dependency_by_id(id) + .expect("should have id") + .as_module_dependency() + { + return !is_async_dependency(dep) && !dep.weak(); + } + false + }) + .filter_map(|id| module_graph.module_identifier_by_dependency_id(&id)) + .collect() + } else { + self + .dependencies + .iter() + .filter(|id| { + if let Some(dep) = module_graph + .dependency_by_id(id) + .expect("should have id") + .as_module_dependency() + { + return !is_async_dependency(dep) && !dep.weak(); + } + false + }) + .filter_map(|id| module_graph.module_identifier_by_dependency_id(id)) + .collect() + } + // dbg!(&self.module_identifier); } pub fn dynamic_depended_modules<'a>( diff --git a/crates/rspack_core/src/normal_module.rs b/crates/rspack_core/src/normal_module.rs index edab59323ad..560cdabe92e 100644 --- a/crates/rspack_core/src/normal_module.rs +++ b/crates/rspack_core/src/normal_module.rs @@ -507,16 +507,18 @@ impl Module for NormalModule { module_chain.insert(self.identifier()); let mut current = ConnectionState::Bool(false); for dependency_id in mgm.dependencies.iter() { - if let Some(dependency) = module_graph.dependency_by_id(dependency_id).expect("should have dependency").as_module_dependency() { + if let Some(dependency) = module_graph.dependency_by_id(dependency_id) { let state = dependency.get_module_evaluation_side_effects_state(module_graph, module_chain); if matches!(state, ConnectionState::Bool(true)) { // TODO add optimization bailout + module_chain.remove(&self.identifier()); return ConnectionState::Bool(true); - } else if matches!(state, ConnectionState::CircularConnection) { + } else if !matches!(state, ConnectionState::CircularConnection) { current = add_connection_states(current, state); } } } + module_chain.remove(&self.identifier()); return current; } } diff --git a/crates/rspack_core/src/normal_module_factory.rs b/crates/rspack_core/src/normal_module_factory.rs index 1cdfe180c32..95325711df8 100644 --- a/crates/rspack_core/src/normal_module_factory.rs +++ b/crates/rspack_core/src/normal_module_factory.rs @@ -615,9 +615,18 @@ impl NormalModuleFactory { .registered_parser_and_generator_builder .get(&resolved_module_type) .ok_or_else(|| { - internal_error!( - "Parser and generator builder for module type {resolved_module_type:?} is not registered" - ) + let mut e = format!("Unexpected `ModuleType` found: {resolved_module_type}. "); + + match resolved_module_type { + ModuleType::Css => e.push_str( + "Setting `'css'` as the `Rule.type` is only possible with `experiments.css` set to `true`", + ), + ModuleType::Ts | ModuleType::Tsx | + ModuleType::Jsx | ModuleType::JsxDynamic | ModuleType::JsxEsm => e.push_str("`Rule.type` that are not supported by webpack is deprecated. See: https://github.com/web-infra-dev/rspack/discussions/4070"), + _ => (), + } + + internal_error!(e) })?(); self.context.module_type = Some(resolved_module_type); diff --git a/crates/rspack_core/src/options/builtins.rs b/crates/rspack_core/src/options/builtins.rs index 3dada906cdf..d9364558895 100644 --- a/crates/rspack_core/src/options/builtins.rs +++ b/crates/rspack_core/src/options/builtins.rs @@ -1,12 +1,10 @@ use std::fmt::Debug; -use std::{fmt::Display, path::PathBuf}; -use glob::Pattern as GlobPattern; use rspack_error::Result; pub use rspack_swc_visitors::{Define, Provide}; use rspack_swc_visitors::{EmotionOptions, ImportOptions, ReactOptions, RelayOptions}; -use crate::{ApplyContext, AssetInfo, CompilerOptions, Plugin, PluginContext}; +use crate::{ApplyContext, CompilerOptions, Plugin, PluginContext}; #[derive(Debug)] pub struct DefinePlugin { @@ -141,54 +139,6 @@ pub struct Builtins { pub relay: Option, } -#[derive(Debug, Clone)] -pub struct CopyPluginConfig { - pub patterns: Vec, -} - -#[derive(Debug, Clone, Copy)] -pub enum FromType { - Dir, - File, - Glob, -} - -#[derive(Debug, Clone)] -pub enum ToType { - Dir, - File, - Template, -} - -impl Display for ToType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(match self { - ToType::Dir => "dir", - ToType::File => "file", - ToType::Template => "template", - }) - } -} - -#[derive(Debug, Clone)] -pub struct Pattern { - pub from: String, - pub to: Option, - pub context: Option, - pub to_type: Option, - pub no_error_on_missing: bool, - pub info: Option, - pub force: bool, - pub priority: i32, - pub glob_options: GlobOptions, -} - -#[derive(Debug, Clone)] -pub struct GlobOptions { - pub case_sensitive_match: Option, - pub dot: Option, - pub ignore: Option>, -} #[derive(Debug, Clone, Default)] pub struct PresetEnv { pub targets: Vec, diff --git a/crates/rspack_core/src/options/compiler_options.rs b/crates/rspack_core/src/options/compiler_options.rs index 02aa8b6118b..44d4af699f9 100644 --- a/crates/rspack_core/src/options/compiler_options.rs +++ b/crates/rspack_core/src/options/compiler_options.rs @@ -38,4 +38,16 @@ impl CompilerOptions { pub fn is_incremental_rebuild_emit_asset_enabled(&self) -> bool { self.experiments.incremental_rebuild.emit_asset } + + pub fn is_new_tree_shaking(&self) -> bool { + self.experiments.rspack_future.new_treeshaking + } + + /// This controls whether we're using the old Rspack behavior to transform a module. + /// - `true`: use the old strategy, and transform the non web standard modules into a standardized one. + /// `Rule.type` that are not supported by webpack is not usable. + /// - `false`: use the new strategy, only web-standard modules are supported. + pub fn should_transform_by_default(&self) -> bool { + !self.experiments.rspack_future.disable_transform_by_default + } } diff --git a/crates/rspack_core/src/options/experiments.rs b/crates/rspack_core/src/options/experiments.rs index c5afa9cce27..78ad175957b 100644 --- a/crates/rspack_core/src/options/experiments.rs +++ b/crates/rspack_core/src/options/experiments.rs @@ -24,6 +24,8 @@ impl IncrementalRebuildMakeState { #[derive(Debug, Default)] pub struct RspackFuture { pub new_resolver: bool, + pub new_treeshaking: bool, + pub disable_transform_by_default: bool, } #[derive(Debug, Default)] diff --git a/crates/rspack_core/src/options/externals.rs b/crates/rspack_core/src/options/externals.rs index 3f1f2f418a2..11dc1e21ab4 100644 --- a/crates/rspack_core/src/options/externals.rs +++ b/crates/rspack_core/src/options/externals.rs @@ -10,8 +10,9 @@ pub type Externals = Vec; #[derive(Debug)] pub enum ExternalItemValue { String(String), + Array(Vec), Bool(bool), - Array(Vec), // TODO: Record + Object(HashMap>), } pub type ExternalItemObject = HashMap; diff --git a/crates/rspack_core/src/options/optimizations.rs b/crates/rspack_core/src/options/optimizations.rs index aa9d309e7f4..c42793a78f7 100644 --- a/crates/rspack_core/src/options/optimizations.rs +++ b/crates/rspack_core/src/options/optimizations.rs @@ -44,9 +44,59 @@ impl SideEffectOption { } } +#[derive(Debug, Clone, Copy, Default)] +pub enum UsedExportsOption { + #[default] + False, + True, + Global, +} + +impl From<&str> for UsedExportsOption { + fn from(value: &str) -> Self { + match value { + "true" => Self::True, + "global" => Self::Global, + _ => Self::False, + } + } +} + +impl UsedExportsOption { + pub fn is_enable(&self) -> bool { + matches!(self, Self::Global | Self::True) + } + + /// Returns `true` if the used exports is [`False`]. + /// + /// [`False`]: UsedExports::False + #[must_use] + pub fn is_false(&self) -> bool { + matches!(self, Self::False) + } + + /// Returns `true` if the used exports is [`True`]. + /// + /// [`True`]: UsedExports::True + #[must_use] + pub fn is_true(&self) -> bool { + matches!(self, Self::True) + } + + /// Returns `true` if the used exports is [`Global`]. + /// + /// [`Global`]: UsedExports::Global + #[must_use] + pub fn is_global(&self) -> bool { + matches!(self, Self::Global) + } +} + #[derive(Debug)] pub struct Optimization { pub remove_available_modules: bool, pub remove_empty_chunks: bool, pub side_effects: SideEffectOption, + pub provided_exports: bool, + pub used_exports: UsedExportsOption, } diff --git a/crates/rspack_core/src/options/output.rs b/crates/rspack_core/src/options/output.rs index 4a448a5c07c..5251a718a10 100644 --- a/crates/rspack_core/src/options/output.rs +++ b/crates/rspack_core/src/options/output.rs @@ -34,6 +34,7 @@ pub struct OutputOptions { pub css_chunk_filename: Filename, pub hot_update_main_filename: Filename, pub hot_update_chunk_filename: Filename, + pub hot_update_global: String, pub library: Option, pub enabled_library_types: Option>, pub strict_module_error_handling: bool, diff --git a/crates/rspack_core/src/plugin/api.rs b/crates/rspack_core/src/plugin/api.rs index 9bca72db1b4..8973374b337 100644 --- a/crates/rspack_core/src/plugin/api.rs +++ b/crates/rspack_core/src/plugin/api.rs @@ -35,7 +35,7 @@ pub type PluginRenderChunkHookOutput = Result>; pub type PluginProcessAssetsOutput = Result<()>; pub type PluginOptimizeChunksOutput = Result<()>; pub type PluginAdditionalChunkRuntimeRequirementsOutput = Result<()>; -pub type PluginRenderModuleContentOutput = Result>; +pub type PluginRenderModuleContentOutput<'a> = Result>; pub type PluginRenderStartupHookOutput = Result>; pub type PluginRenderHookOutput = Result>; pub type PluginJsChunkHashHookOutput = Result<()>; @@ -189,12 +189,12 @@ pub trait Plugin: Debug + Send + Sync { } // JavascriptModulesPlugin hook - fn render_module_content( - &self, + fn render_module_content<'a>( + &'a self, _ctx: PluginContext, - _args: &RenderModuleContentArgs, - ) -> PluginRenderModuleContentOutput { - Ok(None) + args: RenderModuleContentArgs<'a>, + ) -> PluginRenderModuleContentOutput<'a> { + Ok(args) } // JavascriptModulesPlugin hook @@ -370,6 +370,14 @@ pub trait Plugin: Debug + Send + Sync { Ok(()) } + async fn optimize_dependencies(&self, _compilation: &mut Compilation) -> Result> { + Ok(None) + } + + async fn optimize_tree(&self, _compilation: &mut Compilation) -> Result<()> { + Ok(()) + } + async fn optimize_chunk_modules(&self, _args: OptimizeChunksArgs<'_>) -> Result<()> { Ok(()) } diff --git a/crates/rspack_core/src/plugin/args.rs b/crates/rspack_core/src/plugin/args.rs index 0c1ab87dc02..5e67ffea144 100644 --- a/crates/rspack_core/src/plugin/args.rs +++ b/crates/rspack_core/src/plugin/args.rs @@ -9,9 +9,9 @@ use rustc_hash::FxHashSet as HashSet; use crate::ast::css::Ast as CssAst; use crate::ast::javascript::Ast as JsAst; use crate::{ - Chunk, ChunkUkey, Compilation, Context, DependencyCategory, DependencyType, ErrorSpan, - FactoryMeta, ModuleDependency, ModuleIdentifier, Resolve, RuntimeGlobals, SharedPluginDriver, - Stats, + Chunk, ChunkInitFragments, ChunkUkey, Compilation, Context, DependencyCategory, DependencyType, + ErrorSpan, FactoryMeta, ModuleDependency, ModuleGraphModule, ModuleIdentifier, Resolve, + RuntimeGlobals, SharedPluginDriver, Stats, }; // #[derive(Debug)] // pub struct ParseModuleArgs<'a> { @@ -235,8 +235,10 @@ impl<'me> RenderChunkArgs<'me> { #[derive(Debug)] pub struct RenderModuleContentArgs<'a> { - pub module_source: &'a BoxSource, + pub module_source: BoxSource, + pub chunk_init_fragments: ChunkInitFragments, pub compilation: &'a Compilation, + pub module_graph_module: &'a ModuleGraphModule, } #[derive(Debug)] diff --git a/crates/rspack_core/src/plugin/plugin_driver.rs b/crates/rspack_core/src/plugin/plugin_driver.rs index d0437ec0f18..fc28fa7fc9a 100644 --- a/crates/rspack_core/src/plugin/plugin_driver.rs +++ b/crates/rspack_core/src/plugin/plugin_driver.rs @@ -294,16 +294,14 @@ impl PluginDriver { Ok(()) } - pub fn render_module_content( - &self, - args: RenderModuleContentArgs, - ) -> PluginRenderModuleContentOutput { + pub fn render_module_content<'a>( + &'a self, + mut args: RenderModuleContentArgs<'a>, + ) -> PluginRenderModuleContentOutput<'a> { for plugin in &self.plugins { - if let Some(source) = plugin.render_module_content(PluginContext::new(), &args)? { - return Ok(Some(source)); - } + args = plugin.render_module_content(PluginContext::new(), args)?; } - Ok(None) + Ok(args) } pub async fn factorize( @@ -501,6 +499,24 @@ impl PluginDriver { Ok(()) } + #[instrument(name = "plugin:optimize_dependencies", skip_all)] + pub async fn optimize_dependencies(&self, compilation: &mut Compilation) -> Result> { + for plugin in &self.plugins { + if let Some(t) = plugin.optimize_dependencies(compilation).await? { + return Ok(Some(t)); + }; + } + Ok(None) + } + + #[instrument(name = "plugin:optimize_tree", skip_all)] + pub async fn optimize_tree(&self, compilation: &mut Compilation) -> Result<()> { + for plugin in &self.plugins { + plugin.optimize_tree(compilation).await?; + } + Ok(()) + } + #[instrument(name = "plugin:optimize_chunk_modules", skip_all)] pub async fn optimize_chunk_modules(&self, compilation: &mut Compilation) -> Result<()> { for plugin in &self.plugins { diff --git a/crates/rspack_core/src/resolver/resolver_impl.rs b/crates/rspack_core/src/resolver/resolver_impl.rs index 47cf507cbdc..74313370fa6 100644 --- a/crates/rspack_core/src/resolver/resolver_impl.rs +++ b/crates/rspack_core/src/resolver/resolver_impl.rs @@ -423,6 +423,10 @@ fn map_oxc_resolver_error( }, ) } + oxc_resolver::ResolveError::TsconfigNotFound(path) => ResolveError( + format!("{} is not a tsconfig", path.display()), + internal_error!("{} is not a tsconfig", path.display()), + ), _ => { let is_recursion = matches!(error, oxc_resolver::ResolveError::Recursion); map_resolver_error(is_recursion, args, plugin_driver) diff --git a/crates/rspack_core/src/runtime_module.rs b/crates/rspack_core/src/runtime_module.rs index c1c8e06393a..9ebd9f6e4b6 100644 --- a/crates/rspack_core/src/runtime_module.rs +++ b/crates/rspack_core/src/runtime_module.rs @@ -7,8 +7,8 @@ pub trait RuntimeModule: Module { fn name(&self) -> Identifier; fn generate(&self, compilation: &Compilation) -> BoxSource; fn attach(&mut self, _chunk: ChunkUkey) {} - fn stage(&self) -> u8 { - 0 + fn stage(&self) -> RuntimeModuleStage { + RuntimeModuleStage::Normal } // webpack fullHash || dependentHash fn cacheable(&self) -> bool { @@ -20,10 +20,13 @@ pub trait RuntimeModule: Module { } } -/** - * Runtime modules which attach to handlers of other runtime modules - */ -pub const RUNTIME_MODULE_STAGE_ATTACH: u8 = 10; +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum RuntimeModuleStage { + Normal, // Runtime modules without any dependencies to other runtime modules + Basic, // Runtime modules with simple dependencies on other runtime modules + Attach, // Runtime modules which attach to handlers of other runtime modules + Trigger, // Runtime modules which trigger actions on bootstrap +} pub trait RuntimeModuleExt { fn boxed(self) -> Box; diff --git a/crates/rspack_core/src/utils/mod.rs b/crates/rspack_core/src/utils/mod.rs index 2d265bc1ce3..a1603ba39be 100644 --- a/crates/rspack_core/src/utils/mod.rs +++ b/crates/rspack_core/src/utils/mod.rs @@ -6,6 +6,9 @@ use rustc_hash::FxHashMap as HashMap; mod identifier; pub use identifier::*; +mod property_access; +pub use property_access::*; + mod comment; pub use comment::*; diff --git a/crates/rspack_core/src/utils/property_access.rs b/crates/rspack_core/src/utils/property_access.rs new file mode 100644 index 00000000000..d54b64d05df --- /dev/null +++ b/crates/rspack_core/src/utils/property_access.rs @@ -0,0 +1,64 @@ +use once_cell::sync::Lazy; +use regex::Regex; + +static SAFE_IDENTIFIER_REGEX: Lazy = + Lazy::new(|| Regex::new(r"^[_a-zA-Z$][_a-zA-Z$0-9]*$").expect("should init regex")); +const RESERVED_IDENTIFIER: [&str; 37] = [ + "break", + "case", + "catch", + "class", + "const", + "continue", + "debugger", + "default", + "delete", + "do", + "else", + "enum", + "export", + "extends", + "false", + "finally", + "for", + "function", + "if", + "import", + "in", + "instanceof", + "new", + "null", + "package", + "return", + "super", + "switch", + "this", + "throw", + "true", + "try", + "typeof", + "var", + "void", + "while", + "with", +]; + +pub fn property_access>(o: impl IntoIterator, start: usize) -> String { + o.into_iter() + .skip(start) + .fold(String::default(), |mut str, property| { + let property = property.as_ref(); + if SAFE_IDENTIFIER_REGEX.is_match(property) && !RESERVED_IDENTIFIER.contains(&property) { + str.push_str(format!(".{property}").as_str()); + } else { + str.push_str( + format!( + "[{}]", + serde_json::to_string(property).expect("should render property") + ) + .as_str(), + ); + } + str + }) +} diff --git a/crates/rspack_error/src/catch_unwind.rs b/crates/rspack_error/src/catch_unwind.rs index b7363605262..6f4d059399c 100644 --- a/crates/rspack_error/src/catch_unwind.rs +++ b/crates/rspack_error/src/catch_unwind.rs @@ -1,5 +1,4 @@ use std::{ - cell::RefCell, future::Future, pin::Pin, task::{Context, Poll}, @@ -9,86 +8,29 @@ use futures::{future::BoxFuture, FutureExt}; use super::{internal_error, Result}; -#[allow(non_snake_case)] -pub mod PanicStrategy { - /// Strategy for panic handling. - /// [`PanicStrategy::Suppressed`] means that panic for `catch_unwind` is suppressed. - /// [`PanicStrategy::NotSuppressed`] means that panic for `catch_unwind` is not suppressed. - pub trait S: 'static + Unpin + Send + Sync { - fn is_suppressed() -> bool; - } - - /// Panic for `catch_unwind` is suppressed. But it is not - /// suppressed for those which are not wrapped by `catch_unwind`. - pub struct Suppressed; - - impl S for Suppressed { - #[inline] - fn is_suppressed() -> bool { - true - } - } - - /// Panic for `catch_unwind` is not suppressed. - /// Every panic will be preserved and propagated to the panic hook set before. - pub struct NotSuppressed; - - impl S for NotSuppressed { - #[inline] - fn is_suppressed() -> bool { - false - } - } -} - -#[inline] -fn panic_hook_handler(f: impl FnOnce() -> R) -> R { - let prev = std::panic::take_hook(); - std::panic::set_hook(Box::new(move |info| { - PANIC_INFO_AND_BACKTRACE.with(|bt| { - *bt.borrow_mut() = Some(( - info.to_string(), - std::backtrace::Backtrace::force_capture().to_string(), - )); - }); - if !S::is_suppressed() { - prev(info); - } - })); - let result = f(); - let _ = std::panic::take_hook(); - - result -} +const GENERIC_FATAL_MESSAGE: &str = + "This is not expected, please file an issue at https://github.com/web-infra-dev/rspack/issues."; -thread_local! { - static PANIC_INFO_AND_BACKTRACE: RefCell> = RefCell::new(None); +fn raise(message: &str) -> crate::Error { + let backtrace = std::backtrace::Backtrace::force_capture().to_string(); + internal_error!( + r#"{message} +{GENERIC_FATAL_MESSAGE} +{backtrace} +"# + ) } -pub fn catch_unwind(f: impl FnOnce() -> R) -> Result { - match panic_hook_handler::(move || { - std::panic::catch_unwind(std::panic::AssertUnwindSafe(f)) - }) { +pub fn catch_unwind(f: impl FnOnce() -> R) -> Result { + match std::panic::catch_unwind(std::panic::AssertUnwindSafe(f)) { Ok(res) => Ok(res), - Err(cause) => { - let (info, backtrace) = PANIC_INFO_AND_BACKTRACE - .with(|b| b.borrow_mut().take()) - .unwrap_or_default(); - - match cause.downcast_ref::<&'static str>() { - None => match cause.downcast_ref::() { - None => Err(internal_error!( - "Unknown fatal error.\nRaw: {info}\n{GENERIC_FATAL_MESSAGE}\n\n{backtrace}" - )), - Some(message) => Err(internal_error!( - "{message}.\nRaw: {info}\n{GENERIC_FATAL_MESSAGE}\n\n{backtrace}" - )), - }, - Some(message) => Err(internal_error!( - "{message}.\nRaw: {info}\n{GENERIC_FATAL_MESSAGE}\n\n{backtrace}" - )), - } - } + Err(cause) => match cause.downcast_ref::<&'static str>() { + None => match cause.downcast_ref::() { + None => Err(raise("Unknown fatal error")), + Some(message) => Err(raise(message)), + }, + Some(message) => Err(raise(message)), + }, } } @@ -108,13 +50,10 @@ impl Future for CatchUnwindFuture { fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let inner = &mut self.inner; - match catch_unwind::(move || inner.poll_unpin(cx)) { + match catch_unwind(move || inner.poll_unpin(cx)) { Ok(Poll::Pending) => Poll::Pending, Ok(Poll::Ready(value)) => Poll::Ready(Ok(value)), Err(cause) => Poll::Ready(Err(cause)), } } } - -const GENERIC_FATAL_MESSAGE: &str = - "This is not expected, please file an issue at https://github.com/web-infra-dev/rspack/issues."; diff --git a/crates/rspack_loader_react_refresh/Cargo.toml b/crates/rspack_loader_react_refresh/Cargo.toml new file mode 100644 index 00000000000..c5776208b2a --- /dev/null +++ b/crates/rspack_loader_react_refresh/Cargo.toml @@ -0,0 +1,14 @@ +[package] +edition = "2021" +license = "MIT" +name = "rspack_loader_react_refresh" +repository = "https://github.com/web-infra-dev/rspack" +version = "0.1.0" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +async-trait = { workspace = true } +rspack_core = { path = "../rspack_core" } +rspack_error = { path = "../rspack_error" } +rspack_loader_runner = { path = "../rspack_loader_runner" } diff --git a/crates/rspack_loader_react_refresh/LICENSE b/crates/rspack_loader_react_refresh/LICENSE new file mode 100644 index 00000000000..46310101ad8 --- /dev/null +++ b/crates/rspack_loader_react_refresh/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2022-present Bytedance, Inc. and its affiliates. + + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/crates/rspack_loader_react_refresh/src/lib.rs b/crates/rspack_loader_react_refresh/src/lib.rs new file mode 100644 index 00000000000..47997e7cf59 --- /dev/null +++ b/crates/rspack_loader_react_refresh/src/lib.rs @@ -0,0 +1,53 @@ +use rspack_core::LoaderRunnerContext; +use rspack_error::{internal_error, Result}; +use rspack_loader_runner::{Identifiable, Identifier, Loader, LoaderContext}; + +pub struct ReactRefreshLoader { + identifier: Identifier, +} + +impl Default for ReactRefreshLoader { + fn default() -> Self { + Self { + identifier: REACT_REFRESH_LOADER_IDENTIFIER.into(), + } + } +} + +impl ReactRefreshLoader { + /// Panics: + /// Panics if `identifier` passed in is not starting with `builtin:react-refresh-loader`. + pub fn with_identifier(mut self, identifier: Identifier) -> Self { + assert!(identifier.starts_with(REACT_REFRESH_LOADER_IDENTIFIER)); + self.identifier = identifier; + self + } +} + +#[async_trait::async_trait] +impl Loader for ReactRefreshLoader { + async fn run(&self, loader_context: &mut LoaderContext<'_, LoaderRunnerContext>) -> Result<()> { + let Some(content) = std::mem::take(&mut loader_context.content) else { + return Err(internal_error!("Content should be available")) + }; + let mut source = content.try_into_string()?; + source += r#" +function $RefreshReg$(type, id) { + $ReactRefreshRuntime$.register(type, __webpack_module__.id + "_" + id); +} +Promise.resolve().then(function() { + $ReactRefreshRuntime$.refresh(__webpack_module__.id, __webpack_module__.hot); +}); +"#; + loader_context.content = Some(source.into()); + Ok(()) + } +} + +pub const REACT_REFRESH_LOADER_IDENTIFIER: &str = "builtin:react-refresh-loader"; + +impl Identifiable for ReactRefreshLoader { + fn identifier(&self) -> Identifier { + self.identifier + } +} diff --git a/crates/rspack_loader_sass/tests/fixtures.rs b/crates/rspack_loader_sass/tests/fixtures.rs index 67a8e4b12f7..76cff787f7e 100644 --- a/crates/rspack_loader_sass/tests/fixtures.rs +++ b/crates/rspack_loader_sass/tests/fixtures.rs @@ -53,6 +53,7 @@ async fn loader_test(actual: impl AsRef, expected: impl AsRef) { css_filename: rspack_core::Filename::from_str("").expect("TODO:"), hot_update_chunk_filename: rspack_core::Filename::from_str("").expect("Should exist"), hot_update_main_filename: rspack_core::Filename::from_str("").expect("Should exist"), + hot_update_global: "webpackHotUpdate".to_string(), library: None, enabled_library_types: None, strict_module_error_handling: false, @@ -87,6 +88,8 @@ async fn loader_test(actual: impl AsRef, expected: impl AsRef) { remove_available_modules: false, remove_empty_chunks: true, side_effects: SideEffectOption::False, + provided_exports: Default::default(), + used_exports: Default::default(), }, profile: false, }), diff --git a/crates/rspack_loader_swc/src/options.rs b/crates/rspack_loader_swc/src/options.rs index 54a9d08c0cc..7e9112c2a02 100644 --- a/crates/rspack_loader_swc/src/options.rs +++ b/crates/rspack_loader_swc/src/options.rs @@ -1,6 +1,5 @@ use rspack_swc_visitors::{ - EmotionOptions, ImportOptions, RawEmotionOptions, RawImportOptions, RawReactOptions, - RawRelayOptions, ReactOptions, RelayOptions, + EmotionOptions, ImportOptions, RawEmotionOptions, RawImportOptions, RawRelayOptions, RelayOptions, }; use serde::Deserialize; use swc_config::config_types::BoolConfig; @@ -13,7 +12,6 @@ use swc_core::base::config::{ #[serde(rename_all = "camelCase", default)] pub struct RawRspackExperiments { pub relay: Option, - pub react: Option, pub import: Option>, pub emotion: Option, } @@ -21,7 +19,6 @@ pub struct RawRspackExperiments { #[derive(Default, Debug)] pub(crate) struct RspackExperiments { pub(crate) relay: Option, - pub(crate) react: Option, pub(crate) import: Option>, pub(crate) emotion: Option, } @@ -30,7 +27,6 @@ impl From for RspackExperiments { fn from(value: RawRspackExperiments) -> Self { Self { relay: value.relay.map(|v| v.into()), - react: value.react.map(|v| v.into()), import: value .import .map(|i| i.into_iter().map(|v| v.into()).collect()), diff --git a/crates/rspack_loader_swc/src/transformer.rs b/crates/rspack_loader_swc/src/transformer.rs index 1e7048740a2..7fca284c27f 100644 --- a/crates/rspack_loader_swc/src/transformer.rs +++ b/crates/rspack_loader_swc/src/transformer.rs @@ -4,10 +4,7 @@ use std::sync::Arc; use either::Either; use rspack_core::CompilerOptions; use swc_core::common::{chain, comments::Comments, Mark, SourceMap}; -use swc_core::ecma::{ - transforms::base::pass::{noop, Optional}, - visit::Fold, -}; +use swc_core::ecma::{transforms::base::pass::noop, visit::Fold}; use crate::options::RspackExperiments; @@ -33,7 +30,7 @@ pub(crate) fn transform<'a>( resource_path: &'a Path, rspack_options: &'a CompilerOptions, comments: Option<&'a dyn Comments>, - top_level_mark: Mark, + _top_level_mark: Mark, unresolved_mark: Mark, cm: Arc, content_hash: Option, @@ -42,17 +39,6 @@ pub(crate) fn transform<'a>( use rspack_swc_visitors::EmotionOptions; chain!( - either!(rspack_experiments.react, |options| { - rspack_swc_visitors::react(top_level_mark, comments, &cm, options, unresolved_mark) - }), - Optional::new( - rspack_swc_visitors::fold_react_refresh(unresolved_mark), - rspack_experiments - .react - .as_ref() - .and_then(|v| v.refresh) - .unwrap_or_default() - ), either!(rspack_experiments.emotion, |options: &EmotionOptions| { // SAFETY: Source content hash should always available if emotion is turned on. let content_hash = content_hash.expect("Content hash should be available"); diff --git a/crates/rspack_loader_swc/tests/fixtures.rs b/crates/rspack_loader_swc/tests/fixtures.rs index de50e0c32d2..5140f574d5f 100644 --- a/crates/rspack_loader_swc/tests/fixtures.rs +++ b/crates/rspack_loader_swc/tests/fixtures.rs @@ -53,6 +53,7 @@ async fn loader_test(actual: impl AsRef, expected: impl AsRef) { css_filename: rspack_core::Filename::from_str("").expect("TODO:"), hot_update_chunk_filename: rspack_core::Filename::from_str("").expect("Should exist"), hot_update_main_filename: rspack_core::Filename::from_str("").expect("Should exist"), + hot_update_global: "webpackHotUpdate".to_string(), library: None, enabled_library_types: None, strict_module_error_handling: false, @@ -87,6 +88,8 @@ async fn loader_test(actual: impl AsRef, expected: impl AsRef) { remove_available_modules: false, remove_empty_chunks: true, side_effects: SideEffectOption::False, + provided_exports: Default::default(), + used_exports: Default::default(), }, profile: false, }), @@ -113,5 +116,5 @@ async fn loader_test(actual: impl AsRef, expected: impl AsRef) { #[fixture("tests/fixtures/*")] fn swc(fixture_path: PathBuf) { - test_fixture(&fixture_path); + test_fixture(&fixture_path, Box::new(|_, _| {}), None); } diff --git a/crates/rspack_plugin_asset/tests/fixtures.rs b/crates/rspack_plugin_asset/tests/fixtures.rs index 339e32a5f58..6a01c7efff1 100644 --- a/crates/rspack_plugin_asset/tests/fixtures.rs +++ b/crates/rspack_plugin_asset/tests/fixtures.rs @@ -4,10 +4,10 @@ use rspack_testing::{fixture, test_fixture}; #[fixture("tests/fixtures/webpack/*")] fn webpack_asset(fixture_path: PathBuf) { - test_fixture(&fixture_path); + test_fixture(&fixture_path, Box::new(|_, _| {}), None); } #[fixture("tests/fixtures/rspack/*")] fn rspack_asset(fixture_path: PathBuf) { - test_fixture(&fixture_path); + test_fixture(&fixture_path, Box::new(|_, _| {}), None); } diff --git a/crates/rspack_plugin_banner/src/lib.rs b/crates/rspack_plugin_banner/src/lib.rs index 9a252480e92..a96ced341f4 100644 --- a/crates/rspack_plugin_banner/src/lib.rs +++ b/crates/rspack_plugin_banner/src/lib.rs @@ -16,19 +16,19 @@ use rspack_regex::RspackRegex; use rspack_util::try_any; #[derive(Debug)] -pub enum BannerCondition { +pub enum BannerRule { String(String), Regexp(RspackRegex), } #[derive(Debug)] -pub enum BannerConditions { +pub enum BannerRules { String(String), Regexp(RspackRegex), - Array(Vec), + Array(Vec), } -impl BannerCondition { +impl BannerRule { #[async_recursion] pub async fn try_match(&self, data: &str) -> Result { match self { @@ -38,7 +38,7 @@ impl BannerCondition { } } -impl BannerConditions { +impl BannerRules { #[async_recursion] pub async fn try_match(&self, data: &str) -> Result { match self { @@ -50,7 +50,7 @@ impl BannerConditions { } #[derive(Debug)] -pub struct BannerConfig { +pub struct BannerPluginOptions { // Specifies the banner. pub banner: BannerContent, // If true, the banner will only be added to the entry chunks. @@ -60,11 +60,11 @@ pub struct BannerConfig { // If true, banner will not be wrapped in a comment. pub raw: Option, // Include all modules that pass test assertion. - pub test: Option, + pub test: Option, // Include all modules matching any of these conditions. - pub include: Option, + pub include: Option, // Exclude all modules matching any of these conditions. - pub exclude: Option, + pub exclude: Option, } pub struct BannerContentFnCtx<'a> { @@ -91,7 +91,7 @@ impl fmt::Debug for BannerContent { } #[async_recursion] -async fn match_object(obj: &BannerConfig, str: &str) -> Result { +async fn match_object(obj: &BannerPluginOptions, str: &str) -> Result { if let Some(condition) = &obj.test { if !condition.try_match(str).await? { return Ok(false); @@ -131,11 +131,11 @@ fn wrap_comment(str: &str) -> String { #[derive(Debug)] pub struct BannerPlugin { - config: BannerConfig, + config: BannerPluginOptions, } impl BannerPlugin { - pub fn new(config: BannerConfig) -> Self { + pub fn new(config: BannerPluginOptions) -> Self { Self { config } } diff --git a/crates/rspack_plugin_copy/src/lib.rs b/crates/rspack_plugin_copy/src/lib.rs index 72efb818acf..d9cf89c59ec 100644 --- a/crates/rspack_plugin_copy/src/lib.rs +++ b/crates/rspack_plugin_copy/src/lib.rs @@ -1,5 +1,6 @@ #![feature(let_chains)] use std::{ + fmt::Display, fs, hash::Hash, path::{Path, PathBuf, MAIN_SEPARATOR}, @@ -8,16 +9,65 @@ use std::{ use async_trait::async_trait; use dashmap::DashSet; -use glob::MatchOptions; +use glob::{MatchOptions, Pattern as GlobPattern}; use regex::Regex; use rspack_core::{ rspack_sources::RawSource, AssetInfo, Compilation, CompilationAsset, CompilationLogger, Filename, - FromType, Logger, PathData, Pattern, Plugin, ToType, + Logger, PathData, Plugin, }; use rspack_error::Diagnostic; use rspack_hash::{HashDigest, HashFunction, HashSalt, RspackHash, RspackHashDigest}; use sugar_path::{AsPath, SugarPath}; +#[derive(Debug, Clone)] +pub struct CopyRspackPluginOptions { + pub patterns: Vec, +} + +#[derive(Debug, Clone, Copy)] +pub enum FromType { + Dir, + File, + Glob, +} + +#[derive(Debug, Clone)] +pub enum ToType { + Dir, + File, + Template, +} + +impl Display for ToType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(match self { + ToType::Dir => "dir", + ToType::File => "file", + ToType::Template => "template", + }) + } +} + +#[derive(Debug, Clone)] +pub struct CopyPattern { + pub from: String, + pub to: Option, + pub context: Option, + pub to_type: Option, + pub no_error_on_missing: bool, + pub info: Option, + pub force: bool, + pub priority: i32, + pub glob_options: CopyGlobOptions, +} + +#[derive(Debug, Clone)] +pub struct CopyGlobOptions { + pub case_sensitive_match: Option, + pub dot: Option, + pub ignore: Option>, +} + #[derive(Debug, Clone)] pub struct RunPatternResult { pub source_filename: PathBuf, @@ -30,8 +80,8 @@ pub struct RunPatternResult { } #[derive(Debug)] -pub struct CopyPlugin { - pub patterns: Vec, +pub struct CopyRspackPlugin { + pub patterns: Vec, } lazy_static::lazy_static! { @@ -39,8 +89,8 @@ lazy_static::lazy_static! { static ref TEMPLATE_RE: Regex = Regex::new(r"\[\\*([\w:]+)\\*\]").expect("This never fail"); } -impl CopyPlugin { - pub fn new(patterns: Vec) -> Self { +impl CopyRspackPlugin { + pub fn new(patterns: Vec) -> Self { Self { patterns } } @@ -65,7 +115,7 @@ impl CopyPlugin { #[allow(clippy::too_many_arguments)] async fn analyze_every_entry( entry: PathBuf, - pattern: &Pattern, + pattern: &CopyPattern, context: &Path, output_path: &Path, from_type: FromType, @@ -216,7 +266,7 @@ impl CopyPlugin { fn run_patter( compilation: &Compilation, - pattern: &Pattern, + pattern: &CopyPattern, _index: usize, file_dependencies: &DashSet, context_dependencies: &DashSet, @@ -432,9 +482,9 @@ impl CopyPlugin { } #[async_trait] -impl Plugin for CopyPlugin { +impl Plugin for CopyRspackPlugin { fn name(&self) -> &'static str { - "rspack.CopyPlugin" + "rspack.CopyRspackPlugin" } async fn process_assets_stage_additional( diff --git a/crates/rspack_plugin_css/src/dependency/compose.rs b/crates/rspack_plugin_css/src/dependency/compose.rs index 2cd9659f98f..ce6c0c5c9e6 100644 --- a/crates/rspack_plugin_css/src/dependency/compose.rs +++ b/crates/rspack_plugin_css/src/dependency/compose.rs @@ -50,6 +50,10 @@ impl ModuleDependency for CssComposeDependency { fn set_request(&mut self, request: String) { self.request = request; } + + fn dependency_debug_name(&self) -> &'static str { + "CssComposeDependency" + } } impl AsDependencyTemplate for CssComposeDependency {} diff --git a/crates/rspack_plugin_css/src/dependency/import.rs b/crates/rspack_plugin_css/src/dependency/import.rs index 0c5fb74cc24..35463bdff55 100644 --- a/crates/rspack_plugin_css/src/dependency/import.rs +++ b/crates/rspack_plugin_css/src/dependency/import.rs @@ -54,6 +54,10 @@ impl ModuleDependency for CssImportDependency { fn set_request(&mut self, request: String) { self.request = request; } + + fn dependency_debug_name(&self) -> &'static str { + "CssImportDependency" + } } impl DependencyTemplate for CssImportDependency { diff --git a/crates/rspack_plugin_css/src/dependency/url.rs b/crates/rspack_plugin_css/src/dependency/url.rs index 75db055930a..800f4c989af 100644 --- a/crates/rspack_plugin_css/src/dependency/url.rs +++ b/crates/rspack_plugin_css/src/dependency/url.rs @@ -86,6 +86,10 @@ impl ModuleDependency for CssUrlDependency { fn set_request(&mut self, request: String) { self.request = request; } + + fn dependency_debug_name(&self) -> &'static str { + "CssUrlDependency" + } } impl DependencyTemplate for CssUrlDependency { diff --git a/crates/rspack_plugin_devtool/src/lib.rs b/crates/rspack_plugin_devtool/src/lib.rs index 9cacb81e906..d2b4867b8e6 100644 --- a/crates/rspack_plugin_devtool/src/lib.rs +++ b/crates/rspack_plugin_devtool/src/lib.rs @@ -68,23 +68,25 @@ impl Plugin for DevtoolPlugin { "rspack.DevtoolPlugin" } - fn render_module_content( - &self, + fn render_module_content<'a>( + &'a self, _ctx: PluginContext, - args: &RenderModuleContentArgs, - ) -> PluginRenderModuleContentOutput { + mut args: RenderModuleContentArgs<'a>, + ) -> PluginRenderModuleContentOutput<'a> { let devtool = &args.compilation.options.devtool; let origin_source = args.module_source.clone(); if devtool.eval() && devtool.source_map() { if let Some(cached) = MODULE_RENDER_CACHE.get(&origin_source) { - return Ok(Some(cached.value().clone())); + args.module_source = cached.value().clone(); + return Ok(args); } else if let Some(map) = origin_source.map(&MapOptions::new(devtool.cheap())) { let source = wrap_eval_source_map(&origin_source.source(), map, args.compilation)?; MODULE_RENDER_CACHE.insert(origin_source, source.clone()); - return Ok(Some(source)); + args.module_source = source; + return Ok(args); } } - Ok(Some(origin_source)) + Ok(args) } fn js_chunk_hash( diff --git a/crates/rspack_plugin_externals/src/http_externals_plugin.rs b/crates/rspack_plugin_externals/src/http_externals_plugin.rs index ff864bd71a2..11c2381f538 100644 --- a/crates/rspack_plugin_externals/src/http_externals_plugin.rs +++ b/crates/rspack_plugin_externals/src/http_externals_plugin.rs @@ -13,11 +13,15 @@ static EXTERNAL_HTTP_STD_REQUEST: Lazy = static EXTERNAL_CSS_REQUEST: Lazy = Lazy::new(|| Regex::new(r"^\.css(\?|$)").expect("Invalid regex")); -pub fn http_externals_plugin(css: bool) -> BoxPlugin { - ExternalsPlugin::new("module".to_owned(), vec![http_external_item(css)]).boxed() +pub fn http_externals_rspack_plugin(css: bool, web_async: bool) -> BoxPlugin { + if web_async { + ExternalsPlugin::new("import".to_owned(), vec![http_external_item_web_async(css)]).boxed() + } else { + ExternalsPlugin::new("module".to_owned(), vec![http_external_item_web(css)]).boxed() + } } -fn http_external_item(css: bool) -> ExternalItem { +fn http_external_item_web(css: bool) -> ExternalItem { ExternalItem::Fn(Box::new(move |ctx: ExternalItemFnCtx| { Box::pin(async move { if ctx.dependency_type == "url" { @@ -54,3 +58,41 @@ fn http_external_item(css: bool) -> ExternalItem { }) })) } + +fn http_external_item_web_async(css: bool) -> ExternalItem { + ExternalItem::Fn(Box::new(move |ctx: ExternalItemFnCtx| { + Box::pin(async move { + if ctx.dependency_type == "url" { + if EXTERNAL_HTTP_REQUEST.is_match(&ctx.request) { + return Ok(ExternalItemFnResult { + external_type: Some("asset".to_owned()), + result: Some(ExternalItemValue::String(ctx.request)), + }); + } + } else if css && ctx.dependency_type == "css-import" { + if EXTERNAL_HTTP_REQUEST.is_match(&ctx.request) { + return Ok(ExternalItemFnResult { + external_type: Some("css-import".to_owned()), + result: Some(ExternalItemValue::String(ctx.request)), + }); + } + } else if EXTERNAL_HTTP_STD_REQUEST.is_match(&ctx.request) { + if css && EXTERNAL_CSS_REQUEST.is_match(&ctx.request) { + return Ok(ExternalItemFnResult { + external_type: Some("css-import".to_owned()), + result: Some(ExternalItemValue::String(ctx.request)), + }); + } else { + return Ok(ExternalItemFnResult { + external_type: Some("import".to_owned()), + result: Some(ExternalItemValue::String(ctx.request)), + }); + } + } + Ok(ExternalItemFnResult { + external_type: None, + result: None, + }) + }) + })) +} diff --git a/crates/rspack_plugin_externals/src/lib.rs b/crates/rspack_plugin_externals/src/lib.rs index 5d840981986..f5881ea19f0 100644 --- a/crates/rspack_plugin_externals/src/lib.rs +++ b/crates/rspack_plugin_externals/src/lib.rs @@ -6,6 +6,6 @@ mod node_target_plugin; mod plugin; pub use electron_target_plugin::{electron_target_plugin, ElectronTargetContext}; -pub use http_externals_plugin::http_externals_plugin; +pub use http_externals_plugin::http_externals_rspack_plugin; pub use node_target_plugin::node_target_plugin; pub use plugin::ExternalsPlugin; diff --git a/crates/rspack_plugin_externals/src/plugin.rs b/crates/rspack_plugin_externals/src/plugin.rs index ecda6aabaf6..1cce3486b3d 100644 --- a/crates/rspack_plugin_externals/src/plugin.rs +++ b/crates/rspack_plugin_externals/src/plugin.rs @@ -3,9 +3,10 @@ use std::fmt::Debug; use once_cell::sync::Lazy; use regex::Regex; use rspack_core::{ - ExternalItem, ExternalItemFnCtx, ExternalItemValue, ExternalModule, ExternalType, FactorizeArgs, - ModuleDependency, ModuleExt, ModuleFactoryResult, NormalModuleFactoryContext, Plugin, - PluginContext, PluginFactorizeHookOutput, + ExternalItem, ExternalItemFnCtx, ExternalItemValue, ExternalModule, ExternalRequest, + ExternalRequestValue, ExternalType, FactorizeArgs, ModuleDependency, ModuleExt, + ModuleFactoryResult, NormalModuleFactoryContext, Plugin, PluginContext, + PluginFactorizeHookOutput, }; static UNSPECIFIED_EXTERNAL_TYPE_REGEXP: Lazy = @@ -36,32 +37,76 @@ impl ExternalsPlugin { r#type: Option, dependency: &dyn ModuleDependency, ) -> Option { - let mut external_module_config: Vec = match config { - ExternalItemValue::String(config) => vec![config.clone()], + let (external_module_config, external_module_type) = match config { + ExternalItemValue::String(config) => { + let (external_type, config) = + if let Some((external_type, new_config)) = parse_external_type_from_str(config) { + (external_type, new_config) + } else { + (self.r#type.clone(), config.to_owned()) + }; + ( + ExternalRequest::Single(ExternalRequestValue::new(config, None)), + external_type, + ) + } + ExternalItemValue::Array(arr) => { + let mut iter = arr.iter().peekable(); + let primary = iter.next()?; + let (external_type, primary) = + if let Some((external_type, new_primary)) = parse_external_type_from_str(primary) { + (external_type, new_primary) + } else { + (self.r#type.clone(), primary.to_owned()) + }; + let rest = iter.peek().is_some().then(|| iter.cloned().collect()); + ( + ExternalRequest::Single(ExternalRequestValue::new(primary, rest)), + external_type, + ) + } ExternalItemValue::Bool(config) => { if *config { - vec![dependency.request().to_string()] + ( + ExternalRequest::Single(ExternalRequestValue::new( + dependency.request().to_string(), + None, + )), + self.r#type.clone(), + ) } else { return None; } } - ExternalItemValue::Array(config) => config.to_vec(), + ExternalItemValue::Object(map) => ( + ExternalRequest::Map( + map + .iter() + .map(|(k, v)| { + let mut iter = v.iter().peekable(); + let primary = iter.next().expect("should have at least one value"); + let rest = iter.peek().is_some().then(|| iter.cloned().collect()); + ( + k.clone(), + ExternalRequestValue::new(primary.to_owned(), rest), + ) + }) + .collect(), + ), + self.r#type.clone(), + ), }; - let external_module_type = r#type.unwrap_or_else(|| { - let head = external_module_config - .get_mut(0) - .expect("should have at least one element"); - if UNSPECIFIED_EXTERNAL_TYPE_REGEXP.is_match(head.as_str()) - && let Some((t, c)) = head.clone().as_str().split_once(' ') { - *head = c.to_string(); - return t.to_owned(); + fn parse_external_type_from_str(v: &str) -> Option<(ExternalType, String)> { + if UNSPECIFIED_EXTERNAL_TYPE_REGEXP.is_match(v) && let Some((t, c)) = v.split_once(' ') { + return Some((t.to_owned(), c.to_owned())); } - self.r#type.clone() - }); + None + } + Some(ExternalModule::new( external_module_config, - external_module_type, + r#type.unwrap_or(external_module_type), dependency.request().to_owned(), )) } diff --git a/crates/rspack_plugin_html/src/config.rs b/crates/rspack_plugin_html/src/config.rs index 87a9b725673..f5892bda760 100644 --- a/crates/rspack_plugin_html/src/config.rs +++ b/crates/rspack_plugin_html/src/config.rs @@ -11,22 +11,25 @@ use crate::sri::HtmlSriHashFunction; #[cfg_attr(feature = "testing", derive(JsonSchema))] #[derive(Deserialize, Debug, Clone, Copy)] #[serde(rename_all = "snake_case")] -pub enum HtmlPluginConfigInject { +pub enum HtmlInject { Head, Body, + False, } -impl FromStr for HtmlPluginConfigInject { +impl FromStr for HtmlInject { type Err = anyhow::Error; fn from_str(s: &str) -> Result { if s.eq("head") { - Ok(HtmlPluginConfigInject::Head) + Ok(HtmlInject::Head) } else if s.eq("body") { - Ok(HtmlPluginConfigInject::Body) + Ok(HtmlInject::Body) + } else if s.eq("false") { + Ok(HtmlInject::False) } else { Err(anyhow::Error::msg( - "inject in html config only support 'head' or 'body'", + "inject in html config only support 'head', 'body', or 'false'", )) } } @@ -35,22 +38,22 @@ impl FromStr for HtmlPluginConfigInject { #[cfg_attr(feature = "testing", derive(JsonSchema))] #[derive(Deserialize, Debug, Clone, Copy)] #[serde(rename_all = "snake_case")] -pub enum HtmlPluginConfigScriptLoading { +pub enum HtmlScriptLoading { Blocking, Defer, Module, } -impl FromStr for HtmlPluginConfigScriptLoading { +impl FromStr for HtmlScriptLoading { type Err = anyhow::Error; fn from_str(s: &str) -> Result { if s.eq("blocking") { - Ok(HtmlPluginConfigScriptLoading::Blocking) + Ok(HtmlScriptLoading::Blocking) } else if s.eq("defer") { - Ok(HtmlPluginConfigScriptLoading::Defer) + Ok(HtmlScriptLoading::Defer) } else if s.eq("module") { - Ok(HtmlPluginConfigScriptLoading::Module) + Ok(HtmlScriptLoading::Module) } else { Err(anyhow::Error::msg( "scriptLoading in html config only support 'blocking', 'defer' or 'module'", @@ -62,7 +65,7 @@ impl FromStr for HtmlPluginConfigScriptLoading { #[cfg_attr(feature = "testing", derive(JsonSchema))] #[derive(Deserialize, Debug)] #[serde(rename_all = "camelCase", deny_unknown_fields)] -pub struct HtmlPluginConfig { +pub struct HtmlRspackPluginOptions { /// emitted file name in output path #[serde(default = "default_filename")] pub filename: String, @@ -70,13 +73,14 @@ pub struct HtmlPluginConfig { pub template: Option, pub template_content: Option, pub template_parameters: Option>, - /// `head`, `body` or None - pub inject: Option, + /// `head`, `body`, `false` + #[serde(default = "default_inject")] + pub inject: HtmlInject, /// path or `auto` pub public_path: Option, /// `blocking`, `defer`, or `module` #[serde(default = "default_script_loading")] - pub script_loading: HtmlPluginConfigScriptLoading, + pub script_loading: HtmlScriptLoading, /// entry_chunk_name (only entry chunks are supported) pub chunks: Option>, @@ -96,18 +100,22 @@ fn default_filename() -> String { String::from("index.html") } -fn default_script_loading() -> HtmlPluginConfigScriptLoading { - HtmlPluginConfigScriptLoading::Defer +fn default_script_loading() -> HtmlScriptLoading { + HtmlScriptLoading::Defer } -impl Default for HtmlPluginConfig { - fn default() -> HtmlPluginConfig { - HtmlPluginConfig { +fn default_inject() -> HtmlInject { + HtmlInject::Head +} + +impl Default for HtmlRspackPluginOptions { + fn default() -> HtmlRspackPluginOptions { + HtmlRspackPluginOptions { filename: default_filename(), template: None, template_content: None, template_parameters: None, - inject: None, + inject: default_inject(), public_path: None, script_loading: default_script_loading(), chunks: None, @@ -121,7 +129,7 @@ impl Default for HtmlPluginConfig { } } -impl HtmlPluginConfig { +impl HtmlRspackPluginOptions { pub fn get_public_path(&self, compilation: &Compilation, filename: &str) -> String { match &self.public_path { Some(p) => PublicPath::ensure_ends_with_slash(p.clone()), diff --git a/crates/rspack_plugin_html/src/parser.rs b/crates/rspack_plugin_html/src/parser.rs index 7b7d7df3d18..3be6f2586a7 100644 --- a/crates/rspack_plugin_html/src/parser.rs +++ b/crates/rspack_plugin_html/src/parser.rs @@ -14,14 +14,14 @@ use swc_html::{ use swc_html_minifier::minify_document; pub use swc_html_minifier::option::MinifyOptions; -use crate::config::HtmlPluginConfig; +use crate::config::HtmlRspackPluginOptions; pub struct HtmlCompiler<'a> { - config: &'a HtmlPluginConfig, + config: &'a HtmlRspackPluginOptions, } impl<'a> HtmlCompiler<'a> { - pub fn new(config: &'a HtmlPluginConfig) -> Self { + pub fn new(config: &'a HtmlRspackPluginOptions) -> Self { Self { config } } diff --git a/crates/rspack_plugin_html/src/plugin.rs b/crates/rspack_plugin_html/src/plugin.rs index c3f755e8551..17b3ad12724 100644 --- a/crates/rspack_plugin_html/src/plugin.rs +++ b/crates/rspack_plugin_html/src/plugin.rs @@ -18,20 +18,20 @@ use serde::Deserialize; use swc_html::visit::VisitMutWith; use crate::{ - config::{HtmlPluginConfig, HtmlPluginConfigInject}, + config::{HtmlInject, HtmlRspackPluginOptions}, parser::HtmlCompiler, sri::{add_sri, create_digest_from_asset}, visitors::asset::{AssetWriter, HTMLPluginTag}, }; #[derive(Deserialize, Debug, Default)] -pub struct HtmlPlugin { - config: HtmlPluginConfig, +pub struct HtmlRspackPlugin { + config: HtmlRspackPluginOptions, } -impl HtmlPlugin { - pub fn new(config: HtmlPluginConfig) -> HtmlPlugin { - HtmlPlugin { config } +impl HtmlRspackPlugin { + pub fn new(config: HtmlRspackPluginOptions) -> HtmlRspackPlugin { + HtmlRspackPlugin { config } } } fn default_template() -> &'static str { @@ -47,9 +47,9 @@ fn default_template() -> &'static str { } #[async_trait] -impl Plugin for HtmlPlugin { +impl Plugin for HtmlRspackPlugin { fn name(&self) -> &'static str { - "html" + "rspack.HtmlRspackPlugin" } async fn process_assets_stage_optimize_inline( @@ -132,36 +132,28 @@ impl Plugin for HtmlPlugin { .collect::>(); let mut tags = vec![]; - for (asset_name, asset) in included_assets { - if let Some(extension) = Path::new(&asset_name).extension() { - let asset_uri = format!( - "{}{asset_name}", - config.get_public_path(compilation, &self.config.filename), - ); - let mut tag: Option = None; - if extension.eq_ignore_ascii_case("css") { - tag = Some(HTMLPluginTag::create_style( - &asset_uri, - Some(if let Some(inject) = &config.inject { - *inject - } else { - HtmlPluginConfigInject::Head - }), - )); - } else if extension.eq_ignore_ascii_case("js") || extension.eq_ignore_ascii_case("mjs") { - tag = Some(HTMLPluginTag::create_script( - &asset_uri, - Some(if let Some(inject) = &config.inject { - *inject - } else { - HtmlPluginConfigInject::Head - }), - &config.script_loading, - )) - } - - if let Some(tag) = tag { - tags.push((tag, asset)); + // if inject is 'false', don't do anything + if !matches!(config.inject, HtmlInject::False) { + for (asset_name, asset) in included_assets { + if let Some(extension) = Path::new(&asset_name).extension() { + let asset_uri = format!( + "{}{asset_name}", + config.get_public_path(compilation, &self.config.filename), + ); + let mut tag: Option = None; + if extension.eq_ignore_ascii_case("css") { + tag = Some(HTMLPluginTag::create_style(&asset_uri, config.inject)); + } else if extension.eq_ignore_ascii_case("js") || extension.eq_ignore_ascii_case("mjs") { + tag = Some(HTMLPluginTag::create_script( + &asset_uri, + config.inject, + &config.script_loading, + )) + } + + if let Some(tag) = tag { + tags.push((tag, asset)); + } } } } diff --git a/crates/rspack_plugin_html/src/visitors/asset.rs b/crates/rspack_plugin_html/src/visitors/asset.rs index 5bbe5585bc4..7e00a6cfa9d 100644 --- a/crates/rspack_plugin_html/src/visitors/asset.rs +++ b/crates/rspack_plugin_html/src/visitors/asset.rs @@ -9,7 +9,7 @@ use swc_html::ast::{Attribute, Child, Element, Namespace, Text}; use swc_html::visit::{VisitMut, VisitMutWith}; use super::utils::create_element; -use crate::config::{HtmlPluginConfig, HtmlPluginConfigInject, HtmlPluginConfigScriptLoading}; +use crate::config::{HtmlInject, HtmlRspackPluginOptions, HtmlScriptLoading}; // the tag #[derive(Debug)] @@ -17,15 +17,15 @@ pub struct HTMLPluginTag { pub tag_name: String, pub attributes: Vec, pub void_tag: bool, - // `head` or `body` - pub append_to: HtmlPluginConfigInject, + // `head`, `body`, `false` + pub append_to: HtmlInject, } impl HTMLPluginTag { - pub fn create_style(href: &str, append_to: Option) -> HTMLPluginTag { + pub fn create_style(href: &str, append_to: HtmlInject) -> HTMLPluginTag { HTMLPluginTag { tag_name: "link".to_string(), - append_to: append_to.unwrap_or(HtmlPluginConfigInject::Head), + append_to, attributes: vec![ HtmlPluginAttribute { attr_name: "href".to_string(), @@ -42,21 +42,21 @@ impl HTMLPluginTag { pub fn create_script( src: &str, - append_to: Option, - script_loading: &HtmlPluginConfigScriptLoading, + append_to: HtmlInject, + script_loading: &HtmlScriptLoading, ) -> HTMLPluginTag { let mut attributes = vec![HtmlPluginAttribute { attr_name: "src".to_string(), attr_value: Some(src.to_string()), }]; match script_loading { - HtmlPluginConfigScriptLoading::Defer => { + HtmlScriptLoading::Defer => { attributes.push(HtmlPluginAttribute { attr_name: "defer".to_string(), attr_value: None, }); } - HtmlPluginConfigScriptLoading::Module => { + HtmlScriptLoading::Module => { attributes.push(HtmlPluginAttribute { attr_name: "type".to_string(), attr_value: Some("module".to_string()), @@ -67,7 +67,7 @@ impl HTMLPluginTag { HTMLPluginTag { tag_name: "script".to_string(), - append_to: append_to.unwrap_or(HtmlPluginConfigInject::Body), + append_to, attributes, void_tag: false, } @@ -85,7 +85,7 @@ pub struct HtmlPluginAttribute { #[derive(Debug)] pub struct AssetWriter<'a, 'c> { - config: &'a HtmlPluginConfig, + config: &'a HtmlRspackPluginOptions, head_tags: Vec<&'a HTMLPluginTag>, body_tags: Vec<&'a HTMLPluginTag>, compilation: &'c Compilation, @@ -93,7 +93,7 @@ pub struct AssetWriter<'a, 'c> { impl<'a, 'c> AssetWriter<'a, 'c> { pub fn new( - config: &'a HtmlPluginConfig, + config: &'a HtmlRspackPluginOptions, tags: &'a [HTMLPluginTag], compilation: &'c Compilation, ) -> AssetWriter<'a, 'c> { @@ -101,12 +101,13 @@ impl<'a, 'c> AssetWriter<'a, 'c> { let mut body_tags: Vec<&HTMLPluginTag> = vec![]; for ele in tags.iter() { match ele.append_to { - HtmlPluginConfigInject::Head => { + HtmlInject::Head => { head_tags.push(ele); } - HtmlPluginConfigInject::Body => { + HtmlInject::Body => { body_tags.push(ele); } + _ => (), } } AssetWriter { diff --git a/crates/rspack_plugin_html/tests/fixtures/filename/snapshot/output.snap b/crates/rspack_plugin_html/tests/fixtures/filename/snapshot/output.snap index aa848b339c3..2e4a45e1941 100644 --- a/crates/rspack_plugin_html/tests/fixtures/filename/snapshot/output.snap +++ b/crates/rspack_plugin_html/tests/fixtures/filename/snapshot/output.snap @@ -1,7 +1,8 @@ --- source: crates/rspack_testing/src/run_fixture.rs +assertion_line: 146 --- -```html title=default.a23ce667a9bd8055.html +```html title=default.9d456d57b4f14d24.html @@ -13,7 +14,7 @@ source: crates/rspack_testing/src/run_fixture.rs ``` -```html title=index.a23ce667a9bd8055.html +```html title=index.9d456d57b4f14d24.html diff --git a/crates/rspack_plugin_javascript/src/ast/stringify.rs b/crates/rspack_plugin_javascript/src/ast/stringify.rs index 1ff2a75e913..634570ec7a0 100644 --- a/crates/rspack_plugin_javascript/src/ast/stringify.rs +++ b/crates/rspack_plugin_javascript/src/ast/stringify.rs @@ -32,7 +32,7 @@ pub fn stringify( EsVersion::Es2022, SourceMapConfig { enable: devtool.source_map(), - inline_sources_content: !devtool.no_sources(), + inline_sources_content: true, emit_columns: !devtool.cheap(), names: Default::default(), }, diff --git a/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_require_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_require_dependency.rs index 406ffd3ead3..4313771b6df 100644 --- a/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_require_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_require_dependency.rs @@ -68,6 +68,10 @@ impl ModuleDependency for CommonJsRequireDependency { fn set_request(&mut self, request: String) { self.request = request.into(); } + + fn dependency_debug_name(&self) -> &'static str { + "CommonJsRequireDependency" + } } impl DependencyTemplate for CommonJsRequireDependency { diff --git a/crates/rspack_plugin_javascript/src/dependency/commonjs/require_resolve_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/commonjs/require_resolve_dependency.rs index 678d36cacfe..60b56d9fc55 100644 --- a/crates/rspack_plugin_javascript/src/dependency/commonjs/require_resolve_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/commonjs/require_resolve_dependency.rs @@ -86,6 +86,10 @@ impl ModuleDependency for RequireResolveDependency { ) -> Vec { vec![] } + + fn dependency_debug_name(&self) -> &'static str { + "RequireResolveDependency" + } } impl DependencyTemplate for RequireResolveDependency { diff --git a/crates/rspack_plugin_javascript/src/dependency/context/common_js_require_context_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/context/common_js_require_context_dependency.rs index ae113cd9906..c9723ffe0a4 100644 --- a/crates/rspack_plugin_javascript/src/dependency/context/common_js_require_context_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/context/common_js_require_context_dependency.rs @@ -74,6 +74,10 @@ impl ModuleDependency for CommonJsRequireContextDependency { fn resource_identifier(&self) -> Option<&str> { Some(&self.resource_identifier) } + + fn dependency_debug_name(&self) -> &'static str { + "CommonJsRequireContextDependency" + } } impl DependencyTemplate for CommonJsRequireContextDependency { diff --git a/crates/rspack_plugin_javascript/src/dependency/context/import_context_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/context/import_context_dependency.rs index 8e10e1e4c78..a2f74d2df0f 100644 --- a/crates/rspack_plugin_javascript/src/dependency/context/import_context_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/context/import_context_dependency.rs @@ -74,6 +74,10 @@ impl ModuleDependency for ImportContextDependency { fn resource_identifier(&self) -> Option<&str> { Some(&self.resource_identifier) } + + fn dependency_debug_name(&self) -> &'static str { + "ImportContextDependency" + } } impl DependencyTemplate for ImportContextDependency { diff --git a/crates/rspack_plugin_javascript/src/dependency/context/require_context_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/context/require_context_dependency.rs index a400d175d3a..94d8e95b479 100644 --- a/crates/rspack_plugin_javascript/src/dependency/context/require_context_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/context/require_context_dependency.rs @@ -66,6 +66,10 @@ impl ModuleDependency for RequireContextDependency { fn resource_identifier(&self) -> Option<&str> { Some(&self.resource_identifier) } + + fn dependency_debug_name(&self) -> &'static str { + "RequireContextDependency" + } } impl DependencyTemplate for RequireContextDependency { diff --git a/crates/rspack_plugin_javascript/src/dependency/esm/harmony_export_expression_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/esm/harmony_export_expression_dependency.rs index 5c2667ecd83..0aaca883556 100644 --- a/crates/rspack_plugin_javascript/src/dependency/esm/harmony_export_expression_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/esm/harmony_export_expression_dependency.rs @@ -1,4 +1,7 @@ -use rspack_core::{DependencyTemplate, TemplateContext, TemplateReplaceSource}; +use rspack_core::{ + AsModuleDependency, Dependency, DependencyId, DependencyTemplate, ModuleDependency, + TemplateContext, TemplateReplaceSource, +}; pub const DEFAULT_EXPORT: &str = "__WEBPACK_DEFAULT_EXPORT__"; // pub const NAMESPACE_OBJECT_EXPORT: &'static str = "__WEBPACK_NAMESPACE_OBJECT__"; @@ -17,6 +20,7 @@ pub struct HarmonyExportExpressionDependency { pub end: u32, pub declaration: bool, pub function: Option, + pub id: DependencyId, } impl HarmonyExportExpressionDependency { @@ -31,10 +35,35 @@ impl HarmonyExportExpressionDependency { end, declaration, function, + id: DependencyId::default(), } } } +impl Dependency for HarmonyExportExpressionDependency { + fn id(&self) -> &rspack_core::DependencyId { + &self.id + } + + fn get_module_evaluation_side_effects_state( + &self, + _module_graph: &rspack_core::ModuleGraph, + _module_chain: &mut rustc_hash::FxHashSet, + ) -> rspack_core::ConnectionState { + rspack_core::ConnectionState::Bool(false) + } +} + +impl AsModuleDependency for HarmonyExportExpressionDependency { + fn as_module_dependency(&self) -> Option<&dyn ModuleDependency> { + None + } + + fn as_module_dependency_mut(&mut self) -> Option<&mut dyn ModuleDependency> { + None + } +} + impl DependencyTemplate for HarmonyExportExpressionDependency { fn apply( &self, diff --git a/crates/rspack_plugin_javascript/src/dependency/esm/harmony_export_imported_specifier_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/esm/harmony_export_imported_specifier_dependency.rs index 0d72b9c4966..903236a996a 100644 --- a/crates/rspack_plugin_javascript/src/dependency/esm/harmony_export_imported_specifier_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/esm/harmony_export_imported_specifier_dependency.rs @@ -1,14 +1,15 @@ use rspack_core::{ create_exports_object_referenced, create_no_exports_referenced, export_from_import, get_exports_type, process_export_info, ConnectionState, Dependency, DependencyCategory, - DependencyId, DependencyTemplate, DependencyType, ErrorSpan, ExportInfoId, ExportInfoProvided, - ExportsType, ExtendedReferencedExport, HarmonyExportInitFragment, ModuleDependency, ModuleGraph, - ModuleIdentifier, RuntimeSpec, TemplateContext, TemplateReplaceSource, UsageState, + DependencyCondition, DependencyId, DependencyTemplate, DependencyType, ErrorSpan, ExportInfoId, + ExportInfoProvided, ExportsType, ExtendedReferencedExport, HarmonyExportInitFragment, + ModuleDependency, ModuleGraph, ModuleIdentifier, RuntimeSpec, TemplateContext, + TemplateReplaceSource, UsageState, UsedName, }; use rustc_hash::FxHashSet as HashSet; use swc_core::ecma::atoms::JsWord; -use super::create_resource_identifier_for_esm_dependency; +use super::{create_resource_identifier_for_esm_dependency, harmony_import_dependency_apply}; // Create _webpack_require__.d(__webpack_exports__, {}). // case1: `import { a } from 'a'; export { a }` @@ -19,30 +20,42 @@ pub struct HarmonyExportImportedSpecifierDependency { pub id: DependencyId, pub request: JsWord, pub ids: Vec<(JsWord, Option)>, + /// used for get_mode + pub mode_ids: Vec<(JsWord, Option)>, name: Option, resource_identifier: String, // Because it is shared by multiply HarmonyExportImportedSpecifierDependency, so put it to `BuildInfo` // pub active_exports: HashSet, // pub all_star_exports: Option>, pub other_star_exports: Option>, // look like it is unused + pub export_all: bool, } impl HarmonyExportImportedSpecifierDependency { - pub fn new(request: JsWord, ids: Vec<(JsWord, Option)>, name: Option) -> Self { + pub fn new( + request: JsWord, + ids: Vec<(JsWord, Option)>, + mode_ids: Vec<(JsWord, Option)>, + name: Option, + export_all: bool, + ) -> Self { let resource_identifier = create_resource_identifier_for_esm_dependency(&request); Self { id: DependencyId::new(), + mode_ids, name, request, ids, resource_identifier, other_star_exports: None, + export_all, } } pub fn active_exports<'a>(&self, module_graph: &'a ModuleGraph) -> &'a HashSet { let build_info = module_graph - .module_graph_module_by_dependency_id(&self.id) + .parent_module_by_dependency_id(&self.id) + .and_then(|ident| module_graph.module_graph_module_by_identifier(&ident)) .expect("should have mgm") .build_info .as_ref() @@ -50,6 +63,7 @@ impl HarmonyExportImportedSpecifierDependency { &build_info.harmony_named_exports } + /// FIXME: this should use parent module id pub fn all_star_exports<'a>(&self, module_graph: &'a ModuleGraph) -> &'a Vec { let build_info = module_graph .module_graph_module_by_dependency_id(&self.id) @@ -75,10 +89,7 @@ impl HarmonyExportImportedSpecifierDependency { { imported_module_identifier } else { - return ExportMode { - kind: ExportModeType::Missing, - ..Default::default() - }; + return ExportMode::new(ExportModeType::Missing); }; let parent_module = module_graph @@ -92,11 +103,16 @@ impl HarmonyExportImportedSpecifierDependency { if let Some(name) = name.as_ref() && !ids.is_empty() && let Some(id) = ids.get(0) && id == "default" { match exports_type { ExportsType::Dynamic => { - return ExportMode { kind: ExportModeType::ReexportDynamicDefault, name: Some(name.clone()), ..Default::default() } + let mut export_mode = ExportMode::new(ExportModeType::ReexportDynamicDefault, ); + export_mode.name = Some(name.clone()); + return export_mode; }, ExportsType::DefaultOnly | ExportsType::DefaultWithNamed => { let export_info = exports_info.id.get_read_only_export_info(name, module_graph).id; - return ExportMode { kind: ExportModeType::ReexportNamedDefault, name: Some(name.clone()), partial_namespace_export_info: Some(export_info), ..Default::default() } + let mut export_mode = ExportMode::new( ExportModeType::ReexportNamedDefault); + export_mode.name = Some(name.clone()); + export_mode.partial_namespace_export_info = Some(export_info); + return export_mode; }, _ => {} } @@ -112,54 +128,44 @@ impl HarmonyExportImportedSpecifierDependency { // export { name as name } match exports_type { ExportsType::DefaultOnly => { - return ExportMode { - kind: ExportModeType::ReexportUndefined, - name: Some(name), - ..Default::default() - } + let mut export_mode = ExportMode::new(ExportModeType::ReexportUndefined); + export_mode.name = Some(name); + return export_mode; } _ => { - return ExportMode { - kind: ExportModeType::NormalReexport, - items: Some(vec![NormalReexportItem { - name, - ids: ids.to_vec(), - hidden: false, - checked: false, - export_info, - }]), - ..Default::default() - } + let mut export_mode = ExportMode::new(ExportModeType::NormalReexport); + export_mode.items = Some(vec![NormalReexportItem { + name, + ids: ids.to_vec(), + hidden: false, + checked: false, + export_info, + }]); + return export_mode; } } } else { // export * as name match exports_type { ExportsType::DefaultOnly => { - return ExportMode { - kind: ExportModeType::ReexportFakeNamespaceObject, - name: Some(name), - partial_namespace_export_info: Some(export_info), - fake_type: Some(0), - ..Default::default() - } + let mut export_mode = ExportMode::new(ExportModeType::ReexportFakeNamespaceObject); + export_mode.name = Some(name); + export_mode.partial_namespace_export_info = Some(export_info); + export_mode.fake_type = 0; + return export_mode; } ExportsType::DefaultWithNamed => { - return ExportMode { - kind: ExportModeType::ReexportFakeNamespaceObject, - name: Some(name), - partial_namespace_export_info: Some(export_info), - fake_type: Some(2), - ..Default::default() - } + let mut export_mode = ExportMode::new(ExportModeType::ReexportFakeNamespaceObject); + export_mode.name = Some(name); + export_mode.partial_namespace_export_info = Some(export_info); + export_mode.fake_type = 2; + return export_mode; } _ => { - return ExportMode { - kind: ExportModeType::ReexportNamespaceObject, - name: Some(name), - partial_namespace_export_info: Some(export_info), - ..Default::default() - } + let mut export_mode = ExportMode::new(ExportModeType::ReexportNamespaceObject); + export_mode.name = Some(name); + export_mode.partial_namespace_export_info = Some(export_info); + return export_mode; } } } @@ -171,14 +177,11 @@ impl HarmonyExportImportedSpecifierDependency { ignored_exports, hidden, } = self.get_star_reexports(module_graph, runtime, imported_module_identifier); - if let Some(exports) = exports { if exports.is_empty() { - return ExportMode { - kind: ExportModeType::EmptyStar, - hidden, - ..Default::default() - }; + let mut export_mode = ExportMode::new(ExportModeType::EmptyStar); + export_mode.hidden = hidden; + return export_mode; } let mut items = exports @@ -209,19 +212,14 @@ impl HarmonyExportImportedSpecifierDependency { }); } } - - ExportMode { - kind: ExportModeType::NormalReexport, - items: Some(items), - ..Default::default() - } + let mut export_mode = ExportMode::new(ExportModeType::NormalReexport); + export_mode.items = Some(items); + export_mode } else { - ExportMode { - kind: ExportModeType::DynamicReexport, - ignored: Some(ignored_exports), - hidden, - ..Default::default() - } + let mut export_mode = ExportMode::new(ExportModeType::DynamicReexport); + export_mode.ignored = Some(ignored_exports); + export_mode.hidden = hidden; + export_mode } } @@ -269,20 +267,28 @@ impl HarmonyExportImportedSpecifierDependency { .parent_module_by_dependency_id(&self.id) .expect("should have parent module"); let exports_info = module_graph.get_exports_info(&parent_module); + if no_extra_imports { for export_info_id in exports_info.get_ordered_exports() { let export_info = module_graph .export_info_map .get(export_info_id) .expect("should have export info"); - if ignored_exports.contains(&export_info.name) + let export_name = export_info.name.clone().unwrap_or_default(); + // dbg!( + // &export_info.get_used(runtime), + // &ignored_exports, + // &export_name + // ); + if ignored_exports.contains(&export_name) || matches!(export_info.get_used(runtime), UsageState::Unused) { continue; } + let imported_export_info = imported_exports_info .id - .get_read_only_export_info(&export_info.name, module_graph); + .get_read_only_export_info(&export_name, module_graph); if matches!( imported_export_info.provided, Some(ExportInfoProvided::False) @@ -290,20 +296,20 @@ impl HarmonyExportImportedSpecifierDependency { continue; } if let Some(hidden) = hidden.as_mut() && hidden_exports.as_ref() - .map(|hidden_exports| hidden_exports.contains(&export_info.name)) + .map(|hidden_exports| hidden_exports.contains(&export_name)) .is_some() { - hidden.insert(export_info.name.clone()); + hidden.insert(export_name.clone()); continue; } - exports.insert(export_info.name.clone()); + exports.insert(export_name.clone()); if matches!( imported_export_info.provided, Some(ExportInfoProvided::True) ) { continue; } - checked.insert(export_info.name.clone()); + checked.insert(export_name); } } else if no_extra_exports { for import_export_info_id in imported_exports_info.get_ordered_exports() { @@ -311,29 +317,30 @@ impl HarmonyExportImportedSpecifierDependency { .export_info_map .get(import_export_info_id) .expect("should have export info"); - if ignored_exports.contains(&import_export_info.name) + let import_export_info_name = import_export_info.name.clone().unwrap_or_default(); + if ignored_exports.contains(&import_export_info_name) || matches!(import_export_info.provided, Some(ExportInfoProvided::False)) { continue; } let export_info = exports_info .id - .get_read_only_export_info(&import_export_info.name, module_graph); + .get_read_only_export_info(&import_export_info_name, module_graph); if matches!(export_info.get_used(runtime), UsageState::Unused) { continue; } if let Some(hidden) = hidden.as_mut() && hidden_exports.as_ref() - .map(|hidden_exports| hidden_exports.contains(&import_export_info.name)) + .map(|hidden_exports| hidden_exports.contains(&import_export_info_name)) .is_some() { - hidden.insert(import_export_info.name.clone()); + hidden.insert(import_export_info_name.clone()); continue; } - exports.insert(import_export_info.name.clone()); + exports.insert(import_export_info_name.clone()); if matches!(import_export_info.provided, Some(ExportInfoProvided::True)) { continue; } - checked.insert(import_export_info.name.clone()); + checked.insert(import_export_info_name); } } @@ -382,18 +389,59 @@ impl DependencyTemplate for HarmonyExportImportedSpecifierDependency { let import_var = compilation .module_graph .get_import_var(&module.identifier(), &self.request); + let is_new_tree_shaking = compilation.options.is_new_tree_shaking(); let used_exports = if compilation.options.builtins.tree_shaking.is_true() { Some( compilation .module_graph .get_exports_info(&module.identifier()) - .get_used_exports(), + .old_get_used_exports(), ) + } else if is_new_tree_shaking { + let exports_info_id = compilation + .module_graph + .get_exports_info(&module.identifier()) + .id; + let res = self + .ids + .iter() + .filter_map(|(local, _)| { + // TODO: runtime opt + exports_info_id.get_used_name( + &compilation.module_graph, + None, + UsedName::Str(local.clone()), + ) + }) + .map(|item| match item { + UsedName::Str(name) => name, + UsedName::Vec(_) => todo!(), + }) + .collect::>(); + Some(res) } else { None }; + if is_new_tree_shaking { + // TODO: runtime opt + let mode = self.get_mode( + self.name.clone(), + &self + .mode_ids + .iter() + .map(|id| id.0.clone()) + .collect::>(), + &compilation.module_graph, + &self.id, + None, + ); + if !matches!(mode.ty, ExportModeType::Unused | ExportModeType::EmptyStar) { + harmony_import_dependency_apply(self, code_generatable_context, &[]); + } + } + let mut exports = vec![]; for id in &self.ids { if used_exports.is_none() || matches!(used_exports.as_ref(), Some(x) if x.contains(&id.0)) { @@ -432,6 +480,14 @@ impl Dependency for HarmonyExportImportedSpecifierDependency { fn dependency_type(&self) -> &DependencyType { &DependencyType::EsmExportImportedSpecifier } + + fn get_module_evaluation_side_effects_state( + &self, + _module_graph: &ModuleGraph, + _module_chain: &mut HashSet, + ) -> ConnectionState { + ConnectionState::Bool(false) + } } impl ModuleDependency for HarmonyExportImportedSpecifierDependency { @@ -455,12 +511,41 @@ impl ModuleDependency for HarmonyExportImportedSpecifierDependency { Some(&self.resource_identifier) } - fn get_module_evaluation_side_effects_state( - &self, - _module_graph: &ModuleGraph, - _module_chain: &mut HashSet, - ) -> ConnectionState { - ConnectionState::Bool(false) + fn is_export_all(&self) -> Option { + if self.export_all { + Some(true) + } else { + None + } + } + + fn get_condition(&self) -> Option { + let id = self.id; + Some(DependencyCondition::Fn(Box::new( + move |_mc, runtime, module_graph: &ModuleGraph| { + let dep = module_graph + .dependency_by_id(&id) + .expect("should have dependency"); + let down_casted_dep = dep + .downcast_ref::() + .expect("should be HarmonyExportImportedSpecifierDependency"); + let mode = down_casted_dep.get_mode( + down_casted_dep.name.clone(), + &down_casted_dep + .mode_ids + .iter() + .map(|id| id.0.clone()) + .collect::>(), + module_graph, + &down_casted_dep.id, + runtime, + ); + ConnectionState::Bool(!matches!( + mode.ty, + ExportModeType::Unused | ExportModeType::EmptyStar + )) + }, + ))) } fn get_referenced_exports( @@ -470,12 +555,16 @@ impl ModuleDependency for HarmonyExportImportedSpecifierDependency { ) -> Vec { let mode = self.get_mode( self.name.clone(), - &self.ids.iter().map(|id| id.0.clone()).collect::>(), + &self + .mode_ids + .iter() + .map(|id| id.0.clone()) + .collect::>(), module_graph, &self.id, runtime, ); - match mode.kind { + match mode.ty { ExportModeType::Missing | ExportModeType::Unused | ExportModeType::EmptyStar @@ -494,7 +583,7 @@ impl ModuleDependency for HarmonyExportImportedSpecifierDependency { &mut referenced_exports, vec![], Some(*partial_namespace_export_info), - mode.kind == ExportModeType::ReexportFakeNamespaceObject, + mode.ty == ExportModeType::ReexportFakeNamespaceObject, &mut Default::default(), ); referenced_exports @@ -528,18 +617,17 @@ impl ModuleDependency for HarmonyExportImportedSpecifierDependency { .map(ExtendedReferencedExport::Array) .collect::>() } - ExportModeType::Unset => { - unreachable!("should not export mode unset"); - } } } + + fn dependency_debug_name(&self) -> &'static str { + "HarmonyExportImportedSpecifierDependency" + } } #[allow(unused)] -#[derive(Debug, Default, PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub enum ExportModeType { - #[default] - Unset, Missing, Unused, EmptyStar, @@ -561,17 +649,32 @@ pub struct NormalReexportItem { pub export_info: ExportInfoId, } -#[derive(Debug, Default)] +#[derive(Debug)] pub struct ExportMode { - pub kind: ExportModeType, + /// corresponding to `type` field in webpack's `EpxortMode` + pub ty: ExportModeType, pub items: Option>, pub name: Option, - pub fake_type: Option, + pub fake_type: u8, pub partial_namespace_export_info: Option, pub ignored: Option>, pub hidden: Option>, } +impl ExportMode { + pub fn new(ty: ExportModeType) -> Self { + Self { + ty, + items: None, + name: None, + fake_type: 0, + partial_namespace_export_info: None, + ignored: None, + hidden: None, + } + } +} + #[derive(Debug, Default)] pub struct StarReexportsInfo { exports: Option>, @@ -599,11 +702,13 @@ fn determine_export_assignments( .export_info_map .get(export_info_id) .expect("should have export info"); + // This is safe because a real export can't export empty string + let export_name = export_info.name.clone().unwrap_or_default(); if matches!(export_info.provided, Some(ExportInfoProvided::True)) - && &export_info.name != "default" - && !names.contains(&export_info.name) + && &export_name != "default" + && !names.contains(&export_name) { - names.insert(export_info.name.clone()); + names.insert(export_name.clone()); } } } diff --git a/crates/rspack_plugin_javascript/src/dependency/esm/harmony_export_specifier_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/esm/harmony_export_specifier_dependency.rs index fc44da3b8e2..0bcdaf2db54 100644 --- a/crates/rspack_plugin_javascript/src/dependency/esm/harmony_export_specifier_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/esm/harmony_export_specifier_dependency.rs @@ -1,7 +1,7 @@ use rspack_core::{ AsModuleDependency, Dependency, DependencyCategory, DependencyId, DependencyTemplate, DependencyType, ExportNameOrSpec, ExportsOfExportsSpec, ExportsSpec, HarmonyExportInitFragment, - TemplateContext, TemplateReplaceSource, + TemplateContext, TemplateReplaceSource, UsedName, }; use swc_core::ecma::atoms::JsWord; @@ -48,6 +48,14 @@ impl Dependency for HarmonyExportSpecifierDependency { exclude_exports: None, }) } + + fn get_module_evaluation_side_effects_state( + &self, + _module_graph: &rspack_core::ModuleGraph, + _module_chain: &mut rustc_hash::FxHashSet, + ) -> rspack_core::ConnectionState { + rspack_core::ConnectionState::Bool(false) + } } impl AsModuleDependency for HarmonyExportSpecifierDependency {} @@ -69,8 +77,25 @@ impl DependencyTemplate for HarmonyExportSpecifierDependency { compilation .module_graph .get_exports_info(&module.identifier()) - .get_used_exports() + .old_get_used_exports() .contains(&self.name) + } else if compilation.options.is_new_tree_shaking() { + let exports_info_id = compilation + .module_graph + .get_exports_info(&module.identifier()) + .id; + let used_name = exports_info_id.get_used_name( + &compilation.module_graph, + None, + UsedName::Str(self.name.clone()), + ); + // dbg!(&used_name); + used_name + .map(|item| match item { + UsedName::Str(name) => name == self.name, + UsedName::Vec(vec) => vec.contains(&self.name), + }) + .unwrap_or_default() } else { true }; diff --git a/crates/rspack_plugin_javascript/src/dependency/esm/harmony_import_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/esm/harmony_import_dependency.rs index bf8e91fd756..97cecb6f4e2 100644 --- a/crates/rspack_plugin_javascript/src/dependency/esm/harmony_import_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/esm/harmony_import_dependency.rs @@ -52,148 +52,172 @@ impl HarmonyImportDependency { } } -impl DependencyTemplate for HarmonyImportDependency { - fn apply( - &self, - _source: &mut TemplateReplaceSource, - code_generatable_context: &mut TemplateContext, - ) { - let compilation = &code_generatable_context.compilation; - let module = &code_generatable_context.module; - - let ref_mgm = compilation +pub fn harmony_import_dependency_apply( + module_dependency: &T, + code_generatable_context: &mut TemplateContext, + specifiers: &[Specifier], +) { + let compilation = &code_generatable_context.compilation; + let module = &code_generatable_context.module; + let ref_mgm = compilation + .module_graph + .module_graph_module_by_dependency_id(module_dependency.id()) + .expect("should have ref module"); + let is_target_active = if compilation.options.is_new_tree_shaking() { + let connection = compilation .module_graph - .module_graph_module_by_dependency_id(&self.id) - .expect("should have ref module"); - if !compilation + .connection_by_dependency(module_dependency.id()); + if let Some(con) = connection { + // TODO: runtime opt + // dbg!( + // &con, + // &ret, + // &compilation + // .module_graph + // .dependency_by_id(&con.dependency_id) + // .and_then(|item| item.as_module_dependency()) + // .map(|item| item.dependency_debug_name()) + // ); + con.is_target_active(&compilation.module_graph, None) + } else { + true + } + } else { + compilation .include_module_ids .contains(&ref_mgm.module_identifier) - { - return; - } - - if !self.export_all { - let specifiers = self - .specifiers - .iter() - .filter(|specifier| { - let is_import = matches!(self.dependency_type, DependencyType::EsmImport); - if is_import && !ref_mgm.module_type.is_js_like() { - return true; - } + }; + if !is_target_active { + return; + } + if module_dependency.is_export_all() == Some(false) { + let specifiers = specifiers + .iter() + .filter(|specifier| { + let is_import = matches!( + module_dependency.dependency_type(), + DependencyType::EsmImport + ); + if is_import && !ref_mgm.module_type.is_js_like() { + return true; + } - match specifier { - Specifier::Namespace(_) => true, - Specifier::Default(local) => { - if is_import { - compilation - .used_symbol_ref - .contains(&SymbolRef::Indirect(IndirectTopLevelSymbol { - src: ref_mgm.module_identifier, - ty: symbol::IndirectType::ImportDefault(local.clone()), - importer: module.identifier(), - dep_id: self.id, - })) - } else { - unreachable!("`export v from ''` is a unrecoverable syntax error") - } - } - Specifier::Named(local, imported) => { - let symbol = if matches!(self.dependency_type, DependencyType::EsmImport) { - SymbolRef::Indirect(IndirectTopLevelSymbol { + match specifier { + Specifier::Namespace(_) => true, + Specifier::Default(local) => { + if is_import { + compilation + .used_symbol_ref + .contains(&SymbolRef::Indirect(IndirectTopLevelSymbol { src: ref_mgm.module_identifier, - ty: symbol::IndirectType::Import(local.clone(), imported.clone()), + ty: symbol::IndirectType::ImportDefault(local.clone()), importer: module.identifier(), - dep_id: self.id, - }) - } else { - SymbolRef::Indirect(IndirectTopLevelSymbol { - src: module.identifier(), - ty: symbol::IndirectType::ReExport(local.clone(), imported.clone()), - importer: module.identifier(), - dep_id: self.id, - }) - }; - - compilation.used_symbol_ref.contains(&symbol) + dep_id: *module_dependency.id(), + })) + } else { + unreachable!("`export v from ''` is a unrecoverable syntax error") } } - }) - .collect::>(); - - if specifiers.is_empty() - && compilation - .side_effects_free_modules - .contains(&ref_mgm.module_identifier) - { - return; - } - } - - let content: (String, String) = - import_statement(code_generatable_context, &self.id, &self.request, false); + Specifier::Named(local, imported) => { + let symbol = if matches!( + module_dependency.dependency_type(), + DependencyType::EsmImport + ) { + SymbolRef::Indirect(IndirectTopLevelSymbol { + src: ref_mgm.module_identifier, + ty: symbol::IndirectType::Import(local.clone(), imported.clone()), + importer: module.identifier(), + dep_id: *module_dependency.id(), + }) + } else { + SymbolRef::Indirect(IndirectTopLevelSymbol { + src: module.identifier(), + ty: symbol::IndirectType::ReExport(local.clone(), imported.clone()), + importer: module.identifier(), + dep_id: *module_dependency.id(), + }) + }; - let TemplateContext { - init_fragments, - compilation, - module, - runtime_requirements, - .. - } = code_generatable_context; + compilation.used_symbol_ref.contains(&symbol) + } + } + }) + .collect::>(); - let ref_module = compilation - .module_graph - .module_identifier_by_dependency_id(&self.id) - .expect("should have dependency referenced module"); - let import_var = compilation - .module_graph - .get_import_var(&module.identifier(), &self.request); - if compilation.module_graph.is_async(ref_module) { - init_fragments.push(Box::new(NormalInitFragment::new( - content.0, - InitFragmentStage::StageHarmonyImports, - None, - ))); - init_fragments.push(Box::new(NormalInitFragment::new( + if specifiers.is_empty() + && compilation + .side_effects_free_modules + .contains(&ref_mgm.module_identifier) + { + return; + } + } + let content: (String, String) = import_statement( + code_generatable_context, + module_dependency.id(), + module_dependency.request(), + false, + ); + let TemplateContext { + init_fragments, + compilation, + module, + runtime_requirements, + .. + } = code_generatable_context; + let ref_module = compilation + .module_graph + .module_identifier_by_dependency_id(module_dependency.id()) + .expect("should have dependency referenced module"); + let import_var = compilation + .module_graph + .get_import_var(&module.identifier(), module_dependency.request()); + if compilation.module_graph.is_async(ref_module) { + init_fragments.push(Box::new(NormalInitFragment::new( + content.0, + InitFragmentStage::StageHarmonyImports, + None, + ))); + init_fragments.push(Box::new(NormalInitFragment::new( format!( "var __webpack_async_dependencies__ = __webpack_handle_async_dependencies__([{import_var}]);\n([{import_var}] = __webpack_async_dependencies__.then ? (await __webpack_async_dependencies__)() : __webpack_async_dependencies__);" ), InitFragmentStage::StageHarmonyImports, None, ))); - init_fragments.push(Box::new(NormalInitFragment::new( - content.1, - InitFragmentStage::StageAsyncHarmonyImports, - None, - ))); - } else { - init_fragments.push(Box::new(NormalInitFragment::new( - format!("{}{}", content.0, content.1), - InitFragmentStage::StageHarmonyImports, - None, - ))); - } - if self.export_all { - runtime_requirements.insert(RuntimeGlobals::EXPORT_STAR); - let exports_argument = compilation - .module_graph - .module_graph_module_by_identifier(&module.identifier()) - .expect("should have mgm") - .get_exports_argument(); - init_fragments.push(Box::new(NormalInitFragment::new( - format!( - "{}.{}({import_var}, {exports_argument});\n", - RuntimeGlobals::REQUIRE, - RuntimeGlobals::EXPORT_STAR, - ), - if compilation.module_graph.is_async(ref_module) { - InitFragmentStage::StageAsyncHarmonyImports - } else { - InitFragmentStage::StageHarmonyImports - }, - None, - ))); - } + init_fragments.push(Box::new(NormalInitFragment::new( + content.1, + InitFragmentStage::StageAsyncHarmonyImports, + None, + ))); + } else { + init_fragments.push(Box::new(NormalInitFragment::new( + format!("{}{}", content.0, content.1), + InitFragmentStage::StageHarmonyImports, + None, + ))); + } + + if module_dependency.is_export_all() == Some(true) { + runtime_requirements.insert(RuntimeGlobals::EXPORT_STAR); + let exports_argument = compilation + .module_graph + .module_graph_module_by_identifier(&module.identifier()) + .expect("should have mgm") + .get_exports_argument(); + init_fragments.push(Box::new(NormalInitFragment::new( + format!( + "{}.{}({import_var}, {exports_argument});\n", + RuntimeGlobals::REQUIRE, + RuntimeGlobals::EXPORT_STAR, + ), + if compilation.module_graph.is_async(ref_module) { + InitFragmentStage::StageAsyncHarmonyImports + } else { + InitFragmentStage::StageHarmonyImports + }, + None, + ))); } } @@ -209,9 +233,28 @@ impl Dependency for HarmonyImportDependency { fn dependency_type(&self) -> &DependencyType { &self.dependency_type } + + fn get_module_evaluation_side_effects_state( + &self, + module_graph: &ModuleGraph, + module_chain: &mut HashSet, + ) -> ConnectionState { + if let Some(module) = module_graph + .module_identifier_by_dependency_id(&self.id) + .and_then(|module_identifier| module_graph.module_by_identifier(module_identifier)) + { + module.get_side_effects_connection_state(module_graph, module_chain) + } else { + ConnectionState::Bool(true) + } + } } impl ModuleDependency for HarmonyImportDependency { + fn is_export_all(&self) -> Option { + Some(self.export_all) + } + fn request(&self) -> &str { &self.request } @@ -240,15 +283,12 @@ impl ModuleDependency for HarmonyImportDependency { vec![] } - // It's from HarmonyImportSideEffectDependency. - fn get_condition(&self, _module_graph: &ModuleGraph) -> Option { - let id = self.id; + // TODO: It's from HarmonyImportSideEffectDependency. + fn get_condition(&self) -> Option { Some(DependencyCondition::Fn(Box::new( - move |_, _, module_graph| { - if let Some(module) = module_graph - .parent_module_by_dependency_id(&id) - .and_then(|module_identifier| module_graph.module_by_identifier(&module_identifier)) - { + move |con, _, module_graph: &ModuleGraph| { + let id = con.module_identifier; + if let Some(module) = module_graph.module_by_identifier(&id) { module.get_side_effects_connection_state(module_graph, &mut HashSet::default()) } else { ConnectionState::Bool(true) @@ -258,18 +298,18 @@ impl ModuleDependency for HarmonyImportDependency { } // It's from HarmonyImportSideEffectDependency. - fn get_module_evaluation_side_effects_state( + + fn dependency_debug_name(&self) -> &'static str { + "HarmonyImportDependency" + } +} + +impl DependencyTemplate for HarmonyImportDependency { + fn apply( &self, - module_graph: &ModuleGraph, - module_chain: &mut HashSet, - ) -> ConnectionState { - if let Some(module) = module_graph - .parent_module_by_dependency_id(&self.id) - .and_then(|module_identifier| module_graph.module_by_identifier(&module_identifier)) - { - module.get_side_effects_connection_state(module_graph, module_chain) - } else { - ConnectionState::Bool(true) - } + _source: &mut TemplateReplaceSource, + code_generatable_context: &mut TemplateContext, + ) { + harmony_import_dependency_apply(self, code_generatable_context, &self.specifiers); } } diff --git a/crates/rspack_plugin_javascript/src/dependency/esm/harmony_import_specifier_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/esm/harmony_import_specifier_dependency.rs index d9d1ca26ae4..e627026ab5c 100644 --- a/crates/rspack_plugin_javascript/src/dependency/esm/harmony_import_specifier_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/esm/harmony_import_specifier_dependency.rs @@ -10,7 +10,9 @@ use rspack_core::{ use rustc_hash::FxHashSet as HashSet; use swc_core::ecma::atoms::JsWord; -use super::{create_resource_identifier_for_esm_dependency, Specifier}; +use super::{ + create_resource_identifier_for_esm_dependency, harmony_import_dependency_apply, Specifier, +}; #[derive(Debug, Clone)] pub struct HarmonyImportSpecifierDependency { @@ -81,12 +83,12 @@ impl HarmonyImportSpecifierDependency { Specifier::Default(_) => compilation .module_graph .get_exports_info(&reference_mgm.module_identifier) - .get_used_exports() + .old_get_used_exports() .contains(&DEFAULT_JS_WORD), Specifier::Named(local, imported) => compilation .module_graph .get_exports_info(&reference_mgm.module_identifier) - .get_used_exports() + .old_get_used_exports() .contains(imported.as_ref().unwrap_or(local)), } } @@ -130,6 +132,20 @@ impl DependencyTemplate for HarmonyImportSpecifierDependency { .module_graph_module_by_dependency_id(&self.id) .expect("should have ref module"); + let compilation = &code_generatable_context.compilation; + if compilation.options.is_new_tree_shaking() { + let connection = compilation.module_graph.connection_by_dependency(&self.id); + let is_target_active = if let Some(con) = connection { + // TODO: runtime opt + con.is_target_active(&compilation.module_graph, None) + } else { + true + }; + + if !is_target_active { + return; + } + }; let used = self.check_used(reference_mgm, compilation); if !used { @@ -148,6 +164,10 @@ impl DependencyTemplate for HarmonyImportSpecifierDependency { .module_graph .get_import_var(&code_generatable_context.module.identifier(), &self.request); + // TODO: scope hoist + if compilation.options.is_new_tree_shaking() { + harmony_import_dependency_apply(self, code_generatable_context, &[self.specifier.clone()]); + } let export_expr = export_from_import( code_generatable_context, true, @@ -177,6 +197,14 @@ impl Dependency for HarmonyImportSpecifierDependency { fn dependency_type(&self) -> &DependencyType { &DependencyType::EsmImportSpecifier } + + fn get_module_evaluation_side_effects_state( + &self, + _module_graph: &ModuleGraph, + _module_chain: &mut HashSet, + ) -> ConnectionState { + ConnectionState::Bool(false) + } } impl ModuleDependency for HarmonyImportSpecifierDependency { @@ -200,16 +228,8 @@ impl ModuleDependency for HarmonyImportSpecifierDependency { Some(&self.resource_identifier) } - fn get_condition(&self, module_graph: &ModuleGraph) -> Option { - get_dependency_used_by_exports_condition(&self.id, &self.used_by_exports, module_graph) - } - - fn get_module_evaluation_side_effects_state( - &self, - _module_graph: &ModuleGraph, - _module_chain: &mut HashSet, - ) -> ConnectionState { - ConnectionState::Bool(false) + fn get_condition(&self) -> Option { + get_dependency_used_by_exports_condition(self.id, &self.used_by_exports) } fn get_referenced_exports( @@ -252,4 +272,8 @@ impl ModuleDependency for HarmonyImportSpecifierDependency { self.get_referenced_exports_in_destructuring(Some(&self.ids)) } + + fn dependency_debug_name(&self) -> &'static str { + "HarmonyImportSpecifierDependency" + } } diff --git a/crates/rspack_plugin_javascript/src/dependency/esm/import_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/esm/import_dependency.rs index ff0f4d00584..271e3353410 100644 --- a/crates/rspack_plugin_javascript/src/dependency/esm/import_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/esm/import_dependency.rs @@ -86,6 +86,10 @@ impl ModuleDependency for ImportDependency { vec![ExtendedReferencedExport::Array(vec![])] } } + + fn dependency_debug_name(&self) -> &'static str { + "ImportDependency" + } } impl DependencyTemplate for ImportDependency { diff --git a/crates/rspack_plugin_javascript/src/dependency/hmr/import_meta_hot_accept.rs b/crates/rspack_plugin_javascript/src/dependency/hmr/import_meta_hot_accept.rs index f7774f9cfe6..75564c994c5 100644 --- a/crates/rspack_plugin_javascript/src/dependency/hmr/import_meta_hot_accept.rs +++ b/crates/rspack_plugin_javascript/src/dependency/hmr/import_meta_hot_accept.rs @@ -55,6 +55,10 @@ impl ModuleDependency for ImportMetaHotAcceptDependency { fn set_request(&mut self, request: String) { self.request = request.into(); } + + fn dependency_debug_name(&self) -> &'static str { + "ImportMetaHotAcceptDependency" + } } impl DependencyTemplate for ImportMetaHotAcceptDependency { diff --git a/crates/rspack_plugin_javascript/src/dependency/hmr/import_meta_hot_decline.rs b/crates/rspack_plugin_javascript/src/dependency/hmr/import_meta_hot_decline.rs index bb010fc3135..246e5e42aaa 100644 --- a/crates/rspack_plugin_javascript/src/dependency/hmr/import_meta_hot_decline.rs +++ b/crates/rspack_plugin_javascript/src/dependency/hmr/import_meta_hot_decline.rs @@ -55,6 +55,10 @@ impl ModuleDependency for ImportMetaHotDeclineDependency { fn set_request(&mut self, request: String) { self.request = request.into(); } + + fn dependency_debug_name(&self) -> &'static str { + "ImportMetaHotDeclineDependency" + } } impl DependencyTemplate for ImportMetaHotDeclineDependency { diff --git a/crates/rspack_plugin_javascript/src/dependency/hmr/module_hot_accept.rs b/crates/rspack_plugin_javascript/src/dependency/hmr/module_hot_accept.rs index c438b6df02a..cf1d1361857 100644 --- a/crates/rspack_plugin_javascript/src/dependency/hmr/module_hot_accept.rs +++ b/crates/rspack_plugin_javascript/src/dependency/hmr/module_hot_accept.rs @@ -55,6 +55,10 @@ impl ModuleDependency for ModuleHotAcceptDependency { fn set_request(&mut self, request: String) { self.request = request.into(); } + + fn dependency_debug_name(&self) -> &'static str { + "ModuleHotAcceptDependency" + } } impl DependencyTemplate for ModuleHotAcceptDependency { diff --git a/crates/rspack_plugin_javascript/src/dependency/hmr/module_hot_decline.rs b/crates/rspack_plugin_javascript/src/dependency/hmr/module_hot_decline.rs index 3b2861b62c7..86b2bb3457e 100644 --- a/crates/rspack_plugin_javascript/src/dependency/hmr/module_hot_decline.rs +++ b/crates/rspack_plugin_javascript/src/dependency/hmr/module_hot_decline.rs @@ -55,6 +55,10 @@ impl ModuleDependency for ModuleHotDeclineDependency { fn set_request(&mut self, request: String) { self.request = request.into(); } + + fn dependency_debug_name(&self) -> &'static str { + "ModuleHotDeclineDependency" + } } impl DependencyTemplate for ModuleHotDeclineDependency { diff --git a/crates/rspack_plugin_javascript/src/dependency/url/mod.rs b/crates/rspack_plugin_javascript/src/dependency/url/mod.rs index 717fbc46a38..0d03441f81b 100644 --- a/crates/rspack_plugin_javascript/src/dependency/url/mod.rs +++ b/crates/rspack_plugin_javascript/src/dependency/url/mod.rs @@ -1,8 +1,7 @@ use rspack_core::{ get_dependency_used_by_exports_condition, module_id, Dependency, DependencyCategory, DependencyCondition, DependencyId, DependencyTemplate, DependencyType, ErrorSpan, - ModuleDependency, ModuleGraph, RuntimeGlobals, TemplateContext, TemplateReplaceSource, - UsedByExports, + ModuleDependency, RuntimeGlobals, TemplateContext, TemplateReplaceSource, UsedByExports, }; use swc_core::ecma::atoms::JsWord; @@ -60,8 +59,12 @@ impl ModuleDependency for URLDependency { self.request = request.into(); } - fn get_condition(&self, module_graph: &ModuleGraph) -> Option { - get_dependency_used_by_exports_condition(&self.id, &self.used_by_exports, module_graph) + fn get_condition(&self) -> Option { + get_dependency_used_by_exports_condition(self.id, &self.used_by_exports) + } + + fn dependency_debug_name(&self) -> &'static str { + "URLDependency" } } diff --git a/crates/rspack_plugin_javascript/src/dependency/worker/mod.rs b/crates/rspack_plugin_javascript/src/dependency/worker/mod.rs index 7c81390a5bc..0491ffade6d 100644 --- a/crates/rspack_plugin_javascript/src/dependency/worker/mod.rs +++ b/crates/rspack_plugin_javascript/src/dependency/worker/mod.rs @@ -78,6 +78,10 @@ impl ModuleDependency for WorkerDependency { ) -> Vec { vec![] } + + fn dependency_debug_name(&self) -> &'static str { + "WorkerDependency" + } } impl DependencyTemplate for WorkerDependency { @@ -94,7 +98,7 @@ impl DependencyTemplate for WorkerDependency { let chunk_id = compilation .module_graph .module_identifier_by_dependency_id(&self.id) - .map(|module| { + .and_then(|module| { compilation .chunk_graph .get_block_chunk_group(module, &compilation.chunk_group_by_ukey) diff --git a/crates/rspack_plugin_javascript/src/parser_and_generator/mod.rs b/crates/rspack_plugin_javascript/src/parser_and_generator/mod.rs index a64994c8f7b..c0aa5cd0522 100644 --- a/crates/rspack_plugin_javascript/src/parser_and_generator/mod.rs +++ b/crates/rspack_plugin_javascript/src/parser_and_generator/mod.rs @@ -1,6 +1,6 @@ use rspack_core::rspack_sources::{ - BoxSource, RawSource, ReplaceSource, Source, SourceExt, SourceMap, SourceMapSource, - WithoutOriginalOptions, + BoxSource, MapOptions, OriginalSource, RawSource, ReplaceSource, Source, SourceExt, SourceMap, + SourceMapSource, SourceMapSourceOptions, }; use rspack_core::tree_shaking::analyzer::OptimizeAnalyzer; use rspack_core::tree_shaking::js_module::JsModule; @@ -10,9 +10,11 @@ use rspack_core::{ ParserAndGenerator, SourceType, TemplateContext, }; use rspack_error::{internal_error, IntoTWithDiagnosticArray, Result, TWithDiagnosticArray}; +use swc_core::common::SyntaxContext; use crate::utils::syntax_by_module_type; use crate::visitors::{run_before_pass, scan_dependencies, swc_visitor::resolver}; +use crate::{SideEffectsFlagPluginVisitor, SyntaxContextInfo}; #[derive(Debug)] pub struct JavaScriptParserAndGenerator; @@ -50,7 +52,11 @@ impl ParserAndGenerator for JavaScriptParserAndGenerator { &resource_data.resource_path, module_type, compiler_options.builtins.decorator.is_some(), + compiler_options.should_transform_by_default(), ); + let use_source_map = compiler_options.devtool.enabled(); + let use_simple_source_map = compiler_options.devtool.source_map(); + let original_map = source.map(&MapOptions::new(!compiler_options.devtool.cheap())); let source = source.source(); let mut ast = match crate::ast::parse( source.to_string(), @@ -62,7 +68,11 @@ impl ParserAndGenerator for JavaScriptParserAndGenerator { Err(e) => { return Ok( ParseResult { - source: RawSource::from(source.to_string()).boxed(), + source: create_source( + source.to_string(), + resource_data.resource_path.to_string_lossy().to_string(), + use_simple_source_map, + ), dependencies: vec![], presentational_dependencies: vec![], analyze_result: Default::default(), @@ -85,8 +95,8 @@ impl ParserAndGenerator for JavaScriptParserAndGenerator { let output: crate::TransformOutput = crate::ast::stringify(&ast, &compiler_options.devtool, Some(true))?; - let mut scan_ast = match crate::ast::parse( - output.code.clone(), // TODO avoid code clone + ast = match crate::ast::parse( + output.code.clone(), syntax, &resource_data.resource_path.to_string_lossy(), module_type, @@ -95,7 +105,11 @@ impl ParserAndGenerator for JavaScriptParserAndGenerator { Err(e) => { return Ok( ParseResult { - source: RawSource::from(output.code.clone()).boxed(), + source: create_source( + source.to_string(), + resource_data.resource_path.to_string_lossy().to_string(), + use_simple_source_map, + ), dependencies: vec![], presentational_dependencies: vec![], analyze_result: Default::default(), @@ -105,7 +119,7 @@ impl ParserAndGenerator for JavaScriptParserAndGenerator { } }; - scan_ast.transform(|program, context| { + ast.transform(|program, context| { program.visit_mut_with(&mut resolver( context.unresolved_mark, context.top_level_mark, @@ -113,7 +127,7 @@ impl ParserAndGenerator for JavaScriptParserAndGenerator { )); }); - let (dependencies, presentational_dependencies) = scan_ast.visit(|program, context| { + let (dependencies, presentational_dependencies) = ast.visit(|program, context| { scan_dependencies( program, context.unresolved_mark, @@ -127,28 +141,46 @@ impl ParserAndGenerator for JavaScriptParserAndGenerator { }); let analyze_result = if compiler_options.builtins.tree_shaking.enable() { - JsModule::new( - &scan_ast, - &dependencies, - module_identifier, - compiler_options, - ) - .analyze() + JsModule::new(&ast, &dependencies, module_identifier, compiler_options).analyze() } else { OptimizeAnalyzeResult::default() }; + if compiler_options.is_new_tree_shaking() + && compiler_options.optimization.side_effects.is_true() + { + ast.transform(|program, context| { + let unresolved_ctxt = SyntaxContext::empty().apply_mark(context.unresolved_mark); + let mut visitor = + SideEffectsFlagPluginVisitor::new(SyntaxContextInfo::new(unresolved_ctxt)); + program.visit_with(&mut visitor); + build_meta.side_effect_free = Some(visitor.side_effects_span.is_none()); + }); + } + let source = if let Some(map) = output.map { - SourceMapSource::new(WithoutOriginalOptions { + SourceMapSource::new(SourceMapSourceOptions { value: output.code, name: resource_data.resource_path.to_string_lossy().to_string(), source_map: SourceMap::from_json(&map).map_err(|e| internal_error!(e.to_string()))?, + inner_source_map: use_source_map.then_some(original_map).flatten(), + remove_original_source: true, + ..Default::default() }) .boxed() + } else if use_simple_source_map { + OriginalSource::new(output.code, resource_data.resource_path.to_string_lossy()).boxed() } else { RawSource::from(output.code).boxed() }; + fn create_source(content: String, resource_path: String, devtool: bool) -> BoxSource { + if devtool { + return OriginalSource::new(content, resource_path).boxed(); + } + RawSource::from(content).boxed() + } + Ok( ParseResult { source, diff --git a/crates/rspack_plugin_javascript/src/plugin/api_plugin.rs b/crates/rspack_plugin_javascript/src/plugin/api_plugin.rs new file mode 100644 index 00000000000..731779dd050 --- /dev/null +++ b/crates/rspack_plugin_javascript/src/plugin/api_plugin.rs @@ -0,0 +1,27 @@ +use rspack_core::{ + InitFragmentStage, NormalInitFragment, Plugin, PluginContext, PluginRenderModuleContentOutput, + RenderModuleContentArgs, +}; + +#[derive(Debug)] +pub struct APIPlugin; + +impl Plugin for APIPlugin { + fn render_module_content<'a>( + &'a self, + _ctx: PluginContext, + mut args: RenderModuleContentArgs<'a>, + ) -> PluginRenderModuleContentOutput<'a> { + if let Some(build_info) = &args.module_graph_module.build_info && build_info.need_create_require { + args.chunk_init_fragments + .entry("external module node-commonjs".to_string()) + .or_insert(NormalInitFragment::new( + "import { createRequire as __WEBPACK_EXTERNAL_createRequire } from 'module';\n" + .to_string(), + InitFragmentStage::StageHarmonyImports, + None, + )); + } + Ok(args) + } +} diff --git a/crates/rspack_plugin_javascript/src/plugin/provided_exports_plugin.rs b/crates/rspack_plugin_javascript/src/plugin/flag_dependency_exports_plugin.rs similarity index 83% rename from crates/rspack_plugin_javascript/src/plugin/provided_exports_plugin.rs rename to crates/rspack_plugin_javascript/src/plugin/flag_dependency_exports_plugin.rs index 418d9018209..d42b4c8f06b 100644 --- a/crates/rspack_plugin_javascript/src/plugin/provided_exports_plugin.rs +++ b/crates/rspack_plugin_javascript/src/plugin/flag_dependency_exports_plugin.rs @@ -2,20 +2,22 @@ use std::collections::hash_map::Entry; use std::collections::VecDeque; use rspack_core::{ - DependencyId, ExportInfoProvided, ExportNameOrSpec, ExportsInfoId, ExportsOfExportsSpec, - ExportsSpec, ModuleGraph, ModuleGraphConnection, ModuleIdentifier, + BuildMetaExportsType, Compilation, DependencyId, ExportInfoProvided, ExportNameOrSpec, + ExportsInfoId, ExportsOfExportsSpec, ExportsSpec, ModuleGraph, ModuleGraphConnection, + ModuleIdentifier, Plugin, }; +use rspack_error::Result; use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet}; use swc_core::ecma::atoms::JsWord; -pub struct ProvidedExportsPlugin<'a> { +struct FlagDependencyExportsProxy<'a> { mg: &'a mut ModuleGraph, changed: bool, current_module_id: ModuleIdentifier, dependencies: HashMap>, } -impl<'a> ProvidedExportsPlugin<'a> { +impl<'a> FlagDependencyExportsProxy<'a> { pub fn new(mg: &'a mut ModuleGraph) -> Self { Self { mg, @@ -27,18 +29,43 @@ impl<'a> ProvidedExportsPlugin<'a> { pub fn apply(&mut self) { let mut q = VecDeque::new(); + + // take the ownership of module_identifier_to_module_graph_module to avoid borrow ref and + // mut ref of `ModuleGraph` at the same time + let module_graph_modules = + std::mem::take(&mut self.mg.module_identifier_to_module_graph_module); + for mgm in module_graph_modules.values() { + let exports_id = mgm.exports; + let is_module_without_exports = if let Some(ref build_meta) = mgm.build_meta { + build_meta.exports_type == BuildMetaExportsType::Unset + } else { + true + } && { + let exports_info = self.mg.get_exports_info_by_id(&exports_id); + let other_exports_info_id = exports_info.other_exports_info; + let other_exports_info = self.mg.get_export_info_by_id(&other_exports_info_id); + other_exports_info.provided.is_some() + }; + + // TODO: mem cache + exports_id.set_has_provide_info(self.mg); + q.push_back(mgm.module_identifier); + if is_module_without_exports { + exports_id.set_unknown_exports_provided(self.mg, false, None, None, None, None); + } + } + self.mg.module_identifier_to_module_graph_module = module_graph_modules; + while let Some(module_id) = q.pop_back() { self.changed = false; self.current_module_id = module_id; let mut exports_specs_from_dependencies: HashMap = HashMap::default(); self.process_dependencies_block(module_id, &mut exports_specs_from_dependencies); - // I use this trick because of rustc borrow rules, it is safe becuase dependency provide plugin is sync, there are no other methods using it at the same time. let exports_info_id = self.mg.get_exports_info(&module_id).id; for (dep_id, exports_spec) in exports_specs_from_dependencies.into_iter() { self.process_exports_spec(dep_id, exports_spec, exports_info_id); } - // Swap it back if self.changed { self.notify_dependencies(&mut q); } @@ -172,7 +199,7 @@ impl<'a> ProvidedExportsPlugin<'a> { .unwrap_or(global_export_info.terminal_binding), spec.exports.as_ref(), if spec.from.is_some() { - spec.from.clone() + spec.from } else { global_export_info.from.cloned() }, @@ -287,3 +314,15 @@ pub struct DefaultExportInfo<'a> { from: Option<&'a ModuleGraphConnection>, priority: Option, } + +#[derive(Debug, Default)] +pub struct FlagDependencyExportsPlugin; + +#[async_trait::async_trait] +impl Plugin for FlagDependencyExportsPlugin { + async fn finish_modules(&self, compilation: &mut Compilation) -> Result<()> { + let mut proxy = FlagDependencyExportsProxy::new(&mut compilation.module_graph); + proxy.apply(); + Ok(()) + } +} diff --git a/crates/rspack_plugin_javascript/src/plugin/flag_usage_plugin.rs b/crates/rspack_plugin_javascript/src/plugin/flag_dependency_usage_plugin.rs similarity index 84% rename from crates/rspack_plugin_javascript/src/plugin/flag_usage_plugin.rs rename to crates/rspack_plugin_javascript/src/plugin/flag_dependency_usage_plugin.rs index 7cf5a905d75..f17aee64926 100644 --- a/crates/rspack_plugin_javascript/src/plugin/flag_usage_plugin.rs +++ b/crates/rspack_plugin_javascript/src/plugin/flag_dependency_usage_plugin.rs @@ -3,23 +3,24 @@ use std::collections::VecDeque; use rspack_core::{ is_exports_object_referenced, is_no_exports_referenced, BuildMetaExportsType, Compilation, - ConnectionState, DependencyId, ExportsInfoId, ExtendedReferencedExport, ModuleIdentifier, + ConnectionState, DependencyId, ExportsInfoId, ExtendedReferencedExport, ModuleIdentifier, Plugin, ReferencedExport, RuntimeSpec, UsageState, }; +use rspack_error::Result; use rspack_identifier::IdentifierMap; use rustc_hash::FxHashMap as HashMap; use crate::utils::join_jsword; #[allow(unused)] -pub struct FlagDependencyUsagePlugin<'a> { +pub struct FlagDependencyUsagePluginProxy<'a> { global: bool, compilation: &'a mut Compilation, exports_info_module_map: HashMap, } #[allow(unused)] -impl<'a> FlagDependencyUsagePlugin<'a> { +impl<'a> FlagDependencyUsagePluginProxy<'a> { pub fn new(global: bool, compilation: &'a mut Compilation) -> Self { Self { global, @@ -53,7 +54,7 @@ impl<'a> FlagDependencyUsagePlugin<'a> { } } // TODO: compilation.globalEntry.dependencies, we don't have now https://github.com/webpack/webpack/blob/3f71468514ae2f179ff34c837ce82fcc8f97e24c/lib/FlagDependencyUsagePlugin.js#L328-L330 - _ = std::mem::replace(&mut self.compilation.entries, entries); + self.compilation.entries = entries; while let Some((module_id, runtime)) = q.pop_front() { self.process_module(module_id, runtime, false, &mut q); @@ -67,6 +68,7 @@ impl<'a> FlagDependencyUsagePlugin<'a> { force_side_effects: bool, q: &mut VecDeque<(ModuleIdentifier, Option)>, ) { + #[derive(Debug, Clone)] enum ProcessModuleReferencedExports { Map(HashMap), ExtendRef(Vec), @@ -88,6 +90,7 @@ impl<'a> FlagDependencyUsagePlugin<'a> { .compilation .module_graph .connection_by_dependency(&dep_id); + let connection = if let Some(connection) = connection { connection } else { @@ -95,6 +98,7 @@ impl<'a> FlagDependencyUsagePlugin<'a> { }; let active_state = connection.get_active_state(&self.compilation.module_graph, runtime.as_ref()); + match active_state { ConnectionState::Bool(false) => { continue; @@ -111,11 +115,21 @@ impl<'a> FlagDependencyUsagePlugin<'a> { .module_graph .dependency_by_id(&dep_id) .expect("should have dep"); + let referenced_exports = if let Some(md) = dep.as_module_dependency() { md.get_referenced_exports(&self.compilation.module_graph, runtime.as_ref()) } else { continue; }; + // dbg!( + // &connection, + // dep + // .as_module_dependency() + // .map(|item| item.dependency_debug_name()), + // &referenced_exports, + // &old_referenced_exports + // ); + if old_referenced_exports.is_none() || matches!(old_referenced_exports.as_ref().expect("should be some"), ProcessModuleReferencedExports::ExtendRef(v) if is_no_exports_referenced(v)) || is_exports_object_referenced(&referenced_exports) @@ -124,33 +138,30 @@ impl<'a> FlagDependencyUsagePlugin<'a> { connection.module_identifier, ProcessModuleReferencedExports::ExtendRef(referenced_exports), ); - } else if old_referenced_exports.is_some() && is_no_exports_referenced(&referenced_exports) - { - continue; - } else { - let mut exports_map = if let Some(old_referenced_exports) = old_referenced_exports { - match old_referenced_exports { - ProcessModuleReferencedExports::Map(map) => map, - ProcessModuleReferencedExports::ExtendRef(ref_items) => { - let mut exports_map = HashMap::default(); - for item in ref_items.iter() { - match item { - ExtendedReferencedExport::Array(arr) => { - exports_map.insert(join_jsword(arr, "\n"), item.clone()); - } - ExtendedReferencedExport::Export(export) => { - exports_map.insert(join_jsword(&export.name, "\n"), item.clone()); - } + } else if let Some(old_referenced_exports) = old_referenced_exports { + if is_no_exports_referenced(&referenced_exports) { + map.insert(connection.module_identifier, old_referenced_exports.clone()); + continue; + } + + let mut exports_map = match old_referenced_exports { + ProcessModuleReferencedExports::Map(map) => map, + ProcessModuleReferencedExports::ExtendRef(ref_items) => { + let mut exports_map = HashMap::default(); + for item in ref_items.iter() { + match item { + ExtendedReferencedExport::Array(arr) => { + exports_map.insert(join_jsword(arr, "\n"), item.clone()); + } + ExtendedReferencedExport::Export(export) => { + exports_map.insert(join_jsword(&export.name, "\n"), item.clone()); } } - exports_map } + exports_map } - } else { - // in else branch above old_referenced_exports must be `Some(T)`, use if let Pattern - // just avoid rust clippy complain - unreachable!() }; + for mut item in referenced_exports.into_iter() { match item { ExtendedReferencedExport::Array(ref arr) => { @@ -181,10 +192,18 @@ impl<'a> FlagDependencyUsagePlugin<'a> { } } } + // dbg!(&exports_map); + map.insert( + connection.module_identifier, + ProcessModuleReferencedExports::Map(exports_map), + ); + } else { } } } + for (module_id, referenced_exports) in map { + // dbg!(&module_id, &referenced_exports); let normalized_refs = match referenced_exports { ProcessModuleReferencedExports::Map(map) => map.into_values().collect::>(), ProcessModuleReferencedExports::ExtendRef(extend_ref) => extend_ref, @@ -327,11 +346,24 @@ impl<'a> FlagDependencyUsagePlugin<'a> { { return; } - let flag = mgm_exports_info_id + let changed_flag = mgm_exports_info_id .set_used_for_side_effects_only(&mut self.compilation.module_graph, runtime.as_ref()); - if flag { + if changed_flag { queue.push_back((module_id, runtime)); } } } } + +#[derive(Debug, Default)] +pub struct FlagDependencyUsagePlugin; + +#[async_trait::async_trait] +impl Plugin for FlagDependencyUsagePlugin { + async fn optimize_dependencies(&self, compilation: &mut Compilation) -> Result> { + // TODO: `global` is always `true`, until we finished runtime optimization. + let mut proxy = FlagDependencyUsagePluginProxy::new(true, compilation); + proxy.apply(); + Ok(None) + } +} diff --git a/crates/rspack_plugin_javascript/src/plugin/impl_plugin_for_js_plugin.rs b/crates/rspack_plugin_javascript/src/plugin/impl_plugin_for_js_plugin.rs index b543fd6aa6b..58c9ba0fb56 100644 --- a/crates/rspack_plugin_javascript/src/plugin/impl_plugin_for_js_plugin.rs +++ b/crates/rspack_plugin_javascript/src/plugin/impl_plugin_for_js_plugin.rs @@ -22,11 +22,34 @@ impl Plugin for JsPlugin { fn apply( &self, ctx: PluginContext<&mut rspack_core::ApplyContext>, - _options: &mut CompilerOptions, + options: &mut CompilerOptions, ) -> Result<()> { let create_parser_and_generator = move || Box::new(JavaScriptParserAndGenerator::new()) as Box; + if options.should_transform_by_default() { + ctx.context.register_parser_and_generator_builder( + ModuleType::Ts, + Box::new(create_parser_and_generator), + ); + ctx.context.register_parser_and_generator_builder( + ModuleType::Tsx, + Box::new(create_parser_and_generator), + ); + ctx.context.register_parser_and_generator_builder( + ModuleType::Jsx, + Box::new(create_parser_and_generator), + ); + ctx.context.register_parser_and_generator_builder( + ModuleType::JsxEsm, + Box::new(create_parser_and_generator), + ); + ctx.context.register_parser_and_generator_builder( + ModuleType::JsxDynamic, + Box::new(create_parser_and_generator), + ); + } + ctx .context .register_parser_and_generator_builder(ModuleType::Js, Box::new(create_parser_and_generator)); @@ -38,25 +61,6 @@ impl Plugin for JsPlugin { ModuleType::JsDynamic, Box::new(create_parser_and_generator), ); - ctx - .context - .register_parser_and_generator_builder(ModuleType::Ts, Box::new(create_parser_and_generator)); - ctx.context.register_parser_and_generator_builder( - ModuleType::Tsx, - Box::new(create_parser_and_generator), - ); - ctx.context.register_parser_and_generator_builder( - ModuleType::Jsx, - Box::new(create_parser_and_generator), - ); - ctx.context.register_parser_and_generator_builder( - ModuleType::JsxEsm, - Box::new(create_parser_and_generator), - ); - ctx.context.register_parser_and_generator_builder( - ModuleType::JsxDynamic, - Box::new(create_parser_and_generator), - ); Ok(()) } diff --git a/crates/rspack_plugin_javascript/src/plugin/mod.rs b/crates/rspack_plugin_javascript/src/plugin/mod.rs index 2085384fea6..44630fd9721 100644 --- a/crates/rspack_plugin_javascript/src/plugin/mod.rs +++ b/crates/rspack_plugin_javascript/src/plugin/mod.rs @@ -1,11 +1,14 @@ -pub mod flag_usage_plugin; +pub mod api_plugin; +mod flag_dependency_exports_plugin; +mod flag_dependency_usage_plugin; pub mod impl_plugin_for_js_plugin; pub mod infer_async_modules_plugin; -pub mod provided_exports_plugin; -pub mod side_effects_flag_plugin; +mod side_effects_flag_plugin; use std::hash::Hash; +pub use flag_dependency_exports_plugin::*; +pub use flag_dependency_usage_plugin::*; use rspack_core::rspack_sources::{BoxSource, ConcatSource, RawSource, SourceExt}; use rspack_core::{ ChunkUkey, Compilation, JsChunkHashArgs, PluginJsChunkHashHookOutput, RenderArgs, @@ -13,6 +16,7 @@ use rspack_core::{ }; use rspack_error::Result; use rspack_hash::RspackHash; +pub use side_effects_flag_plugin::*; use crate::runtime::{ render_chunk_init_fragments, render_chunk_modules, render_iife, render_runtime_modules, diff --git a/crates/rspack_plugin_javascript/src/plugin/side_effects_flag_plugin.rs b/crates/rspack_plugin_javascript/src/plugin/side_effects_flag_plugin.rs index a14f0e99210..b660ae69c38 100644 --- a/crates/rspack_plugin_javascript/src/plugin/side_effects_flag_plugin.rs +++ b/crates/rspack_plugin_javascript/src/plugin/side_effects_flag_plugin.rs @@ -1,13 +1,14 @@ +// use rspack_core::Plugin; +// use rspack_error::Result; use swc_core::common::{Span, Spanned, SyntaxContext, GLOBALS}; use swc_core::ecma::ast::*; use swc_core::ecma::utils::{ExprCtx, ExprExt}; use swc_core::ecma::visit::{noop_visit_type, Visit, VisitWith}; #[derive(Debug)] -pub struct SideEffectsFlagPlugin { +pub struct SideEffectsFlagPluginVisitor { unresolved_ctxt: SyntaxContext, - // module_identifier: ModuleIdentifier, - side_effects_span: Option, + pub side_effects_span: Option, is_top_level: bool, } @@ -22,7 +23,7 @@ impl SyntaxContextInfo { } } -impl SideEffectsFlagPlugin { +impl SideEffectsFlagPluginVisitor { pub fn new(mark_info: SyntaxContextInfo) -> Self { Self { unresolved_ctxt: mark_info.unresolved_ctxt, @@ -32,7 +33,7 @@ impl SideEffectsFlagPlugin { } } -impl Visit for SideEffectsFlagPlugin { +impl Visit for SideEffectsFlagPluginVisitor { noop_visit_type!(); fn visit_program(&mut self, node: &Program) { assert!(GLOBALS.is_set()); @@ -94,81 +95,82 @@ impl Visit for SideEffectsFlagPlugin { } } -impl SideEffectsFlagPlugin { +impl SideEffectsFlagPluginVisitor { /// If we find a stmt that has side effects, we will skip the rest of the stmts. /// And mark the module as having side effects. fn analyze_stmt_side_effects(&mut self, ele: &Stmt) { - if self.side_effects_span.is_none() { - match ele { - Stmt::If(stmt) => { - if !is_pure_expression(&stmt.test, self.unresolved_ctxt) { - self.side_effects_span = Some(stmt.span); - } + if self.side_effects_span.is_some() { + return; + } + match ele { + Stmt::If(stmt) => { + if !is_pure_expression(&stmt.test, self.unresolved_ctxt) { + self.side_effects_span = Some(stmt.span); } - Stmt::While(stmt) => { - if !is_pure_expression(&stmt.test, self.unresolved_ctxt) { - self.side_effects_span = Some(stmt.span); - } + } + Stmt::While(stmt) => { + if !is_pure_expression(&stmt.test, self.unresolved_ctxt) { + self.side_effects_span = Some(stmt.span); } - Stmt::DoWhile(stmt) => { - if !is_pure_expression(&stmt.test, self.unresolved_ctxt) { - self.side_effects_span = Some(stmt.span); - } + } + Stmt::DoWhile(stmt) => { + if !is_pure_expression(&stmt.test, self.unresolved_ctxt) { + self.side_effects_span = Some(stmt.span); } - Stmt::For(stmt) => { - let pure_init = match stmt.init { - Some(ref init) => match init { - VarDeclOrExpr::VarDecl(decl) => is_pure_var_decl(decl, self.unresolved_ctxt), - VarDeclOrExpr::Expr(expr) => is_pure_expression(expr, self.unresolved_ctxt), - }, - None => true, - }; + } + Stmt::For(stmt) => { + let pure_init = match stmt.init { + Some(ref init) => match init { + VarDeclOrExpr::VarDecl(decl) => is_pure_var_decl(decl, self.unresolved_ctxt), + VarDeclOrExpr::Expr(expr) => is_pure_expression(expr, self.unresolved_ctxt), + }, + None => true, + }; - if !pure_init { - self.side_effects_span = Some(stmt.span); - return; - } + if !pure_init { + self.side_effects_span = Some(stmt.span); + return; + } - let pure_test = match stmt.test { - Some(box ref test) => is_pure_expression(test, self.unresolved_ctxt), - None => true, - }; + let pure_test = match stmt.test { + Some(box ref test) => is_pure_expression(test, self.unresolved_ctxt), + None => true, + }; - if !pure_test { - self.side_effects_span = Some(stmt.span); - return; - } + if !pure_test { + self.side_effects_span = Some(stmt.span); + return; + } - let pure_update = match stmt.update { - Some(ref expr) => is_pure_expression(expr, self.unresolved_ctxt), - None => true, - }; + let pure_update = match stmt.update { + Some(ref expr) => is_pure_expression(expr, self.unresolved_ctxt), + None => true, + }; - if !pure_update { - self.side_effects_span = Some(stmt.span); - } + if !pure_update { + self.side_effects_span = Some(stmt.span); } - Stmt::Expr(stmt) => { - if !is_pure_expression(&stmt.expr, self.unresolved_ctxt) { - self.side_effects_span = Some(stmt.span); - } + } + Stmt::Expr(stmt) => { + if !is_pure_expression(&stmt.expr, self.unresolved_ctxt) { + self.side_effects_span = Some(stmt.span); } - Stmt::Switch(stmt) => { - if !is_pure_expression(&stmt.discriminant, self.unresolved_ctxt) { - self.side_effects_span = Some(stmt.span); - } + } + Stmt::Switch(stmt) => { + if !is_pure_expression(&stmt.discriminant, self.unresolved_ctxt) { + self.side_effects_span = Some(stmt.span); } - Stmt::Decl(stmt) => { - if !is_pure_decl(stmt, self.unresolved_ctxt) { - self.side_effects_span = Some(stmt.span()); - } + } + Stmt::Decl(stmt) => { + if !is_pure_decl(stmt, self.unresolved_ctxt) { + self.side_effects_span = Some(stmt.span()); } - Stmt::Empty(_) => {} - Stmt::Labeled(_) => {} - Stmt::Block(_) => {} - _ => self.side_effects_span = Some(ele.span()), - }; - } + } + Stmt::Empty(_) => {} + Stmt::Labeled(_) => {} + Stmt::Block(_) => {} + _ => self.side_effects_span = Some(ele.span()), + }; } } @@ -275,3 +277,6 @@ impl ClassKey for ClassMember { } } } + +#[derive(Debug, Default)] +pub struct SideEffectsFlagPlugin; diff --git a/crates/rspack_plugin_javascript/src/runtime.rs b/crates/rspack_plugin_javascript/src/runtime.rs index 9323f758823..c046d6c85f2 100644 --- a/crates/rspack_plugin_javascript/src/runtime.rs +++ b/crates/rspack_plugin_javascript/src/runtime.rs @@ -35,17 +35,14 @@ pub fn render_chunk_modules( .get(&mgm.module_identifier, Some(&chunk.runtime)) .expect("should have code generation result"); if let Some(origin_source) = code_gen_result.get(&SourceType::JavaScript) { - let module_source = if let Some(source) = plugin_driver + let render_module_result = plugin_driver .render_module_content(RenderModuleContentArgs { compilation, - module_source: origin_source, + module_graph_module: mgm, + module_source: origin_source.clone(), + chunk_init_fragments: ChunkInitFragments::default(), }) - .expect("render_module_content failed") - { - source - } else { - origin_source.clone() - }; + .expect("render_module_content failed"); let runtime_requirements = compilation .chunk_graph @@ -54,12 +51,13 @@ pub fn render_chunk_modules( Some(( mgm.module_identifier, render_module( - module_source, + render_module_result.module_source, mgm, runtime_requirements, mgm.id(&compilation.chunk_graph), ), &code_gen_result.chunk_init_fragments, + render_module_result.chunk_init_fragments, )) } else { None @@ -67,21 +65,20 @@ pub fn render_chunk_modules( }) .collect::>(); - module_code_array.sort_unstable_by_key(|(module_identifier, _, _)| *module_identifier); + module_code_array.sort_unstable_by_key(|(module_identifier, _, _, _)| *module_identifier); let chunk_init_fragments = module_code_array.iter().fold( ChunkInitFragments::default(), - |mut chunk_init_fragments, (_, _, fragments)| { - for (k, v) in fragments.iter() { - chunk_init_fragments.insert(k.to_string(), v.clone()); - } + |mut chunk_init_fragments, (_, _, fragments, additional_fragments)| { + chunk_init_fragments.extend((*fragments).clone()); + chunk_init_fragments.extend(additional_fragments.clone()); chunk_init_fragments }, ); let module_sources: Vec<_> = module_code_array .into_iter() - .map(|(_, source, _)| source) + .map(|(_, source, _, _)| source) .collect::>()?; let module_sources = module_sources .into_par_iter() diff --git a/crates/rspack_plugin_javascript/src/utils.rs b/crates/rspack_plugin_javascript/src/utils.rs index f78825336b7..0d9ada461f3 100644 --- a/crates/rspack_plugin_javascript/src/utils.rs +++ b/crates/rspack_plugin_javascript/src/utils.rs @@ -8,7 +8,11 @@ use swc_core::ecma::atoms::{js_word, JsWord}; use swc_core::ecma::parser::Syntax; use swc_core::ecma::parser::{EsConfig, TsConfig}; -fn syntax_by_ext(filename: &Path, enable_decorators: bool) -> Syntax { +fn syntax_by_ext( + filename: &Path, + enable_decorators: bool, + should_transform_by_default: bool, +) -> Syntax { // swc_core::base::Compiler::process_js_with_custom_pass() let ext = filename .extension() @@ -28,7 +32,7 @@ fn syntax_by_ext(filename: &Path, enable_decorators: bool) -> Syntax { jsx: ext == "jsx", export_default_from: true, decorators_before_export: true, - decorators: enable_decorators, + decorators: should_transform_by_default && enable_decorators, fn_bind: true, allow_super_outside_method: true, ..Default::default() @@ -40,28 +44,42 @@ pub fn syntax_by_module_type( filename: &Path, module_type: &ModuleType, enable_decorators: bool, + should_transform_by_default: bool, ) -> Syntax { - match module_type { - ModuleType::Js | ModuleType::Jsx => Syntax::Es(EsConfig { - jsx: matches!(module_type, ModuleType::Jsx), - export_default_from: true, - decorators_before_export: true, - decorators: enable_decorators, - fn_bind: true, - allow_super_outside_method: true, - ..Default::default() - }), - ModuleType::Ts | ModuleType::Tsx => { - let filename = filename.to_string_lossy(); - Syntax::Typescript(TsConfig { - decorators: enable_decorators, - tsx: matches!(module_type, ModuleType::Tsx), - dts: filename.ends_with(".d.ts") || filename.ends_with(".d.tsx"), - ..Default::default() - }) - } - _ => syntax_by_ext(filename, enable_decorators), + let js_syntax = Syntax::Es(EsConfig { + jsx: matches!(module_type, ModuleType::Jsx), + export_default_from: true, + decorators_before_export: true, + // If `disableTransformByDefault` is on, then we treat everything passed in as a web standard stuff, + // which means everything that is not a web standard would results in a parsing error. + // So as the decorator. + decorators: should_transform_by_default && enable_decorators, + fn_bind: true, + allow_super_outside_method: true, + ..Default::default() + }); + + // Legacy behavior: `ts`, `tsx`, etc. + if should_transform_by_default { + return match module_type { + ModuleType::Js | ModuleType::Jsx => js_syntax, + ModuleType::Ts | ModuleType::Tsx => { + let filename = filename.to_string_lossy(); + Syntax::Typescript(TsConfig { + // `disableTransformByDefault` will not affect TypeScript-like modules, + // as we are following standard of TypeScript compiler. + // This is not a web standard by all means. + decorators: enable_decorators, + tsx: matches!(module_type, ModuleType::Tsx), + dts: filename.ends_with(".d.ts") || filename.ends_with(".d.tsx"), + ..Default::default() + }) + } + _ => syntax_by_ext(filename, enable_decorators, should_transform_by_default), + }; } + + js_syntax } pub fn set_require_literal_args(e: &mut CallExpr, arg_value: &str) { diff --git a/crates/rspack_plugin_javascript/src/visitors/dependency/api_scanner.rs b/crates/rspack_plugin_javascript/src/visitors/dependency/api_scanner.rs index 6e6d015dea3..8a495c77c0d 100644 --- a/crates/rspack_plugin_javascript/src/visitors/dependency/api_scanner.rs +++ b/crates/rspack_plugin_javascript/src/visitors/dependency/api_scanner.rs @@ -1,6 +1,6 @@ use rspack_core::{ - ConstDependency, DependencyTemplate, ResourceData, RuntimeGlobals, RuntimeRequirementsDependency, - SpanExt, + BuildInfo, ConstDependency, DependencyTemplate, ResourceData, RuntimeGlobals, + RuntimeRequirementsDependency, SpanExt, }; use swc_core::{ common::{Spanned, SyntaxContext}, @@ -18,9 +18,13 @@ pub const WEBPACK_MODULES: &str = "__webpack_modules__"; pub const WEBPACK_MODULE: &str = "__webpack_module__"; pub const WEBPACK_RESOURCE_QUERY: &str = "__resourceQuery"; pub const WEBPACK_CHUNK_LOAD: &str = "__webpack_chunk_load__"; +pub const WEBPACK_BASE_URI: &str = "__webpack_base_uri__"; +pub const NON_WEBPACK_REQUIRE: &str = "__non_webpack_require__"; pub struct ApiScanner<'a> { pub unresolved_ctxt: &'a SyntaxContext, + pub module: bool, + pub build_info: &'a mut BuildInfo, pub enter_assign: bool, pub resource_data: &'a ResourceData, pub presentational_dependencies: &'a mut Vec>, @@ -31,9 +35,13 @@ impl<'a> ApiScanner<'a> { unresolved_ctxt: &'a SyntaxContext, resource_data: &'a ResourceData, presentational_dependencies: &'a mut Vec>, + module: bool, + build_info: &'a mut BuildInfo, ) -> Self { Self { unresolved_ctxt, + module, + build_info, enter_assign: false, resource_data, presentational_dependencies, @@ -141,6 +149,31 @@ impl Visit for ApiScanner<'_> { None, ))); } + WEBPACK_BASE_URI => { + self + .presentational_dependencies + .push(Box::new(ConstDependency::new( + ident.span.real_lo(), + ident.span.real_hi(), + RuntimeGlobals::BASE_URI.name().into(), + Some(RuntimeGlobals::BASE_URI), + ))); + } + NON_WEBPACK_REQUIRE => { + self + .presentational_dependencies + .push(Box::new(ConstDependency::new( + ident.span.real_lo(), + ident.span.real_hi(), + if self.module { + self.build_info.need_create_require = true; + "__WEBPACK_EXTERNAL_createRequire(import.meta.url)".into() + } else { + "require".into() + }, + None, + ))); + } _ => {} } } diff --git a/crates/rspack_plugin_javascript/src/visitors/dependency/harmony_export_dependency_scanner.rs b/crates/rspack_plugin_javascript/src/visitors/dependency/harmony_export_dependency_scanner.rs index 4582bde8024..b0c58dee323 100644 --- a/crates/rspack_plugin_javascript/src/visitors/dependency/harmony_export_dependency_scanner.rs +++ b/crates/rspack_plugin_javascript/src/visitors/dependency/harmony_export_dependency_scanner.rs @@ -17,7 +17,8 @@ use swc_core::{ use super::harmony_import_dependency_scanner::ImportMap; use crate::dependency::{ AnonymousFunctionRangeInfo, HarmonyExportExpressionDependency, HarmonyExportHeaderDependency, - HarmonyExportImportedSpecifierDependency, HarmonyExportSpecifierDependency, DEFAULT_EXPORT, + HarmonyExportImportedSpecifierDependency, HarmonyExportSpecifierDependency, Specifier, + DEFAULT_EXPORT, }; pub struct HarmonyExportDependencyScanner<'a> { @@ -100,12 +101,21 @@ impl Visit for HarmonyExportDependencyScanner<'_> { _ => unreachable!(), }; if let Some(reference) = self.import_map.get(&orig.to_id()) { + let ids = vec![(export.clone(), reference.names.clone())]; + let mode_ids = match reference.specifier { + Specifier::Namespace(_) => { + vec![] + } + _ => ids.clone(), + }; self .dependencies .push(Box::new(HarmonyExportImportedSpecifierDependency::new( reference.request.clone(), - vec![(export.clone(), reference.names.clone())], + ids, + mode_ids, Some(export), + false, ))); } else { self diff --git a/crates/rspack_plugin_javascript/src/visitors/dependency/harmony_import_dependency_scanner.rs b/crates/rspack_plugin_javascript/src/visitors/dependency/harmony_import_dependency_scanner.rs index 141df218b50..d9a4efaa78b 100644 --- a/crates/rspack_plugin_javascript/src/visitors/dependency/harmony_import_dependency_scanner.rs +++ b/crates/rspack_plugin_javascript/src/visitors/dependency/harmony_import_dependency_scanner.rs @@ -41,6 +41,7 @@ impl ImporterReferenceInfo { pub type ImportMap = HashMap; +#[derive(Debug)] pub struct ImporterInfo { pub span: Span, pub specifiers: Vec, @@ -100,12 +101,15 @@ impl Visit for HarmonyImportDependencyScanner<'_> { .iter() .for_each(|specifier| match specifier { Specifier::Namespace(n) => { + let ids = vec![(n.clone(), None)]; self .dependencies .push(Box::new(HarmonyExportImportedSpecifierDependency::new( request.clone(), - vec![(n.clone(), None)], + ids.clone(), + ids, Some(n.clone()), + false, ))); self.build_info.harmony_named_exports.insert(n.clone()); } @@ -114,12 +118,15 @@ impl Visit for HarmonyImportDependencyScanner<'_> { } Specifier::Named(orig, exported) => { let name = exported.clone().unwrap_or(orig.clone()); + let ids = vec![(name.clone(), Some(orig.clone()))]; self .dependencies .push(Box::new(HarmonyExportImportedSpecifierDependency::new( request.clone(), - vec![(name.clone(), Some(orig.clone()))], + ids.clone(), + ids, Some(name.clone()), + false, ))); self.build_info.harmony_named_exports.insert(name); } @@ -134,6 +141,15 @@ impl Visit for HarmonyImportDependencyScanner<'_> { ); if importer_info.exports_all { self.build_info.all_star_exports.push(dependency.id); + self + .dependencies + .push(Box::new(HarmonyExportImportedSpecifierDependency::new( + request.clone(), + vec![], + vec![], + None, + true, + ))); } self.dependencies.push(Box::new(dependency)); } @@ -259,6 +275,7 @@ impl Visit for HarmonyImportDependencyScanner<'_> { fn visit_export_all(&mut self, export_all: &ExportAll) { let key = (export_all.src.value.clone(), DependencyType::EsmExport); + if let Some(importer_info) = self.imports.get_mut(&key) { importer_info.exports_all = true; } else { @@ -266,6 +283,7 @@ impl Visit for HarmonyImportDependencyScanner<'_> { .imports .insert(key, ImporterInfo::new(export_all.span, vec![], true)); } + 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 24c702aaf07..6cb7c6fde72 100644 --- a/crates/rspack_plugin_javascript/src/visitors/dependency/mod.rs +++ b/crates/rspack_plugin_javascript/src/visitors/dependency/mod.rs @@ -58,6 +58,8 @@ pub fn scan_dependencies( &unresolved_ctxt, resource_data, &mut presentational_dependencies, + compiler_options.output.module, + build_info, )); program.visit_with(&mut CompatibilityScanner::new( diff --git a/crates/rspack_plugin_javascript/src/visitors/mod.rs b/crates/rspack_plugin_javascript/src/visitors/mod.rs index 6989e2d185f..9c9f5cd9bbc 100644 --- a/crates/rspack_plugin_javascript/src/visitors/mod.rs +++ b/crates/rspack_plugin_javascript/src/visitors/mod.rs @@ -1,9 +1,11 @@ mod dependency; use std::path::{Path, PathBuf}; +use std::sync::Arc; pub use dependency::*; use either::Either; use swc_core::common::comments::Comments; +use swc_core::ecma::visit::Fold; use xxhash_rust::xxh32::xxh32; mod clear_mark; @@ -12,12 +14,12 @@ use swc_core::ecma::transforms::base::Assumptions; pub mod swc_visitor; use rspack_core::{ast::javascript::Ast, CompilerOptions, ResourceData}; use rspack_error::Result; -use swc_core::common::chain; +use swc_core::common::{chain, Mark, SourceMap}; use swc_core::ecma::parser::Syntax; use swc_core::ecma::transforms::base::pass::{noop, Optional}; macro_rules! either { - ($config: expr, $f: expr) => { + ($config:expr, $f:expr) => { if let Some(config) = &$config { Either::Left($f(config)) } else { @@ -26,7 +28,154 @@ macro_rules! either { }; } -/// return (ast, top_level_mark, unresolved_mark, globals) +/// Rspack builtins +/// - `react`: a port of `react-refresh/babel`, and `react-fast-refresh-loader` +/// - `relay`: a port of `babel-plugin-relay` +/// - `import`: a port of `babel-plugin-import` +/// - `emotion`: a port of `babel-plugin-emotion` +// #[deprecated( +// note = "Builtin transform is deprecated and will be removed in JS version 0.5.0, see: https://github.com/web-infra-dev/rspack/pull/4133" +// )] +#[allow(clippy::too_many_arguments)] +fn builtins_additional_feature_transforms<'b>( + resource_data: &'b ResourceData, + options: &'b CompilerOptions, + module_type: &'b ModuleType, + source: &'b str, + top_level_mark: Mark, + unresolved_mark: Mark, + cm: Arc, +) -> impl Fold + 'b { + let comments = None; + // TODO: should use react-loader to get exclude/include + let should_transform_by_react = module_type.is_jsx_like(); + + chain!( + Optional::new( + rspack_swc_visitors::react( + top_level_mark, + comments, + &cm, + &options.builtins.react, + unresolved_mark + ), + should_transform_by_react + ), + Optional::new( + rspack_swc_visitors::fold_react_refresh(unresolved_mark), + should_transform_by_react && options.builtins.react.refresh.unwrap_or_default() + ), + either!( + options.builtins.emotion, + |emotion_options: &rspack_swc_visitors::EmotionOptions| { + rspack_swc_visitors::emotion( + emotion_options.clone(), + &resource_data.resource_path, + xxh32(source.as_bytes(), 0), + cm.clone(), + comments, + ) + } + ), + either!(options.builtins.relay, |relay_option| { + rspack_swc_visitors::relay( + relay_option, + &resource_data.resource_path, + PathBuf::from(AsRef::::as_ref(&options.context)), + unresolved_mark, + ) + }), + either!(options.builtins.plugin_import, |config| { + swc_plugin_import::plugin_import(config) + }) + ) +} + +/// Webpack builtin plugins +/// - `define`: a port of `DefinePlugin` +/// - `provide`: a port of `ProvidePlugin` +fn builtins_webpack_plugin(options: &CompilerOptions, unresolved_mark: Mark) -> impl Fold + '_ { + chain!( + Optional::new( + rspack_swc_visitors::define(&options.builtins.define), + !options.builtins.define.is_empty() + ), + Optional::new( + builtins_webpack_plugin_define_optimizer(unresolved_mark), + !options.builtins.define.is_empty() + ), + Optional::new( + rspack_swc_visitors::provide_builtin(&options.builtins.provide, unresolved_mark), + !options.builtins.provide.is_empty() + ) + ) +} + +/// Removing this will **not** cause semantic difference, but will avoid overheads that are not necessary. +/// Expression simplifier and dead branch remover are working together to avoid parsing not necessary path. +/// +/// Example: +/// ```js +/// if(process.env.NODE_ENV === "development") { +/// module.exports = require(".../xxx.development.js") +/// } else { +/// module.exports = require(".../xxx.production.js") +/// } +/// ``` +/// The ordering of these two is important, `expr_simplifier` goes first and `dead_branch_remover` goes second. +/// +/// `if(process.env.NODE_ENV === "development")` -> -> `if("development" === "development")` +/// `if("development" === "development") {} else {}` -> -> `if(true) {} else {}` +/// `if(true) {} else {}` -> -> `else` branch is removed +fn builtins_webpack_plugin_define_optimizer(unresolved_mark: Mark) -> impl Fold { + chain!( + swc_visitor::expr_simplifier(unresolved_mark, Default::default()), + swc_visitor::dead_branch_remover(unresolved_mark) + ) +} + +#[allow(clippy::too_many_arguments)] +// #[deprecated( +// note = "Compat transform is deprecated and will be removed in JS version 0.5.0, see: https://github.com/web-infra-dev/rspack/discussions/4070" +// )] +fn compat_transform<'b>( + resource_data: &'b ResourceData, + options: &'b CompilerOptions, + top_level_mark: Mark, + unresolved_mark: Mark, + assumptions: Assumptions, + syntax: Syntax, +) -> impl Fold + 'b { + let es_version = match options.target.es_version { + rspack_core::TargetEsVersion::Esx(es_version) => Some(es_version), + _ => None, + }; + let resource_path = resource_data.resource_path.to_string_lossy(); + + chain!( + Optional::new( + swc_visitor::export_default_from(), + syntax.export_default_from() + ), + swc_visitor::paren_remover(None), + Optional::new( + swc_visitor::compat( + options.builtins.preset_env.clone(), + es_version, + assumptions, + top_level_mark, + unresolved_mark, + None, + syntax.typescript(), + ), + !resource_path.contains("@swc/helpers") + && !resource_path.contains("tslib") + && !resource_path.contains("core-js"), + ), + swc_visitor::reserved_words(), + ) +} + #[allow(clippy::too_many_arguments)] pub fn run_before_pass( resource_data: &ResourceData, @@ -37,13 +186,7 @@ pub fn run_before_pass( module_type: &ModuleType, source: &str, ) -> Result<()> { - let es_version = match options.target.es_version { - rspack_core::TargetEsVersion::Esx(es_version) => Some(es_version), - _ => None, - }; let cm = ast.get_context().source_map.clone(); - // TODO: should use react-loader to get exclude/include - let should_transform_by_react = module_type.is_jsx_like(); ast.transform_with_handler(cm.clone(), |_handler, program, context| { let top_level_mark = context.top_level_mark; let unresolved_mark = context.unresolved_mark; @@ -55,108 +198,44 @@ pub fn run_before_pass( assumptions.set_public_class_fields = true; } - let resource_path = resource_data.resource_path.to_string_lossy(); - let mut pass = chain!( swc_visitor::resolver(unresolved_mark, top_level_mark, syntax.typescript()), - // swc_visitor::lint( - // &ast, - // top_level_mark, - // unresolved_mark, - // EsVersion::Es2022, - // &cm - // ), Optional::new( swc_visitor::decorator(assumptions, &options.builtins.decorator), - syntax.decorators() + // 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() ), - // swc_visitor::import_assertions(), Optional::new( swc_visitor::typescript(assumptions, top_level_mark, comments, &cm), syntax.typescript() ), - Optional::new( - rspack_swc_visitors::react( - top_level_mark, - comments, - &cm, - &options.builtins.react, - unresolved_mark - ), - should_transform_by_react - ), - Optional::new( - rspack_swc_visitors::fold_react_refresh(unresolved_mark), - should_transform_by_react - && options - .builtins - .react - .refresh - .and_then(|v| if v { Some(v) } else { None }) - .is_some() - ), - either!( - options.builtins.emotion, - |emotion_options: &rspack_swc_visitors::EmotionOptions| { - rspack_swc_visitors::emotion( - emotion_options.clone(), - &resource_data.resource_path, - xxh32(source.as_bytes(), 0), - cm.clone(), - comments, - ) - } - ), - either!(options.builtins.relay, |relay_option| { - rspack_swc_visitors::relay( - relay_option, - resource_data.resource_path.as_path(), - PathBuf::from(AsRef::::as_ref(&options.context)), - unresolved_mark, - ) - }), - either!(options.builtins.plugin_import, |options| { - rspack_swc_visitors::import(options) - }), - // enable if configurable - // swc_visitor::const_modules(cm, globals), - Optional::new( - rspack_swc_visitors::define(&options.builtins.define), - !options.builtins.define.is_empty() - ), - Optional::new( - rspack_swc_visitors::provide_builtin(&options.builtins.provide, unresolved_mark), - !options.builtins.provide.is_empty() - ), - Optional::new( - swc_visitor::export_default_from(), - syntax.export_default_from() + builtins_additional_feature_transforms( + resource_data, + options, + module_type, + source, + top_level_mark, + unresolved_mark, + cm ), - // enable if necessary - // swc_visitor::simplifier(unresolved_mark, Default::default()), - // enable if configurable - // swc_visitor::json_parse(min_cost), - swc_visitor::paren_remover(comments.map(|v| v as &dyn Comments)), - // es_version Optional::new( - swc_visitor::compat( - options.builtins.preset_env.clone(), - es_version, - assumptions, + compat_transform( + resource_data, + options, top_level_mark, unresolved_mark, - comments, - syntax.typescript() + assumptions, + syntax ), - !resource_path.contains("@swc/helpers") - && !resource_path.contains("tslib") - && !resource_path.contains("core-js") + options.should_transform_by_default() ), - swc_visitor::reserved_words(), + 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), - // The ordering of these two is important, `expr_simplifier` goes first and `dead_branch_remover` goes second. - swc_visitor::expr_simplifier(unresolved_mark, Default::default()), - swc_visitor::dead_branch_remover(unresolved_mark), swc_visitor::hygiene(false, top_level_mark), swc_visitor::fixer(comments.map(|v| v as &dyn Comments)), ); diff --git a/crates/rspack_plugin_javascript/tests/fixtures.rs b/crates/rspack_plugin_javascript/tests/fixtures.rs index 01a67779194..2d7272f96f6 100644 --- a/crates/rspack_plugin_javascript/tests/fixtures.rs +++ b/crates/rspack_plugin_javascript/tests/fixtures.rs @@ -5,5 +5,5 @@ use rspack_testing::{fixture, test_fixture}; #[fixture("tests/fixtures/**/*.config.json")] fn js(config_path: PathBuf) { let fixture_path = config_path.parent().expect("TODO:"); - test_fixture(fixture_path); + test_fixture(fixture_path, Box::new(|_, _| {}), None); } diff --git a/crates/rspack_plugin_javascript/tests/fixtures/provide/snapshot/output.snap b/crates/rspack_plugin_javascript/tests/fixtures/provide/snapshot/output.snap index faecc3f57a7..139d3df982b 100644 --- a/crates/rspack_plugin_javascript/tests/fixtures/provide/snapshot/output.snap +++ b/crates/rspack_plugin_javascript/tests/fixtures/provide/snapshot/output.snap @@ -47,21 +47,29 @@ function defaultClearTimeout() { } (function() { try { - if (typeof setTimeout === "function") cachedSetTimeout = setTimeout; - else cachedSetTimeout = defaultSetTimout; + if (typeof setTimeout === "function") { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; + } } catch (e) { cachedSetTimeout = defaultSetTimout; } try { - if (typeof clearTimeout === "function") cachedClearTimeout = clearTimeout; - else cachedClearTimeout = defaultClearTimeout; + if (typeof clearTimeout === "function") { + cachedClearTimeout = clearTimeout; + } else { + cachedClearTimeout = defaultClearTimeout; + } } catch (e1) { cachedClearTimeout = defaultClearTimeout; } })(); function runTimeout(fun) { - if (cachedSetTimeout === setTimeout) //normal enviroments in sane situations - return setTimeout(fun, 0); + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } // if setTimeout wasn't available but was latter defined if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { cachedSetTimeout = setTimeout; @@ -81,8 +89,10 @@ function runTimeout(fun) { } } function runClearTimeout(marker) { - if (cachedClearTimeout === clearTimeout) //normal enviroments in sane situations - return clearTimeout(marker); + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } // if clearTimeout wasn't available but was latter defined if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { cachedClearTimeout = clearTimeout; @@ -107,21 +117,34 @@ var draining = false; var currentQueue; var queueIndex = -1; function cleanUpNextTick() { - if (!draining || !currentQueue) return; + if (!draining || !currentQueue) { + return; + } draining = false; - if (currentQueue.length) queue = currentQueue.concat(queue); - else queueIndex = -1; - if (queue.length) drainQueue(); + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } } function drainQueue() { - if (draining) return; + if (draining) { + return; + } var timeout = runTimeout(cleanUpNextTick); draining = true; var len = queue.length; while(len){ currentQueue = queue; queue = []; - while(++queueIndex < len)if (currentQueue) currentQueue[queueIndex].run(); + while(++queueIndex < len){ + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } queueIndex = -1; len = queue.length; } @@ -131,9 +154,15 @@ function drainQueue() { } process.nextTick = function(fun) { var args = new Array(arguments.length - 1); - if (arguments.length > 1) for(var i = 1; i < arguments.length; i++)args[i - 1] = arguments[i]; + if (arguments.length > 1) { + for(var i = 1; i < arguments.length; i++){ + args[i - 1] = arguments[i]; + } + } queue.push(new Item(fun, args)); - if (queue.length === 1 && !draining) runTimeout(drainQueue); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } }; // v8 likes predictible objects function Item(fun, array) { diff --git a/crates/rspack_plugin_json/tests/fixtures.rs b/crates/rspack_plugin_json/tests/fixtures.rs index 2b4daa7ca21..72402088639 100644 --- a/crates/rspack_plugin_json/tests/fixtures.rs +++ b/crates/rspack_plugin_json/tests/fixtures.rs @@ -4,5 +4,5 @@ use rspack_testing::{fixture, test_fixture}; #[fixture("tests/fixtures/*")] fn json(fixture_path: PathBuf) { - test_fixture(&fixture_path); + test_fixture(&fixture_path, Box::new(|_, _| {}), None); } diff --git a/crates/rspack_plugin_library/src/amd_library_plugin.rs b/crates/rspack_plugin_library/src/amd_library_plugin.rs index 57e6bab1f21..6904ced6ca5 100644 --- a/crates/rspack_plugin_library/src/amd_library_plugin.rs +++ b/crates/rspack_plugin_library/src/amd_library_plugin.rs @@ -7,7 +7,7 @@ use rspack_core::{ PluginJsChunkHashHookOutput, PluginRenderHookOutput, RenderArgs, RuntimeGlobals, SourceType, }; -use super::utils::{external_arguments, external_dep_array}; +use super::utils::{external_arguments, externals_dep_array}; use crate::utils::normalize_name; #[derive(Debug)] @@ -70,7 +70,7 @@ impl Plugin for AmdLibraryPlugin { }) }) .collect::>(); - let external_deps_array = external_dep_array(&modules); + let externals_deps_array = externals_dep_array(&modules)?; let external_arguments = external_arguments(&modules, compilation); let mut fn_start = format!("function({external_arguments}){{\n"); if compilation.options.output.iife || !chunk.has_runtime(&compilation.chunk_group_by_ukey) { @@ -80,7 +80,7 @@ impl Plugin for AmdLibraryPlugin { let mut source = ConcatSource::default(); if self.require_as_wrapper { source.add(RawSource::from(format!( - "require({external_deps_array}, {fn_start}" + "require({externals_deps_array}, {fn_start}" ))); } else if let Some(name) = name { let normalize_name = compilation.get_path( @@ -93,13 +93,13 @@ impl Plugin for AmdLibraryPlugin { ), ); source.add(RawSource::from(format!( - "define('{normalize_name}', {external_deps_array}, {fn_start}" + "define('{normalize_name}', {externals_deps_array}, {fn_start}" ))); } else if modules.is_empty() { source.add(RawSource::from(format!("define({fn_start}"))); } else { source.add(RawSource::from(format!( - "define({external_deps_array}, {fn_start}" + "define({externals_deps_array}, {fn_start}" ))); } source.add(args.source.clone()); diff --git a/crates/rspack_plugin_library/src/assign_library_plugin.rs b/crates/rspack_plugin_library/src/assign_library_plugin.rs index 3b3dfa9e8f1..c23ebf3a41d 100644 --- a/crates/rspack_plugin_library/src/assign_library_plugin.rs +++ b/crates/rspack_plugin_library/src/assign_library_plugin.rs @@ -2,6 +2,7 @@ use std::hash::Hash; use once_cell::sync::Lazy; use regex::Regex; +use rspack_core::property_access; use rspack_core::tree_shaking::webpack_ext::ExportInfoExt; use rspack_core::{ rspack_sources::{ConcatSource, RawSource, SourceExt}, @@ -11,8 +12,6 @@ use rspack_core::{ }; use rspack_error::internal_error; -use crate::utils::property_access; - const COMMON_LIBRARY_NAME_MESSAGE: &str = "Common configuration options that specific library names are 'output.library[.name]', 'entry.xyz.library[.name]', 'ModuleFederationPlugin.name' and 'ModuleFederationPlugin.library[.name]'."; #[derive(Debug)] @@ -29,10 +28,36 @@ pub enum Named { Assign, } +#[derive(Debug)] +pub enum Prefix { + Global, + Array(Vec), +} + +impl Prefix { + pub fn value(&self, compilation: &Compilation) -> Vec { + match self { + Prefix::Global => vec![compilation.options.output.global_object.clone()], + Prefix::Array(v) => v.clone(), + } + } + + pub fn len(&self) -> usize { + match self { + Prefix::Global => 1, + Prefix::Array(v) => v.len(), + } + } + + pub fn is_empty(&self) -> bool { + self.len() == 0 + } +} + #[derive(Debug)] pub struct AssignLibraryPluginOptions { pub library_type: String, - pub prefix: Vec, + pub prefix: Prefix, pub declare: bool, pub unnamed: Unnamed, pub named: Option, @@ -52,7 +77,7 @@ impl AssignLibraryPlugin { if let Some(library) = &compilation.options.output.library { if let Some(name) = &library.name { if let Some(root) = &name.root { - let mut prefix = self.options.prefix.clone(); + let mut prefix = self.options.prefix.value(compilation); prefix.extend( root .iter() @@ -73,7 +98,7 @@ impl AssignLibraryPlugin { } } } - self.options.prefix.clone() + self.options.prefix.value(compilation) } } @@ -143,7 +168,7 @@ impl Plugin for AssignLibraryPlugin { .get(&args.module) { for info in analyze_results.ordered_exports() { - let name_access = property_access(&vec![info.name.to_string()]); + let name_access = property_access(&vec![info.name], 0); source.add(RawSource::from(format!( "{export_target}{name_access} = __webpack_exports__{export_access}{name_access};\n", ))); @@ -208,7 +233,7 @@ impl Plugin for AssignLibraryPlugin { fn property_library(library: &Option) -> String { if let Some(library) = library { if let Some(export) = &library.export { - return property_access(export); + return property_access(export, 0); } } String::default() @@ -230,7 +255,7 @@ fn access_with_init(accessor: &Vec, existing_length: usize, init_last: b if existing_length > i { props_so_far = accessor[1..existing_length].to_vec(); i = existing_length; - current.push_str(property_access(&props_so_far).as_str()); + current.push_str(property_access(&props_so_far, 0).as_str()); } let init_until = if init_last { @@ -243,8 +268,8 @@ fn access_with_init(accessor: &Vec, existing_length: usize, init_last: b props_so_far.push(accessor[i].clone()); current = format!( "({current}{} = {base}{} || {{}})", - property_access(&vec![accessor[i].clone()]), - property_access(&props_so_far) + property_access(&vec![&accessor[i]], 0), + property_access(&props_so_far, 0) ); i += 1; } @@ -252,7 +277,7 @@ fn access_with_init(accessor: &Vec, existing_length: usize, init_last: b if i < accessor.len() { current = format!( "{current}{}", - property_access(&vec![accessor[accessor.len() - 1].clone()]), + property_access([&accessor[accessor.len() - 1]], 0), ); } diff --git a/crates/rspack_plugin_library/src/export_property_plugin.rs b/crates/rspack_plugin_library/src/export_property_plugin.rs index ea95dc821ed..3dddf79f95e 100644 --- a/crates/rspack_plugin_library/src/export_property_plugin.rs +++ b/crates/rspack_plugin_library/src/export_property_plugin.rs @@ -1,10 +1,9 @@ use rspack_core::{ + property_access, rspack_sources::{ConcatSource, RawSource, SourceExt}, Plugin, PluginContext, PluginRenderStartupHookOutput, RenderStartupArgs, }; -use crate::utils::property_access; - #[derive(Debug, Default)] pub struct ExportPropertyLibraryPlugin; @@ -40,7 +39,7 @@ impl Plugin for ExportPropertyLibraryPlugin { s.add(args.source.clone()); s.add(RawSource::from(format!( "__webpack_exports__ = __webpack_exports__{};", - property_access(export) + property_access(export, 0) ))); return Ok(Some(s.boxed())); } diff --git a/crates/rspack_plugin_library/src/lib.rs b/crates/rspack_plugin_library/src/lib.rs index 0172b680cb0..6b2633c1563 100644 --- a/crates/rspack_plugin_library/src/lib.rs +++ b/crates/rspack_plugin_library/src/lib.rs @@ -1,14 +1,114 @@ -mod assign_library_plugin; -pub use assign_library_plugin::*; -mod umd_library_plugin; -pub use umd_library_plugin::UmdLibraryPlugin; mod amd_library_plugin; -pub use amd_library_plugin::AmdLibraryPlugin; -mod module_library_plugin; -pub use module_library_plugin::ModuleLibraryPlugin; +mod assign_library_plugin; mod export_property_plugin; -pub use system_library_plugin::SystemLibraryPlugin; +mod module_library_plugin; mod system_library_plugin; +mod umd_library_plugin; mod utils; +pub use amd_library_plugin::AmdLibraryPlugin; +pub use assign_library_plugin::*; pub use export_property_plugin::ExportPropertyLibraryPlugin; +pub use module_library_plugin::ModuleLibraryPlugin; +use rspack_core::{BoxPlugin, PluginExt}; +pub use system_library_plugin::SystemLibraryPlugin; +pub use umd_library_plugin::UmdLibraryPlugin; + +pub fn enable_library_plugin(library_type: String, plugins: &mut Vec) { + match library_type.as_str() { + "var" => plugins.push( + AssignLibraryPlugin::new(AssignLibraryPluginOptions { + library_type, + prefix: Prefix::Array(vec![]), + declare: true, + unnamed: Unnamed::Error, + named: None, + }) + .boxed(), + ), + "assign-properties" => plugins.push( + AssignLibraryPlugin::new(AssignLibraryPluginOptions { + library_type, + prefix: Prefix::Array(vec![]), + declare: false, + unnamed: Unnamed::Error, + named: Some(Named::Copy), + }) + .boxed(), + ), + "assign" => plugins.push( + AssignLibraryPlugin::new(AssignLibraryPluginOptions { + library_type, + prefix: Prefix::Array(vec![]), + declare: false, + unnamed: Unnamed::Error, + named: None, + }) + .boxed(), + ), + "this" | "window" | "self" => plugins.push( + AssignLibraryPlugin::new(AssignLibraryPluginOptions { + library_type: library_type.clone(), + prefix: Prefix::Array(vec![library_type]), + declare: false, + unnamed: Unnamed::Copy, + named: None, + }) + .boxed(), + ), + "global" => plugins.push( + AssignLibraryPlugin::new(AssignLibraryPluginOptions { + library_type, + prefix: Prefix::Global, + declare: false, + unnamed: Unnamed::Copy, + named: None, + }) + .boxed(), + ), + "commonjs" => plugins.push( + AssignLibraryPlugin::new(AssignLibraryPluginOptions { + library_type, + prefix: Prefix::Array(vec!["exports".to_string()]), + declare: false, + unnamed: Unnamed::Copy, + named: None, + }) + .boxed(), + ), + "commonjs-static" => plugins.push( + AssignLibraryPlugin::new(AssignLibraryPluginOptions { + library_type, + prefix: Prefix::Array(vec!["exports".to_string()]), + declare: false, + unnamed: Unnamed::Static, + named: None, + }) + .boxed(), + ), + "commonjs2" | "commonjs-module" => plugins.push( + AssignLibraryPlugin::new(AssignLibraryPluginOptions { + library_type, + prefix: Prefix::Array(vec!["module".to_string(), "exports".to_string()]), + declare: false, + unnamed: Unnamed::Assign, + named: None, + }) + .boxed(), + ), + "umd" | "umd2" => { + plugins.push(ExportPropertyLibraryPlugin::default().boxed()); + plugins.push(UmdLibraryPlugin::new("umd2".eq(&library_type)).boxed()); + } + "amd" | "amd-require" => { + plugins.push(ExportPropertyLibraryPlugin::default().boxed()); + plugins.push(AmdLibraryPlugin::new("amd-require".eq(&library_type)).boxed()); + } + "module" => { + plugins.push(ExportPropertyLibraryPlugin::default().boxed()); + plugins.push(ModuleLibraryPlugin::default().boxed()); + } + "system" => plugins.push(SystemLibraryPlugin::default().boxed()), + _ => {} + } +} diff --git a/crates/rspack_plugin_library/src/module_library_plugin.rs b/crates/rspack_plugin_library/src/module_library_plugin.rs index 9d5fcf84a44..62b976f033c 100644 --- a/crates/rspack_plugin_library/src/module_library_plugin.rs +++ b/crates/rspack_plugin_library/src/module_library_plugin.rs @@ -1,6 +1,7 @@ use std::hash::Hash; use rspack_core::{ + property_access, rspack_sources::{ConcatSource, RawSource, SourceExt}, to_identifier, tree_shaking::webpack_ext::ExportInfoExt, @@ -8,8 +9,6 @@ use rspack_core::{ PluginRenderStartupHookOutput, RenderStartupArgs, }; -use crate::utils::property_access; - #[derive(Debug, Default)] pub struct ModuleLibraryPlugin; @@ -46,7 +45,7 @@ impl Plugin for ModuleLibraryPlugin { let var_name = format!("__webpack_exports__{}", name); source.add(RawSource::from(format!( "var {var_name} = __webpack_exports__{};\n", - property_access(&vec![info.name.to_string()]) + property_access(&vec![&info.name], 0) ))); exports.push(format!("{var_name} as {}", info.name)); } diff --git a/crates/rspack_plugin_library/src/system_library_plugin.rs b/crates/rspack_plugin_library/src/system_library_plugin.rs index 0a6081a1275..d9461a43230 100644 --- a/crates/rspack_plugin_library/src/system_library_plugin.rs +++ b/crates/rspack_plugin_library/src/system_library_plugin.rs @@ -2,12 +2,12 @@ use std::hash::Hash; use rspack_core::{ rspack_sources::{ConcatSource, RawSource, SourceExt}, - AdditionalChunkRuntimeRequirementsArgs, ExternalModule, JsChunkHashArgs, Plugin, + AdditionalChunkRuntimeRequirementsArgs, ExternalModule, ExternalRequest, JsChunkHashArgs, Plugin, PluginAdditionalChunkRuntimeRequirementsOutput, PluginContext, PluginJsChunkHashHookOutput, PluginRenderHookOutput, RenderArgs, RuntimeGlobals, }; +use rspack_error::internal_error; -use super::utils::external_system_dep_array; use crate::utils::{external_module_names, normalize_name}; #[derive(Debug, Default)] @@ -65,7 +65,15 @@ impl Plugin for SystemLibraryPlugin { .and_then(|m| (m.get_external_type() == "system").then_some(m)) }) .collect::>(); - let external_deps_array = external_system_dep_array(&modules); + let external_deps_array = modules + .iter() + .map(|m| match &m.request { + ExternalRequest::Single(request) => Some(request.primary()), + ExternalRequest::Map(map) => map.get("amd").map(|request| request.primary()), + }) + .collect::>(); + let external_deps_array = + serde_json::to_string(&external_deps_array).map_err(|e| internal_error!(e.to_string()))?; let external_arguments = external_module_names(&modules, compilation); // The name of the variable provided by System for exporting diff --git a/crates/rspack_plugin_library/src/umd_library_plugin.rs b/crates/rspack_plugin_library/src/umd_library_plugin.rs index 8a7ab6bc8cc..6c1a5144160 100644 --- a/crates/rspack_plugin_library/src/umd_library_plugin.rs +++ b/crates/rspack_plugin_library/src/umd_library_plugin.rs @@ -2,13 +2,14 @@ use std::hash::Hash; use rspack_core::{ rspack_sources::{ConcatSource, RawSource, SourceExt}, - AdditionalChunkRuntimeRequirementsArgs, Chunk, Compilation, ExternalModule, Filename, - JsChunkHashArgs, LibraryAuxiliaryComment, PathData, Plugin, + AdditionalChunkRuntimeRequirementsArgs, Chunk, Compilation, ExternalModule, ExternalRequest, + Filename, JsChunkHashArgs, LibraryAuxiliaryComment, PathData, Plugin, PluginAdditionalChunkRuntimeRequirementsOutput, PluginContext, PluginJsChunkHashHookOutput, PluginRenderHookOutput, RenderArgs, RuntimeGlobals, SourceType, }; +use rspack_error::{internal_error, Result}; -use super::utils::{external_arguments, external_dep_array}; +use super::utils::{external_arguments, externals_dep_array}; #[derive(Debug)] pub struct UmdLibraryPlugin { @@ -104,12 +105,12 @@ impl Plugin for UmdLibraryPlugin { format!( "define({}, {}, {amd_factory});\n", library_name(&[amd.to_string()], chunk, compilation), - external_dep_array(&required_externals) + externals_dep_array(&required_externals)? ) } else { format!( "define({}, {amd_factory});\n", - external_dep_array(&required_externals) + externals_dep_array(&required_externals)? ) }; @@ -125,7 +126,7 @@ impl Plugin for UmdLibraryPlugin { .clone() .map(|root| library_name(&root, chunk, compilation))) .unwrap_or_default(), - externals_require_array("commonjs", &externals), + externals_require_array("commonjs", &externals)?, ); let root_code = format!( "{} @@ -142,7 +143,7 @@ impl Plugin for UmdLibraryPlugin { chunk, compilation, ), - external_root_array(&externals) + external_root_array(&externals)? ); format!( "}} else if(typeof exports === 'object'){{\n @@ -157,8 +158,8 @@ impl Plugin for UmdLibraryPlugin { } else { format!( "var a = typeof exports === 'object' ? factory({}) : factory({});\n", - externals_require_array("commonjs", &externals), - external_root_array(&externals) + externals_require_array("commonjs", &externals)?, + external_root_array(&externals)? ) }; format!( @@ -179,7 +180,7 @@ impl Plugin for UmdLibraryPlugin { module.exports = factory({}); }}"#, get_auxiliary_comment("commonjs2", auxiliary_comment), - externals_require_array("commonjs2", &externals) + externals_require_array("commonjs2", &externals)? ))); source.add(RawSource::from(format!( "else if(typeof define === 'function' && define.amd) {{ @@ -239,36 +240,61 @@ fn replace_keys(v: String, chunk: &Chunk, compilation: &Compilation) -> String { ) } -fn externals_require_array(_t: &str, externals: &[&ExternalModule]) -> String { - externals - .iter() - .map(|m| { - let request = &m.request; - // TODO: check if external module is optional - format!("require('{}')", request.as_str()) - }) - .collect::>() - .join(", ") +fn externals_require_array(typ: &str, externals: &[&ExternalModule]) -> Result { + Ok( + externals + .iter() + .map(|m| { + let request = match &m.request { + ExternalRequest::Single(r) => r, + ExternalRequest::Map(map) => map + .get(typ) + .ok_or_else(|| internal_error!("Missing external configuration for type: {typ}"))?, + }; + // TODO: check if external module is optional + let primary = + serde_json::to_string(request.primary()).map_err(|e| internal_error!(e.to_string()))?; + let expr = if let Some(rest) = request.rest() { + format!("require({}){}", primary, &accessor_to_object_access(rest)) + } else { + format!("require({})", primary) + }; + Ok(expr) + }) + .collect::>>()? + .join(", "), + ) } -fn external_root_array(modules: &[&ExternalModule]) -> String { - modules - .iter() - .map(|m| { - let request = &m.request; - format!( - "root{}", - accessor_to_object_access(&[request.as_str().to_owned()]) - ) - }) - .collect::>() - .join(", ") +fn external_root_array(modules: &[&ExternalModule]) -> Result { + Ok( + modules + .iter() + .map(|m| { + let typ = "root"; + let request = match &m.request { + ExternalRequest::Single(r) => r.primary(), + ExternalRequest::Map(map) => map + .get(typ) + .map(|r| r.primary()) + .ok_or_else(|| internal_error!("Missing external configuration for type: {typ}"))?, + }; + Ok(format!("root{}", accessor_to_object_access([request]))) + }) + .collect::>>()? + .join(", "), + ) } -fn accessor_to_object_access(accessor: &[String]) -> String { +fn accessor_to_object_access>(accessor: impl IntoIterator) -> String { accessor - .iter() - .map(|s| format!("['{s}']")) + .into_iter() + .map(|s| { + format!( + "[{}]", + serde_json::to_string(s.as_ref()).expect("failed to serde_json::to_string") + ) + }) .collect::>() .join("") } diff --git a/crates/rspack_plugin_library/src/utils.rs b/crates/rspack_plugin_library/src/utils.rs index 38498aeb7f0..b5a136ba559 100644 --- a/crates/rspack_plugin_library/src/utils.rs +++ b/crates/rspack_plugin_library/src/utils.rs @@ -1,30 +1,20 @@ -use rspack_core::{to_identifier, Compilation, ExternalModule, LibraryName, LibraryOptions}; -use rspack_error::Result; +use rspack_core::{ + to_identifier, Compilation, ExternalModule, ExternalRequest, LibraryName, LibraryOptions, +}; +use rspack_error::{internal_error, Result}; use rspack_identifier::Identifiable; -pub fn external_dep_array(modules: &[&ExternalModule]) -> String { - let value = modules - .iter() - .map(|m| serde_json::to_string(&m.request.as_str()).expect("invalid json to_string")) - .collect::>() - .join(", "); - format!("[{value}]") -} - -pub fn external_system_dep_array(modules: &[&ExternalModule]) -> String { +pub fn externals_dep_array(modules: &[&ExternalModule]) -> Result { let value = modules .iter() .map(|m| { - m.request - .0 - .iter() - .map(|r| format!("\"{r}\"")) - .collect::>() - .join(",") + Ok(match &m.request { + ExternalRequest::Single(s) => Some(s.primary()), + ExternalRequest::Map(map) => map.get("amd").map(|r| r.primary()), + }) }) - .collect::>() - .join(", "); - format!("[{value}]") + .collect::>>()?; + serde_json::to_string(&value).map_err(|e| internal_error!(e.to_string())) } fn inner_external_arguments(modules: &[&ExternalModule], compilation: &Compilation) -> Vec { @@ -71,11 +61,3 @@ pub fn normalize_name(o: &Option) -> Result> { } Ok(None) } - -pub fn property_access(o: &Vec) -> String { - let mut str = String::default(); - for property in o { - str.push_str(format!(r#"["{property}"]"#).as_str()); - } - str -} diff --git a/crates/rspack_plugin_progress/src/lib.rs b/crates/rspack_plugin_progress/src/lib.rs index 1e1439653ee..79f5ad1d114 100644 --- a/crates/rspack_plugin_progress/src/lib.rs +++ b/crates/rspack_plugin_progress/src/lib.rs @@ -11,14 +11,14 @@ use rspack_core::{ use rspack_error::Result; #[derive(Debug, Clone, Default)] -pub struct ProgressPluginConfig { +pub struct ProgressPluginOptions { // the prefix name of progress bar pub prefix: Option, } #[derive(Debug)] pub struct ProgressPlugin { - pub options: ProgressPluginConfig, + pub options: ProgressPluginOptions, pub progress_bar: ProgressBar, pub modules_count: AtomicU32, pub modules_done: AtomicU32, @@ -26,11 +26,14 @@ pub struct ProgressPlugin { } impl ProgressPlugin { - pub fn new(options: ProgressPluginConfig) -> Self { + pub fn new(options: ProgressPluginOptions) -> Self { let progress_bar = ProgressBar::with_draw_target(Some(100), ProgressDrawTarget::stdout()); progress_bar.set_style( - ProgressStyle::with_template("{prefix} {bar:40.cyan/blue} {percent}% {wide_msg}") - .expect("TODO:"), + ProgressStyle::with_template( + "● {prefix:.bold} {bar:25.green/white.dim} ({percent}%) {wide_msg:.dim}", + ) + .expect("TODO:") + .progress_chars("━━"), ); Self { options, @@ -84,14 +87,21 @@ impl Plugin for ProgressPlugin { async fn succeed_module(&self, _module: &dyn Module) -> Result<()> { let previous_modules_done = self.modules_done.fetch_add(1, SeqCst); let modules_done = previous_modules_done + 1; + + // Assume a minimum of 200 modules to avoid progress growing too quickly + let min_total_module: u32 = 200; + let percent = (modules_done as f32) / (cmp::max( - self.last_modules_count.read().expect("TODO:").unwrap_or(1), - self.modules_count.load(SeqCst), + cmp::max( + self.last_modules_count.read().expect("TODO:").unwrap_or(1), + self.modules_count.load(SeqCst), + ), + min_total_module, ) as f32); self .progress_bar - .set_position((10.0 + 55.0 * percent) as u64); + .set_position((10.0 + 65.0 * percent) as u64); Ok(()) } 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 0e9fdd7f4de..d1f41b083b1 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 @@ -8,6 +8,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_runtime_modules}; use super::{generate_entry_startup, update_hash_for_entry_startup}; @@ -67,6 +68,7 @@ impl Plugin for ArrayPushCallbackChunkFormatPlugin { let output = &args.compilation.options.output; output.global_object.hash(&mut args.hasher); output.chunk_loading_global.hash(&mut args.hasher); + output.hot_update_global.hash(&mut args.hasher); update_hash_for_entry_startup( args.hasher, @@ -91,13 +93,15 @@ impl Plugin for ArrayPushCallbackChunkFormatPlugin { .compilation .chunk_graph .get_chunk_runtime_modules_in_order(args.chunk_ukey); - let global_object: &String = &args.compilation.options.output.global_object; + let global_object = &args.compilation.options.output.global_object; + let hot_update_global = &args.compilation.options.output.hot_update_global; let mut source = ConcatSource::default(); if matches!(chunk.kind, ChunkKind::HotUpdate) { source.add(RawSource::Source(format!( - "{}['hotUpdate']('{}', ", + "{}[{}]('{}', ", global_object, + serde_json::to_string(hot_update_global).map_err(|e| internal_error!(e.to_string()))?, chunk.expect_id() ))); source.add(args.module_source.clone()); 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 90e38efcb4b..7c924784c98 100644 --- a/crates/rspack_plugin_runtime/src/common_js_chunk_format.rs +++ b/crates/rspack_plugin_runtime/src/common_js_chunk_format.rs @@ -21,7 +21,7 @@ pub struct CommonJsChunkFormatPlugin; #[async_trait] impl Plugin for CommonJsChunkFormatPlugin { fn name(&self) -> &'static str { - "CommonJsChunkFormatPlugin" + "rspack.CommonJsChunkFormatPlugin" } fn additional_chunk_runtime_requirements( diff --git a/crates/rspack_plugin_runtime/src/lib.rs b/crates/rspack_plugin_runtime/src/lib.rs index 1a2f26b861c..da9205efab0 100644 --- a/crates/rspack_plugin_runtime/src/lib.rs +++ b/crates/rspack_plugin_runtime/src/lib.rs @@ -43,7 +43,7 @@ pub fn enable_chunk_loading_plugin(loading_type: ChunkLoadingType, plugins: &mut plugins.push( StartupChunkDependenciesPlugin::new( ChunkLoading::Enable(ChunkLoadingType::AsyncNode), - false, + true, ) .boxed(), ); diff --git a/crates/rspack_plugin_runtime/src/runtime_module/auto_public_path.rs b/crates/rspack_plugin_runtime/src/runtime_module/auto_public_path.rs new file mode 100644 index 00000000000..c08668674cb --- /dev/null +++ b/crates/rspack_plugin_runtime/src/runtime_module/auto_public_path.rs @@ -0,0 +1,101 @@ +use rspack_core::{ + get_js_chunk_filename_template, + rspack_sources::{BoxSource, RawSource, SourceExt}, + ChunkUkey, Compilation, OutputOptions, PathData, RuntimeGlobals, RuntimeModule, + RuntimeModuleStage, SourceType, +}; +use rspack_identifier::Identifier; + +use super::utils::get_undo_path; +use crate::impl_runtime_module; + +#[derive(Debug, Eq)] +pub struct AutoPublicPathRuntimeModule { + id: Identifier, + chunk: Option, +} + +impl Default for AutoPublicPathRuntimeModule { + fn default() -> Self { + Self { + id: Identifier::from("webpack/runtime/auto_public_path"), + chunk: None, + } + } +} + +impl RuntimeModule for AutoPublicPathRuntimeModule { + fn name(&self) -> Identifier { + self.id + } + + fn attach(&mut self, chunk: ChunkUkey) { + self.chunk = Some(chunk); + } + + fn stage(&self) -> RuntimeModuleStage { + RuntimeModuleStage::Attach + } + + fn generate(&self, compilation: &Compilation) -> BoxSource { + let chunk = self.chunk.expect("The chunk should be attached"); + let chunk = compilation + .chunk_by_ukey + .get(&chunk) + .expect("Chunk is not found, make sure you had attach chunkUkey successfully."); + let filename = get_js_chunk_filename_template( + chunk, + &compilation.options.output, + &compilation.chunk_group_by_ukey, + ); + let filename = compilation.get_path( + filename, + PathData::default().chunk(chunk).content_hash_optional( + chunk + .content_hash + .get(&SourceType::JavaScript) + .map(|i| i.rendered(compilation.options.output.hash_digest_length)), + ), + ); + RawSource::from(auto_public_path_template( + &filename, + &compilation.options.output, + )) + .boxed() + } +} + +fn auto_public_path_template(filename: &str, output: &OutputOptions) -> String { + let output_path = output.path.display().to_string(); + let undo_path = get_undo_path(filename, output_path, false); + let assign = if undo_path.is_empty() { + format!("{} = scriptUrl", RuntimeGlobals::PUBLIC_PATH) + } else { + format!( + "{} = scriptUrl + '{undo_path}'", + RuntimeGlobals::PUBLIC_PATH + ) + }; + let global = RuntimeGlobals::GLOBAL.name(); + format!( + r#" + var scriptUrl; + if ({global}.importScripts) scriptUrl = {global}.location + ""; + var document = {global}.document; + if (!scriptUrl && document) {{ + if (document.currentScript) scriptUrl = document.currentScript.src; + if (!scriptUrl) {{ + var scripts = document.getElementsByTagName("script"); + if (scripts.length) scriptUrl = scripts[scripts.length - 1].src; + }} + }} + // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration", + // or pass an empty string ("") and set the __webpack_public_path__ variable from your code to use your own logic.', + if (!scriptUrl) throw new Error("Automatic publicPath is not supported in this browser"); + scriptUrl = scriptUrl.replace(/#.*$/, "").replace(/\?.*$/, "").replace(/\/[^\/]+$/, "/"); + {assign} + "# + ) +} + +impl_runtime_module!(AutoPublicPathRuntimeModule); diff --git a/crates/rspack_plugin_runtime/src/runtime_module/css_loading.rs b/crates/rspack_plugin_runtime/src/runtime_module/css_loading.rs index ce005b99aec..a512f7ca84e 100644 --- a/crates/rspack_plugin_runtime/src/runtime_module/css_loading.rs +++ b/crates/rspack_plugin_runtime/src/runtime_module/css_loading.rs @@ -1,6 +1,6 @@ use rspack_core::{ rspack_sources::{BoxSource, ConcatSource, RawSource, SourceExt}, - ChunkUkey, Compilation, RuntimeGlobals, RuntimeModule, RUNTIME_MODULE_STAGE_ATTACH, + ChunkUkey, Compilation, RuntimeGlobals, RuntimeModule, RuntimeModuleStage, }; use rspack_identifier::Identifier; use rustc_hash::FxHashSet as HashSet; @@ -116,8 +116,8 @@ impl RuntimeModule for CssLoadingRuntimeModule { self.chunk = Some(chunk); } - fn stage(&self) -> u8 { - RUNTIME_MODULE_STAGE_ATTACH + fn stage(&self) -> RuntimeModuleStage { + RuntimeModuleStage::Attach } } diff --git a/crates/rspack_plugin_runtime/src/runtime_module/import_scripts_chunk_loading.rs b/crates/rspack_plugin_runtime/src/runtime_module/import_scripts_chunk_loading.rs index a0a4980c3f1..ec08d5ef391 100644 --- a/crates/rspack_plugin_runtime/src/runtime_module/import_scripts_chunk_loading.rs +++ b/crates/rspack_plugin_runtime/src/runtime_module/import_scripts_chunk_loading.rs @@ -1,6 +1,6 @@ use rspack_core::{ rspack_sources::{BoxSource, ConcatSource, RawSource, SourceExt}, - Chunk, ChunkUkey, Compilation, RuntimeGlobals, RuntimeModule, RUNTIME_MODULE_STAGE_ATTACH, + Chunk, ChunkUkey, Compilation, RuntimeGlobals, RuntimeModule, RuntimeModuleStage, }; use rspack_identifier::Identifier; @@ -138,7 +138,12 @@ impl RuntimeModule for ImportScriptsChunkLoadingRuntimeModule { source.add(RawSource::from( include_str!("runtime/import_scripts_chunk_loading_with_hmr.js") .replace("$URL$", &url) - .replace("$globalObject$", &compilation.options.output.global_object), + .replace("$globalObject$", &compilation.options.output.global_object) + .replace( + "$hotUpdateGlobal$", + &serde_json::to_string(&compilation.options.output.hot_update_global) + .expect("failed to serde_json::to_string(hot_update_global)"), + ), )); source.add(RawSource::from( include_str!("runtime/javascript_hot_module_replacement.js") @@ -163,8 +168,8 @@ impl RuntimeModule for ImportScriptsChunkLoadingRuntimeModule { self.chunk = Some(chunk); } - fn stage(&self) -> u8 { - RUNTIME_MODULE_STAGE_ATTACH + fn stage(&self) -> RuntimeModuleStage { + RuntimeModuleStage::Attach } } diff --git a/crates/rspack_plugin_runtime/src/runtime_module/jsonp_chunk_loading.rs b/crates/rspack_plugin_runtime/src/runtime_module/jsonp_chunk_loading.rs index fdd1e3fbbf3..2a4b30915b1 100644 --- a/crates/rspack_plugin_runtime/src/runtime_module/jsonp_chunk_loading.rs +++ b/crates/rspack_plugin_runtime/src/runtime_module/jsonp_chunk_loading.rs @@ -1,6 +1,6 @@ use rspack_core::{ rspack_sources::{BoxSource, ConcatSource, RawSource, SourceExt}, - Chunk, ChunkUkey, Compilation, RuntimeGlobals, RuntimeModule, RUNTIME_MODULE_STAGE_ATTACH, + Chunk, ChunkUkey, Compilation, RuntimeGlobals, RuntimeModule, RuntimeModuleStage, }; use rspack_identifier::Identifier; @@ -85,7 +85,12 @@ impl RuntimeModule for JsonpChunkLoadingRuntimeModule { { source.add(RawSource::from( include_str!("runtime/jsonp_chunk_loading_with_hmr.js") - .replace("$globalObject$", &compilation.options.output.global_object), + .replace("$globalObject$", &compilation.options.output.global_object) + .replace( + "$hotUpdateGlobal$", + &serde_json::to_string(&compilation.options.output.hot_update_global) + .expect("failed to serde_json::to_string(hot_update_global)"), + ), )); source.add(RawSource::from( include_str!("runtime/javascript_hot_module_replacement.js").replace("$key$", "jsonp"), @@ -136,8 +141,8 @@ impl RuntimeModule for JsonpChunkLoadingRuntimeModule { self.chunk = Some(chunk); } - fn stage(&self) -> u8 { - RUNTIME_MODULE_STAGE_ATTACH + fn stage(&self) -> RuntimeModuleStage { + RuntimeModuleStage::Attach } } diff --git a/crates/rspack_plugin_runtime/src/runtime_module/load_chunk_with_module.rs b/crates/rspack_plugin_runtime/src/runtime_module/load_chunk_with_module.rs index 499f51aea0c..6545d11eec9 100644 --- a/crates/rspack_plugin_runtime/src/runtime_module/load_chunk_with_module.rs +++ b/crates/rspack_plugin_runtime/src/runtime_module/load_chunk_with_module.rs @@ -50,11 +50,11 @@ impl RuntimeModule for LoadChunkWithModuleRuntimeModule { let map = async_modules .par_iter() .filter_map(|identifier| { - let mut chunk_ids = { - let chunk_group = compilation - .chunk_graph - .get_block_chunk_group(identifier, &compilation.chunk_group_by_ukey); - chunk_group + if let Some(chunk_group) = compilation + .chunk_graph + .get_block_chunk_group(identifier, &compilation.chunk_group_by_ukey) + { + let mut chunk_ids = chunk_group .chunks .iter() .filter_map(|chunk_ukey| { @@ -68,21 +68,22 @@ impl RuntimeModule for LoadChunkWithModuleRuntimeModule { None } }) - .collect::>() - }; - if chunk_ids.is_empty() { - return None; - } - chunk_ids.sort_unstable(); - let module = compilation - .module_graph - .module_graph_module_by_identifier(identifier) - .expect("no module found"); + .collect::>(); + if chunk_ids.is_empty() { + return None; + } + chunk_ids.sort_unstable(); + let module = compilation + .module_graph + .module_graph_module_by_identifier(identifier) + .expect("no module found"); - let module_id = module.id(&compilation.chunk_graph); - let module_id_expr = serde_json::to_string(module_id).expect("invalid module_id"); + let module_id = module.id(&compilation.chunk_graph); + let module_id_expr = serde_json::to_string(module_id).expect("invalid module_id"); - Some((module_id_expr, chunk_ids)) + return Some((module_id_expr, chunk_ids)); + } + None }) .collect::>>(); diff --git a/crates/rspack_plugin_runtime/src/runtime_module/mod.rs b/crates/rspack_plugin_runtime/src/runtime_module/mod.rs index cfa608b46d6..421f80127c9 100644 --- a/crates/rspack_plugin_runtime/src/runtime_module/mod.rs +++ b/crates/rspack_plugin_runtime/src/runtime_module/mod.rs @@ -1,4 +1,5 @@ mod async_module; +mod auto_public_path; mod base_uri; mod compat_get_default_export; mod create_fake_namespace_object; @@ -32,6 +33,7 @@ mod startup_chunk_dependencies; mod startup_entry_point; mod utils; pub use async_module::AsyncRuntimeModule; +pub use auto_public_path::AutoPublicPathRuntimeModule; pub use base_uri::BaseUriRuntimeModule; pub use compat_get_default_export::CompatGetDefaultExportRuntimeModule; pub use create_fake_namespace_object::CreateFakeNamespaceObjectRuntimeModule; diff --git a/crates/rspack_plugin_runtime/src/runtime_module/module_chunk_loading.rs b/crates/rspack_plugin_runtime/src/runtime_module/module_chunk_loading.rs index beba0d519b8..deaa22d96b6 100644 --- a/crates/rspack_plugin_runtime/src/runtime_module/module_chunk_loading.rs +++ b/crates/rspack_plugin_runtime/src/runtime_module/module_chunk_loading.rs @@ -1,6 +1,6 @@ use rspack_core::{ rspack_sources::{BoxSource, ConcatSource, RawSource, SourceExt}, - Chunk, ChunkUkey, Compilation, RuntimeGlobals, RuntimeModule, RUNTIME_MODULE_STAGE_ATTACH, + Chunk, ChunkUkey, Compilation, RuntimeGlobals, RuntimeModule, RuntimeModuleStage, }; use rspack_identifier::Identifier; @@ -137,8 +137,8 @@ impl RuntimeModule for ModuleChunkLoadingRuntimeModule { self.chunk = Some(chunk); } - fn stage(&self) -> u8 { - RUNTIME_MODULE_STAGE_ATTACH + fn stage(&self) -> RuntimeModuleStage { + RuntimeModuleStage::Attach } } diff --git a/crates/rspack_plugin_runtime/src/runtime_module/public_path.rs b/crates/rspack_plugin_runtime/src/runtime_module/public_path.rs index 2c9933edef7..f9fb7448c25 100644 --- a/crates/rspack_plugin_runtime/src/runtime_module/public_path.rs +++ b/crates/rspack_plugin_runtime/src/runtime_module/public_path.rs @@ -1,25 +1,22 @@ use rspack_core::{ - get_js_chunk_filename_template, rspack_sources::{BoxSource, RawSource, SourceExt}, - ChunkUkey, Compilation, OutputOptions, PathData, PublicPath, RuntimeGlobals, RuntimeModule, - SourceType, + Compilation, RuntimeModule, }; use rspack_identifier::Identifier; -use super::utils::get_undo_path; use crate::impl_runtime_module; #[derive(Debug, Eq)] pub struct PublicPathRuntimeModule { id: Identifier, - chunk: Option, + public_path: Box, } -impl Default for PublicPathRuntimeModule { - fn default() -> Self { +impl PublicPathRuntimeModule { + pub fn new(public_path: Box) -> Self { Self { id: Identifier::from("webpack/runtime/public_path"), - chunk: None, + public_path, } } } @@ -29,83 +26,13 @@ impl RuntimeModule for PublicPathRuntimeModule { self.id } - fn attach(&mut self, chunk: ChunkUkey) { - self.chunk = Some(chunk); - } - - fn generate(&self, compilation: &Compilation) -> BoxSource { - let chunk = self.chunk.expect("The chunk should be attached"); - let chunk = compilation - .chunk_by_ukey - .get(&chunk) - .expect("Chunk is not found, make sure you had attach chunkUkey successfully."); - let public_path = chunk - .get_entry_options(&compilation.chunk_group_by_ukey) - .and_then(|options| options.public_path.as_ref()) - .unwrap_or(&compilation.options.output.public_path); - match public_path { - PublicPath::String(str) => RawSource::from( - include_str!("runtime/public_path.js").replace("__PUBLIC_PATH_PLACEHOLDER__", str), - ) - .boxed(), - PublicPath::Auto => { - let filename = get_js_chunk_filename_template( - chunk, - &compilation.options.output, - &compilation.chunk_group_by_ukey, - ); - let filename = compilation.get_path( - filename, - PathData::default().chunk(chunk).content_hash_optional( - chunk - .content_hash - .get(&SourceType::JavaScript) - .map(|i| i.rendered(compilation.options.output.hash_digest_length)), - ), - ); - RawSource::from(auto_public_path_template( - &filename, - &compilation.options.output, - )) - .boxed() - } - } - } -} - -// TODO: should use `__webpack_require__.g` -const GLOBAL: &str = "self"; - -fn auto_public_path_template(filename: &str, output: &OutputOptions) -> String { - let output_path = output.path.display().to_string(); - let undo_path = get_undo_path(filename, output_path, false); - let assign = if undo_path.is_empty() { - format!("{} = scriptUrl", RuntimeGlobals::PUBLIC_PATH) - } else { - format!( - "{} = scriptUrl + '{undo_path}'", - RuntimeGlobals::PUBLIC_PATH + fn generate(&self, _compilation: &Compilation) -> BoxSource { + RawSource::from( + include_str!("runtime/public_path.js") + .replace("__PUBLIC_PATH_PLACEHOLDER__", &self.public_path), ) - }; - format!( - r#" - var scriptUrl; - if ({GLOBAL}.importScripts) scriptUrl = {GLOBAL}.location + ""; - var document = {GLOBAL}.document; - if (!scriptUrl && document) {{ - if (document.currentScript) scriptUrl = document.currentScript.src; - if (!scriptUrl) {{ - var scripts = document.getElementsByTagName("script"); - if (scripts.length) scriptUrl = scripts[scripts.length - 1].src; - }} - }} - // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration", - // or pass an empty string ("") and set the __webpack_public_path__ variable from your code to use your own logic.', - if (!scriptUrl) throw new Error("Automatic publicPath is not supported in this browser"); - scriptUrl = scriptUrl.replace(/#.*$/, "").replace(/\?.*$/, "").replace(/\/[^\/]+$/, "/"); - {assign} - "# - ) + .boxed() + } } impl_runtime_module!(PublicPathRuntimeModule); diff --git a/crates/rspack_plugin_runtime/src/runtime_module/readfile_chunk_loading.rs b/crates/rspack_plugin_runtime/src/runtime_module/readfile_chunk_loading.rs index 1fee3386855..e94ffa66356 100644 --- a/crates/rspack_plugin_runtime/src/runtime_module/readfile_chunk_loading.rs +++ b/crates/rspack_plugin_runtime/src/runtime_module/readfile_chunk_loading.rs @@ -1,6 +1,6 @@ use rspack_core::{ rspack_sources::{BoxSource, ConcatSource, RawSource, SourceExt}, - Chunk, ChunkUkey, Compilation, RuntimeGlobals, RuntimeModule, RUNTIME_MODULE_STAGE_ATTACH, + Chunk, ChunkUkey, Compilation, RuntimeGlobals, RuntimeModule, RuntimeModuleStage, }; use rspack_identifier::Identifier; @@ -156,8 +156,8 @@ impl RuntimeModule for ReadFileChunkLoadingRuntimeModule { fn attach(&mut self, chunk: ChunkUkey) { self.chunk = Some(chunk) } - fn stage(&self) -> u8 { - RUNTIME_MODULE_STAGE_ATTACH + fn stage(&self) -> RuntimeModuleStage { + RuntimeModuleStage::Attach } } impl_runtime_module!(ReadFileChunkLoadingRuntimeModule); diff --git a/crates/rspack_plugin_runtime/src/runtime_module/require_js_chunk_loading.rs b/crates/rspack_plugin_runtime/src/runtime_module/require_js_chunk_loading.rs index 79c83debaa0..88288540717 100644 --- a/crates/rspack_plugin_runtime/src/runtime_module/require_js_chunk_loading.rs +++ b/crates/rspack_plugin_runtime/src/runtime_module/require_js_chunk_loading.rs @@ -1,6 +1,6 @@ use rspack_core::{ rspack_sources::{BoxSource, ConcatSource, RawSource, SourceExt}, - Chunk, ChunkUkey, Compilation, RuntimeGlobals, RuntimeModule, RUNTIME_MODULE_STAGE_ATTACH, + Chunk, ChunkUkey, Compilation, RuntimeGlobals, RuntimeModule, RuntimeModuleStage, }; use rspack_identifier::Identifier; @@ -159,8 +159,8 @@ impl RuntimeModule for RequireChunkLoadingRuntimeModule { self.chunk = Some(chunk); } - fn stage(&self) -> u8 { - RUNTIME_MODULE_STAGE_ATTACH + fn stage(&self) -> RuntimeModuleStage { + RuntimeModuleStage::Attach } } diff --git a/crates/rspack_plugin_runtime/src/runtime_module/runtime/css_loading_with_loading.js b/crates/rspack_plugin_runtime/src/runtime_module/runtime/css_loading_with_loading.js index 1f2aecd3caf..636ae7d5ca4 100644 --- a/crates/rspack_plugin_runtime/src/runtime_module/runtime/css_loading_with_loading.js +++ b/crates/rspack_plugin_runtime/src/runtime_module/runtime/css_loading_with_loading.js @@ -60,7 +60,9 @@ var loadCssChunkCallback = function (parentChunkLoadingFunction, data) { var chunkIds = data[0]; if (parentChunkLoadingFunction) parentChunkLoadingFunction(data); for (var i = 0; i < chunkIds.length; i++) { - installedChunks[chunkIds[i]] = 0; + if (installedChunks[chunkIds[i]] === undefined) { + installedChunks[chunkIds[i]] = 0; + } } }; var chunkLoadingGlobal = $CHUNK_LOADING_GLOBAL_EXPR$ = $CHUNK_LOADING_GLOBAL_EXPR$ || []; diff --git a/crates/rspack_plugin_runtime/src/runtime_module/runtime/import_scripts_chunk_loading_with_hmr.js b/crates/rspack_plugin_runtime/src/runtime_module/runtime/import_scripts_chunk_loading_with_hmr.js index e73550a05d3..a8fb94bcfea 100644 --- a/crates/rspack_plugin_runtime/src/runtime_module/runtime/import_scripts_chunk_loading_with_hmr.js +++ b/crates/rspack_plugin_runtime/src/runtime_module/runtime/import_scripts_chunk_loading_with_hmr.js @@ -1,6 +1,6 @@ function loadUpdateChunk(chunkId, updatedModulesList) { var success = false; - $globalObject$["hotUpdate"] = function (_, moreModules, runtime) { + $globalObject$[$hotUpdateGlobal$] = function (_, moreModules, runtime) { for(var moduleId in moreModules) { for (var moduleId in moreModules) { if (__webpack_require__.o(moreModules, moduleId)) { diff --git a/crates/rspack_plugin_runtime/src/runtime_module/runtime/jsonp_chunk_loading_with_hmr.js b/crates/rspack_plugin_runtime/src/runtime_module/runtime/jsonp_chunk_loading_with_hmr.js index 695481e7004..87fb464fe48 100644 --- a/crates/rspack_plugin_runtime/src/runtime_module/runtime/jsonp_chunk_loading_with_hmr.js +++ b/crates/rspack_plugin_runtime/src/runtime_module/runtime/jsonp_chunk_loading_with_hmr.js @@ -33,7 +33,7 @@ function loadUpdateChunk(chunkId, updatedModulesList) { }); } -$globalObject$["hotUpdate"] = function (chunkId, moreModules, runtime) { +$globalObject$[$hotUpdateGlobal$] = function (chunkId, moreModules, runtime) { for (var moduleId in moreModules) { if (__webpack_require__.o(moreModules, moduleId)) { currentUpdate[moduleId] = moreModules[moduleId]; diff --git a/crates/rspack_plugin_runtime/src/runtime_plugin.rs b/crates/rspack_plugin_runtime/src/runtime_plugin.rs index d1c910d8cd9..4bd2ea618f6 100644 --- a/crates/rspack_plugin_runtime/src/runtime_plugin.rs +++ b/crates/rspack_plugin_runtime/src/runtime_plugin.rs @@ -4,11 +4,11 @@ use async_trait::async_trait; use rspack_core::{ AdditionalChunkRuntimeRequirementsArgs, ChunkLoading, JsChunkHashArgs, Plugin, PluginAdditionalChunkRuntimeRequirementsOutput, PluginContext, PluginJsChunkHashHookOutput, - RuntimeGlobals, RuntimeModuleExt, SourceType, + PublicPath, RuntimeGlobals, RuntimeModuleExt, SourceType, }; use crate::runtime_module::{ - is_enabled_for_chunk, AsyncRuntimeModule, BaseUriRuntimeModule, + is_enabled_for_chunk, AsyncRuntimeModule, AutoPublicPathRuntimeModule, BaseUriRuntimeModule, CompatGetDefaultExportRuntimeModule, CreateFakeNamespaceObjectRuntimeModule, CreateScriptUrlRuntimeModule, DefinePropertyGettersRuntimeModule, EnsureChunkRuntimeModule, GetChunkFilenameRuntimeModule, GetChunkUpdateFilenameRuntimeModule, GetFullHashRuntimeModule, @@ -53,6 +53,7 @@ impl Plugin for RuntimePlugin { Ok(()) } + #[allow(clippy::unwrap_in_result)] fn runtime_requirements_in_tree( &self, _ctx: PluginContext, @@ -121,6 +122,23 @@ impl Plugin for RuntimePlugin { runtime_requirements.insert(RuntimeGlobals::REQUIRE_SCOPE); } + let public_path = { + let chunk = compilation + .chunk_by_ukey + .get(chunk) + .expect("should have chunk"); + chunk + .get_entry_options(&compilation.chunk_group_by_ukey) + .and_then(|options| options.public_path.clone()) + .unwrap_or(compilation.options.output.public_path.clone()) + }; + // TODO check output.scriptType + if matches!(public_path, PublicPath::Auto) + && runtime_requirements.contains(RuntimeGlobals::PUBLIC_PATH) + { + runtime_requirements.insert(RuntimeGlobals::GLOBAL); + } + for runtime_requirement in runtime_requirements.iter() { match runtime_requirement { RuntimeGlobals::ASYNC_MODULE => { @@ -135,7 +153,16 @@ impl Plugin for RuntimePlugin { compilation.add_runtime_module(chunk, EnsureChunkRuntimeModule::new(true).boxed()); } RuntimeGlobals::PUBLIC_PATH => { - compilation.add_runtime_module(chunk, PublicPathRuntimeModule::default().boxed()) + match &public_path { + // TODO string publicPath support [hash] placeholder + PublicPath::String(str) => compilation.add_runtime_module( + chunk, + PublicPathRuntimeModule::new(str.as_str().into()).boxed(), + ), + PublicPath::Auto => { + compilation.add_runtime_module(chunk, AutoPublicPathRuntimeModule::default().boxed()) + } + } } RuntimeGlobals::GET_CHUNK_SCRIPT_FILENAME => compilation.add_runtime_module( chunk, diff --git a/crates/rspack_plugin_swc_css_minimizer/src/lib.rs b/crates/rspack_plugin_swc_css_minimizer/src/lib.rs index 8c9cb077260..126b7c90e17 100644 --- a/crates/rspack_plugin_swc_css_minimizer/src/lib.rs +++ b/crates/rspack_plugin_swc_css_minimizer/src/lib.rs @@ -5,12 +5,12 @@ use rspack_error::Result; use rspack_plugin_css::swc_css_compiler::{SwcCssCompiler, SwcCssSourceMapGenConfig}; #[derive(Debug)] -pub struct SwcCssMinimizerPlugin; +pub struct SwcCssMinimizerRspackPlugin; #[async_trait] -impl Plugin for SwcCssMinimizerPlugin { +impl Plugin for SwcCssMinimizerRspackPlugin { fn name(&self) -> &'static str { - "rspack.SwcCssMinimizerPlugin" + "rspack.SwcCssMinimizerRspackPlugin" } // TODO: chunk hash diff --git a/crates/rspack_plugin_swc_js_minimizer/Cargo.toml b/crates/rspack_plugin_swc_js_minimizer/Cargo.toml index 8356eb8e30b..0529bd7b1c8 100644 --- a/crates/rspack_plugin_swc_js_minimizer/Cargo.toml +++ b/crates/rspack_plugin_swc_js_minimizer/Cargo.toml @@ -8,6 +8,7 @@ version = "0.1.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +rayon = { workspace = true } rspack_core = { path = "../rspack_core" } rspack_error = { path = "../rspack_error" } rspack_plugin_javascript = { path = "../rspack_plugin_javascript" } diff --git a/crates/rspack_plugin_swc_js_minimizer/src/lib.rs b/crates/rspack_plugin_swc_js_minimizer/src/lib.rs index ea3bda313ce..45c4b5b3bcd 100644 --- a/crates/rspack_plugin_swc_js_minimizer/src/lib.rs +++ b/crates/rspack_plugin_swc_js_minimizer/src/lib.rs @@ -6,9 +6,9 @@ use std::{ sync::{mpsc, Mutex}, }; -use async_recursion::async_recursion; use async_trait::async_trait; use minify::{match_object, minify}; +use rayon::prelude::*; use rspack_core::{ rspack_sources::{ MapOptions, RawSource, SourceExt, SourceMap, SourceMapSource, SourceMapSourceOptions, @@ -16,9 +16,9 @@ use rspack_core::{ AssetInfo, CompilationAsset, JsChunkHashArgs, Plugin, PluginContext, PluginJsChunkHashHookOutput, PluginProcessAssetsOutput, ProcessAssetsArgs, }; -use rspack_error::{internal_error, Diagnostic}; +use rspack_error::{internal_error, Diagnostic, Result}; use rspack_regex::RspackRegex; -use rspack_util::try_any; +use rspack_util::try_any_sync; use swc_config::config_types::BoolOrDataConfig; use swc_ecma_minifier::option::{ terser::{TerserCompressorOptions, TerserEcmaVersion}, @@ -26,7 +26,7 @@ use swc_ecma_minifier::option::{ }; #[derive(Debug, Clone, Default, Hash)] -pub struct Minification { +pub struct SwcJsMinimizerRspackPluginOptions { pub passes: usize, pub drop_console: bool, pub keep_class_names: bool, @@ -35,20 +35,19 @@ pub struct Minification { pub extract_comments: Option, pub ascii_only: bool, pub comments: String, - pub test: Option, - pub include: Option, - pub exclude: Option, + pub test: Option, + pub include: Option, + pub exclude: Option, } #[derive(Debug, Clone, Hash)] -pub enum MinificationCondition { +pub enum SwcJsMinimizerRule { String(String), Regexp(RspackRegex), } -impl MinificationCondition { - #[async_recursion] - pub async fn try_match(&self, data: &str) -> rspack_error::Result { +impl SwcJsMinimizerRule { + pub fn try_match(&self, data: &str) -> rspack_error::Result { match self { Self::String(s) => Ok(data.starts_with(s)), Self::Regexp(r) => Ok(r.test(data)), @@ -57,38 +56,37 @@ impl MinificationCondition { } #[derive(Debug, Clone, Hash)] -pub enum MinificationConditions { +pub enum SwcJsMinimizerRules { String(String), Regexp(rspack_regex::RspackRegex), - Array(Vec), + Array(Vec), } -impl MinificationConditions { - #[async_recursion] - pub async fn try_match(&self, data: &str) -> rspack_error::Result { +impl SwcJsMinimizerRules { + pub fn try_match(&self, data: &str) -> rspack_error::Result { match self { Self::String(s) => Ok(data.starts_with(s)), Self::Regexp(r) => Ok(r.test(data)), - Self::Array(l) => try_any(l, |i| async { i.try_match(data).await }).await, + Self::Array(l) => try_any_sync(l, |i| i.try_match(data)), } } } #[derive(Debug)] -pub struct SwcJsMinimizerPlugin { - options: Minification, +pub struct SwcJsMinimizerRspackPlugin { + options: SwcJsMinimizerRspackPluginOptions, } -impl SwcJsMinimizerPlugin { - pub fn new(options: Minification) -> Self { +impl SwcJsMinimizerRspackPlugin { + pub fn new(options: SwcJsMinimizerRspackPluginOptions) -> Self { Self { options } } } #[async_trait] -impl Plugin for SwcJsMinimizerPlugin { +impl Plugin for SwcJsMinimizerRspackPlugin { fn name(&self) -> &'static str { - "rspack.SwcJsMinimizerPlugin" + "rspack.SwcJsMinimizerRspackPlugin" } async fn process_assets_stage_optimize_size( @@ -136,66 +134,70 @@ impl Plugin for SwcJsMinimizerPlugin { ..Default::default() }; - for (filename, original) in compilation.assets_mut() { - if !(filename.ends_with(".js") || filename.ends_with(".cjs") || filename.ends_with(".mjs")) { - continue; - } + compilation + .assets_mut() + .par_iter_mut() + .filter(|(filename, original)| { + if !(filename.ends_with(".js") || filename.ends_with(".cjs") || filename.ends_with(".mjs")) { + return false + } - let is_matched = match_object(minify_options, filename) - .await - .unwrap_or(false); + let is_matched = match_object(minify_options, filename) + .unwrap_or(false); - if !is_matched || original.get_info().minimized { - continue; - } + if !is_matched || original.get_info().minimized { + return false + } - if let Some(original_source) = original.get_source() { - let input = original_source.source().to_string(); - let input_source_map = original_source.map(&MapOptions::default()); - let js_minify_options = JsMinifyOptions { - compress: BoolOrDataConfig::from_obj(compress.clone()), - mangle: BoolOrDataConfig::from_obj(mangle.clone()), - format: format.clone(), - source_map: BoolOrDataConfig::from_bool(input_source_map.is_some()), - inline_sources_content: true, /* Using true so original_source can be None in SourceMapSource */ - emit_source_map_columns, - module: is_module, - ..Default::default() - }; + true + }) + .try_for_each_with(tx,|tx,(filename, original)| -> Result<()> { + if let Some(original_source) = original.get_source() { + let input = original_source.source().to_string(); + let input_source_map = original_source.map(&MapOptions::default()); + let js_minify_options = JsMinifyOptions { + compress: BoolOrDataConfig::from_obj(compress.clone()), + mangle: BoolOrDataConfig::from_obj(mangle.clone()), + format: format.clone(), + source_map: BoolOrDataConfig::from_bool(input_source_map.is_some()), + inline_sources_content: true, /* Using true so original_source can be None in SourceMapSource */ + emit_source_map_columns, + module: is_module, + ..Default::default() + }; + let output = match minify( + &js_minify_options, + input, + filename, + &all_extracted_comments, + extract_comments_option, + ) { + Ok(r) => r, + Err(e) => { + tx.send(e.into()) + .map_err(|e| internal_error!(e.to_string()))?; + return Ok(()) + } + }; + let source = if let Some(map) = &output.map { + SourceMapSource::new(SourceMapSourceOptions { + value: output.code, + name: filename, + source_map: SourceMap::from_json(map).map_err(|e| internal_error!(e.to_string()))?, + original_source: None, + inner_source_map: input_source_map, + remove_original_source: true, + }) + .boxed() + } else { + RawSource::from(output.code).boxed() + }; + original.set_source(Some(source)); + original.get_info_mut().minimized = true; + } - let output = match minify( - &js_minify_options, - input, - filename, - &all_extracted_comments, - extract_comments_option, - ) { - Ok(r) => r, - Err(e) => { - tx.send(e.into()) - .map_err(|e| internal_error!(e.to_string()))?; - continue; - } - }; - let source = if let Some(map) = &output.map { - SourceMapSource::new(SourceMapSourceOptions { - value: output.code, - name: filename, - source_map: SourceMap::from_json(map).map_err(|e| internal_error!(e.to_string()))?, - original_source: None, - inner_source_map: input_source_map, - remove_original_source: true, - }) - .boxed() - } else { - RawSource::from(output.code).boxed() - }; - original.set_source(Some(source)); - original.get_info_mut().minimized = true; - } - } - - drop(tx); + Ok(()) + })?; compilation.push_batch_diagnostic(rx.into_iter().flatten().collect::>()); diff --git a/crates/rspack_plugin_swc_js_minimizer/src/minify.rs b/crates/rspack_plugin_swc_js_minimizer/src/minify.rs index f948be4dc27..cc57fd709f2 100644 --- a/crates/rspack_plugin_swc_js_minimizer/src/minify.rs +++ b/crates/rspack_plugin_swc_js_minimizer/src/minify.rs @@ -3,7 +3,6 @@ use std::{ sync::{mpsc, Arc, Mutex}, }; -use async_recursion::async_recursion; use regex::Regex; use rspack_core::{ rspack_sources::{RawSource, SourceExt}, @@ -41,22 +40,21 @@ use swc_ecma_minifier::{ option::{MinifyOptions, TopLevelOptions}, }; -use crate::{JsMinifyCommentOption, JsMinifyOptions, Minification}; +use crate::{JsMinifyCommentOption, JsMinifyOptions, SwcJsMinimizerRspackPluginOptions}; -#[async_recursion] -pub async fn match_object(obj: &Minification, str: &str) -> Result { +pub fn match_object(obj: &SwcJsMinimizerRspackPluginOptions, str: &str) -> Result { if let Some(condition) = &obj.test { - if !condition.try_match(str).await? { + if !condition.try_match(str)? { return Ok(false); } } if let Some(condition) = &obj.include { - if !condition.try_match(str).await? { + if !condition.try_match(str)? { return Ok(false); } } if let Some(condition) = &obj.exclude { - if condition.try_match(str).await? { + if condition.try_match(str)? { return Ok(false); } } diff --git a/crates/rspack_plugin_wasm/src/dependency.rs b/crates/rspack_plugin_wasm/src/dependency.rs index 59506941efc..07e58a3a89d 100644 --- a/crates/rspack_plugin_wasm/src/dependency.rs +++ b/crates/rspack_plugin_wasm/src/dependency.rs @@ -72,6 +72,10 @@ impl ModuleDependency for WasmImportDependency { ) -> Vec { vec![ExtendedReferencedExport::Array(vec![self.name.clone()])] } + + fn dependency_debug_name(&self) -> &'static str { + "WasmImportDependency" + } } impl AsDependencyTemplate for WasmImportDependency {} diff --git a/crates/rspack_plugin_wasm/src/runtime.rs b/crates/rspack_plugin_wasm/src/runtime.rs index 43bc55c05b5..4d3a579a649 100644 --- a/crates/rspack_plugin_wasm/src/runtime.rs +++ b/crates/rspack_plugin_wasm/src/runtime.rs @@ -1,5 +1,5 @@ use rspack_core::rspack_sources::{BoxSource, RawSource, SourceExt}; -use rspack_core::{Compilation, RuntimeModule, RUNTIME_MODULE_STAGE_ATTACH}; +use rspack_core::{Compilation, RuntimeModule, RuntimeModuleStage}; use rspack_identifier::Identifier; use rspack_plugin_runtime::impl_runtime_module; @@ -33,8 +33,8 @@ impl RuntimeModule for AsyncWasmLoadingRuntimeModule { .boxed() } - fn stage(&self) -> u8 { - RUNTIME_MODULE_STAGE_ATTACH + fn stage(&self) -> RuntimeModuleStage { + RuntimeModuleStage::Attach } } diff --git a/crates/rspack_plugin_wasm/tests/fixtures.rs b/crates/rspack_plugin_wasm/tests/fixtures.rs index a0728eccf2c..9355c42bc58 100644 --- a/crates/rspack_plugin_wasm/tests/fixtures.rs +++ b/crates/rspack_plugin_wasm/tests/fixtures.rs @@ -5,5 +5,5 @@ use rspack_testing::{fixture, test_fixture}; #[fixture("tests/fixtures/**/*.config.js*")] fn wasm(config_path: PathBuf) { let fixture_path = config_path.parent().expect("TODO:"); - test_fixture(fixture_path); + test_fixture(fixture_path, Box::new(|_, _| {}), None); } diff --git a/crates/rspack_testing/examples/test-cli.rs b/crates/rspack_testing/examples/test-cli.rs index c34328b7213..e44081a8fc8 100644 --- a/crates/rspack_testing/examples/test-cli.rs +++ b/crates/rspack_testing/examples/test-cli.rs @@ -13,5 +13,5 @@ fn main() { let cwd = env::current_dir().expect("current_dir"); cwd.join(fixture).canonicalize().expect("canonicalize") }; - test_fixture(&fixture); + test_fixture(&fixture, Box::new(|_, _| {}), None); } diff --git a/crates/rspack_testing/src/run_fixture.rs b/crates/rspack_testing/src/run_fixture.rs index 7b93d9fa2ec..0b137def679 100644 --- a/crates/rspack_testing/src/run_fixture.rs +++ b/crates/rspack_testing/src/run_fixture.rs @@ -11,6 +11,8 @@ use rspack_tracing::enable_tracing_by_env; use crate::{eval_raw::evaluate_to_json, test_config::TestConfig}; +pub type MutTestOptionsFn = dyn FnMut(&mut Vec, &mut CompilerOptions); + pub fn apply_from_fixture(fixture_path: &Path) -> (CompilerOptions, Vec) { let js_config = fixture_path.join("test.config.js"); if js_config.exists() { @@ -26,48 +28,88 @@ pub fn apply_from_fixture(fixture_path: &Path) -> (CompilerOptions, Vec Compiler { - test_fixture_share(fixture_path, &|s| s.ends_with(".html")).await + test_fixture_share( + fixture_path, + &|s| s.ends_with(".html"), + Box::new(|_, _| {}), + None, + ) + .await } #[tokio::main] pub async fn test_fixture_js(fixture_path: &Path) -> Compiler { - test_fixture_share(fixture_path, &|s| { - s.ends_with(".js") && !s.contains("runtime.js") - }) + test_fixture_share( + fixture_path, + &|s| s.ends_with(".js") && !s.contains("runtime.js"), + Box::new(|_, _| {}), + None, + ) .await } #[tokio::main] pub async fn test_fixture_css(fixture_path: &Path) -> Compiler { - test_fixture_share(fixture_path, &|s| s.ends_with(".css")).await + test_fixture_share( + fixture_path, + &|s| s.ends_with(".css"), + Box::new(|_, _| {}), + None, + ) + .await } #[tokio::main] pub async fn test_fixture_css_modules(fixture_path: &Path) -> Compiler { - test_fixture_share(fixture_path, &|s| { - s.ends_with(".css") || (s.ends_with(".js") && !s.contains("runtime.js")) - }) + test_fixture_share( + fixture_path, + &|s| s.ends_with(".css") || (s.ends_with(".js") && !s.contains("runtime.js")), + Box::new(|_, _| {}), + None, + ) .await } #[tokio::main] pub async fn test_fixture_insta( fixture_path: &Path, stats_filter: &dyn Fn(&str) -> bool, + mut_settings: Box, ) -> Compiler { - test_fixture_share(fixture_path, stats_filter).await + test_fixture_share(fixture_path, stats_filter, mut_settings, None).await } + #[tokio::main] -pub async fn test_fixture(fixture_path: &Path) -> Compiler { - test_fixture_share(fixture_path, &|s| { - s.ends_with(".js") && !s.contains("runtime.js") - }) +pub async fn test_fixture( + fixture_path: &Path, + mut_settings: Box, + snapshot_name: Option, +) -> Compiler { + test_fixture_share( + fixture_path, + &|s| s.ends_with(".js") && !s.contains("runtime.js"), + mut_settings, + snapshot_name, + ) .await } +/// You can mutate the `Settings` of insta and `CompilerOptions` of rspack via `mut_settings` mut closure pub async fn test_fixture_share( fixture_path: &Path, stats_filter: &dyn Fn(&str) -> bool, + mut mut_settings: Box, + snapshot_name: Option, ) -> Compiler { enable_tracing_by_env(&std::env::var("TRACE").ok().unwrap_or_default(), "stdout"); - let (options, plugins) = apply_from_fixture(fixture_path); + let snapshot_name = snapshot_name.unwrap_or("output".to_string()); + + let mut settings = Settings::clone_current(); + settings.set_snapshot_path(Path::new(fixture_path).join("snapshot")); + settings.set_omit_expression(true); + settings.set_prepend_module_to_snapshot(false); + + let (mut options, mut plugins) = apply_from_fixture(fixture_path); + + mut_settings(&mut plugins, &mut options); + // clean output if options.output.path.exists() { std::fs::remove_dir_all(&options.output.path).expect("should remove output"); @@ -80,10 +122,6 @@ pub async fn test_fixture_share( .unwrap_or_else(|e| panic!("failed to compile in fixture {fixture_path:?}, {e:#?}")); let assets = compiler.compilation.assets(); - let mut settings = Settings::clone_current(); - settings.set_snapshot_path(Path::new(fixture_path).join("snapshot")); - settings.set_omit_expression(true); - settings.set_prepend_module_to_snapshot(false); let content = assets .iter() .filter_map(|(filename, asset)| { @@ -105,7 +143,7 @@ pub async fn test_fixture_share( .sorted() .join("\n\n"); settings.bind(|| { - assert_snapshot!("output", content); + assert_snapshot!(snapshot_name.as_str(), content); }); let stats = compiler.compilation.get_stats(); let warnings = stats.get_warnings(); diff --git a/crates/rspack_testing/src/test_config.rs b/crates/rspack_testing/src/test_config.rs index 0c997701ea3..fc6dfa5f822 100644 --- a/crates/rspack_testing/src/test_config.rs +++ b/crates/rspack_testing/src/test_config.rs @@ -6,7 +6,7 @@ use std::{ }; use rspack_core::{BoxPlugin, CompilerOptions, ModuleType, PluginExt}; -use rspack_plugin_html::config::HtmlPluginConfig; +use rspack_plugin_html::config::HtmlRspackPluginOptions; use rspack_regex::RspackRegex; use schemars::JsonSchema; use serde::Deserialize; @@ -68,7 +68,7 @@ fn default_optimization_chunk_ids() -> String { "named".to_string() } -fn default_optimization_side_effects() -> String { +fn default_optimization_false_string_lit() -> String { "false".to_string() } @@ -121,8 +121,12 @@ pub struct Optimization { pub module_ids: String, #[serde(default = "default_optimization_chunk_ids")] pub chunk_ids: String, - #[serde(default = "default_optimization_side_effects")] + #[serde(default = "default_optimization_false_string_lit")] pub side_effects: String, + #[serde(default = "true_by_default")] + pub provided_exports: bool, + #[serde(default = "default_optimization_false_string_lit")] + pub used_exports: String, } #[derive(Debug, JsonSchema, Deserialize)] @@ -168,7 +172,7 @@ pub struct Builtins { #[serde(default)] pub provide: HashMap>, #[serde(default)] - pub html: Vec, + pub html: Vec, #[serde(default)] pub minify_options: Option, #[serde(default = "default_tree_shaking")] @@ -362,6 +366,7 @@ impl TestConfig { .expect("Should exist"), hot_update_main_filename: c::Filename::from_str("[runtime].[fullhash].hot-update.json") .expect("Should exist"), + hot_update_global: "rspack_testing".to_string(), asset_module_filename: c::Filename::from_str("[hash][ext][query]").expect("Should exist"), wasm_loading: c::WasmLoading::Enable(c::WasmLoadingType::from("fetch")), webassembly_module_filename: c::Filename::from_str("[hash].module.wasm") @@ -436,6 +441,8 @@ impl TestConfig { remove_available_modules: self.optimization.remove_available_modules, remove_empty_chunks: self.optimization.remove_empty_chunks, side_effects: c::SideEffectOption::from(self.optimization.side_effects.as_str()), + provided_exports: self.optimization.provided_exports, + used_exports: c::UsedExportsOption::from(self.optimization.used_exports.as_str()), }, profile: false, }; @@ -464,8 +471,9 @@ impl TestConfig { plugins .push(rspack_plugin_dev_friendly_split_chunks::DevFriendlySplitChunksPlugin::new().boxed()); } + for html in self.builtins.html { - plugins.push(rspack_plugin_html::HtmlPlugin::new(html).boxed()); + plugins.push(rspack_plugin_html::HtmlRspackPlugin::new(html).boxed()); } plugins.push( rspack_plugin_css::CssPlugin::new(rspack_plugin_css::plugin::CssConfig { @@ -549,7 +557,9 @@ impl TestConfig { plugins.push(rspack_plugin_wasm::FetchCompileAsyncWasmPlugin {}.boxed()); plugins.push(rspack_plugin_wasm::AsyncWasmPlugin::new().boxed()); } - plugins.push(rspack_plugin_externals::http_externals_plugin(true)); + plugins.push(rspack_plugin_externals::http_externals_rspack_plugin( + true, false, + )); // Support resolving builtin loaders on the Native side plugins.push(crate::loader::BuiltinLoaderResolver.boxed()); diff --git a/crates/rspack_testing/test.config.scheme.json b/crates/rspack_testing/test.config.scheme.json index 539757d2b2d..24c028270c8 100644 --- a/crates/rspack_testing/test.config.scheme.json +++ b/crates/rspack_testing/test.config.scheme.json @@ -76,7 +76,7 @@ "html": { "type": "array", "items": { - "$ref": "#/definitions/HtmlPluginConfig" + "$ref": "#/definitions/HtmlRspackPluginOptions" } }, "minifyOptions": { @@ -89,9 +89,6 @@ } ] }, - "postcss": { - "$ref": "#/definitions/Postcss" - }, "presetEnv": { "anyOf": [ { @@ -113,8 +110,8 @@ } }, "treeShaking": { - "default": false, - "type": "boolean" + "default": "false", + "type": "string" } }, "additionalProperties": false @@ -172,7 +169,15 @@ }, "additionalProperties": false }, - "HtmlPluginConfig": { + "HtmlInject": { + "type": "string", + "enum": [ + "head", + "body", + "false" + ] + }, + "HtmlRspackPluginOptions": { "type": "object", "properties": { "chunks": { @@ -206,13 +211,10 @@ "type": "string" }, "inject": { - "description": "`head`, `body` or None", - "anyOf": [ - { - "$ref": "#/definitions/HtmlPluginConfigInject" - }, + "description": "`head`, `body`, `false`", + "allOf": [ { - "type": "null" + "$ref": "#/definitions/HtmlInject" } ] }, @@ -243,7 +245,7 @@ "description": "`blocking`, `defer`, or `module`", "allOf": [ { - "$ref": "#/definitions/HtmlPluginConfigScriptLoading" + "$ref": "#/definitions/HtmlScriptLoading" } ] }, @@ -289,14 +291,7 @@ }, "additionalProperties": false }, - "HtmlPluginConfigInject": { - "type": "string", - "enum": [ - "head", - "body" - ] - }, - "HtmlPluginConfigScriptLoading": { + "HtmlScriptLoading": { "type": "string", "enum": [ "blocking", @@ -346,14 +341,6 @@ "default": false, "type": "boolean" }, - "keepClassNames": { - "default": false, - "type": "boolean" - }, - "keepFnNames": { - "default": false, - "type": "boolean" - }, "extractComments": { "default": null, "type": [ @@ -451,17 +438,33 @@ "Optimization": { "type": "object", "properties": { + "chunkIds": { + "default": "named", + "type": "string" + }, "moduleIds": { "default": "named", "type": "string" }, + "providedExports": { + "default": true, + "type": "boolean" + }, "removeAvailableModules": { "default": true, "type": "boolean" }, + "removeEmptyChunks": { + "default": true, + "type": "boolean" + }, "sideEffects": { "default": "false", "type": "string" + }, + "usedExports": { + "default": "false", + "type": "string" } }, "additionalProperties": false @@ -470,7 +473,7 @@ "type": "object", "properties": { "chunkFilename": { - "default": "[name][ext]", + "default": "[name].js", "type": "string" }, "clean": { @@ -478,15 +481,15 @@ "type": "boolean" }, "cssChunkFilename": { - "default": "[name][ext]", + "default": "[name].css", "type": "string" }, "cssFilename": { - "default": "[name][ext]", + "default": "[name].css", "type": "string" }, "filename": { - "default": "[name][ext]", + "default": "[name].js", "type": "string" }, "library": { @@ -504,28 +507,12 @@ "type": "string" }, "sourceMapFilename": { - "default": "[name][ext]", + "default": "[file].map", "type": "string" } }, "additionalProperties": false }, - "Postcss": { - "type": "object", - "properties": { - "pxtorem": { - "anyOf": [ - { - "$ref": "#/definitions/PxToRem" - }, - { - "type": "null" - } - ] - } - }, - "additionalProperties": false - }, "PresetEnv": { "type": "object", "required": [ @@ -553,72 +540,6 @@ }, "additionalProperties": false }, - "PxToRem": { - "type": "object", - "properties": { - "mediaQuery": { - "default": null, - "type": [ - "boolean", - "null" - ] - }, - "minPixelValue": { - "default": null, - "type": [ - "number", - "null" - ], - "format": "double" - }, - "propList": { - "default": null, - "type": [ - "array", - "null" - ], - "items": { - "type": "string" - } - }, - "replace": { - "default": null, - "type": [ - "boolean", - "null" - ] - }, - "rootValue": { - "default": null, - "type": [ - "integer", - "null" - ], - "format": "uint32", - "minimum": 0.0 - }, - "selectorBlackList": { - "default": null, - "type": [ - "array", - "null" - ], - "items": { - "type": "string" - } - }, - "unitPrecision": { - "default": null, - "type": [ - "integer", - "null" - ], - "format": "uint32", - "minimum": 0.0 - } - }, - "additionalProperties": false - }, "Rule": { "type": "object", "properties": { diff --git a/crates/rspack_util/src/lib.rs b/crates/rspack_util/src/lib.rs index 5dcd3be0e84..fd252cce4ed 100644 --- a/crates/rspack_util/src/lib.rs +++ b/crates/rspack_util/src/lib.rs @@ -21,6 +21,19 @@ where Ok(false) } +pub fn try_any_sync(it: impl IntoIterator, f: F) -> Result +where + F: Fn(T) -> Result, +{ + let it = it.into_iter(); + for i in it { + if f(i)? { + return Ok(true); + } + } + Ok(false) +} + pub async fn try_all(it: impl IntoIterator, f: F) -> Result where Fut: Future>, diff --git a/examples/builtin-swc-loader/rspack.config.js b/examples/builtin-swc-loader/rspack.config.js index 60c31bfa10e..797a4a4e79e 100644 --- a/examples/builtin-swc-loader/rspack.config.js +++ b/examples/builtin-swc-loader/rspack.config.js @@ -43,6 +43,11 @@ const config = { template: "./index.html" } ] + }, + experiments: { + rspackFuture: { + disableTransformByDefault: true + } } }; module.exports = config; diff --git a/examples/builtin-swc-loader/src/App.jsx b/examples/builtin-swc-loader/src/App.jsx index ce9cbd2946d..37845757234 100644 --- a/examples/builtin-swc-loader/src/App.jsx +++ b/examples/builtin-swc-loader/src/App.jsx @@ -1,4 +1,3 @@ -import React from 'react'; import logo from './logo.svg'; import './App.css'; diff --git a/examples/builtin-swc-loader/src/index.jsx b/examples/builtin-swc-loader/src/index.jsx index 2cb1087e76e..01f8bc38561 100644 --- a/examples/builtin-swc-loader/src/index.jsx +++ b/examples/builtin-swc-loader/src/index.jsx @@ -1,4 +1,3 @@ -import React from 'react'; import ReactDOM from 'react-dom/client'; import './index.css'; import App from './App'; diff --git a/examples/emotion/rspack.config.js b/examples/emotion/rspack.config.js index 3c2ded6087d..38e788a1c72 100644 --- a/examples/emotion/rspack.config.js +++ b/examples/emotion/rspack.config.js @@ -20,11 +20,16 @@ const config = { parser: { syntax: "ecmascript", jsx: true + }, + transform: { + react: { + importSource: "@emotion/react", + runtime: "automatic" + } } }, rspackExperiments: { - emotion: true, - react: {} + emotion: true } }, type: "javascript/auto" diff --git a/examples/nestjs/rspack.config.js b/examples/nestjs/rspack.config.js index 7bfd7019239..71b28b47073 100644 --- a/examples/nestjs/rspack.config.js +++ b/examples/nestjs/rspack.config.js @@ -2,11 +2,34 @@ const { RunScriptWebpackPlugin } = require("run-script-webpack-plugin"); /** @type {import('@rspack/cli').Configuration} */ const config = { + experiments: { + rspackFuture: { + disableTransformByDefault: true + } + }, context: __dirname, target: "node", entry: { main: ["webpack/hot/poll?100", "./src/main.ts"] }, + module: { + rules: [ + { + test: /\.ts$/, + use: { + loader: "builtin:swc-loader", + options: { + jsc: { + parser: { + syntax: "typescript", + decorators: true, + }, + } + } + }, + } + ] + }, optimization: { minimize: false }, @@ -59,6 +82,6 @@ const config = { } callback(); } - ] + ], }; module.exports = config; diff --git a/examples/plugin-compat/package.json b/examples/plugin-compat/package.json index 85ef4d97bf6..0b6220322e7 100644 --- a/examples/plugin-compat/package.json +++ b/examples/plugin-compat/package.json @@ -13,14 +13,14 @@ "license": "ISC", "devDependencies": { "@rspack/cli": "workspace:*", - "@rspack/plugin-html": "workspace:*", "@rspack/plugin-minify": "workspace:*", "copy-webpack-plugin": "5.1.2", + "fork-ts-checker-webpack-plugin": "8.0.0", "generate-package-json-webpack-plugin": "^2.6.0", + "html-webpack-plugin": "^5.5.0", "license-webpack-plugin": "^4.0.2", - "webpack-bundle-analyzer": "4.7.0", - "webpack-stats-plugin": "1.1.1", "rspack-manifest-plugin": "5.0.0-alpha0", - "fork-ts-checker-webpack-plugin": "8.0.0" + "webpack-bundle-analyzer": "4.7.0", + "webpack-stats-plugin": "1.1.1" } } diff --git a/examples/plugin-compat/rspack.config.js b/examples/plugin-compat/rspack.config.js index 02a55ec0f7f..14b35f07363 100644 --- a/examples/plugin-compat/rspack.config.js +++ b/examples/plugin-compat/rspack.config.js @@ -1,7 +1,7 @@ const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin; const CopyPlugin = require("copy-webpack-plugin"); -const HtmlPlugin = require("@rspack/plugin-html").default; +const HtmlPlugin = require("html-webpack-plugin") const { StatsWriterPlugin } = require("webpack-stats-plugin"); const minifyPlugin = require("@rspack/plugin-minify"); const manifestPlugin = require("rspack-manifest-plugin").WebpackManifestPlugin; diff --git a/examples/proxy/package.json b/examples/proxy/package.json index 84662fd26da..81d41984a7e 100644 --- a/examples/proxy/package.json +++ b/examples/proxy/package.json @@ -8,6 +8,9 @@ "build": "rspack build", "dev": "rspack serve" }, + "devDependencies": { + "@rspack/cli": "workspace:*" + }, "keywords": [], "author": "", "license": "ISC" diff --git a/examples/react-refresh-babel-loader/index.html b/examples/react-refresh-babel-loader/index.html new file mode 100644 index 00000000000..1fd94734cd0 --- /dev/null +++ b/examples/react-refresh-babel-loader/index.html @@ -0,0 +1,15 @@ + + + + + + + + Document + + + +
+ + + \ No newline at end of file diff --git a/examples/react-refresh-babel-loader/package.json b/examples/react-refresh-babel-loader/package.json new file mode 100644 index 00000000000..951f215ed36 --- /dev/null +++ b/examples/react-refresh-babel-loader/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-rspack-react-refresh", + "version": "1.0.0", + "description": "", + "main": "index.js", + "private": true, + "scripts": { + "dev": "rspack serve ", + "build": "cross-env NODE_ENV=production rspack build" + }, + "keywords": [], + "author": "", + "license": "MIT", + "dependencies": { + "react": "18.0.0", + "react-dom": "18.0.0" + }, + "devDependencies": { + "@babel/core": "^7.22.20", + "@babel/preset-react": "^7.22.15", + "@babel/preset-typescript": "^7.22.5", + "@rspack/cli": "workspace:*", + "@rspack/core": "workspace:*", + "@rspack/plugin-react-refresh": "workspace:*", + "babel-loader": "^9.1.3", + "react-refresh": "0.13.0" + } +} \ No newline at end of file diff --git a/examples/react-refresh-babel-loader/rspack.config.js b/examples/react-refresh-babel-loader/rspack.config.js new file mode 100644 index 00000000000..20510987d57 --- /dev/null +++ b/examples/react-refresh-babel-loader/rspack.config.js @@ -0,0 +1,40 @@ +const rspack = require("@rspack/core") +const ReactRefreshPlugin = require("@rspack/plugin-react-refresh") + +const isProduction = process.env.NODE_ENV === "production" + +/** @type {import('@rspack/cli').Configuration} */ +const config = { + experiments: { + rspackFuture: { + disableTransformByDefault: true, + } + }, + mode: isProduction ? "production" : "development", + entry: { main: "./src/index.tsx" }, + devtool: 'source-map', + module: { + rules: [ + { + test: /\.tsx$/, + use: { + loader: "babel-loader", + options: { + presets: [ + ["@babel/preset-react", { runtime: "automatic" }], + '@babel/preset-typescript', + ], + plugins: [!isProduction && require.resolve('react-refresh/babel')].filter(Boolean) + } + } + } + ] + }, + plugins: [ + new rspack.HtmlRspackPlugin({ template: "./index.html" }), + new rspack.DefinePlugin({ "process.env.NODE_ENV": "'development'" }), + !isProduction && new ReactRefreshPlugin(), + ].filter(Boolean) +}; + +module.exports = config; diff --git a/examples/react-refresh-babel-loader/src/App.tsx b/examples/react-refresh-babel-loader/src/App.tsx new file mode 100644 index 00000000000..0837177fc5a --- /dev/null +++ b/examples/react-refresh-babel-loader/src/App.tsx @@ -0,0 +1,25 @@ +import { lazy, Suspense } from 'react' +import { ArrowFunction } from './ArrowFunction' +import ClassDefault from './ClassDefault' +import { ClassNamed } from './ClassNamed' +import FunctionDefault from './FunctionDefault' +import { FunctionNamed } from './FunctionNamed' + +const LazyComponent = lazy(() => import('./LazyComponent')) + +function App() { + return ( +
+ + + + + + Loading}> + + +
+ ) +} + +export default App diff --git a/examples/react-refresh-babel-loader/src/ArrowFunction.tsx b/examples/react-refresh-babel-loader/src/ArrowFunction.tsx new file mode 100644 index 00000000000..bbd4f03ab22 --- /dev/null +++ b/examples/react-refresh-babel-loader/src/ArrowFunction.tsx @@ -0,0 +1 @@ +export const ArrowFunction = () =>

Arrow Function

diff --git a/examples/react-refresh-babel-loader/src/ClassDefault.tsx b/examples/react-refresh-babel-loader/src/ClassDefault.tsx new file mode 100644 index 00000000000..a4c63f932d6 --- /dev/null +++ b/examples/react-refresh-babel-loader/src/ClassDefault.tsx @@ -0,0 +1,9 @@ +import { Component } from 'react' + +class ClassDefault extends Component { + render() { + return

Default Export Class

+ } +} + +export default ClassDefault diff --git a/examples/react-refresh-babel-loader/src/ClassNamed.tsx b/examples/react-refresh-babel-loader/src/ClassNamed.tsx new file mode 100644 index 00000000000..f80310692a8 --- /dev/null +++ b/examples/react-refresh-babel-loader/src/ClassNamed.tsx @@ -0,0 +1,7 @@ +import { Component } from 'react' + +export class ClassNamed extends Component { + render() { + return

Named Export Class

+ } +} diff --git a/examples/react-refresh-babel-loader/src/FunctionDefault.tsx b/examples/react-refresh-babel-loader/src/FunctionDefault.tsx new file mode 100644 index 00000000000..8ce88b8c315 --- /dev/null +++ b/examples/react-refresh-babel-loader/src/FunctionDefault.tsx @@ -0,0 +1,5 @@ +function FunctionDefault() { + return

Default Export Function

+} + +export default FunctionDefault diff --git a/examples/react-refresh-babel-loader/src/FunctionNamed.tsx b/examples/react-refresh-babel-loader/src/FunctionNamed.tsx new file mode 100644 index 00000000000..635805f56ea --- /dev/null +++ b/examples/react-refresh-babel-loader/src/FunctionNamed.tsx @@ -0,0 +1,13 @@ +import { useEffect, useState } from 'react' + +export function FunctionNamed() { + const [data, setData] = useState(0) + + useEffect(() => { + setInterval(() => { + setData((i) => i + 1) + }, 100) + }, []) + + return

Named Export Function {data}

+} diff --git a/examples/react-refresh-babel-loader/src/LazyComponent.tsx b/examples/react-refresh-babel-loader/src/LazyComponent.tsx new file mode 100644 index 00000000000..de5635fce1a --- /dev/null +++ b/examples/react-refresh-babel-loader/src/LazyComponent.tsx @@ -0,0 +1,5 @@ +function LazyComponent() { + return

Lazy Component

+} + +export default LazyComponent diff --git a/examples/react-refresh-babel-loader/src/index.tsx b/examples/react-refresh-babel-loader/src/index.tsx new file mode 100644 index 00000000000..12b3ed8af4c --- /dev/null +++ b/examples/react-refresh-babel-loader/src/index.tsx @@ -0,0 +1,6 @@ +import { createRoot } from 'react-dom/client' +import App from './App' + +const container = document.getElementById('root') +const root = createRoot(container!) +root.render() \ No newline at end of file diff --git a/examples/react-refresh/package.json b/examples/react-refresh/package.json index a34b24734f6..ad6729b1d9d 100644 --- a/examples/react-refresh/package.json +++ b/examples/react-refresh/package.json @@ -6,15 +6,19 @@ "private": true, "scripts": { "dev": "rspack serve ", - "build": "rspack build" + "build": "cross-env NODE_ENV=production rspack build" }, "keywords": [], "author": "", "license": "MIT", "dependencies": { - "@rspack/cli": "workspace:*", "react": "18.0.0", - "react-dom": "18.0.0", + "react-dom": "18.0.0" + }, + "devDependencies": { + "@rspack/cli": "workspace:*", + "@rspack/core": "workspace:*", + "@rspack/plugin-react-refresh": "workspace:*", "react-refresh": "0.13.0" } } \ No newline at end of file diff --git a/examples/react-refresh/rspack.config.js b/examples/react-refresh/rspack.config.js index cc6fb651af4..5e798e18184 100644 --- a/examples/react-refresh/rspack.config.js +++ b/examples/react-refresh/rspack.config.js @@ -1,14 +1,49 @@ -/** - * @type {import('@rspack/cli').Configuration} - */ +const rspack = require("@rspack/core") +const ReactRefreshPlugin = require("@rspack/plugin-react-refresh") + +const isProduction = process.env.NODE_ENV === "production" + +/** @type {import('@rspack/cli').Configuration} */ const config = { - mode: "development", - entry: { main: "./src/index.tsx" }, - builtins: { - html: [{ template: "./index.html" }], - define: { - "process.env.NODE_ENV": "'development'" + experiments: { + rspackFuture: { + disableTransformByDefault: true, } - } + }, + mode: isProduction ? "production" : "development", + entry: { main: "./src/index.tsx" }, + devtool: 'source-map', + module: { + rules: [ + { + test: /\.tsx$/, + use: { + loader: "builtin:swc-loader", + options: { + sourceMap: true, + jsc: { + parser: { + syntax: "typescript", + tsx: true + }, + transform: { + react: { + runtime: "automatic", + development: !isProduction, + refresh: !isProduction, + } + } + } + } + } + } + ] + }, + plugins: [ + new rspack.HtmlRspackPlugin({ template: "./index.html" }), + new rspack.DefinePlugin({ "process.env.NODE_ENV": "'development'" }), + !isProduction && new ReactRefreshPlugin(), + ].filter(Boolean) }; + module.exports = config; diff --git a/examples/worklet/index.html b/examples/worklet/index.html new file mode 100644 index 00000000000..7bac4f56868 --- /dev/null +++ b/examples/worklet/index.html @@ -0,0 +1,12 @@ + + + + + + + Document + + +
+ + diff --git a/examples/worklet/loader/worklet-loader.js b/examples/worklet/loader/worklet-loader.js new file mode 100644 index 00000000000..c2fe2613ae1 --- /dev/null +++ b/examples/worklet/loader/worklet-loader.js @@ -0,0 +1,10 @@ +const esbuild = require("esbuild"); +module.exports = function workletLoader(source) { + const result = esbuild.buildSync({ + entryPoints: [this.resource], + write: false, + bundle: true + }); + const content = result.outputFiles[0].text; + return content; +}; diff --git a/examples/worklet/package.json b/examples/worklet/package.json new file mode 100644 index 00000000000..481c77ac543 --- /dev/null +++ b/examples/worklet/package.json @@ -0,0 +1,19 @@ +{ + "name": "example-basic", + "version": "1.0.0", + "description": "", + "main": "index.js", + "private": true, + "scripts": { + "dev": "rspack serve", + "build": "rspack build" + }, + "devDependencies": { + "esbuild": "0.19.3", + "@rspack/cli": "workspace:*" + }, + "sideEffects": false, + "keywords": [], + "author": "", + "license": "MIT" +} \ No newline at end of file diff --git a/examples/worklet/rspack.config.js b/examples/worklet/rspack.config.js new file mode 100644 index 00000000000..a5b68d57e03 --- /dev/null +++ b/examples/worklet/rspack.config.js @@ -0,0 +1,41 @@ +/** @type {import('@rspack/cli').Configuration} */ +const config = { + context: __dirname, + mode: "development", + entry: { + main: "./src/index.js" + }, + devServer: { + devMiddleware: { + writeToDisk: true + } + }, + module: { + rules: [ + { + resourceQuery: /url/, + type: "asset" + }, + { + test: /complex\.worklet/, + use: [ + { + loader: "./loader/worklet-loader.js" + } + ], + type: "asset" + } + ] + }, + builtins: { + html: [ + { + template: "./index.html" + } + ], + react: { + refresh: false + } + } +}; +module.exports = config; diff --git a/examples/worklet/src/answer.js b/examples/worklet/src/answer.js new file mode 100644 index 00000000000..64a32fd291e --- /dev/null +++ b/examples/worklet/src/answer.js @@ -0,0 +1 @@ +export const answer = 42; diff --git a/examples/worklet/src/index.js b/examples/worklet/src/index.js new file mode 100644 index 00000000000..c1d7739a654 --- /dev/null +++ b/examples/worklet/src/index.js @@ -0,0 +1,23 @@ +import simpleWorklet from "./worklet/simple.worklet?url"; +import complexWorklet from "./worklet/complex.worklet"; +let context = new AudioContext(); + +context.audioWorklet.addModule(simpleWorklet).then(() => { + let node = new AudioWorkletNode(context, "port-processor"); + node.port.onmessage = event => { + // Handling data from the processor. + console.log(event.data); + }; + + node.port.postMessage("Hello!"); +}); + +context.audioWorklet.addModule(complexWorklet).then(() => { + let node = new AudioWorkletNode(context, "complex-processor"); + node.port.onmessage = event => { + // Handling data from the processor. + console.log(event.data); + }; + + node.port.postMessage("Hello!"); +}); diff --git a/examples/worklet/src/lib.js b/examples/worklet/src/lib.js new file mode 100644 index 00000000000..84c67edefbd --- /dev/null +++ b/examples/worklet/src/lib.js @@ -0,0 +1 @@ +export const a = 3; diff --git a/examples/worklet/src/worklet/answer.ts b/examples/worklet/src/worklet/answer.ts new file mode 100644 index 00000000000..64a32fd291e --- /dev/null +++ b/examples/worklet/src/worklet/answer.ts @@ -0,0 +1 @@ +export const answer = 42; diff --git a/examples/worklet/src/worklet/complex.worklet.js b/examples/worklet/src/worklet/complex.worklet.js new file mode 100644 index 00000000000..1d603f16aa3 --- /dev/null +++ b/examples/worklet/src/worklet/complex.worklet.js @@ -0,0 +1,19 @@ +import { answer } from "./answer"; +class PortProcessor extends AudioWorkletProcessor { + constructor() { + super(); + this.port.onmessage = event => { + // Handling data from the node. + console.log(event.data); + }; + + this.port.postMessage("Hi!" + answer); + } + + process(inputs, outputs, parameters) { + // Do nothing, producing silent output. + return true; + } +} + +registerProcessor("complex-processor", PortProcessor); diff --git a/examples/worklet/src/worklet/simple.worklet.js b/examples/worklet/src/worklet/simple.worklet.js new file mode 100644 index 00000000000..cfaa23d32fa --- /dev/null +++ b/examples/worklet/src/worklet/simple.worklet.js @@ -0,0 +1,18 @@ +class PortProcessor extends AudioWorkletProcessor { + constructor() { + super(); + this.port.onmessage = event => { + // Handling data from the node. + console.log(event.data); + }; + + this.port.postMessage("Hi!"); + } + + process(inputs, outputs, parameters) { + // Do nothing, producing silent output. + return true; + } +} + +registerProcessor("port-processor", PortProcessor); diff --git a/npm/darwin-arm64/package.json b/npm/darwin-arm64/package.json index 1ff4f4623b6..65eb6e812a9 100644 --- a/npm/darwin-arm64/package.json +++ b/npm/darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@rspack/binding-darwin-arm64", - "version": "0.3.2", + "version": "0.3.4", "license": "MIT", "description": "Node binding for rspack", "main": "rspack.darwin-arm64.node", diff --git a/npm/darwin-x64/package.json b/npm/darwin-x64/package.json index 488bec64304..38bd76fd14f 100644 --- a/npm/darwin-x64/package.json +++ b/npm/darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "@rspack/binding-darwin-x64", - "version": "0.3.2", + "version": "0.3.4", "license": "MIT", "description": "Node binding for rspack", "main": "rspack.darwin-x64.node", diff --git a/npm/linux-x64-gnu/package.json b/npm/linux-x64-gnu/package.json index b9f230c3a1a..d1e91ec44d6 100644 --- a/npm/linux-x64-gnu/package.json +++ b/npm/linux-x64-gnu/package.json @@ -1,6 +1,6 @@ { "name": "@rspack/binding-linux-x64-gnu", - "version": "0.3.2", + "version": "0.3.4", "license": "MIT", "description": "Node binding for rspack", "main": "rspack.linux-x64-gnu.node", diff --git a/npm/win32-x64-msvc/package.json b/npm/win32-x64-msvc/package.json index ed6f8f80cc7..1a61775c0d5 100644 --- a/npm/win32-x64-msvc/package.json +++ b/npm/win32-x64-msvc/package.json @@ -1,6 +1,6 @@ { "name": "@rspack/binding-win32-x64-msvc", - "version": "0.3.2", + "version": "0.3.4", "license": "MIT", "description": "Node binding for rspack", "main": "rspack.win32-x64-msvc.node", diff --git a/package.json b/package.json index 084907596c3..98a351f8daf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "monorepo", - "version": "0.3.2", + "version": "0.3.4", "license": "MIT", "description": "A Fast Rust-based web bundler", "private": true, diff --git a/packages/create-rspack/package.json b/packages/create-rspack/package.json index 1fb2cb9f270..e6e799031aa 100644 --- a/packages/create-rspack/package.json +++ b/packages/create-rspack/package.json @@ -1,6 +1,6 @@ { "name": "create-rspack", - "version": "0.3.2", + "version": "0.3.4", "license": "MIT", "main": "index.js", "bin": { diff --git a/packages/playground/cases/react/basic-disableTransformByDefault/index.test.ts b/packages/playground/cases/react/basic-disableTransformByDefault/index.test.ts new file mode 100644 index 00000000000..33fefe02749 --- /dev/null +++ b/packages/playground/cases/react/basic-disableTransformByDefault/index.test.ts @@ -0,0 +1,59 @@ +import { test, expect } from "@/fixtures"; + +test("render should work", async ({ page }) => { + expect(await page.textContent(".header")).toBe("Hello World"); + expect(await page.textContent("#lazy-component")).toBe("Lazy Component"); +}); + +test("hmr should work", async ({ page, fileAction, rspack }) => { + expect(await page.textContent("button")).toBe("10"); + await page.click("button"); + expect(await page.textContent("button")).toBe("11"); + expect(await page.textContent(".placeholder")).toBe("__PLACE_HOLDER__"); + fileAction.updateFile("src/App.jsx", content => + content.replace("__PLACE_HOLDER__", "__EDITED__") + ); + await rspack.waitingForHmr(async function () { + return (await page.textContent(".placeholder")) === "__EDITED__"; + }); + expect(await page.textContent("button")).toBe("11"); +}); + +test("context+component should work", async ({ page, fileAction, rspack }) => { + expect(await page.textContent("#context")).toBe("context-value"); + await page.click("#context"); + expect(await page.textContent("#context")).toBe("context-value-click"); + fileAction.updateFile("src/CountProvider.jsx", content => + content.replace("context-value", "context-value-update") + ); + await rspack.waitingForHmr(async function () { + return (await page.textContent("#context")) === "context-value-update"; + }); +}); + +test("ReactRefreshFinder should work", async ({ page }) => { + expect(await page.textContent("#nest-function")).toBe("nest-function"); +}); + +test("update same export name from different module should work", async ({ + page, + fileAction, + rspack +}) => { + expect(await page.textContent(".same-export-name1")).toBe("__NAME_1__"); + expect(await page.textContent(".same-export-name2")).toBe("__NAME_2__"); + fileAction.updateFile("src/SameExportName1.jsx", content => + content.replace("__NAME_1__", "__name_1__") + ); + await rspack.waitingForHmr(async function () { + return (await page.textContent(".same-export-name1")) === "__name_1__"; + }); + expect(await page.textContent(".same-export-name2")).toBe("__NAME_2__"); + fileAction.updateFile("src/SameExportName2.jsx", content => + content.replace("__NAME_2__", "__name_2__") + ); + await rspack.waitingForHmr(async function () { + return (await page.textContent(".same-export-name2")) === "__name_2__"; + }); + expect(await page.textContent(".same-export-name1")).toBe("__name_1__"); +}); diff --git a/packages/playground/cases/react/basic-disableTransformByDefault/rspack.config.js b/packages/playground/cases/react/basic-disableTransformByDefault/rspack.config.js new file mode 100644 index 00000000000..0a562f79625 --- /dev/null +++ b/packages/playground/cases/react/basic-disableTransformByDefault/rspack.config.js @@ -0,0 +1,54 @@ +const rspack = require("@rspack/core"); +const ReactRefreshPlugin = require("@rspack/plugin-react-refresh"); + +/** @type { import('@rspack/core').RspackOptions } */ +module.exports = { + experiments: { + rspackFuture: { + disableTransformByDefault: true + } + }, + context: __dirname, + mode: "development", + module: { + rules: [ + { + test: /\.jsx$/, + use: { + loader: "builtin:swc-loader", + options: { + jsc: { + parser: { + syntax: "ecmascript", + jsx: true + }, + transform: { + react: { + runtime: "automatic", + development: true, + refresh: true + } + } + } + } + } + } + ] + }, + plugins: [ + new rspack.HtmlRspackPlugin({ template: "./src/index.html" }), + new ReactRefreshPlugin() + ], + entry: "./src/index.jsx", + devServer: { + hot: true + }, + cache: false, + stats: "none", + infrastructureLogging: { + debug: false + }, + watchOptions: { + poll: 1000 + } +}; diff --git a/packages/playground/cases/react/basic-disableTransformByDefault/src/App.jsx b/packages/playground/cases/react/basic-disableTransformByDefault/src/App.jsx new file mode 100644 index 00000000000..a72ff3a972a --- /dev/null +++ b/packages/playground/cases/react/basic-disableTransformByDefault/src/App.jsx @@ -0,0 +1,30 @@ +import React from 'react' +import './index.css' +import { ContextComponent } from './CountProvider' +import { ReactRefreshFinder } from './ReactRefreshFinder' +import { SameExportName as SameExportName1 } from './SameExportName1' +import { SameExportName as SameExportName2 } from './SameExportName2' + +const Button = () => { + const [count, setCount] = React.useState(10) + return +} + +const LazyComponent = React.lazy(() => import('./LazyComponent')) + +export const App = () => { + return ( +
+
Hello World
+
}> + + + + ) +} diff --git a/packages/playground/cases/react/basic-disableTransformByDefault/src/CountProvider.jsx b/packages/playground/cases/react/basic-disableTransformByDefault/src/CountProvider.jsx new file mode 100644 index 00000000000..afbe1fcbe34 --- /dev/null +++ b/packages/playground/cases/react/basic-disableTransformByDefault/src/CountProvider.jsx @@ -0,0 +1,19 @@ +import React from 'react'; + +export const CountContext = React.createContext(); + +export function CountProvider({ children }) { + const [count, setCount] = React.useState('context-value'); + return ( + + {children} + + ); +} + +export function ContextComponent() { + const { count, setCount } = React.useContext(CountContext); + return
setCount((count) => count + '-click')}> + {count} +
+} \ No newline at end of file diff --git a/packages/playground/cases/react/basic-disableTransformByDefault/src/LazyComponent.css b/packages/playground/cases/react/basic-disableTransformByDefault/src/LazyComponent.css new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/playground/cases/react/basic-disableTransformByDefault/src/LazyComponent.jsx b/packages/playground/cases/react/basic-disableTransformByDefault/src/LazyComponent.jsx new file mode 100644 index 00000000000..65545394690 --- /dev/null +++ b/packages/playground/cases/react/basic-disableTransformByDefault/src/LazyComponent.jsx @@ -0,0 +1,7 @@ +import './LazyComponent.css' + +function LazyComponent () { + return
Lazy Component
+} + +export default LazyComponent diff --git a/packages/playground/cases/react/basic-disableTransformByDefault/src/ReactRefreshFinder.jsx b/packages/playground/cases/react/basic-disableTransformByDefault/src/ReactRefreshFinder.jsx new file mode 100644 index 00000000000..83b0509d747 --- /dev/null +++ b/packages/playground/cases/react/basic-disableTransformByDefault/src/ReactRefreshFinder.jsx @@ -0,0 +1,10 @@ +import React, { useState } from 'react'; + +function CreateReactRefreshFinder() { + return function Component() { + useState(1); + return
nest-function
; + }; +} + +export const ReactRefreshFinder = CreateReactRefreshFinder() \ No newline at end of file diff --git a/packages/playground/cases/react/basic-disableTransformByDefault/src/SameExportName1.jsx b/packages/playground/cases/react/basic-disableTransformByDefault/src/SameExportName1.jsx new file mode 100644 index 00000000000..2a7f2b45f15 --- /dev/null +++ b/packages/playground/cases/react/basic-disableTransformByDefault/src/SameExportName1.jsx @@ -0,0 +1,3 @@ +export function SameExportName() { + return
__NAME_1__
+} diff --git a/packages/playground/cases/react/basic-disableTransformByDefault/src/SameExportName2.jsx b/packages/playground/cases/react/basic-disableTransformByDefault/src/SameExportName2.jsx new file mode 100644 index 00000000000..8bf62ab6bb5 --- /dev/null +++ b/packages/playground/cases/react/basic-disableTransformByDefault/src/SameExportName2.jsx @@ -0,0 +1,3 @@ +export function SameExportName() { + return
__NAME_2__
+} diff --git a/packages/playground/cases/react/basic-disableTransformByDefault/src/index.css b/packages/playground/cases/react/basic-disableTransformByDefault/src/index.css new file mode 100644 index 00000000000..753f48a591f --- /dev/null +++ b/packages/playground/cases/react/basic-disableTransformByDefault/src/index.css @@ -0,0 +1,3 @@ +body { + background-color: rgba(0, 0, 0, 0); +} diff --git a/packages/playground/cases/react/basic-disableTransformByDefault/src/index.html b/packages/playground/cases/react/basic-disableTransformByDefault/src/index.html new file mode 100644 index 00000000000..127a457455b --- /dev/null +++ b/packages/playground/cases/react/basic-disableTransformByDefault/src/index.html @@ -0,0 +1,12 @@ + + + + + + + Document + + +
+ + diff --git a/packages/playground/cases/react/basic-disableTransformByDefault/src/index.jsx b/packages/playground/cases/react/basic-disableTransformByDefault/src/index.jsx new file mode 100644 index 00000000000..52e72c3334e --- /dev/null +++ b/packages/playground/cases/react/basic-disableTransformByDefault/src/index.jsx @@ -0,0 +1,11 @@ +import React from "react"; +import { createRoot } from "react-dom/client"; +import { App } from './App'; +import { CountProvider } from "./CountProvider"; + +const container = createRoot(document.getElementById("root")); +container.render( + + + +); diff --git a/packages/playground/cases/react/basic/index.test.ts b/packages/playground/cases/react/basic/index.test.ts index a6a420c194b..33fefe02749 100644 --- a/packages/playground/cases/react/basic/index.test.ts +++ b/packages/playground/cases/react/basic/index.test.ts @@ -2,6 +2,7 @@ import { test, expect } from "@/fixtures"; test("render should work", async ({ page }) => { expect(await page.textContent(".header")).toBe("Hello World"); + expect(await page.textContent("#lazy-component")).toBe("Lazy Component"); }); test("hmr should work", async ({ page, fileAction, rspack }) => { diff --git a/packages/playground/cases/react/basic/src/App.jsx b/packages/playground/cases/react/basic/src/App.jsx index 229770f9d16..a72ff3a972a 100644 --- a/packages/playground/cases/react/basic/src/App.jsx +++ b/packages/playground/cases/react/basic/src/App.jsx @@ -1,25 +1,30 @@ -import React from "react"; -import "./index.css"; -import { ContextComponent } from "./CountProvider"; -import { ReactRefreshFinder } from "./ReactRefreshFinder"; +import React from 'react' +import './index.css' +import { ContextComponent } from './CountProvider' +import { ReactRefreshFinder } from './ReactRefreshFinder' import { SameExportName as SameExportName1 } from './SameExportName1' import { SameExportName as SameExportName2 } from './SameExportName2' const Button = () => { - const [count, setCount] = React.useState(10); - return ; -}; + const [count, setCount] = React.useState(10) + return +} + +const LazyComponent = React.lazy(() => import('./LazyComponent')) export const App = () => { return ( -
-
Hello World
+
+
Hello World
}> + +
- ); -}; + ) +} diff --git a/packages/playground/cases/react/basic/src/LazyComponent.css b/packages/playground/cases/react/basic/src/LazyComponent.css new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/playground/cases/react/basic/src/LazyComponent.jsx b/packages/playground/cases/react/basic/src/LazyComponent.jsx new file mode 100644 index 00000000000..65545394690 --- /dev/null +++ b/packages/playground/cases/react/basic/src/LazyComponent.jsx @@ -0,0 +1,7 @@ +import './LazyComponent.css' + +function LazyComponent () { + return
Lazy Component
+} + +export default LazyComponent diff --git a/packages/playground/cases/react/class-component-disableTransformByDefault/index.test.ts b/packages/playground/cases/react/class-component-disableTransformByDefault/index.test.ts new file mode 100644 index 00000000000..b1c3c5f0a17 --- /dev/null +++ b/packages/playground/cases/react/class-component-disableTransformByDefault/index.test.ts @@ -0,0 +1,24 @@ +import { test, expect } from "@/fixtures"; + +test("render should work", async ({ page }) => { + expect(await page.textContent(".header")).toBe("Hello World"); +}); + +test("class component hmr should work", async ({ + page, + fileAction, + rspack +}) => { + expect(await page.textContent("button")).toBe("10"); + await page.click("button"); + expect(await page.textContent("button")).toBe("11"); + expect(await page.textContent(".placeholder")).toBe("__PLACE_HOLDER__"); + fileAction.updateFile("src/App.jsx", content => + content.replace("__PLACE_HOLDER__", "__EDITED__") + ); + await rspack.waitingForHmr(async function () { + return (await page.textContent(".placeholder")) === "__EDITED__"; + }); + // class component will not keep local status + expect(await page.textContent("button")).toBe("10"); +}); diff --git a/packages/playground/cases/react/class-component-disableTransformByDefault/rspack.config.js b/packages/playground/cases/react/class-component-disableTransformByDefault/rspack.config.js new file mode 100644 index 00000000000..b3cc8c5472d --- /dev/null +++ b/packages/playground/cases/react/class-component-disableTransformByDefault/rspack.config.js @@ -0,0 +1,54 @@ +const rspack = require("@rspack/core"); +const ReactRefreshPlugin = require("@rspack/plugin-react-refresh"); + +/** @type { import('@rspack/core').RspackOptions } */ +module.exports = { + experiments: { + rspackFuture: { + disableTransformByDefault: true + } + }, + context: __dirname, + mode: "development", + entry: "./src/index.jsx", + module: { + rules: [ + { + test: /\.jsx$/, + use: { + loader: "builtin:swc-loader", + options: { + jsc: { + parser: { + syntax: "ecmascript", + jsx: true + }, + transform: { + react: { + runtime: "automatic", + development: true, + refresh: true + } + } + } + } + } + } + ] + }, + plugins: [ + new rspack.HtmlRspackPlugin({ template: "./src/index.html" }), + new ReactRefreshPlugin() + ], + devServer: { + hot: true + }, + cache: false, + stats: "none", + infrastructureLogging: { + debug: false + }, + watchOptions: { + poll: 1000 + } +}; diff --git a/packages/playground/cases/react/class-component-disableTransformByDefault/src/App.jsx b/packages/playground/cases/react/class-component-disableTransformByDefault/src/App.jsx new file mode 100644 index 00000000000..dd95da73edd --- /dev/null +++ b/packages/playground/cases/react/class-component-disableTransformByDefault/src/App.jsx @@ -0,0 +1,18 @@ +import React from "react"; + +const Button = () => { + const [count, setCount] = React.useState(10); + return ; +}; + +export class App extends React.Component { + render() { + return ( +
+
Hello World
+
+ ); + } +} diff --git a/packages/playground/cases/react/class-component-disableTransformByDefault/src/index.html b/packages/playground/cases/react/class-component-disableTransformByDefault/src/index.html new file mode 100644 index 00000000000..127a457455b --- /dev/null +++ b/packages/playground/cases/react/class-component-disableTransformByDefault/src/index.html @@ -0,0 +1,12 @@ + + + + + + + Document + + +
+ + diff --git a/packages/playground/cases/react/class-component-disableTransformByDefault/src/index.jsx b/packages/playground/cases/react/class-component-disableTransformByDefault/src/index.jsx new file mode 100644 index 00000000000..18f79ce0697 --- /dev/null +++ b/packages/playground/cases/react/class-component-disableTransformByDefault/src/index.jsx @@ -0,0 +1,6 @@ +import React from 'react' +import { createRoot } from 'react-dom/client' +import { App } from './App' + +const container = createRoot(document.getElementById('root')) +container.render() diff --git a/packages/playground/cases/react/tailwindcss-disableTransformByDefault/index.test.ts b/packages/playground/cases/react/tailwindcss-disableTransformByDefault/index.test.ts new file mode 100644 index 00000000000..72eda5d7793 --- /dev/null +++ b/packages/playground/cases/react/tailwindcss-disableTransformByDefault/index.test.ts @@ -0,0 +1,32 @@ +import { test, expect } from "@/fixtures"; + +test("tailwindcss should work when modify js file", async ({ + page, + fileAction, + rspack +}) => { + function getAppFontSize() { + return page.evaluate(() => { + const app = document.querySelector("#app"); + if (!app) { + return ""; + } + return window.getComputedStyle(app).fontSize; + }); + } + + let appFontSize = await getAppFontSize(); + expect(appFontSize).toBe("24px"); + + // update + fileAction.updateFile("src/App.jsx", content => { + return content.replace("text-2xl", "text-3xl"); + }); + await rspack.waitingForHmr(async () => { + const classNames = await page.getAttribute("#app", "class"); + return classNames?.includes("text-3xl") || false; + }); + + appFontSize = await getAppFontSize(); + expect(appFontSize).toBe("30px"); +}); diff --git a/packages/playground/cases/react/tailwindcss-disableTransformByDefault/rspack.config.js b/packages/playground/cases/react/tailwindcss-disableTransformByDefault/rspack.config.js new file mode 100644 index 00000000000..2ea530d10ab --- /dev/null +++ b/packages/playground/cases/react/tailwindcss-disableTransformByDefault/rspack.config.js @@ -0,0 +1,62 @@ +const path = require("path"); +const rspack = require("@rspack/core"); +const ReactRefreshPlugin = require("@rspack/plugin-react-refresh"); + +module.exports = { + experiments: { + rspackFuture: { + disableTransformByDefault: true + } + }, + context: __dirname, + entry: { + main: "./src/main.jsx" + }, + plugins: [ + new rspack.HtmlRspackPlugin({ template: "./src/index.html" }), + new ReactRefreshPlugin() + ], + module: { + rules: [ + { + test: /\.jsx$/, + use: { + loader: "builtin:swc-loader", + options: { + jsc: { + parser: { + syntax: "ecmascript", + jsx: true + }, + transform: { + react: { + runtime: "automatic", + development: true, + refresh: true + } + } + } + } + } + }, + { + test: /\.css$/, + use: [ + { + loader: "postcss-loader", + options: { + postcssOptions: { + plugins: { + tailwindcss: { + config: path.join(__dirname, "./tailwind.config.js") + } + } + } + } + } + ], + type: "css" + } + ] + } +}; diff --git a/packages/playground/cases/react/tailwindcss-disableTransformByDefault/src/App.css b/packages/playground/cases/react/tailwindcss-disableTransformByDefault/src/App.css new file mode 100644 index 00000000000..6300d8a49d6 --- /dev/null +++ b/packages/playground/cases/react/tailwindcss-disableTransformByDefault/src/App.css @@ -0,0 +1,10 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +#root { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} diff --git a/packages/playground/cases/react/tailwindcss-disableTransformByDefault/src/App.jsx b/packages/playground/cases/react/tailwindcss-disableTransformByDefault/src/App.jsx new file mode 100644 index 00000000000..51826c77656 --- /dev/null +++ b/packages/playground/cases/react/tailwindcss-disableTransformByDefault/src/App.jsx @@ -0,0 +1,12 @@ +import React from "react"; +import "./App.css"; + +function App() { + return ( +

+ Hello world! +

+ ); +} + +export default App; diff --git a/packages/playground/cases/react/tailwindcss-disableTransformByDefault/src/index.html b/packages/playground/cases/react/tailwindcss-disableTransformByDefault/src/index.html new file mode 100644 index 00000000000..127a457455b --- /dev/null +++ b/packages/playground/cases/react/tailwindcss-disableTransformByDefault/src/index.html @@ -0,0 +1,12 @@ + + + + + + + Document + + +
+ + diff --git a/packages/playground/cases/react/tailwindcss-disableTransformByDefault/src/main.jsx b/packages/playground/cases/react/tailwindcss-disableTransformByDefault/src/main.jsx new file mode 100644 index 00000000000..d0d585c0881 --- /dev/null +++ b/packages/playground/cases/react/tailwindcss-disableTransformByDefault/src/main.jsx @@ -0,0 +1,5 @@ +import React from "react"; +import ReactDOM from "react-dom/client"; +import App from "./App"; + +ReactDOM.createRoot(document.getElementById("root")).render(); diff --git a/packages/playground/cases/react/tailwindcss-disableTransformByDefault/tailwind.config.js b/packages/playground/cases/react/tailwindcss-disableTransformByDefault/tailwind.config.js new file mode 100644 index 00000000000..c0d9e5130a2 --- /dev/null +++ b/packages/playground/cases/react/tailwindcss-disableTransformByDefault/tailwind.config.js @@ -0,0 +1,9 @@ +/** @type {import('tailwindcss').Config} */ +const path = require("path"); +module.exports = { + content: [path.join(__dirname, "./src/**/*.{html,js,jsx}")], + theme: { + extend: {} + }, + plugins: [] +}; diff --git a/packages/playground/cases/react/with-babel/index.test.ts b/packages/playground/cases/react/with-babel/index.test.ts new file mode 100644 index 00000000000..33fefe02749 --- /dev/null +++ b/packages/playground/cases/react/with-babel/index.test.ts @@ -0,0 +1,59 @@ +import { test, expect } from "@/fixtures"; + +test("render should work", async ({ page }) => { + expect(await page.textContent(".header")).toBe("Hello World"); + expect(await page.textContent("#lazy-component")).toBe("Lazy Component"); +}); + +test("hmr should work", async ({ page, fileAction, rspack }) => { + expect(await page.textContent("button")).toBe("10"); + await page.click("button"); + expect(await page.textContent("button")).toBe("11"); + expect(await page.textContent(".placeholder")).toBe("__PLACE_HOLDER__"); + fileAction.updateFile("src/App.jsx", content => + content.replace("__PLACE_HOLDER__", "__EDITED__") + ); + await rspack.waitingForHmr(async function () { + return (await page.textContent(".placeholder")) === "__EDITED__"; + }); + expect(await page.textContent("button")).toBe("11"); +}); + +test("context+component should work", async ({ page, fileAction, rspack }) => { + expect(await page.textContent("#context")).toBe("context-value"); + await page.click("#context"); + expect(await page.textContent("#context")).toBe("context-value-click"); + fileAction.updateFile("src/CountProvider.jsx", content => + content.replace("context-value", "context-value-update") + ); + await rspack.waitingForHmr(async function () { + return (await page.textContent("#context")) === "context-value-update"; + }); +}); + +test("ReactRefreshFinder should work", async ({ page }) => { + expect(await page.textContent("#nest-function")).toBe("nest-function"); +}); + +test("update same export name from different module should work", async ({ + page, + fileAction, + rspack +}) => { + expect(await page.textContent(".same-export-name1")).toBe("__NAME_1__"); + expect(await page.textContent(".same-export-name2")).toBe("__NAME_2__"); + fileAction.updateFile("src/SameExportName1.jsx", content => + content.replace("__NAME_1__", "__name_1__") + ); + await rspack.waitingForHmr(async function () { + return (await page.textContent(".same-export-name1")) === "__name_1__"; + }); + expect(await page.textContent(".same-export-name2")).toBe("__NAME_2__"); + fileAction.updateFile("src/SameExportName2.jsx", content => + content.replace("__NAME_2__", "__name_2__") + ); + await rspack.waitingForHmr(async function () { + return (await page.textContent(".same-export-name2")) === "__name_2__"; + }); + expect(await page.textContent(".same-export-name1")).toBe("__name_1__"); +}); diff --git a/packages/playground/cases/react/with-babel/rspack.config.js b/packages/playground/cases/react/with-babel/rspack.config.js new file mode 100644 index 00000000000..127adbe0308 --- /dev/null +++ b/packages/playground/cases/react/with-babel/rspack.config.js @@ -0,0 +1,43 @@ +const rspack = require("@rspack/core"); +const ReactRefreshPlugin = require("@rspack/plugin-react-refresh"); + +/** @type { import('@rspack/core').RspackOptions } */ +module.exports = { + experiments: { + rspackFuture: { + disableTransformByDefault: true + } + }, + context: __dirname, + mode: "development", + module: { + rules: [ + { + test: /\.jsx$/, + use: { + loader: "babel-loader", + options: { + presets: [["@babel/preset-react", { runtime: "automatic" }]], + plugins: [require.resolve("react-refresh/babel")] + } + } + } + ] + }, + plugins: [ + new rspack.HtmlRspackPlugin({ template: "./src/index.html" }), + new ReactRefreshPlugin() + ], + entry: "./src/index.jsx", + devServer: { + hot: true + }, + cache: false, + stats: "none", + infrastructureLogging: { + debug: false + }, + watchOptions: { + poll: 1000 + } +}; diff --git a/packages/playground/cases/react/with-babel/src/App.jsx b/packages/playground/cases/react/with-babel/src/App.jsx new file mode 100644 index 00000000000..a72ff3a972a --- /dev/null +++ b/packages/playground/cases/react/with-babel/src/App.jsx @@ -0,0 +1,30 @@ +import React from 'react' +import './index.css' +import { ContextComponent } from './CountProvider' +import { ReactRefreshFinder } from './ReactRefreshFinder' +import { SameExportName as SameExportName1 } from './SameExportName1' +import { SameExportName as SameExportName2 } from './SameExportName2' + +const Button = () => { + const [count, setCount] = React.useState(10) + return +} + +const LazyComponent = React.lazy(() => import('./LazyComponent')) + +export const App = () => { + return ( +
+
Hello World
+
}> + + + + ) +} diff --git a/packages/playground/cases/react/with-babel/src/CountProvider.jsx b/packages/playground/cases/react/with-babel/src/CountProvider.jsx new file mode 100644 index 00000000000..afbe1fcbe34 --- /dev/null +++ b/packages/playground/cases/react/with-babel/src/CountProvider.jsx @@ -0,0 +1,19 @@ +import React from 'react'; + +export const CountContext = React.createContext(); + +export function CountProvider({ children }) { + const [count, setCount] = React.useState('context-value'); + return ( + + {children} + + ); +} + +export function ContextComponent() { + const { count, setCount } = React.useContext(CountContext); + return
setCount((count) => count + '-click')}> + {count} +
+} \ No newline at end of file diff --git a/packages/playground/cases/react/with-babel/src/LazyComponent.css b/packages/playground/cases/react/with-babel/src/LazyComponent.css new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/playground/cases/react/with-babel/src/LazyComponent.jsx b/packages/playground/cases/react/with-babel/src/LazyComponent.jsx new file mode 100644 index 00000000000..65545394690 --- /dev/null +++ b/packages/playground/cases/react/with-babel/src/LazyComponent.jsx @@ -0,0 +1,7 @@ +import './LazyComponent.css' + +function LazyComponent () { + return
Lazy Component
+} + +export default LazyComponent diff --git a/packages/playground/cases/react/with-babel/src/ReactRefreshFinder.jsx b/packages/playground/cases/react/with-babel/src/ReactRefreshFinder.jsx new file mode 100644 index 00000000000..83b0509d747 --- /dev/null +++ b/packages/playground/cases/react/with-babel/src/ReactRefreshFinder.jsx @@ -0,0 +1,10 @@ +import React, { useState } from 'react'; + +function CreateReactRefreshFinder() { + return function Component() { + useState(1); + return
nest-function
; + }; +} + +export const ReactRefreshFinder = CreateReactRefreshFinder() \ No newline at end of file diff --git a/packages/playground/cases/react/with-babel/src/SameExportName1.jsx b/packages/playground/cases/react/with-babel/src/SameExportName1.jsx new file mode 100644 index 00000000000..2a7f2b45f15 --- /dev/null +++ b/packages/playground/cases/react/with-babel/src/SameExportName1.jsx @@ -0,0 +1,3 @@ +export function SameExportName() { + return
__NAME_1__
+} diff --git a/packages/playground/cases/react/with-babel/src/SameExportName2.jsx b/packages/playground/cases/react/with-babel/src/SameExportName2.jsx new file mode 100644 index 00000000000..8bf62ab6bb5 --- /dev/null +++ b/packages/playground/cases/react/with-babel/src/SameExportName2.jsx @@ -0,0 +1,3 @@ +export function SameExportName() { + return
__NAME_2__
+} diff --git a/packages/playground/cases/react/with-babel/src/index.css b/packages/playground/cases/react/with-babel/src/index.css new file mode 100644 index 00000000000..753f48a591f --- /dev/null +++ b/packages/playground/cases/react/with-babel/src/index.css @@ -0,0 +1,3 @@ +body { + background-color: rgba(0, 0, 0, 0); +} diff --git a/packages/playground/cases/react/with-babel/src/index.html b/packages/playground/cases/react/with-babel/src/index.html new file mode 100644 index 00000000000..127a457455b --- /dev/null +++ b/packages/playground/cases/react/with-babel/src/index.html @@ -0,0 +1,12 @@ + + + + + + + Document + + +
+ + diff --git a/packages/playground/cases/react/with-babel/src/index.jsx b/packages/playground/cases/react/with-babel/src/index.jsx new file mode 100644 index 00000000000..52e72c3334e --- /dev/null +++ b/packages/playground/cases/react/with-babel/src/index.jsx @@ -0,0 +1,11 @@ +import React from "react"; +import { createRoot } from "react-dom/client"; +import { App } from './App'; +import { CountProvider } from "./CountProvider"; + +const container = createRoot(document.getElementById("root")); +container.render( + + + +); diff --git a/packages/playground/cases/react/worker-disableTransformByDefault/index.test.ts b/packages/playground/cases/react/worker-disableTransformByDefault/index.test.ts new file mode 100644 index 00000000000..e5cf91b389c --- /dev/null +++ b/packages/playground/cases/react/worker-disableTransformByDefault/index.test.ts @@ -0,0 +1,13 @@ +import { test, expect } from "@/fixtures"; + +test("should successfully render the page", async ({ page }) => { + expect(await page.textContent("button")).toBe("+"); + expect(await page.textContent("h1")).toBe("0"); +}); + +// test("worker should work", async ({ page, fileAction, rspack }) => { +// await page.click("button"); +// expect(await page.textContent("h1")).toBe("1"); +// await page.click("button"); +// expect(await page.textContent("h1")).toBe("2"); +// }); diff --git a/packages/playground/cases/react/worker-disableTransformByDefault/rspack.config.js b/packages/playground/cases/react/worker-disableTransformByDefault/rspack.config.js new file mode 100644 index 00000000000..b3cc8c5472d --- /dev/null +++ b/packages/playground/cases/react/worker-disableTransformByDefault/rspack.config.js @@ -0,0 +1,54 @@ +const rspack = require("@rspack/core"); +const ReactRefreshPlugin = require("@rspack/plugin-react-refresh"); + +/** @type { import('@rspack/core').RspackOptions } */ +module.exports = { + experiments: { + rspackFuture: { + disableTransformByDefault: true + } + }, + context: __dirname, + mode: "development", + entry: "./src/index.jsx", + module: { + rules: [ + { + test: /\.jsx$/, + use: { + loader: "builtin:swc-loader", + options: { + jsc: { + parser: { + syntax: "ecmascript", + jsx: true + }, + transform: { + react: { + runtime: "automatic", + development: true, + refresh: true + } + } + } + } + } + } + ] + }, + plugins: [ + new rspack.HtmlRspackPlugin({ template: "./src/index.html" }), + new ReactRefreshPlugin() + ], + devServer: { + hot: true + }, + cache: false, + stats: "none", + infrastructureLogging: { + debug: false + }, + watchOptions: { + poll: 1000 + } +}; diff --git a/packages/playground/cases/react/worker-disableTransformByDefault/src/App.jsx b/packages/playground/cases/react/worker-disableTransformByDefault/src/App.jsx new file mode 100644 index 00000000000..9ccfd1f8ac4 --- /dev/null +++ b/packages/playground/cases/react/worker-disableTransformByDefault/src/App.jsx @@ -0,0 +1,21 @@ +import React, { useState } from "react"; +import Button from './Button' + +let updateRenderTimes; + +const worker = new Worker(new URL("./worker", import.meta.url)); + +worker.onmessage = (e) => { + updateRenderTimes(e.data) +} + +export const App = () => { + const [renderTimes, setRenderTimes] = useState(0) + updateRenderTimes = setRenderTimes; + return ( +
+

{renderTimes}

+
+ ); +}; diff --git a/packages/playground/cases/react/worker-disableTransformByDefault/src/Button.jsx b/packages/playground/cases/react/worker-disableTransformByDefault/src/Button.jsx new file mode 100644 index 00000000000..ddaa59b3bee --- /dev/null +++ b/packages/playground/cases/react/worker-disableTransformByDefault/src/Button.jsx @@ -0,0 +1,15 @@ +import React from "react"; + +export default function Button({ onClick }) { + return ; +}; + +Button.count = 0; + +Button.get = () => { + return Button.count; +} + +Button.add = () => { + Button.count += 1; +} diff --git a/packages/playground/cases/react/worker-disableTransformByDefault/src/index.html b/packages/playground/cases/react/worker-disableTransformByDefault/src/index.html new file mode 100644 index 00000000000..127a457455b --- /dev/null +++ b/packages/playground/cases/react/worker-disableTransformByDefault/src/index.html @@ -0,0 +1,12 @@ + + + + + + + Document + + +
+ + diff --git a/packages/playground/cases/react/worker-disableTransformByDefault/src/index.jsx b/packages/playground/cases/react/worker-disableTransformByDefault/src/index.jsx new file mode 100644 index 00000000000..032d1403b0c --- /dev/null +++ b/packages/playground/cases/react/worker-disableTransformByDefault/src/index.jsx @@ -0,0 +1,6 @@ +import React from "react"; +import { createRoot } from "react-dom/client"; +import { App } from './App'; + +const container = createRoot(document.getElementById("root")); +container.render(); diff --git a/packages/playground/cases/react/worker-disableTransformByDefault/src/worker.js b/packages/playground/cases/react/worker-disableTransformByDefault/src/worker.js new file mode 100644 index 00000000000..01baa84f07d --- /dev/null +++ b/packages/playground/cases/react/worker-disableTransformByDefault/src/worker.js @@ -0,0 +1,6 @@ +import Button from "./Button"; + +onmessage = e => { + Button.add(); + postMessage(Button.get()); +}; diff --git a/packages/playground/fixtures/index.ts b/packages/playground/fixtures/index.ts index 5358095e7c7..57c677c5fec 100644 --- a/packages/playground/fixtures/index.ts +++ b/packages/playground/fixtures/index.ts @@ -5,7 +5,8 @@ import { fileActionFixtures } from "./fileAction"; const test = base .extend(pathInfoFixtures) - .extend(rspackFixtures) + .extend(rspackFixtures(true)) + .extend(rspackFixtures(false)) .extend(fileActionFixtures); export type { RspackOptions }; diff --git a/packages/playground/fixtures/rspack.ts b/packages/playground/fixtures/rspack.ts index 5098b5fd90a..41dd4c21126 100644 --- a/packages/playground/fixtures/rspack.ts +++ b/packages/playground/fixtures/rspack.ts @@ -2,16 +2,18 @@ import path from "path"; import { Fixtures, PlaywrightTestArgs } from "@playwright/test"; import { Compiler, Configuration, createCompiler } from "@rspack/core"; import { RspackDevServer } from "@rspack/dev-server"; +import WebpackDevServer from "webpack-dev-server"; import type { PathInfoFixtures } from "./pathInfo"; import { sleep } from "@/utils/sleep"; class Rspack { projectDir: string; compiler: Compiler; - devServer: RspackDevServer; + devServer: RspackDevServer | WebpackDevServer; private onDone: Array<() => void> = []; constructor( projectDir: string, + wds: boolean, handleRspackConfig: (config: Configuration) => Configuration ) { const configPath = path.resolve(projectDir, "rspack.config.js"); @@ -28,7 +30,8 @@ class Rspack { item(); } }); - this.devServer = new RspackDevServer( + const DevServerConstructor = wds ? WebpackDevServer : RspackDevServer; + this.devServer = new DevServerConstructor( compiler.options.devServer ?? {}, compiler ); @@ -79,84 +82,88 @@ type RspackWorkerFixtures = { ) => Promise; }; -export const rspackFixtures: Fixtures< +export const rspackFixtures = ( + wds: boolean +): Fixtures< RspackOptions & RspackFixtures, RspackWorkerFixtures, PlaywrightTestArgs & PathInfoFixtures -> = { - defaultRspackConfig: [{ handleConfig: c => c }, { option: true }], - rspack: [ - async ( - { page, pathInfo, _startRspackServer, defaultRspackConfig }, - use - ) => { - const rspack = await _startRspackServer( - pathInfo.testFile, - pathInfo.tempProjectDir, - defaultRspackConfig.handleConfig - ); - const port = rspack.devServer.options.port; - await rspack.waitingForBuild(); - await page.goto(`http://localhost:${port}`); - await use(rspack); - }, - { - auto: true - } - ], +> => { + return { + defaultRspackConfig: [{ handleConfig: c => c }, { option: true }], + rspack: [ + async ( + { page, pathInfo, _startRspackServer, defaultRspackConfig }, + use + ) => { + const rspack = await _startRspackServer( + pathInfo.testFile, + pathInfo.tempProjectDir, + defaultRspackConfig.handleConfig + ); + const port = rspack.devServer.options.port; + await rspack.waitingForBuild(); + await page.goto(`http://localhost:${port}`); + await use(rspack); + }, + { + auto: true + } + ], - _startRspackServer: [ - async ({}, use, { workerIndex }) => { - let currentTestFile = ""; - let rspack: Rspack | null = null as any; - await use(async function (testFile, projectDir, handleRspackConfig) { - if (rspack && currentTestFile !== testFile) { - await rspack.devServer.stop(); - rspack = null; - currentTestFile = testFile; - } - if (!rspack) { - const port = 8000 + workerIndex; - rspack = new Rspack(projectDir, function (config) { - // rewrite port - if (!config.devServer) { - config.devServer = {}; - } - config.devServer.port = port; + _startRspackServer: [ + async ({}, use, { workerIndex }) => { + let currentTestFile = ""; + let rspack: Rspack | null = null as any; + await use(async function (testFile, projectDir, handleRspackConfig) { + if (rspack && currentTestFile !== testFile) { + await rspack.devServer.stop(); + rspack = null; + currentTestFile = testFile; + } + if (!rspack) { + const port = 8000 + workerIndex; + rspack = new Rspack(projectDir, wds, function (config) { + // rewrite port + if (!config.devServer) { + config.devServer = {}; + } + config.devServer.port = port; - // set default context - if (!config.context) { - config.context = projectDir; - } + // set default context + if (!config.context) { + config.context = projectDir; + } - // set default define - if (!config.builtins) { - config.builtins = {}; - } - config.builtins.define = Object.assign( - { - "process.env.NODE_ENV": JSON.stringify( - config.mode || "development" - ) - }, - config.builtins.define - ); + // set default define + if (!config.builtins) { + config.builtins = {}; + } + config.builtins.define = Object.assign( + { + "process.env.NODE_ENV": JSON.stringify( + config.mode || "development" + ) + }, + config.builtins.define + ); - return handleRspackConfig(config); - }); - await rspack.devServer.start(); - } + return handleRspackConfig(config); + }); + await rspack.devServer.start(); + } - return rspack; - }); + return rspack; + }); - if (rspack?.projectDir) { - await rspack.devServer.stop(); + if (rspack?.projectDir) { + await rspack.devServer.stop(); + } + }, + { + scope: "worker", + timeout: 60000 } - }, - { - scope: "worker", - timeout: 60000 - } - ] + ] + }; }; diff --git a/packages/playground/package.json b/packages/playground/package.json index 727b958a185..57c83908ac5 100644 --- a/packages/playground/package.json +++ b/packages/playground/package.json @@ -12,20 +12,24 @@ "directory": "packages/playground" }, "devDependencies": { + "@babel/core": "^7.22.20", + "@babel/preset-react": "^7.22.15", "@playwright/test": "1.35.0", "@rspack/core": "workspace:*", - "@rspack/plugin-react-refresh": "workspace:*", "@rspack/dev-client": "workspace:*", "@rspack/dev-server": "workspace:*", + "@rspack/plugin-react-refresh": "workspace:*", "@types/fs-extra": "11.0.1", + "babel-loader": "^9.1.3", "fs-extra": "11.1.1", "postcss": "^8.4.21", "postcss-loader": "^7.3.0", "react": "^18.2.0", "react-dom": "^18.2.0", "tailwindcss": "^3.3.0", - "ws": "8.8.1", "vue": "3.2.47", - "vue-loader": "^17.2.2" + "vue-loader": "^17.2.2", + "webpack-dev-server": "4.13.1", + "ws": "8.8.1" } } \ No newline at end of file diff --git a/packages/rspack-cli/package.json b/packages/rspack-cli/package.json index 2d6f2eca4e4..27e9d2fdf77 100644 --- a/packages/rspack-cli/package.json +++ b/packages/rspack-cli/package.json @@ -1,6 +1,6 @@ { "name": "@rspack/cli", - "version": "0.3.2", + "version": "0.3.4", "license": "MIT", "description": "CLI for rspack", "bin": { diff --git a/packages/rspack-cli/src/utils/profile.ts b/packages/rspack-cli/src/utils/profile.ts index 0fd45650da5..f3e293e1fde 100644 --- a/packages/rspack-cli/src/utils/profile.ts +++ b/packages/rspack-cli/src/utils/profile.ts @@ -1,3 +1,36 @@ +/* +The full syntax, remember update this when you change something in this file. + +`RSPACK_PROFILE='TRACE=filter=trace&output=./rspack.trace&layer=chrome|JSCPU=output=./rspack.jscpuprofile|LOGGING=output=./rspack.logging' rspack build` + ^----------------------------------------------: querystring syntax trace options + ^: | is a delimiter for different profile options + ^---------------------------------: querystring syntax js cpuprofile options + ^: | is a delimiter for different profile options + ^------------------------------: querystring syntax stats.logging options + ^-----------: trace filter, default to `trace`, more syntax: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#example-syntax + ^--------------------: trace output, `stderr`, `stdout`, or a file path, default to `./.rspack-profile-${timestamp}/trace.json` for layer `chrome` and default to `stdout` for layer `logger` + ^-----------: trace layer, `chrome` or `logger`, default to `chrome` + ^---------------------------: js cpuprofile output, `stderr`, `stdout`, or a file path, default to `./.rspack-profile-${timestamp}/jscpuprofile.json` + ^----------------------: stats.logging output, default to `./.rspack-profile-${timestamp}/logging.json` + +`RSPACK_PROFILE='TRACE=filter=trace&output=./rspack.trace&layer=chrome' rspack build`: only enable trace + +`RSPACK_PROFILE=TRACE rspack build`: only enable trace, and use default options for trace + +`RSPACK_PROFILE='JSCPU=output=./rspack.jscpuprofile' rspack build`: only enable js cpuprofile + +`RSPACK_PROFILE=JSCPU rspack build`: only enable js cpuprofile, and use default options for js cpuprofile + +`RSPACK_PROFILE='LOGGING=output=./rspack.logging' rspack build`: only enable stats.logging + +`RSPACK_PROFILE=LOGGING rspack build`: only enable stats.logging, and use default options for stats.logging + +`RSPACK_PROFILE=ALL rspack build`: enable all, and use default options + +`RSPACK_PROFILE=[rspack_node,rspack_core] rspack build`: enable all, but customize trace filter + +*/ + import inspector from "inspector"; import fs from "fs"; import path from "path"; diff --git a/packages/rspack-dev-client/package.json b/packages/rspack-dev-client/package.json index 9d3317c5d4e..264b4f5431b 100644 --- a/packages/rspack-dev-client/package.json +++ b/packages/rspack-dev-client/package.json @@ -1,6 +1,6 @@ { "name": "@rspack/dev-client", - "version": "0.3.2", + "version": "0.3.4", "license": "MIT", "description": "Development client for rspack", "scripts": { diff --git a/packages/rspack-dev-server/package.json b/packages/rspack-dev-server/package.json index 047bbdcfd1f..4abdfc4f58f 100644 --- a/packages/rspack-dev-server/package.json +++ b/packages/rspack-dev-server/package.json @@ -1,6 +1,6 @@ { "name": "@rspack/dev-server", - "version": "0.3.2", + "version": "0.3.4", "license": "MIT", "description": "Development server for rspack", "main": "./dist/index.js", diff --git a/packages/rspack-dev-server/src/server.ts b/packages/rspack-dev-server/src/server.ts index b7731665383..3506b9534d6 100644 --- a/packages/rspack-dev-server/src/server.ts +++ b/packages/rspack-dev-server/src/server.ts @@ -154,12 +154,35 @@ export class RspackDevServer extends WebpackDevServer { "Make sure to disable HMR for production by setting `devServer.hot` to `false` in the configuration." ); } + // enable hot by default compiler.options.devServer ??= {}; compiler.options.devServer.hot = true; - compiler.options.builtins.react ??= {}; - compiler.options.builtins.react.refresh ??= true; - compiler.options.builtins.react.development ??= true; - new ReactRefreshPlugin().apply(compiler); + if ( + !compiler.options.experiments.rspackFuture.disableTransformByDefault + ) { + compiler.options.builtins.react ??= {}; + // enable react.development by default + compiler.options.builtins.react.development ??= true; + // enable react.refresh by default + compiler.options.builtins.react.refresh ??= true; + if (compiler.options.builtins.react.refresh) { + const runtimePaths = ReactRefreshPlugin.deprecated_runtimePaths; + new compiler.webpack.EntryPlugin( + compiler.context, + runtimePaths[0], + { + name: undefined + } + ).apply(compiler); + new compiler.webpack.ProvidePlugin({ + $ReactRefreshRuntime$: runtimePaths[1] + }).apply(compiler); + compiler.options.module.rules.unshift({ + include: runtimePaths, + type: "js" + }); + } + } } else if (compiler.options.builtins.react.refresh) { if (mode === "production") { this.logger.warn( diff --git a/packages/rspack-dev-server/tests/__snapshots__/normalizeOptions.test.ts.snap b/packages/rspack-dev-server/tests/__snapshots__/normalizeOptions.test.ts.snap index 77c7fc6b02a..b1998299d23 100644 --- a/packages/rspack-dev-server/tests/__snapshots__/normalizeOptions.test.ts.snap +++ b/packages/rspack-dev-server/tests/__snapshots__/normalizeOptions.test.ts.snap @@ -139,3 +139,15 @@ exports[`normalize options snapshot react-refresh client added when react/refres ], } `; + +exports[`normalize options snapshot shouldn't have reactRefreshEntry.js when react.refresh is false 1`] = ` +{ + "main": [ + "/./placeholder.js", + ], + "undefined": [ + "/webpack-dev-server/client/index.js?protocol=ws%3A&hostname=0.0.0.0&&pathname=%2Fws&logging=info&overlay=true&reconnect=10&hot=true&live-reload=true", + "/webpack/hot/dev-server.js", + ], +} +`; diff --git a/packages/rspack-dev-server/tests/normalizeOptions.test.ts b/packages/rspack-dev-server/tests/normalizeOptions.test.ts index 7951141955d..d71e6832fc2 100644 --- a/packages/rspack-dev-server/tests/normalizeOptions.test.ts +++ b/packages/rspack-dev-server/tests/normalizeOptions.test.ts @@ -1,6 +1,7 @@ import { RspackOptions, rspack } from "@rspack/core"; import { RspackDevServer, Configuration } from "@rspack/dev-server"; import { createCompiler } from "@rspack/core"; +import ReactRefreshPlugin from "@rspack/plugin-react-refresh"; import serializer from "jest-serializer-path"; expect.addSnapshotSerializer(serializer); @@ -24,26 +25,71 @@ describe("normalize options snapshot", () => { }); it("additional entires should added", async () => { - await matchAdditionEntries( + expect( + await getAdditionEntries({}, { entry: ["something"] }) + ).toMatchSnapshot(); + }); + + it("react-refresh client added when react/refresh enabled", async () => { + expect( + await getAdditionEntries( + {}, + { + entry: ["something"], + builtins: { + react: { + refresh: true + } + } + } + ) + ).toMatchSnapshot(); + }); + + it("shouldn't have reactRefreshEntry.js when react.refresh is false", async () => { + expect( + await getAdditionEntries( + {}, + { + entry: ["something"], + builtins: { + react: { + refresh: false + } + } + } + ) + ).toMatchSnapshot(); + }); + + it("shouldn't have reactRefreshEntry.js by default when rspackFuture.disableReactRefreshByDefault is enabled", async () => { + const reactRefreshEntry = + "/rspack-plugin-react-refresh/client/reactRefreshEntry.js"; + const entries1 = await getAdditionEntries( {}, { - entry: ["something"] + entry: ["something"], + experiments: { + rspackFuture: { + disableTransformByDefault: true + } + } } ); - }); - - it("react-refresh client added when react/refresh enabled", async () => { - await matchAdditionEntries( + expect(entries1["undefined"]).not.toContain(reactRefreshEntry); + const entries2 = await getAdditionEntries( {}, { entry: ["something"], - builtins: { - react: { - refresh: true + plugins: [new ReactRefreshPlugin()], + experiments: { + rspackFuture: { + disableTransformByDefault: true } } } ); + expect(entries2["undefined"]).toContain(reactRefreshEntry); }); it("react.development and react.refresh should be true by default when hot enabled", async () => { @@ -110,7 +156,7 @@ async function match(config: RspackOptions) { await server.stop(); } -async function matchAdditionEntries( +async function getAdditionEntries( serverConfig: Configuration, config: RspackOptions ) { @@ -123,9 +169,8 @@ async function matchAdditionEntries( const server = new RspackDevServer(serverConfig, compiler); await server.start(); const entries = compiler.builtinPlugins - .map(p => p.raw()) - .filter(p => p.kind === "Entry" /* BuiltinPluginKind.Entry */) - .map(p => p.options) + .filter(p => p.name === "EntryPlugin") + .map(p => p.raw().options) .reduce((acc, cur: any) => { const name = cur.options.name; const request = cur.entry; @@ -149,6 +194,6 @@ async function matchAdditionEntries( return [key, replaced]; }) ); - expect(value).toMatchSnapshot(); await server.stop(); + return value; } diff --git a/packages/rspack-plugin-html/package.json b/packages/rspack-plugin-html/package.json index 18ed78ce0c4..657c44baa57 100644 --- a/packages/rspack-plugin-html/package.json +++ b/packages/rspack-plugin-html/package.json @@ -1,6 +1,6 @@ { "name": "@rspack/plugin-html", - "version": "0.3.2", + "version": "0.3.4", "license": "MIT", "description": "HTML plugin for rspack", "main": "index.cjs", diff --git a/packages/rspack-plugin-minify/package.json b/packages/rspack-plugin-minify/package.json index 95af1e1d0b7..23915a5c5c1 100644 --- a/packages/rspack-plugin-minify/package.json +++ b/packages/rspack-plugin-minify/package.json @@ -1,6 +1,6 @@ { "name": "@rspack/plugin-minify", - "version": "0.3.2", + "version": "0.3.4", "license": "MIT", "description": "Minify plugin for rspack", "main": "src/index.js", diff --git a/packages/rspack-plugin-node-polyfill/package.json b/packages/rspack-plugin-node-polyfill/package.json index 5754f26ca97..ae672c31bcd 100644 --- a/packages/rspack-plugin-node-polyfill/package.json +++ b/packages/rspack-plugin-node-polyfill/package.json @@ -1,6 +1,6 @@ { "name": "@rspack/plugin-node-polyfill", - "version": "0.3.2", + "version": "0.3.4", "license": "MIT", "description": "Node polyfill plugin for rspack", "main": "src/index.js", diff --git a/packages/rspack-plugin-react-refresh/client/reactRefreshEntry.js b/packages/rspack-plugin-react-refresh/client/reactRefreshEntry.js index 26eb38307b3..89fc7535f53 100644 --- a/packages/rspack-plugin-react-refresh/client/reactRefreshEntry.js +++ b/packages/rspack-plugin-react-refresh/client/reactRefreshEntry.js @@ -1,4 +1,50 @@ -const RefreshRuntime = require("react-refresh/runtime"); +/** + * The following code is modified based on + * https://github.com/pmmmwh/react-refresh-webpack-plugin/blob/0b960573797bf38926937994c481e4fec9ed8aa6/client/ReactRefreshEntry.js + * + * MIT Licensed + * Author Michael Mok + * Copyright (c) 2019 Michael Mok + * https://github.com/pmmmwh/react-refresh-webpack-plugin/blob/0b960573797bf38926937994c481e4fec9ed8aa6/LICENSE + */ -RefreshRuntime.injectIntoGlobalHook(self); -self.$RefreshSig$ = RefreshRuntime.createSignatureFunctionForTransform; +var RefreshRuntime = require("react-refresh/runtime"); +var safeThis = (function () { + // copied from core-js-pure/features/global-this + "use strict"; + + var check = function (it) { + return it && it.Math == Math && it; + }; + + // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028 + // eslint-disable-next-line es/no-global-this -- safe + return ( + check(typeof globalThis == "object" && globalThis) || + check(typeof window == "object" && window) || + // eslint-disable-next-line no-restricted-globals -- safe + check(typeof self == "object" && self) || + check(typeof __webpack_require__.g == "object" && __webpack_require__.g) || + // eslint-disable-next-line no-new-func -- fallback + (function () { + return this; + })() || + this || + Function("return this")() + ); +})(); + +if (process.env.NODE_ENV !== "production") { + if (typeof safeThis !== "undefined") { + var $RefreshInjected$ = "__reactRefreshInjected"; + // Only inject the runtime if it hasn't been injected + if (!safeThis[$RefreshInjected$]) { + RefreshRuntime.injectIntoGlobalHook(safeThis); + safeThis.$RefreshSig$ = + RefreshRuntime.createSignatureFunctionForTransform; + + // Mark the runtime as injected to prevent double-injection + safeThis[$RefreshInjected$] = true; + } + } +} diff --git a/packages/rspack-plugin-react-refresh/package.json b/packages/rspack-plugin-react-refresh/package.json index bde2c1bd0e8..78351b08c09 100644 --- a/packages/rspack-plugin-react-refresh/package.json +++ b/packages/rspack-plugin-react-refresh/package.json @@ -1,6 +1,6 @@ { "name": "@rspack/plugin-react-refresh", - "version": "0.3.2", + "version": "0.3.4", "license": "MIT", "description": "React refresh plugin for rspack", "main": "src/index.js", @@ -10,9 +10,10 @@ "./react-refresh-entry": "./client/reactRefreshEntry.js" }, "scripts": { - "test": "echo success" + "test": "jest --runInBand" }, "files": [ + "client", "src" ], "publishConfig": { @@ -26,9 +27,12 @@ "directory": "packages/rspack-plugin-react-refresh" }, "dependencies": { - "@pmmmwh/react-refresh-webpack-plugin": "0.5.10" + "@pmmmwh/react-refresh-webpack-plugin": "0.5.10", + "schema-utils": "^4.0.0" }, "devDependencies": { + "@rspack/core": "workspace:*", + "@rspack/plugin-react-refresh": "workspace:*", "react-refresh": "0.14.0" }, "peerDependencies": { @@ -38,5 +42,12 @@ "react-refresh": { "optional": true } + }, + "jest": { + "watchPathIgnorePatterns": [ + "/dist", + "/tests/dist" + ], + "testEnvironment": "../../scripts/test/patch-node-env.cjs" } } diff --git a/packages/rspack-plugin-react-refresh/src/index.js b/packages/rspack-plugin-react-refresh/src/index.js index 92b057de0ed..567436fee99 100644 --- a/packages/rspack-plugin-react-refresh/src/index.js +++ b/packages/rspack-plugin-react-refresh/src/index.js @@ -1,6 +1,11 @@ const path = require("path"); +const { validate: validateOptions } = require("schema-utils"); + const reactRefreshPath = require.resolve("../client/reactRefresh.js"); const reactRefreshEntryPath = require.resolve("../client/reactRefreshEntry.js"); +const schema = require("./options.json"); +const { normalizeOptions } = require("./options"); + const refreshUtilsPath = require.resolve( "@pmmmwh/react-refresh-webpack-plugin/lib/runtime/RefreshUtils", { @@ -13,12 +18,32 @@ const refreshRuntimeDirPath = path.dirname( }) ); const runtimePaths = [ + reactRefreshEntryPath, reactRefreshPath, refreshUtilsPath, refreshRuntimeDirPath ]; +/** + * @typedef {Object} Options + * @property {(string | RegExp | (string | RegExp)[] | null)=} include included resourcePath for loader + * @property {(string | RegExp | (string | RegExp)[] | null)=} exclude excluded resourcePath for loader + */ + module.exports = class ReactRefreshRspackPlugin { + /** + * @param {Options} options + */ + constructor(options = {}) { + validateOptions(schema, options, { + name: "React Refresh Rspack Plugin", + baseDataPath: "options" + }); + /** + * @type {Options} + */ + this.options = normalizeOptions(options); + } apply(compiler) { new compiler.webpack.EntryPlugin(compiler.context, reactRefreshEntryPath, { name: undefined @@ -27,9 +52,14 @@ module.exports = class ReactRefreshRspackPlugin { $ReactRefreshRuntime$: reactRefreshPath }).apply(compiler); - compiler.options.module.rules.push({ - include: runtimePaths, - type: "js" + compiler.options.module.rules.unshift({ + include: this.options.include, + exclude: { + or: [this.options.exclude, [...runtimePaths]].filter(Boolean) + }, + use: "builtin:react-refresh-loader" }); } }; + +module.exports.deprecated_runtimePaths = runtimePaths; diff --git a/packages/rspack-plugin-react-refresh/src/options.js b/packages/rspack-plugin-react-refresh/src/options.js new file mode 100644 index 00000000000..5396d0aada6 --- /dev/null +++ b/packages/rspack-plugin-react-refresh/src/options.js @@ -0,0 +1,17 @@ +const d = (object, property, defaultValue) => { + if ( + typeof object[property] === "undefined" && + typeof defaultValue !== "undefined" + ) { + object[property] = defaultValue; + } + return object[property]; +}; + +const normalizeOptions = function (options) { + d(options, "exclude", /node_modules/i); + d(options, "include", /\.([cm]js|[jt]sx?|flow)$/i); + return options; +}; + +module.exports = { normalizeOptions }; diff --git a/packages/rspack-plugin-react-refresh/src/options.json b/packages/rspack-plugin-react-refresh/src/options.json new file mode 100644 index 00000000000..31a60acca20 --- /dev/null +++ b/packages/rspack-plugin-react-refresh/src/options.json @@ -0,0 +1,33 @@ +{ + "additionalProperties": false, + "type": "object", + "definitions": { + "Path": { "type": "string" }, + "MatchCondition": { + "anyOf": [ + { "instanceof": "RegExp" }, + { "$ref": "#/definitions/Path" }, + { "type": "null" } + ] + }, + "MatchConditions": { + "type": "array", + "items": { "$ref": "#/definitions/MatchCondition" }, + "minItems": 1 + } + }, + "properties": { + "exclude": { + "anyOf": [ + { "$ref": "#/definitions/MatchCondition" }, + { "$ref": "#/definitions/MatchConditions" } + ] + }, + "include": { + "anyOf": [ + { "$ref": "#/definitions/MatchCondition" }, + { "$ref": "#/definitions/MatchConditions" } + ] + } + } +} diff --git a/packages/rspack-plugin-react-refresh/tests/fixtures/.gitignore b/packages/rspack-plugin-react-refresh/tests/fixtures/.gitignore new file mode 100644 index 00000000000..736e8ae58ad --- /dev/null +++ b/packages/rspack-plugin-react-refresh/tests/fixtures/.gitignore @@ -0,0 +1 @@ +!node_modules \ No newline at end of file diff --git a/packages/rspack-plugin-react-refresh/tests/fixtures/custom/index.js b/packages/rspack-plugin-react-refresh/tests/fixtures/custom/index.js new file mode 100644 index 00000000000..347e2083214 --- /dev/null +++ b/packages/rspack-plugin-react-refresh/tests/fixtures/custom/index.js @@ -0,0 +1 @@ +require("foo"); diff --git a/packages/rspack-plugin-react-refresh/tests/fixtures/default/index.js b/packages/rspack-plugin-react-refresh/tests/fixtures/default/index.js new file mode 100644 index 00000000000..5882cb5bbc5 --- /dev/null +++ b/packages/rspack-plugin-react-refresh/tests/fixtures/default/index.js @@ -0,0 +1,2 @@ +require("foo"); +module.exports = "default"; diff --git a/packages/rspack-plugin-react-refresh/tests/fixtures/node_modules/foo/index.js b/packages/rspack-plugin-react-refresh/tests/fixtures/node_modules/foo/index.js new file mode 100644 index 00000000000..539eee6809a --- /dev/null +++ b/packages/rspack-plugin-react-refresh/tests/fixtures/node_modules/foo/index.js @@ -0,0 +1 @@ +module.exports = "foo" diff --git a/packages/rspack-plugin-react-refresh/tests/fixtures/node_modules/foo/package.json b/packages/rspack-plugin-react-refresh/tests/fixtures/node_modules/foo/package.json new file mode 100644 index 00000000000..9035eef7f7a --- /dev/null +++ b/packages/rspack-plugin-react-refresh/tests/fixtures/node_modules/foo/package.json @@ -0,0 +1,4 @@ +{ + "name": "foo", + "main": "./index.js" +} \ No newline at end of file diff --git a/packages/rspack-plugin-react-refresh/tests/test.spec.ts b/packages/rspack-plugin-react-refresh/tests/test.spec.ts new file mode 100644 index 00000000000..779e0714291 --- /dev/null +++ b/packages/rspack-plugin-react-refresh/tests/test.spec.ts @@ -0,0 +1,131 @@ +const fs = require("fs"); +const path = require("path"); +const { rspack } = require("@rspack/core"); +const ReactRefreshPlugin = require("@rspack/plugin-react-refresh"); + +const compileWithReactRefresh = (fixturePath, refreshOptions, callback) => { + let dist = path.join(fixturePath, "dist"); + rspack( + { + mode: "development", + context: fixturePath, + entry: { + fixture: path.join(fixturePath, "index.js") + }, + output: { + path: dist + }, + plugins: [new ReactRefreshPlugin(refreshOptions)], + optimization: { + runtimeChunk: { + name: "runtime" + }, + splitChunks: { + cacheGroups: { + reactRefresh: { + test: /[\\/](react-refresh|rspack-plugin-react-refresh\/client|react-refresh-webpack-plugin)[\\/]/, + name: "react-refresh", + chunks: "all", + priority: -1000 + }, + foo: { + test: /[\\/]node_modules[\\/]foo/, + name: "vendor", + chunks: "all", + priority: -500, + enforce: true + } + } + } + } + }, + (error, stats) => { + expect(error).toBeFalsy(); + const statsJson = stats.toJson({ all: true }); + expect(statsJson.errors).toHaveLength(0); + expect(statsJson.warnings).toHaveLength(0); + callback(error, stats, { + reactRefresh: fs.readFileSync( + path.join(fixturePath, "dist", "react-refresh.js"), + "utf-8" + ), + fixture: fs.readFileSync( + path.join(fixturePath, "dist", "fixture.js"), + "utf-8" + ), + runtime: fs.readFileSync( + path.join(fixturePath, "dist", "runtime.js"), + "utf-8" + ), + vendor: fs.readFileSync( + path.join(fixturePath, "dist", "vendor.js"), + "utf-8" + ) + }); + } + ); +}; + +describe("react-refresh-rspack-plugin", () => { + it("should exclude node_modules when compiling with default options", done => { + compileWithReactRefresh( + path.join(__dirname, "fixtures/default"), + {}, + (_, __, { reactRefresh, fixture, runtime, vendor }) => { + expect(vendor).not.toContain("$RefreshReg$"); + done(); + } + ); + }); + + it("should include non node_modules when compiling with default options", done => { + compileWithReactRefresh( + path.join(__dirname, "fixtures/default"), + {}, + (_, __, { reactRefresh, fixture, runtime, vendor }) => { + expect(fixture).toContain("$RefreshReg$"); + done(); + } + ); + }); + + it("should include selected file when compiling", done => { + compileWithReactRefresh( + path.join(__dirname, "fixtures/custom"), + { + exclude: null, + include: path.join(__dirname, "fixtures/node_modules/foo") + }, + (_, __, { reactRefresh, fixture, runtime, vendor }) => { + expect(vendor).toContain("$RefreshReg$"); + done(); + } + ); + }); + + it("should exclude selected file when compiling", done => { + compileWithReactRefresh( + path.join(__dirname, "fixtures/custom"), + { + exclude: path.join(__dirname, "fixtures/custom/index.js") + }, + (_, __, { reactRefresh, fixture, runtime, vendor }) => { + expect(fixture).not.toContain("$RefreshReg$"); + done(); + } + ); + }); + + it("should always exclude react-refresh related modules", done => { + compileWithReactRefresh( + path.join(__dirname, "fixtures/custom"), + { + exclude: null + }, + (_, __, { reactRefresh, fixture, runtime, vendor }) => { + expect(reactRefresh).not.toContain("$RefreshReg$"); + done(); + } + ); + }); +}); diff --git a/packages/rspack/package.json b/packages/rspack/package.json index 71fc60fd230..fbe7ffd3de0 100644 --- a/packages/rspack/package.json +++ b/packages/rspack/package.json @@ -1,6 +1,6 @@ { "name": "@rspack/core", - "version": "0.3.2", + "version": "0.3.4", "webpackVersion": "5.75.0", "license": "MIT", "description": "A Fast Rust-based Web Bundler", @@ -39,11 +39,14 @@ "copy-webpack-plugin": "5", "cross-env": "^7.0.3", "file-loader": "^6.2.0", + "html-loader": "^4.2.0", + "html-webpack-plugin": "^5.5.0", "jest-serializer-path": "^0.1.15", "less": "4.1.3", "less-loader": "^11.1.0", "postcss-loader": "^7.0.2", "postcss-pxtorem": "^6.0.0", + "pug-loader": "^2.4.0", "react-relay": "^14.1.0", "sass": "^1.56.2", "sass-loader": "^13.2.0", diff --git a/packages/rspack/src/Compilation.ts b/packages/rspack/src/Compilation.ts index 14e761a0d44..cf7c13b003d 100644 --- a/packages/rspack/src/Compilation.ts +++ b/packages/rspack/src/Compilation.ts @@ -49,7 +49,8 @@ import { concatErrorMsgAndStack, isJsStatsError, toJsAssetInfo } from "./util"; import { createRawFromSource, createSourceFromRaw } from "./util/createSource"; import { createFakeCompilationDependencies, - createFakeProcessAssetsHook + createFakeProcessAssetsHook, + createProcessAssetsHook } from "./util/fake"; import { NormalizedJsModule, normalizeJsModule } from "./util/normalization"; import MergeCaller from "./util/MergeCaller"; @@ -85,11 +86,12 @@ export class Compilation { hooks: { processAssets: ReturnType; log: tapable.SyncBailHook<[string, LogEntry], true>; - additionalAssets: tapable.AsyncSeriesHook< - Assets, - tapable.UnsetAdditionalOptions - >; + additionalAssets: any; optimizeModules: tapable.SyncBailHook, undefined>; + optimizeTree: tapable.AsyncSeriesBailHook< + [Iterable, Iterable], + undefined + >; optimizeChunkModules: tapable.AsyncSeriesBailHook< [Iterable, Iterable], undefined @@ -116,6 +118,12 @@ export class Compilation { normalModuleFactory?: NormalModuleFactory; children: Compilation[] = []; contextModuleFactory?: ContextModuleFactory; + fileSystemInfo = { + createSnapshot() { + // fake implement to support html-webpack-plugin + return null; + } + }; constructor(compiler: Compiler, inner: JsCompilation) { this.name = undefined; @@ -126,9 +134,15 @@ export class Compilation { processAssets: processAssetsHooks, // TODO: webpack 6 deprecate, keep it just for compatibility /** @deprecated */ - additionalAssets: processAssetsHooks.stageAdditional, + additionalAssets: createProcessAssetsHook( + processAssetsHooks, + "additionalAssets", + Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL, + () => [] + ), log: new tapable.SyncBailHook(["origin", "logEntry"]), optimizeModules: new tapable.SyncBailHook(["modules"]), + optimizeTree: new tapable.AsyncSeriesBailHook(["chunks", "modules"]), optimizeChunkModules: new tapable.AsyncSeriesBailHook([ "chunks", "modules" @@ -444,15 +458,25 @@ export class Compilation { get errors() { let inner = this.#inner; return { - push: (...errs: (Error | JsStatsError)[]) => { + push: (...errs: (Error | JsStatsError | string)[]) => { // compatible for javascript array for (let i = 0; i < errs.length; i++) { let error = errs[i]; - this.#inner.pushDiagnostic( - "error", - isJsStatsError(error) ? error.title : error.name, - concatErrorMsgAndStack(error) - ); + if (isJsStatsError(error)) { + this.#inner.pushDiagnostic( + "error", + error.title, + concatErrorMsgAndStack(error) + ); + } else if (typeof error === "string") { + this.#inner.pushDiagnostic("error", "Error", error); + } else { + this.#inner.pushDiagnostic( + "error", + error.name, + concatErrorMsgAndStack(error) + ); + } } }, [Symbol.iterator]() { diff --git a/packages/rspack/src/Compiler.ts b/packages/rspack/src/Compiler.ts index 06eab2a2c1e..7c5f4168d0d 100644 --- a/packages/rspack/src/Compiler.ts +++ b/packages/rspack/src/Compiler.ts @@ -42,29 +42,10 @@ import Watching from "./Watching"; import { NormalModule } from "./NormalModule"; import { normalizeJsModule } from "./util/normalization"; import { - ElectronTargetPlugin, - ExternalsPlugin, - HttpExternalsPlugin, - NodeTargetPlugin, RspackBuiltinPlugin, deprecated_resolveBuiltins } from "./builtin-plugin"; -import assert from "assert"; -import EntryOptionPlugin from "./lib/EntryOptionPlugin"; - -class NodeTemplatePlugin { - apply() {} -} - -class EnableLibraryPlugin { - constructor(private libraryType: string) {} - apply(compiler: Compiler) { - compiler.options.output.enabledLibraryTypes = [this.libraryType]; - } -} -class HotModuleReplacementPlugin { - apply() {} -} +import { optionsApply_compat } from "./rspackOptionsApply"; class Compiler { #_instance?: binding.Rspack; @@ -138,7 +119,6 @@ class Compiler { this.builtinPlugins = []; // to workaround some plugin access webpack, we may change dev-server to avoid this hack in the future this.webpack = { - HotModuleReplacementPlugin, // modernjs/server will auto inject this plugin not set NormalModule, get sources(): typeof import("webpack-sources") { return require("webpack-sources"); @@ -168,21 +148,44 @@ class Compiler { get ExternalsPlugin() { return require("./builtin-plugin").ExternalsPlugin; }, + get HotModuleReplacementPlugin() { + return require("./builtin-plugin").HotModuleReplacementPlugin; + }, + get LoaderOptionsPlugin() { + return require("./lib/LoaderOptionsPlugin").LoaderOptionsPlugin; + }, + get LoaderTargetPlugin() { + return require("./lib/LoaderTargetPlugin").LoaderTargetPlugin; + }, WebpackError: Error, ModuleFilenameHelpers, + javascript: { + get EnableChunkLoadingPlugin() { + return require("./builtin-plugin").EnableChunkLoadingPlugin; + } + }, node: { get NodeTargetPlugin() { return require("./builtin-plugin").NodeTargetPlugin; }, - NodeTemplatePlugin + get NodeTemplatePlugin() { + return require("./node/NodeTemplatePlugin").default; + } }, electron: { get ElectronTargetPlugin() { return require("./builtin-plugin").ElectronTargetPlugin; } }, + wasm: { + get EnableWasmLoadingPlugin() { + return require("./builtin-plugin").EnableWasmLoadingPlugin; + } + }, library: { - EnableLibraryPlugin + get EnableLibraryPlugin() { + return require("./builtin-plugin").EnableLibraryPlugin; + } }, util: { get createHash() { @@ -203,6 +206,19 @@ class Compiler { // get LazySet() { // return require("./util/LazySet"); // } + }, + // XxxRspackPlugin, Rspack-only plugins + get HtmlRspackPlugin() { + return require("./builtin-plugin").HtmlRspackPlugin; + }, + get SwcJsMinimizerRspackPlugin() { + return require("./builtin-plugin").SwcJsMinimizerRspackPlugin; + }, + get SwcCssMinimizerRspackPlugin() { + return require("./builtin-plugin").SwcCssMinimizerRspackPlugin; + }, + get CopyRspackPlugin() { + return require("./builtin-plugin").CopyRspackPlugin; } }; this.root = this; @@ -306,45 +322,7 @@ class Compiler { const options = this.options; // TODO: remove this in v0.4 - if (this.parentCompilation === undefined) { - if (options.externals) { - assert( - options.externalsType, - "options.externalsType should have value after `applyRspackOptionsDefaults`" - ); - new ExternalsPlugin(options.externalsType, options.externals).apply( - this - ); - } - - if (options.externalsPresets.node) { - new NodeTargetPlugin().apply(this); - } - if (options.externalsPresets.electronMain) { - new ElectronTargetPlugin("main").apply(this); - } - if (options.externalsPresets.electronPreload) { - new ElectronTargetPlugin("preload").apply(this); - } - if (options.externalsPresets.electronRenderer) { - new ElectronTargetPlugin("renderer").apply(this); - } - if ( - options.externalsPresets.electron && - !options.externalsPresets.electronMain && - !options.externalsPresets.electronPreload && - !options.externalsPresets.electronRenderer - ) { - new ElectronTargetPlugin().apply(this); - } - if ( - options.externalsPresets.web || - (options.externalsPresets.node && options.experiments.css) - ) { - new HttpExternalsPlugin(!!options.experiments.css).apply(this); - } - EntryOptionPlugin.applyEntryOption(this, this.context, options.entry); - } + optionsApply_compat(this, options); // TODO: remove this when drop support for builtins options options.builtins = deprecated_resolveBuiltins( options.builtins, @@ -440,6 +418,7 @@ class Compiler { // No matter how it will be implemented, it will be copied to the child compiler. compilation: this.#compilation.bind(this), optimizeModules: this.#optimizeModules.bind(this), + optimizeTree: this.#optimizeTree.bind(this), optimizeChunkModule: this.#optimizeChunkModules.bind(this), finishModules: this.#finishModules.bind(this), normalModuleFactoryResolveForScheme: @@ -748,6 +727,7 @@ class Compiler { ), compilation: this.hooks.compilation, optimizeChunkModules: this.compilation.hooks.optimizeChunkModules, + optimizeTree: this.compilation.hooks.optimizeTree, finishModules: this.compilation.hooks.finishModules, optimizeModules: this.compilation.hooks.optimizeModules, chunkAsset: this.compilation.hooks.chunkAsset, @@ -873,6 +853,15 @@ class Compiler { ); this.#updateDisabledHooks(); } + + async #optimizeTree() { + await this.compilation.hooks.optimizeTree.promise( + this.compilation.__internal__getChunks(), + this.compilation.modules + ); + this.#updateDisabledHooks(); + } + async #optimizeModules() { await this.compilation.hooks.optimizeModules.promise( this.compilation.modules diff --git a/packages/rspack/src/builtin-plugin/ArrayPushCallbackChunkFormatPlugin.ts b/packages/rspack/src/builtin-plugin/ArrayPushCallbackChunkFormatPlugin.ts new file mode 100644 index 00000000000..11950cd8a77 --- /dev/null +++ b/packages/rspack/src/builtin-plugin/ArrayPushCallbackChunkFormatPlugin.ts @@ -0,0 +1,6 @@ +import { BuiltinPluginName, create } from "./base"; + +export const ArrayPushCallbackChunkFormatPlugin = create( + BuiltinPluginName.ArrayPushCallbackChunkFormatPlugin, + () => {} +); diff --git a/packages/rspack/src/builtin-plugin/BannerPlugin.ts b/packages/rspack/src/builtin-plugin/BannerPlugin.ts index efe3deb332d..0e46bdd6589 100644 --- a/packages/rspack/src/builtin-plugin/BannerPlugin.ts +++ b/packages/rspack/src/builtin-plugin/BannerPlugin.ts @@ -1,12 +1,12 @@ import { z } from "zod"; import { JsChunk, - RawBannerCondition, - RawBannerConditions, - RawBannerConfig, - RawBannerContent + RawBannerContent, + RawBannerPluginOptions, + RawBannerRule, + RawBannerRules } from "@rspack/binding"; -import { BuiltinPluginKind, create } from "./base"; +import { BuiltinPluginName, create } from "./base"; const rule = z.string().or(z.instanceof(RegExp)); export type Rule = z.infer; @@ -43,7 +43,7 @@ export type BannerPluginOptions = z.infer; const bannerPluginArgument = bannerContent.or(bannerPluginOptions); export type BannerPluginArgument = z.infer; -function getRawBannerRule(condition: Rule): RawBannerCondition { +function getRawBannerRule(condition: Rule): RawBannerRule { if (typeof condition === "string") { return { type: "string", @@ -59,7 +59,7 @@ function getRawBannerRule(condition: Rule): RawBannerCondition { throw new Error("unreachable: condition should be one of string, RegExp"); } -function getRawBannerRules(condition?: Rules): RawBannerConditions | undefined { +function getRawBannerRules(condition?: Rules): RawBannerRules | undefined { if (!condition) return undefined; if (Array.isArray(condition)) { @@ -89,8 +89,8 @@ function getRawBannerContent(content: BannerContent): RawBannerContent { } export const BannerPlugin = create( - BuiltinPluginKind.Banner, - (args: BannerPluginArgument): RawBannerConfig => { + BuiltinPluginName.BannerPlugin, + (args: BannerPluginArgument): RawBannerPluginOptions => { if (typeof args === "string") { return { banner: getRawBannerContent(args) diff --git a/packages/rspack/src/builtin-plugin/CommonJsChunkFormatPlugin.ts b/packages/rspack/src/builtin-plugin/CommonJsChunkFormatPlugin.ts new file mode 100644 index 00000000000..57e73be6452 --- /dev/null +++ b/packages/rspack/src/builtin-plugin/CommonJsChunkFormatPlugin.ts @@ -0,0 +1,6 @@ +import { BuiltinPluginName, create } from "./base"; + +export const CommonJsChunkFormatPlugin = create( + BuiltinPluginName.CommonJsChunkFormatPlugin, + () => {} +); diff --git a/packages/rspack/src/builtin-plugin/CopyPlugin.ts b/packages/rspack/src/builtin-plugin/CopyPlugin.ts deleted file mode 100644 index e56c3b6e7be..00000000000 --- a/packages/rspack/src/builtin-plugin/CopyPlugin.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { RawCopyConfig, RawPattern } from "@rspack/binding"; -import { BuiltinPluginKind, create } from "./base"; - -export type CopyPluginOptions = { - patterns: ( - | string - | ({ - from: string; - } & Partial) - )[]; -}; - -export const CopyPlugin = create( - BuiltinPluginKind.Copy, - (copy: CopyPluginOptions): RawCopyConfig => { - const ret: RawCopyConfig = { - patterns: [] - }; - - ret.patterns = (copy.patterns || []).map(pattern => { - if (typeof pattern === "string") { - pattern = { from: pattern }; - } - - pattern.force ??= false; - pattern.noErrorOnMissing ??= false; - pattern.priority ??= 0; - pattern.globOptions ??= {}; - - return pattern as RawPattern; - }); - - return ret; - } -); diff --git a/packages/rspack/src/builtin-plugin/CopyRspackPlugin.ts b/packages/rspack/src/builtin-plugin/CopyRspackPlugin.ts new file mode 100644 index 00000000000..49713227f16 --- /dev/null +++ b/packages/rspack/src/builtin-plugin/CopyRspackPlugin.ts @@ -0,0 +1,35 @@ +import { RawCopyPattern, RawCopyRspackPluginOptions } from "@rspack/binding"; +import { BuiltinPluginName, create } from "./base"; + +export type CopyRspackPluginOptions = { + patterns: ( + | string + | ({ + from: string; + } & Partial) + )[]; +}; + +export const CopyRspackPlugin = create( + BuiltinPluginName.CopyRspackPlugin, + (copy: CopyRspackPluginOptions): RawCopyRspackPluginOptions => { + const ret: RawCopyRspackPluginOptions = { + patterns: [] + }; + + ret.patterns = (copy.patterns || []).map(pattern => { + if (typeof pattern === "string") { + pattern = { from: pattern }; + } + + pattern.force ??= false; + pattern.noErrorOnMissing ??= false; + pattern.priority ??= 0; + pattern.globOptions ??= {}; + + return pattern as RawCopyPattern; + }); + + return ret; + } +); diff --git a/packages/rspack/src/builtin-plugin/DefinePlugin.ts b/packages/rspack/src/builtin-plugin/DefinePlugin.ts index d1f0215f69c..f1ba1734928 100644 --- a/packages/rspack/src/builtin-plugin/DefinePlugin.ts +++ b/packages/rspack/src/builtin-plugin/DefinePlugin.ts @@ -1,8 +1,8 @@ -import { BuiltinPluginKind, create } from "./base"; +import { BuiltinPluginName, create } from "./base"; export type DefinePluginOptions = Record; export const DefinePlugin = create( - BuiltinPluginKind.Define, + BuiltinPluginName.DefinePlugin, (define: DefinePluginOptions): Record => { const entries = Object.entries(define).map(([key, value]) => { if (typeof value !== "string") { diff --git a/packages/rspack/src/builtin-plugin/ElectronTargetPlugin.ts b/packages/rspack/src/builtin-plugin/ElectronTargetPlugin.ts index ccf766992c2..bbb004be6e6 100644 --- a/packages/rspack/src/builtin-plugin/ElectronTargetPlugin.ts +++ b/packages/rspack/src/builtin-plugin/ElectronTargetPlugin.ts @@ -1,6 +1,6 @@ -import { BuiltinPluginKind, create } from "./base"; +import { BuiltinPluginName, create } from "./base"; export const ElectronTargetPlugin = create( - BuiltinPluginKind.ElectronTarget, + BuiltinPluginName.ElectronTargetPlugin, (context?: string) => context ?? "none" ); diff --git a/packages/rspack/src/builtin-plugin/EnableChunkLoadingPlugin.ts b/packages/rspack/src/builtin-plugin/EnableChunkLoadingPlugin.ts new file mode 100644 index 00000000000..f035133ebbd --- /dev/null +++ b/packages/rspack/src/builtin-plugin/EnableChunkLoadingPlugin.ts @@ -0,0 +1,6 @@ +import { BuiltinPluginName, create } from "./base"; + +export const EnableChunkLoadingPlugin = create( + BuiltinPluginName.EnableChunkLoadingPlugin, + type => type +); diff --git a/packages/rspack/src/builtin-plugin/EnableLibraryPlugin.ts b/packages/rspack/src/builtin-plugin/EnableLibraryPlugin.ts new file mode 100644 index 00000000000..6a553f2dfc5 --- /dev/null +++ b/packages/rspack/src/builtin-plugin/EnableLibraryPlugin.ts @@ -0,0 +1,6 @@ +import { BuiltinPluginName, create } from "./base"; + +export const EnableLibraryPlugin = create( + BuiltinPluginName.EnableLibraryPlugin, + type => type +); diff --git a/packages/rspack/src/builtin-plugin/EnableWasmLoadingPlugin.ts b/packages/rspack/src/builtin-plugin/EnableWasmLoadingPlugin.ts new file mode 100644 index 00000000000..2a07374a1bf --- /dev/null +++ b/packages/rspack/src/builtin-plugin/EnableWasmLoadingPlugin.ts @@ -0,0 +1,6 @@ +import { BuiltinPluginName, create } from "./base"; + +export const EnableWasmLoadingPlugin = create( + BuiltinPluginName.EnableWasmLoadingPlugin, + type => type +); diff --git a/packages/rspack/src/builtin-plugin/EntryPlugin.ts b/packages/rspack/src/builtin-plugin/EntryPlugin.ts index 2449a1923a8..f05914fdea7 100644 --- a/packages/rspack/src/builtin-plugin/EntryPlugin.ts +++ b/packages/rspack/src/builtin-plugin/EntryPlugin.ts @@ -1,5 +1,5 @@ import { RawEntryOptions, RawEntryPluginOptions } from "@rspack/binding"; -import { BuiltinPluginKind, create } from "./base"; +import { BuiltinPluginName, create } from "./base"; import { ChunkLoading, EntryRuntime, Filename, PublicPath } from ".."; export type EntryOptions = { @@ -12,16 +12,18 @@ export type EntryOptions = { filename?: Filename; }; export const EntryPlugin = create( - BuiltinPluginKind.Entry, + BuiltinPluginName.EntryPlugin, ( context: string, entry: string, - options: EntryOptions + options: EntryOptions | string = "" ): RawEntryPluginOptions => { + let entryOptions = + typeof options === "string" ? { name: options } : options; return { context, entry, - options: getRawEntryOptions(options) + options: getRawEntryOptions(entryOptions) }; } ); diff --git a/packages/rspack/src/builtin-plugin/ExternalsPlugin.ts b/packages/rspack/src/builtin-plugin/ExternalsPlugin.ts index e40fdd03dd6..3577d3025df 100644 --- a/packages/rspack/src/builtin-plugin/ExternalsPlugin.ts +++ b/packages/rspack/src/builtin-plugin/ExternalsPlugin.ts @@ -3,11 +3,11 @@ import { RawExternalItemValue, RawExternalsPluginOptions } from "@rspack/binding"; -import { BuiltinPluginKind, create } from "./base"; +import { BuiltinPluginName, create } from "./base"; import { ExternalItem, ExternalItemValue, Externals } from ".."; export const ExternalsPlugin = create( - BuiltinPluginKind.Externals, + BuiltinPluginName.ExternalsPlugin, (type: string, externals: Externals): RawExternalsPluginOptions => { return { type, @@ -75,6 +75,13 @@ function getRawExternalItemValue( type: "array", arrayPayload: value }; + } else if (typeof value === "object" && value !== null) { + return { + type: "object", + objectPayload: Object.fromEntries( + Object.entries(value).map(([k, v]) => [k, Array.isArray(v) ? v : [v]]) + ) + }; } throw new Error("unreachable"); } diff --git a/packages/rspack/src/builtin-plugin/HotModuleReplacementPlugin.ts b/packages/rspack/src/builtin-plugin/HotModuleReplacementPlugin.ts new file mode 100644 index 00000000000..acb9a9738ee --- /dev/null +++ b/packages/rspack/src/builtin-plugin/HotModuleReplacementPlugin.ts @@ -0,0 +1,6 @@ +import { BuiltinPluginName, create } from "./base"; + +export const HotModuleReplacementPlugin = create( + BuiltinPluginName.HotModuleReplacementPlugin, + () => undefined +); diff --git a/packages/rspack/src/builtin-plugin/HtmlPlugin.ts b/packages/rspack/src/builtin-plugin/HtmlRspackPlugin.ts similarity index 53% rename from packages/rspack/src/builtin-plugin/HtmlPlugin.ts rename to packages/rspack/src/builtin-plugin/HtmlRspackPlugin.ts index 0a4f4471b68..3fb22b67473 100644 --- a/packages/rspack/src/builtin-plugin/HtmlPlugin.ts +++ b/packages/rspack/src/builtin-plugin/HtmlRspackPlugin.ts @@ -1,14 +1,14 @@ import { z } from "zod"; -import { RawHtmlPluginConfig } from "@rspack/binding"; -import { BuiltinPluginKind, create } from "./base"; +import { RawHtmlRspackPluginOptions } from "@rspack/binding"; +import { BuiltinPluginName, create } from "./base"; import { validate } from "../util/validate"; -const htmlPluginOptions = z.strictObject({ +const htmlRspackPluginOptions = z.strictObject({ filename: z.string().optional(), template: z.string().optional(), templateContent: z.string().optional(), templateParameters: z.record(z.string()).optional(), - inject: z.enum(["head", "body"]).optional(), + inject: z.enum(["head", "body"]).or(z.boolean()).optional(), publicPath: z.string().optional(), scriptLoading: z.enum(["blocking", "defer", "module"]).optional(), chunks: z.string().array().optional(), @@ -19,11 +19,11 @@ const htmlPluginOptions = z.strictObject({ favicon: z.string().optional(), meta: z.record(z.string().or(z.record(z.string()))).optional() }); -export type HtmlPluginOptions = z.infer; -export const HtmlPlugin = create( - BuiltinPluginKind.Html, - (c: HtmlPluginOptions): RawHtmlPluginConfig => { - validate(c, htmlPluginOptions); +export type HtmlRspackPluginOptions = z.infer; +export const HtmlRspackPlugin = create( + BuiltinPluginName.HtmlRspackPlugin, + (c: HtmlRspackPluginOptions): RawHtmlRspackPluginOptions => { + validate(c, htmlRspackPluginOptions); const meta: Record> = {}; for (const key in c.meta) { const value = c.meta[key]; @@ -34,9 +34,21 @@ export const HtmlPlugin = create( }; } } + const scriptLoading = c.scriptLoading ?? "defer"; + const configInject = c.inject ?? true; + const inject = + configInject === true + ? scriptLoading === "blocking" + ? "body" + : "head" + : configInject === false + ? "false" + : configInject; return { ...c, - meta + meta, + scriptLoading, + inject }; } ); diff --git a/packages/rspack/src/builtin-plugin/HttpExternalsPlugin.ts b/packages/rspack/src/builtin-plugin/HttpExternalsPlugin.ts deleted file mode 100644 index c77eeaadd4c..00000000000 --- a/packages/rspack/src/builtin-plugin/HttpExternalsPlugin.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { RawHttpExternalsPluginOptions } from "@rspack/binding"; -import { BuiltinPluginKind, create } from "./base"; - -export const HttpExternalsPlugin = create( - BuiltinPluginKind.HttpExternals, - (css: boolean): RawHttpExternalsPluginOptions => { - return { - css - }; - } -); diff --git a/packages/rspack/src/builtin-plugin/HttpExternalsRspackPlugin.ts b/packages/rspack/src/builtin-plugin/HttpExternalsRspackPlugin.ts new file mode 100644 index 00000000000..851b41b92b9 --- /dev/null +++ b/packages/rspack/src/builtin-plugin/HttpExternalsRspackPlugin.ts @@ -0,0 +1,12 @@ +import { RawHttpExternalsRspackPluginOptions } from "@rspack/binding"; +import { BuiltinPluginName, create } from "./base"; + +export const HttpExternalsRspackPlugin = create( + BuiltinPluginName.HttpExternalsRspackPlugin, + (css: boolean, webAsync: boolean): RawHttpExternalsRspackPluginOptions => { + return { + css, + webAsync + }; + } +); diff --git a/packages/rspack/src/builtin-plugin/ModuleChunkFormatPlugin.ts b/packages/rspack/src/builtin-plugin/ModuleChunkFormatPlugin.ts new file mode 100644 index 00000000000..27f77401584 --- /dev/null +++ b/packages/rspack/src/builtin-plugin/ModuleChunkFormatPlugin.ts @@ -0,0 +1,6 @@ +import { BuiltinPluginName, create } from "./base"; + +export const ModuleChunkFormatPlugin = create( + BuiltinPluginName.ModuleChunkFormatPlugin, + () => {} +); diff --git a/packages/rspack/src/builtin-plugin/NodeTargetPlugin.ts b/packages/rspack/src/builtin-plugin/NodeTargetPlugin.ts index 914e11b8685..9277a6ef910 100644 --- a/packages/rspack/src/builtin-plugin/NodeTargetPlugin.ts +++ b/packages/rspack/src/builtin-plugin/NodeTargetPlugin.ts @@ -1,6 +1,6 @@ -import { BuiltinPluginKind, create } from "./base"; +import { BuiltinPluginName, create } from "./base"; export const NodeTargetPlugin = create( - BuiltinPluginKind.NodeTarget, + BuiltinPluginName.NodeTargetPlugin, () => undefined ); diff --git a/packages/rspack/src/builtin-plugin/ProgressPlugin.ts b/packages/rspack/src/builtin-plugin/ProgressPlugin.ts index 49b2d8612cd..a7f4beee126 100644 --- a/packages/rspack/src/builtin-plugin/ProgressPlugin.ts +++ b/packages/rspack/src/builtin-plugin/ProgressPlugin.ts @@ -1,8 +1,8 @@ -import { RawProgressPluginConfig } from "@rspack/binding"; -import { BuiltinPluginKind, create } from "./base"; +import { RawProgressPluginOptions } from "@rspack/binding"; +import { BuiltinPluginName, create } from "./base"; -export type ProgressPluginArgument = RawProgressPluginConfig | undefined; +export type ProgressPluginArgument = RawProgressPluginOptions | undefined; export const ProgressPlugin = create( - BuiltinPluginKind.Progress, - (progress: ProgressPluginArgument = {}): RawProgressPluginConfig => progress + BuiltinPluginName.ProgressPlugin, + (progress: ProgressPluginArgument = {}): RawProgressPluginOptions => progress ); diff --git a/packages/rspack/src/builtin-plugin/ProvidePlugin.ts b/packages/rspack/src/builtin-plugin/ProvidePlugin.ts index 8b7ef3b0eec..c89fcee25fd 100644 --- a/packages/rspack/src/builtin-plugin/ProvidePlugin.ts +++ b/packages/rspack/src/builtin-plugin/ProvidePlugin.ts @@ -1,8 +1,8 @@ -import { BuiltinPluginKind, create } from "./base"; +import { BuiltinPluginName, create } from "./base"; export type ProvidePluginOptions = Record; export const ProvidePlugin = create( - BuiltinPluginKind.Provide, + BuiltinPluginName.ProvidePlugin, (provide: ProvidePluginOptions): Record => { const entries = Object.entries(provide).map(([key, value]) => { if (typeof value === "string") { diff --git a/packages/rspack/src/builtin-plugin/SwcCssMinimizerPlugin.ts b/packages/rspack/src/builtin-plugin/SwcCssMinimizerPlugin.ts index a444a4efbf9..842f4f248bf 100644 --- a/packages/rspack/src/builtin-plugin/SwcCssMinimizerPlugin.ts +++ b/packages/rspack/src/builtin-plugin/SwcCssMinimizerPlugin.ts @@ -1,6 +1,6 @@ -import { BuiltinPluginKind, create } from "./base"; +import { BuiltinPluginName, create } from "./base"; -export const SwcCssMinimizerPlugin = create( - BuiltinPluginKind.SwcCssMinimizer, +export const SwcCssMinimizerRspackPlugin = create( + BuiltinPluginName.SwcCssMinimizerRspackPlugin, (options?: any /* TODO: extend more options */) => undefined ); diff --git a/packages/rspack/src/builtin-plugin/SwcJsMinimizerPlugin.ts b/packages/rspack/src/builtin-plugin/SwcJsMinimizerPlugin.ts index f4d5459882e..4233ecc1309 100644 --- a/packages/rspack/src/builtin-plugin/SwcJsMinimizerPlugin.ts +++ b/packages/rspack/src/builtin-plugin/SwcJsMinimizerPlugin.ts @@ -1,13 +1,13 @@ import { - RawMinification, - RawMinificationCondition, - RawMinificationConditions + RawSwcJsMinimizerRspackPluginOptions, + RawSwcJsMinimizerRule, + RawSwcJsMinimizerRules } from "@rspack/binding"; -import { BuiltinPluginKind, create } from "./base"; +import { BuiltinPluginName, create } from "./base"; type MinifyCondition = string | RegExp; type MinifyConditions = MinifyCondition | MinifyCondition[]; -export type SwcJsMinimizerPluginOptions = { +export type SwcJsMinimizerRspackPluginOptions = { passes?: number; dropConsole?: boolean; keepClassNames?: boolean; @@ -21,9 +21,9 @@ export type SwcJsMinimizerPluginOptions = { include?: MinifyConditions; }; -function getMinifyCondition( +function getRawSwcJsMinimizerRule( condition: MinifyCondition -): RawMinificationCondition { +): RawSwcJsMinimizerRule { if (typeof condition === "string") { return { type: "string", @@ -39,24 +39,26 @@ function getMinifyCondition( throw new Error("unreachable: condition should be one of string, RegExp"); } -function getMinifyConditions( +function getRawSwcJsMinimizerRules( condition?: MinifyConditions -): RawMinificationConditions | undefined { +): RawSwcJsMinimizerRules | undefined { if (!condition) return undefined; if (Array.isArray(condition)) { return { type: "array", - arrayMatcher: condition.map(i => getMinifyCondition(i)) + arrayMatcher: condition.map(i => getRawSwcJsMinimizerRule(i)) }; } - return getMinifyCondition(condition); + return getRawSwcJsMinimizerRule(condition); } -export const SwcJsMinimizerPlugin = create( - BuiltinPluginKind.SwcJsMinimizer, - (options?: SwcJsMinimizerPluginOptions): RawMinification => { +export const SwcJsMinimizerRspackPlugin = create( + BuiltinPluginName.SwcJsMinimizerRspackPlugin, + ( + options?: SwcJsMinimizerRspackPluginOptions + ): RawSwcJsMinimizerRspackPluginOptions => { return { passes: options?.passes ?? 1, dropConsole: options?.dropConsole ?? false, @@ -68,9 +70,9 @@ export const SwcJsMinimizerPlugin = create( extractComments: options?.extractComments ? String(options.extractComments) : undefined, - test: getMinifyConditions(options?.test), - include: getMinifyConditions(options?.include), - exclude: getMinifyConditions(options?.exclude) + test: getRawSwcJsMinimizerRules(options?.test), + include: getRawSwcJsMinimizerRules(options?.include), + exclude: getRawSwcJsMinimizerRules(options?.exclude) }; } ); diff --git a/packages/rspack/src/builtin-plugin/base.ts b/packages/rspack/src/builtin-plugin/base.ts index cef64202d50..24b246f846d 100644 --- a/packages/rspack/src/builtin-plugin/base.ts +++ b/packages/rspack/src/builtin-plugin/base.ts @@ -2,34 +2,43 @@ import * as binding from "@rspack/binding"; import { Compiler, RspackPluginInstance } from ".."; // TODO: workaround for https://github.com/napi-rs/napi-rs/pull/1690 -export enum BuiltinPluginKind { - Define = "Define", - Provide = "Provide", - Banner = "Banner", - Progress = "Progress", - Copy = "Copy", - Html = "Html", - SwcJsMinimizer = "SwcJsMinimizer", - SwcCssMinimizer = "SwcCssMinimizer", - Entry = "Entry", - Externals = "Externals", - NodeTarget = "NodeTarget", - ElectronTarget = "ElectronTarget", - HttpExternals = "HttpExternals" +export enum BuiltinPluginName { + DefinePlugin = "DefinePlugin", + ProvidePlugin = "ProvidePlugin", + BannerPlugin = "BannerPlugin", + ProgressPlugin = "ProgressPlugin", + EntryPlugin = "EntryPlugin", + ExternalsPlugin = "ExternalsPlugin", + NodeTargetPlugin = "NodeTargetPlugin", + ElectronTargetPlugin = "ElectronTargetPlugin", + EnableChunkLoadingPlugin = "EnableChunkLoadingPlugin", + EnableLibraryPlugin = "EnableLibraryPlugin", + EnableWasmLoadingPlugin = "EnableWasmLoadingPlugin", + CommonJsChunkFormatPlugin = "CommonJsChunkFormatPlugin", + ArrayPushCallbackChunkFormatPlugin = "ArrayPushCallbackChunkFormatPlugin", + ModuleChunkFormatPlugin = "ModuleChunkFormatPlugin", + HotModuleReplacementPlugin = "HotModuleReplacementPlugin", + HttpExternalsRspackPlugin = "HttpExternalsRspackPlugin", + CopyRspackPlugin = "CopyRspackPlugin", + HtmlRspackPlugin = "HtmlRspackPlugin", + SwcJsMinimizerRspackPlugin = "SwcJsMinimizerRspackPlugin", + SwcCssMinimizerRspackPlugin = "SwcCssMinimizerRspackPlugin" } export abstract class RspackBuiltinPlugin implements RspackPluginInstance { abstract raw(): binding.BuiltinPlugin; + abstract name: BuiltinPluginName; apply(compiler: Compiler) { compiler.__internal__registerBuiltinPlugin(this); } } export function create( - kind: BuiltinPluginKind, + name: BuiltinPluginName, resolve: (...args: T) => R ) { return class Plugin extends RspackBuiltinPlugin { + name = name; _options: R; constructor(...args: T) { @@ -41,7 +50,7 @@ export function create( raw(): binding.BuiltinPlugin { return { - kind: kind as any, + name: name as any, options: this._options }; } diff --git a/packages/rspack/src/builtin-plugin/index.ts b/packages/rspack/src/builtin-plugin/index.ts index 2d3a43d7a90..c80986f5211 100644 --- a/packages/rspack/src/builtin-plugin/index.ts +++ b/packages/rspack/src/builtin-plugin/index.ts @@ -8,10 +8,17 @@ export * from "./EntryPlugin"; export * from "./ExternalsPlugin"; export * from "./NodeTargetPlugin"; export * from "./ElectronTargetPlugin"; -export * from "./HttpExternalsPlugin"; +export * from "./HttpExternalsRspackPlugin"; +export * from "./EnableChunkLoadingPlugin"; +export * from "./EnableLibraryPlugin"; +export * from "./EnableWasmLoadingPlugin"; +export * from "./ArrayPushCallbackChunkFormatPlugin"; +export * from "./CommonJsChunkFormatPlugin"; +export * from "./ModuleChunkFormatPlugin"; +export * from "./HotModuleReplacementPlugin"; -export * from "./HtmlPlugin"; -export * from "./CopyPlugin"; +export * from "./HtmlRspackPlugin"; +export * from "./CopyRspackPlugin"; export * from "./SwcJsMinimizerPlugin"; export * from "./SwcCssMinimizerPlugin"; @@ -19,26 +26,28 @@ export * from "./SwcCssMinimizerPlugin"; import { RawDecoratorOptions, RawPresetEnv, - RawProgressPluginConfig, + RawProgressPluginOptions, RawBuiltins, RawCssModulesConfig } from "@rspack/binding"; import { termlink, deprecatedWarn } from "../util"; -import { Compiler, RspackOptionsNormalized } from ".."; import { - HtmlPluginOptions, - SwcJsMinimizerPluginOptions, - CopyPluginOptions, + Compiler, + CopyRspackPlugin, + CopyRspackPluginOptions, + HtmlRspackPlugin, + HtmlRspackPluginOptions, + RspackOptionsNormalized, + SwcCssMinimizerRspackPlugin, + SwcJsMinimizerRspackPlugin, + SwcJsMinimizerRspackPluginOptions +} from ".."; +import { BannerPluginOptions, DefinePlugin, ProvidePlugin, ProgressPlugin, - HtmlPlugin, - CopyPlugin, - BannerPlugin, - SwcJsMinimizerPlugin, - SwcCssMinimizerPlugin, - RspackBuiltinPlugin + BannerPlugin } from "."; import { loadConfig } from "browserslist"; import { @@ -132,16 +141,16 @@ function resolveDecorator( export interface Builtins { css?: BuiltinsCssConfig; treeShaking?: boolean | "module"; - progress?: boolean | RawProgressPluginConfig; + progress?: boolean | RawProgressPluginOptions; noEmitAssets?: boolean; define?: Record; provide?: Record; - html?: Array; + html?: Array; decorator?: boolean | Partial; - minifyOptions?: SwcJsMinimizerPluginOptions; + minifyOptions?: SwcJsMinimizerRspackPluginOptions; presetEnv?: Partial; devFriendlySplitChunks?: boolean; - copy?: CopyPluginOptions; + copy?: CopyRspackPluginOptions; banner?: BannerPluginOptions | BannerPluginOptions[]; react?: ReactOptions; pluginImport?: PluginImportOptions; @@ -154,10 +163,6 @@ export function deprecated_resolveBuiltins( options: RspackOptionsNormalized, compiler: Compiler ): RawBuiltins { - const defaultEnableDeprecatedWarning = false; - const enableDeprecatedWarning = - (process.env.RSPACK_BUILTINS_DEPRECATED ?? - `${defaultEnableDeprecatedWarning}`) !== "false"; // deprecatedWarn( // `'configuration.builtins' has been deprecated, and will be drop support in 0.6.0, please follow ${termlink( // "the migration guide", @@ -171,8 +176,10 @@ export function deprecated_resolveBuiltins( deprecatedWarn( `'builtins.define = ${JSON.stringify( builtins.define - )}' has been deprecated, please migrate to rspack.DefinePlugin`, - enableDeprecatedWarning + )}' has been deprecated, please migrate to ${termlink( + "rspack.DefinePlugin", + "https://www.rspack.dev/config/plugins.html#defineplugin" + )}` ); new DefinePlugin(builtins.define).apply(compiler); } @@ -180,8 +187,10 @@ export function deprecated_resolveBuiltins( deprecatedWarn( `'builtins.provide = ${JSON.stringify( builtins.provide - )}' has been deprecated, please migrate to rspack.ProvidePlugin`, - enableDeprecatedWarning + )}' has been deprecated, please migrate to ${termlink( + "rspack.ProvidePlugin", + "https://www.rspack.dev/config/plugins.html#provideplugin" + )}` ); new ProvidePlugin(builtins.provide).apply(compiler); } @@ -189,8 +198,10 @@ export function deprecated_resolveBuiltins( deprecatedWarn( `'builtins.progress = ${JSON.stringify( builtins.progress - )}' has been deprecated, please migrate to rspack.ProgressPlugin`, - enableDeprecatedWarning + )}' has been deprecated, please migrate to ${termlink( + "rspack.ProgressPlugin", + "https://www.rspack.dev/config/plugins.html#progressplugin" + )}` ); const progress = builtins.progress === true ? {} : builtins.progress; new ProgressPlugin(progress).apply(compiler); @@ -199,8 +210,10 @@ export function deprecated_resolveBuiltins( deprecatedWarn( `'builtins.banner = ${JSON.stringify( builtins.banner - )}' has been deprecated, please migrate to rspack.BannerPlugin`, - enableDeprecatedWarning + )}' has been deprecated, please migrate to ${termlink( + "rspack.BannerPlugin", + "https://www.rspack.dev/config/plugins.html#bannerplugin" + )}` ); if (Array.isArray(builtins.banner)) { for (const banner of builtins.banner) { @@ -215,36 +228,45 @@ export function deprecated_resolveBuiltins( deprecatedWarn( `'builtins.html = ${JSON.stringify( builtins.html - )}' has been deprecated, please migrate to rspack.HtmlPlugin`, - enableDeprecatedWarning + )}' has been deprecated, please migrate to ${termlink( + "rspack.HtmlRspackPlugin", + "https://www.rspack.dev/config/plugins.html#htmlrspackplugin" + )}` ); for (const html of builtins.html) { - new HtmlPlugin(html).apply(compiler); + new HtmlRspackPlugin(html).apply(compiler); } } if (builtins.copy) { deprecatedWarn( `'builtins.copy = ${JSON.stringify( builtins.copy - )}' has been deprecated, please migrate to rspack.CopyPlugin`, - enableDeprecatedWarning + )}' has been deprecated, please migrate to ${termlink( + "rspack.CopyRspackPlugin", + "https://www.rspack.dev/config/plugins.html#copyrspackplugin" + )}` ); - new CopyPlugin(builtins.copy).apply(compiler); + new CopyRspackPlugin(builtins.copy).apply(compiler); } if (builtins.minifyOptions) { deprecatedWarn( `'builtins.minifyOptions = ${JSON.stringify( builtins.minifyOptions - )}' has been deprecated, please migrate to rspack.SwcJsMinimizerPlugin and rspack.SwcCssMinimizerPlugin`, - enableDeprecatedWarning + )}' has been deprecated, please migrate to ${termlink( + "rspack.SwcJsMinimizerRspackPlugin", + "https://www.rspack.dev/config/plugins.html#SwcJsMinimizerRspackPlugin" + )} and ${termlink( + "rspack.SwcCssMinimizerRspackPlugin", + "https://www.rspack.dev/config/plugins.html#SwcCssMinimizerRspackPlugin" + )}` ); } const disableMinify = !options.optimization.minimize || options.optimization.minimizer!.some(item => item !== "..."); if (!disableMinify) { - new SwcJsMinimizerPlugin(builtins.minifyOptions).apply(compiler); - new SwcCssMinimizerPlugin().apply(compiler); + new SwcJsMinimizerRspackPlugin(builtins.minifyOptions).apply(compiler); + new SwcCssMinimizerRspackPlugin().apply(compiler); } let noEmitAssets = false; @@ -252,8 +274,7 @@ export function deprecated_resolveBuiltins( deprecatedWarn( `'builtins.noEmitAssets = ${JSON.stringify( builtins.noEmitAssets - )}' has been deprecated, this is only a temporary workaround for memory output FS, since Rspack have already supported memory output FS, so you can safely remove this`, - enableDeprecatedWarning + )}' has been deprecated, this is only a temporary workaround for memory output FS, since Rspack have already supported memory output FS, so you can safely remove this` ); noEmitAssets = true; } diff --git a/packages/rspack/src/config/adapter.ts b/packages/rspack/src/config/adapter.ts index fa2e7ad9cb8..8d2a2b1ec6d 100644 --- a/packages/rspack/src/config/adapter.ts +++ b/packages/rspack/src/config/adapter.ts @@ -20,7 +20,7 @@ import type { import assert from "assert"; import { Compiler } from "../Compiler"; import { normalizeStatsPreset } from "../Stats"; -import { isNil } from "../util"; +import { deprecatedWarn, isNil } from "../util"; import { parseResource } from "../util/identifier"; import { ComposeJsUseOptions, @@ -75,6 +75,7 @@ export const getRawOptions = ( ); const devtool = options.devtool === false ? "" : options.devtool; const mode = options.mode; + const experiments = getRawExperiments(options.experiments); return { mode, target: getRawTarget(options.target), @@ -86,7 +87,8 @@ export const getRawOptions = ( compiler, devtool, mode, - context: options.context + context: options.context, + experiments }), devtool, optimization: getRawOptimization(options.optimization), @@ -107,7 +109,7 @@ export const getRawOptions = ( name: "", version: "" }, - experiments: getRawExperiments(options.experiments), + experiments, node: getRawNode(options.node), profile: options.profile!, // TODO: remove this @@ -180,7 +182,6 @@ function getRawOutput(output: OutputNormalized): RawOptions["output"] { clean: output.clean!, assetModuleFilename: output.assetModuleFilename!, filename: output.filename!, - chunkFormat: output.chunkFormat === false ? "false" : output.chunkFormat!, chunkFilename: output.chunkFilename!, chunkLoading: chunkLoading === false ? "false" : chunkLoading, crossOriginLoading: getRawCrossOriginLoading(output.crossOriginLoading!), @@ -188,6 +189,7 @@ function getRawOutput(output: OutputNormalized): RawOptions["output"] { cssChunkFilename: output.cssChunkFilename!, hotUpdateChunkFilename: output.hotUpdateChunkFilename!, hotUpdateMainFilename: output.hotUpdateMainFilename!, + hotUpdateGlobal: output.hotUpdateGlobal!, uniqueName: output.uniqueName!, chunkLoadingGlobal: output.chunkLoadingGlobal!, enabledLibraryTypes: output.enabledLibraryTypes, @@ -319,6 +321,15 @@ function tryMatch(payload: string, condition: RuleSetCondition): boolean { return false; } +const deprecatedRuleType = (type?: string) => { + type ??= "javascript/auto"; + if (/ts|typescript|tsx|typescriptx|jsx|javascriptx/.test(type)) { + deprecatedWarn( + `'Rule.type: ${type}' has been deprecated, please migrate to builtin:swc-loader with type 'javascript/auto'` + ); + } +}; + const getRawModuleRule = ( rule: RuleSetRule, path: string, @@ -443,6 +454,9 @@ const getRawModuleRule = ( return true; }); } + if (options.experiments.rspackFuture.disableTransformByDefault) { + deprecatedRuleType(rule.type); + } return rawModuleRule; }; @@ -638,8 +652,10 @@ function getRawOptimization( !isNil(optimization.removeAvailableModules) && !isNil(optimization.removeEmptyChunks) && !isNil(optimization.sideEffects) && - !isNil(optimization.realContentHash), - "optimization.moduleIds, optimization.removeAvailableModules, optimization.removeEmptyChunks, optimization.sideEffects, optimization.realContentHash should not be nil after defaults" + !isNil(optimization.realContentHash) && + !isNil(optimization.providedExports) && + !isNil(optimization.usedExports), + "optimization.moduleIds, optimization.removeAvailableModules, optimization.removeEmptyChunks, optimization.sideEffects, optimization.realContentHash, optimization.providedExports, optimization.usedExports should not be nil after defaults" ); return { chunkIds: optimization.chunkIds, @@ -648,7 +664,9 @@ function getRawOptimization( removeAvailableModules: optimization.removeAvailableModules, removeEmptyChunks: optimization.removeEmptyChunks, sideEffects: String(optimization.sideEffects), - realContentHash: optimization.realContentHash + realContentHash: optimization.realContentHash, + usedExports: String(optimization.usedExports), + providedExports: optimization.providedExports }; } @@ -740,8 +758,12 @@ function getRawRspackFutureOptions( future: RspackFutureOptions ): RawRspackFuture { assert(!isNil(future.newResolver)); + assert(!isNil(future.newTreeshaking)); + assert(!isNil(future.disableTransformByDefault)); return { - newResolver: future.newResolver + newResolver: future.newResolver, + newTreeshaking: future.newTreeshaking, + disableTransformByDefault: future.disableTransformByDefault }; } diff --git a/packages/rspack/src/config/adapterRuleUse.ts b/packages/rspack/src/config/adapterRuleUse.ts index 682fc1428b2..987d5008307 100644 --- a/packages/rspack/src/config/adapterRuleUse.ts +++ b/packages/rspack/src/config/adapterRuleUse.ts @@ -17,7 +17,7 @@ import { RuleSetLoaderWithOptions } from "./zod"; import { parsePathQueryFragment } from "../loader-runner"; -import { isNil } from "../util"; +import { deprecatedWarn, isNil, termlink } from "../util"; import { resolveEmotion, resolvePluginImport, @@ -31,6 +31,7 @@ export interface ComposeJsUseOptions { devtool: RawOptions["devtool"]; context: RawOptions["context"]; mode: RawOptions["mode"]; + experiments: RawOptions["experiments"]; compiler: Compiler; } @@ -269,6 +270,12 @@ function getBuiltinLoaderOptions( options: ComposeJsUseOptions ): RuleSetLoaderWithOptions["options"] { if (identifier.startsWith(`${BUILTIN_LOADER_PREFIX}sass-loader`)) { + deprecatedWarn( + `'builtin:sass-loader' has been deprecated, please migrate to ${termlink( + "sass-loader", + "https://github.com/webpack-contrib/sass-loader" + )}` + ); return getSassLoaderOptions(o, options); } diff --git a/packages/rspack/src/config/defaults.ts b/packages/rspack/src/config/defaults.ts index d24bb093faa..e97cfd8d345 100644 --- a/packages/rspack/src/config/defaults.ts +++ b/packages/rspack/src/config/defaults.ts @@ -82,6 +82,8 @@ export const applyRspackOptionsDefaults = ( applyModuleDefaults(options.module, { // syncWebAssembly: options.experiments.syncWebAssembly, asyncWebAssembly: options.experiments.asyncWebAssembly!, + disableTransformByDefault: + options.experiments.rspackFuture!.disableTransformByDefault!, css: options.experiments.css! }); @@ -174,6 +176,8 @@ const applyExperimentsDefaults = ( D(experiments, "rspackFuture", {}); if (typeof experiments.rspackFuture === "object") { D(experiments.rspackFuture, "newResolver", false); + D(experiments.rspackFuture, "newTreeshaking", false); + D(experiments.rspackFuture, "disableTransformByDefault", false); } }; @@ -195,7 +199,15 @@ const applySnapshotDefaults = ( const applyModuleDefaults = ( module: ModuleOptions, - { asyncWebAssembly, css }: { asyncWebAssembly: boolean; css: boolean } + { + asyncWebAssembly, + css, + disableTransformByDefault + }: { + asyncWebAssembly: boolean; + css: boolean; + disableTransformByDefault: boolean; + } ) => { F(module.parser!, "asset", () => ({})); F(module.parser!.asset!, "dataUrlCondition", () => ({})); @@ -257,21 +269,27 @@ const applyModuleDefaults = ( or: ["text/javascript", "application/javascript"] }, ...esm - }, - { - test: /\.jsx$/i, - type: "jsx" - }, - { - test: /\.ts$/i, - type: "ts" - }, - { - test: /\.tsx$/i, - type: "tsx" } ]; + // TODO: remove in 0.5.0 + if (!disableTransformByDefault) { + rules.push( + { + test: /\.jsx$/i, + type: "jsx" + }, + { + test: /\.ts$/i, + type: "ts" + }, + { + test: /\.tsx$/i, + type: "tsx" + } + ); + } + if (asyncWebAssembly) { const wasm = { type: "webassembly/async", @@ -420,6 +438,7 @@ const applyOutputDefaults = ( `[id].[fullhash].hot-update.${output.module ? "mjs" : "js"}` ); D(output, "hotUpdateMainFilename", "[runtime].[fullhash].hot-update.json"); + F(output, "hotUpdateGlobal", () => "webpackHotUpdate" + output.uniqueName); D(output, "assetModuleFilename", "[hash][ext][query]"); D(output, "webassemblyModuleFilename", "[hash].module.wasm"); F(output, "path", () => path.join(process.cwd(), "dist")); @@ -666,6 +685,8 @@ const applyOptimizationDefaults = ( }); F(optimization, "chunkIds", (): "named" | "deterministic" => "named"); F(optimization, "sideEffects", () => (production ? true : "flag")); + D(optimization, "providedExports", true); + D(optimization, "usedExports", production); D(optimization, "runtimeChunk", false); D(optimization, "realContentHash", production); D(optimization, "minimize", production); diff --git a/packages/rspack/src/config/normalization.ts b/packages/rspack/src/config/normalization.ts index c90ce038e8a..08ff924a3aa 100644 --- a/packages/rspack/src/config/normalization.ts +++ b/packages/rspack/src/config/normalization.ts @@ -73,7 +73,8 @@ import type { ParserOptionsByModuleType, GeneratorOptionsByModuleType, IncrementalRebuildOptions, - RspackFutureOptions + RspackFutureOptions, + HotUpdateGlobal } from "./zod"; export const getNormalizedRspackOptions = ( @@ -150,6 +151,7 @@ export const getNormalizedRspackOptions = ( cssChunkFilename: output.cssChunkFilename, hotUpdateMainFilename: output.hotUpdateMainFilename, hotUpdateChunkFilename: output.hotUpdateChunkFilename, + hotUpdateGlobal: output.hotUpdateGlobal, assetModuleFilename: output.assetModuleFilename, wasmLoading: output.wasmLoading, enabledChunkLoadingTypes: output.enabledChunkLoadingTypes @@ -438,6 +440,7 @@ export interface OutputNormalized { cssChunkFilename?: CssChunkFilename; hotUpdateMainFilename?: HotUpdateMainFilename; hotUpdateChunkFilename?: HotUpdateChunkFilename; + hotUpdateGlobal?: HotUpdateGlobal; assetModuleFilename?: AssetModuleFilename; uniqueName?: UniqueName; chunkLoadingGlobal?: ChunkLoadingGlobal; diff --git a/packages/rspack/src/config/zod.ts b/packages/rspack/src/config/zod.ts index b3e4ec53103..3ae4d88b6fe 100644 --- a/packages/rspack/src/config/zod.ts +++ b/packages/rspack/src/config/zod.ts @@ -125,6 +125,9 @@ export type HotUpdateChunkFilename = z.infer; const hotUpdateMainFilename = filenameTemplate; export type HotUpdateMainFilename = z.infer; +const hotUpdateGlobal = z.string(); +export type HotUpdateGlobal = z.infer; + const uniqueName = z.string(); export type UniqueName = z.infer; @@ -262,6 +265,7 @@ const output = z.strictObject({ cssChunkFilename: cssChunkFilename.optional(), hotUpdateMainFilename: hotUpdateMainFilename.optional(), hotUpdateChunkFilename: hotUpdateChunkFilename.optional(), + hotUpdateGlobal: hotUpdateGlobal.optional(), assetModuleFilename: assetModuleFilename.optional(), uniqueName: uniqueName.optional(), chunkLoadingGlobal: chunkLoadingGlobal.optional(), @@ -337,20 +341,22 @@ export type Resolve = z.infer; //#endregion //#region Module -export type RuleSetCondition = - | RegExp - | string - | RuleSetConditions - | RuleSetLogicalConditions - | ((value: string) => boolean); -const ruleSetCondition: z.ZodType = z +const baseRuleSetCondition = z .instanceof(RegExp) .or(z.string()) - .or(z.lazy(() => ruleSetConditions)) - .or(z.lazy(() => ruleSetLogicalConditions)) .or(z.function().args(z.string()).returns(z.boolean())); +export type RuleSetCondition = + | z.infer + | RuleSetConditions + | RuleSetLogicalConditions; + +const ruleSetCondition: z.ZodType = baseRuleSetCondition + .or(z.lazy(() => ruleSetConditions)) + .or(z.lazy(() => ruleSetLogicalConditions)); + export type RuleSetConditions = RuleSetCondition[]; + const ruleSetConditions: z.ZodType = z.lazy(() => z.array(ruleSetCondition) ); @@ -360,6 +366,7 @@ export type RuleSetLogicalConditions = { or?: RuleSetConditions; not?: RuleSetConditions; }; + const ruleSetLogicalConditions: z.ZodType = z.strictObject({ and: ruleSetConditions.optional(), @@ -390,37 +397,7 @@ const ruleSetUse = ruleSetUseItem ); export type RuleSetUse = z.infer; -export type RuleSetRule = { - test?: RuleSetCondition; - exclude?: RuleSetCondition; - include?: RuleSetCondition; - issuer?: RuleSetCondition; - dependency?: RuleSetCondition; - resource?: RuleSetCondition; - resourceFragment?: RuleSetCondition; - resourceQuery?: RuleSetCondition; - scheme?: RuleSetCondition; - mimetype?: RuleSetCondition; - descriptionData?: { - [k: string]: RuleSetCondition; - }; - oneOf?: RuleSetRule[]; - rules?: RuleSetRule[]; - type?: string; - loader?: RuleSetLoader; - options?: RuleSetLoaderOptions; - use?: RuleSetUse; - parser?: { - [k: string]: any; - }; - generator?: { - [k: string]: any; - }; - resolve?: ResolveOptions; - sideEffects?: boolean; - enforce?: "pre" | "post"; -}; -const ruleSetRule: z.ZodType = z.strictObject({ +const baseRuleSetRule = z.strictObject({ test: ruleSetCondition.optional(), exclude: ruleSetCondition.optional(), include: ruleSetCondition.optional(), @@ -432,8 +409,6 @@ const ruleSetRule: z.ZodType = z.strictObject({ scheme: ruleSetCondition.optional(), mimetype: ruleSetCondition.optional(), descriptionData: z.record(ruleSetCondition).optional(), - oneOf: z.lazy(() => ruleSetRule.array()).optional(), - rules: z.lazy(() => ruleSetRule.array()).optional(), type: z.string().optional(), loader: ruleSetLoader.optional(), options: ruleSetLoaderOptions.optional(), @@ -445,6 +420,16 @@ const ruleSetRule: z.ZodType = z.strictObject({ enforce: z.literal("pre").or(z.literal("post")).optional() }); +export type RuleSetRule = z.infer & { + oneOf?: RuleSetRule[]; + rules?: RuleSetRule[]; +}; + +const ruleSetRule: z.ZodType = baseRuleSetRule.extend({ + oneOf: z.lazy(() => ruleSetRule.array()).optional(), + rules: z.lazy(() => ruleSetRule.array()).optional() +}); + const ruleSetRules = z.array(z.literal("...").or(ruleSetRule)); export type RuleSetRules = z.infer; @@ -650,7 +635,11 @@ export type ExternalsType = z.infer; //#endregion //#region Externals -const externalItemValue = z.string().or(z.boolean()).or(z.string().array()); +const externalItemValue = z + .string() + .or(z.boolean()) + .or(z.string().array().min(1)) + .or(z.record(z.string().or(z.string().array()))); export type ExternalItemValue = z.infer; const externalItemObjectUnknown = z.record(externalItemValue); @@ -700,6 +689,7 @@ export type Externals = z.infer; const externalsPresets = z.strictObject({ node: z.boolean().optional(), web: z.boolean().optional(), + webAsync: z.boolean().optional(), electron: z.boolean().optional(), electronMain: z.boolean().optional(), electronPreload: z.boolean().optional(), @@ -936,7 +926,9 @@ const optimization = z.strictObject({ removeAvailableModules: z.boolean().optional(), removeEmptyChunks: z.boolean().optional(), realContentHash: z.boolean().optional(), - sideEffects: z.enum(["flag"]).or(z.boolean()).optional() + sideEffects: z.enum(["flag"]).or(z.boolean()).optional(), + providedExports: z.boolean().optional(), + usedExports: z.enum(["global"]).or(z.boolean()).optional() }); export type Optimization = z.infer; //#endregion @@ -951,7 +943,9 @@ export type IncrementalRebuildOptions = z.infer< >; const rspackFutureOptions = z.strictObject({ - newResolver: z.boolean().optional() + newResolver: z.boolean().optional(), + newTreeshaking: z.boolean().optional(), + disableTransformByDefault: z.boolean().optional() }); export type RspackFutureOptions = z.infer; @@ -960,7 +954,17 @@ const experiments = z.strictObject({ incrementalRebuild: z.boolean().or(incrementalRebuildOptions).optional(), asyncWebAssembly: z.boolean().optional(), outputModule: z.boolean().optional(), - newSplitChunks: z.boolean().optional(), + newSplitChunks: z + .boolean() + .optional() + .refine(val => { + if (val === false || val === true) { + console.warn( + "`experiments.newSplitChunks` will be removed at 0.4.0. See details at https://github.com/web-infra-dev/rspack/discussions/4168" + ); + } + return true; + }), css: z.boolean().optional(), futureDefaults: z.boolean().optional(), rspackFuture: rspackFutureOptions.optional() diff --git a/packages/rspack/src/index.ts b/packages/rspack/src/index.ts index b4ec6762100..4cc90f3238a 100644 --- a/packages/rspack/src/index.ts +++ b/packages/rspack/src/index.ts @@ -12,6 +12,7 @@ export * from "./NormalModuleFactory"; export { cachedCleverMerge as cleverMerge } from "./util/cleverMerge"; export { EnvironmentPlugin } from "./lib/EnvironmentPlugin"; export { LoaderOptionsPlugin } from "./lib/LoaderOptionsPlugin"; +export { LoaderTargetPlugin } from "./lib/LoaderTargetPlugin"; export { registerGlobalTrace as experimental_registerGlobalTrace, cleanupGlobalTrace as experimental_cleanupGlobalTrace @@ -26,25 +27,37 @@ export { DefinePlugin, ProvidePlugin, ProgressPlugin, - HtmlPlugin, - SwcJsMinimizerPlugin, - SwcCssMinimizerPlugin, - CopyPlugin, + HtmlRspackPlugin, + SwcJsMinimizerRspackPlugin, + SwcCssMinimizerRspackPlugin, + CopyRspackPlugin, EntryPlugin, - ExternalsPlugin + ExternalsPlugin, + EnableChunkLoadingPlugin, + HotModuleReplacementPlugin } from "./builtin-plugin"; export type { BannerPluginArgument, DefinePluginOptions, ProvidePluginOptions, ProgressPluginArgument, - HtmlPluginOptions, - SwcJsMinimizerPluginOptions, - CopyPluginOptions, + HtmlRspackPluginOptions, + SwcJsMinimizerRspackPluginOptions, + CopyRspackPluginOptions, EntryOptions } from "./builtin-plugin"; -import { ElectronTargetPlugin, NodeTargetPlugin } from "./builtin-plugin"; -export const node = { NodeTargetPlugin }; + +import NodeTemplatePlugin from "./node/NodeTemplatePlugin"; +import { NodeTargetPlugin } from "./builtin-plugin"; +export const node = { NodeTargetPlugin, NodeTemplatePlugin }; + +import { ElectronTargetPlugin } from "./builtin-plugin"; export const electron = { ElectronTargetPlugin }; +import { EnableLibraryPlugin } from "./builtin-plugin"; +export const library = { EnableLibraryPlugin }; + +import { EnableWasmLoadingPlugin } from "./builtin-plugin"; +export const wasm = { EnableWasmLoadingPlugin }; + export { Watching }; diff --git a/packages/rspack/src/lib/AbstractMethodError.js b/packages/rspack/src/lib/AbstractMethodError.js new file mode 100644 index 00000000000..bbf2d08a6c7 --- /dev/null +++ b/packages/rspack/src/lib/AbstractMethodError.js @@ -0,0 +1,49 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Ivan Kopeykin @vankop +*/ + +"use strict"; + +const WebpackError = require("./WebpackError"); +const CURRENT_METHOD_REGEXP = /at ([a-zA-Z0-9_.]*)/; + +/** + * @param {string=} method method name + * @returns {string} message + */ +function createMessage(method) { + return `Abstract method${method ? " " + method : ""}. Must be overridden.`; +} + +/** + * @constructor + */ +function Message() { + /** @type {string} */ + this.stack = undefined; + Error.captureStackTrace(this); + /** @type {RegExpMatchArray} */ + const match = this.stack.split("\n")[3].match(CURRENT_METHOD_REGEXP); + + this.message = match && match[1] ? createMessage(match[1]) : createMessage(); +} + +/** + * Error for abstract method + * @example + * class FooClass { + * abstractMethod() { + * throw new AbstractMethodError(); // error message: Abstract method FooClass.abstractMethod. Must be overridden. + * } + * } + * + */ +class AbstractMethodError extends WebpackError { + constructor() { + super(new Message().message); + this.name = "AbstractMethodError"; + } +} + +module.exports = AbstractMethodError; diff --git a/packages/rspack/src/lib/LoaderTargetPlugin.js b/packages/rspack/src/lib/LoaderTargetPlugin.js new file mode 100644 index 00000000000..7156e5fa4c9 --- /dev/null +++ b/packages/rspack/src/lib/LoaderTargetPlugin.js @@ -0,0 +1,37 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ + +"use strict"; + +const NormalModule = require("../NormalModule"); + +/** @typedef {import("./Compiler")} Compiler */ + +class LoaderTargetPlugin { + /** + * @param {string} target the target + */ + constructor(target) { + this.target = target; + } + + /** + * Apply the plugin + * @param {Compiler} compiler the compiler instance + * @returns {void} + */ + apply(compiler) { + compiler.hooks.compilation.tap("LoaderTargetPlugin", compilation => { + NormalModule.getCompilationHooks(compilation).loader.tap( + "LoaderTargetPlugin", + loaderContext => { + loaderContext.target = this.target; + } + ); + }); + } +} + +export { LoaderTargetPlugin }; diff --git a/packages/rspack/src/node/NodeTemplatePlugin.ts b/packages/rspack/src/node/NodeTemplatePlugin.ts new file mode 100644 index 00000000000..c9f64bb7653 --- /dev/null +++ b/packages/rspack/src/node/NodeTemplatePlugin.ts @@ -0,0 +1,30 @@ +/** + * The following code is modified based on + * https://github.com/webpack/webpack/blob/4b4ca3b/lib/node/NodeTemplatePlugin.js + * + * MIT Licensed + * Author Tobias Koppers @sokra + * Copyright (c) JS Foundation and other contributors + * https://github.com/webpack/webpack/blob/main/LICENSE + */ + +import { Compiler } from "../Compiler"; +import { + CommonJsChunkFormatPlugin, + EnableChunkLoadingPlugin +} from "../builtin-plugin"; + +export type NodeTemplatePluginOptions = { asyncChunkLoading?: boolean }; + +export default class NodeTemplatePlugin { + constructor(private _options: NodeTemplatePluginOptions = {}) {} + + apply(compiler: Compiler) { + const chunkLoading = this._options.asyncChunkLoading + ? "async-node" + : "require"; + compiler.options.output.chunkLoading = chunkLoading; + new CommonJsChunkFormatPlugin().apply(compiler); + new EnableChunkLoadingPlugin(chunkLoading).apply(compiler); + } +} diff --git a/packages/rspack/src/rspackOptionsApply.ts b/packages/rspack/src/rspackOptionsApply.ts index 860164cada6..2d3b9ba5d45 100644 --- a/packages/rspack/src/rspackOptionsApply.ts +++ b/packages/rspack/src/rspackOptionsApply.ts @@ -20,14 +20,127 @@ import { DefaultStatsFactoryPlugin } from "./stats/DefaultStatsFactoryPlugin"; import { DefaultStatsPrinterPlugin } from "./stats/DefaultStatsPrinterPlugin"; import { cleverMerge } from "./util/cleverMerge"; import assert from "assert"; +import IgnoreWarningsPlugin from "./lib/ignoreWarningsPlugin"; +import EntryOptionPlugin from "./lib/EntryOptionPlugin"; import { + ArrayPushCallbackChunkFormatPlugin, + CommonJsChunkFormatPlugin, + ElectronTargetPlugin, + EnableChunkLoadingPlugin, + EnableLibraryPlugin, + EnableWasmLoadingPlugin, ExternalsPlugin, - HttpExternalsPlugin, - NodeTargetPlugin, - ElectronTargetPlugin + HttpExternalsRspackPlugin, + ModuleChunkFormatPlugin, + NodeTargetPlugin } from "./builtin-plugin"; -import IgnoreWarningsPlugin from "./lib/ignoreWarningsPlugin"; -import EntryOptionPlugin from "./lib/EntryOptionPlugin"; + +export function optionsApply_compat( + compiler: Compiler, + options: RspackOptionsNormalized +) { + if (compiler.parentCompilation === undefined) { + if (options.externals) { + assert( + options.externalsType, + "options.externalsType should have value after `applyRspackOptionsDefaults`" + ); + new ExternalsPlugin(options.externalsType, options.externals).apply( + compiler + ); + } + + if (options.externalsPresets.node) { + new NodeTargetPlugin().apply(compiler); + } + if (options.externalsPresets.electronMain) { + new ElectronTargetPlugin("main").apply(compiler); + } + if (options.externalsPresets.electronPreload) { + new ElectronTargetPlugin("preload").apply(compiler); + } + if (options.externalsPresets.electronRenderer) { + new ElectronTargetPlugin("renderer").apply(compiler); + } + if ( + options.externalsPresets.electron && + !options.externalsPresets.electronMain && + !options.externalsPresets.electronPreload && + !options.externalsPresets.electronRenderer + ) { + new ElectronTargetPlugin().apply(compiler); + } + if ( + options.externalsPresets.web || + options.externalsPresets.webAsync || + (options.externalsPresets.node && options.experiments.css) + ) { + new HttpExternalsRspackPlugin( + !!options.experiments.css, + !!options.externalsPresets.webAsync + ).apply(compiler); + } + + if (typeof options.output.chunkFormat === "string") { + switch (options.output.chunkFormat) { + case "array-push": { + new ArrayPushCallbackChunkFormatPlugin().apply(compiler); + break; + } + case "commonjs": { + new CommonJsChunkFormatPlugin().apply(compiler); + break; + } + case "module": { + new ModuleChunkFormatPlugin().apply(compiler); + break; + } + default: + throw new Error( + "Unsupported chunk format '" + options.output.chunkFormat + "'." + ); + } + } + + if ( + options.output.enabledChunkLoadingTypes && + options.output.enabledChunkLoadingTypes.length > 0 + ) { + for (const type of options.output.enabledChunkLoadingTypes) { + new EnableChunkLoadingPlugin(type).apply(compiler); + } + } + + if ( + options.output.enabledWasmLoadingTypes && + options.output.enabledWasmLoadingTypes.length > 0 + ) { + for (const type of options.output.enabledWasmLoadingTypes) { + new EnableWasmLoadingPlugin(type).apply(compiler); + } + } + + if ( + options.output.enabledLibraryTypes && + options.output.enabledLibraryTypes.length > 0 + ) { + for (const type of options.output.enabledLibraryTypes) { + new EnableLibraryPlugin(type).apply(compiler); + } + } + + // TODO: change to new EntryOptionPlugin().apply(compiler); + EntryOptionPlugin.applyEntryOption( + compiler, + compiler.context, + options.entry + ); + + if (options.devServer?.hot) { + new compiler.webpack.HotModuleReplacementPlugin().apply(compiler); + } + } +} export class RspackOptionsApply { constructor() {} @@ -40,43 +153,6 @@ export class RspackOptionsApply { compiler.name = options.name; compiler.outputFileSystem = fs; - // if (options.externals) { - // assert( - // options.externalsType, - // "options.externalsType should have value after `applyRspackOptionsDefaults`" - // ); - // new ExternalsPlugin(options.externalsType, options.externals).apply( - // compiler - // ); - // } - - // if (options.externalsPresets.node) { - // new NodeTargetPlugin().apply(compiler); - // } - // if (options.externalsPresets.electronMain) { - // new ElectronTargetPlugin("main").apply(compiler); - // } - // if (options.externalsPresets.electronPreload) { - // new ElectronTargetPlugin("preload").apply(compiler); - // } - // if (options.externalsPresets.electronRenderer) { - // new ElectronTargetPlugin("renderer").apply(compiler); - // } - // if ( - // options.externalsPresets.electron && - // !options.externalsPresets.electronMain && - // !options.externalsPresets.electronPreload && - // !options.externalsPresets.electronRenderer - // ) { - // new ElectronTargetPlugin().apply(compiler); - // } - // if ( - // options.externalsPresets.web || - // (options.externalsPresets.node && options.experiments.css) - // ) { - // new HttpExternalsPlugin(!!options.experiments.css).apply(compiler); - // } - const runtimeChunk = options.optimization .runtimeChunk as OptimizationRuntimeChunkNormalized; if (runtimeChunk) { diff --git a/packages/rspack/src/stats/DefaultStatsPrinterPlugin.ts b/packages/rspack/src/stats/DefaultStatsPrinterPlugin.ts index 6e50b374276..bc220ef7aa0 100644 --- a/packages/rspack/src/stats/DefaultStatsPrinterPlugin.ts +++ b/packages/rspack/src/stats/DefaultStatsPrinterPlugin.ts @@ -105,7 +105,7 @@ const SIMPLE_PRINTERS: Record< const builtAtMessage = root && builtAt ? `${formatDateTime(builtAt)}: ` : ""; const versionMessage = - root && rspackVersion ? `rspack ${rspackVersion}` : ""; + root && rspackVersion ? `Rspack ${rspackVersion}` : ""; const nameMessage = root && name ? bold(name) @@ -117,7 +117,7 @@ const SIMPLE_PRINTERS: Record< const subjectMessage = nameMessage && versionMessage ? `${nameMessage} (${versionMessage})` - : versionMessage || nameMessage || "rspack"; + : versionMessage || nameMessage || "Rspack"; let statusMessage; if (errorsMessage && warningsMessage) { statusMessage = `compiled with ${errorsMessage} and ${warningsMessage}`; diff --git a/packages/rspack/src/util/fake.ts b/packages/rspack/src/util/fake.ts index 1ba2a259697..d8486f63ce9 100644 --- a/packages/rspack/src/util/fake.ts +++ b/packages/rspack/src/util/fake.ts @@ -49,6 +49,58 @@ export const createFakeProcessAssetsHook = (compilation: Compilation) => { }; }; +export type FakeHook = T & { _fakeHook: true }; + +export const createFakeHook = (fakeHook: T): FakeHook => { + return Object.freeze(Object.assign(fakeHook, { _fakeHook: true as const })); +}; + +export const createProcessAssetsHook = ( + processAssetsHooks: ReturnType, + name: string, + stage: number, + getArgs: () => tapable.AsArray +): FakeHook< + Pick, "tap" | "tapAsync" | "tapPromise" | "name"> +> => { + const errorMessage = ( + reason: string + ) => `Can't automatically convert plugin using Compilation.hooks.${name} to Compilation.hooks.processAssets because ${reason}. +BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a single Compilation.hooks.processAssets hook.`; + const getOptions = ( + options: string | (tapable.TapOptions & { name: string }) + ) => { + if (typeof options === "string") options = { name: options }; + if (options.stage) { + throw new Error(errorMessage("it's using the 'stage' option")); + } + return { ...options, stage: stage }; + }; + const tap: tapable.AsyncSeriesHook["tap"] = (options, fn) => { + processAssetsHooks.tap(getOptions(options), () => fn(...getArgs())); + }; + const tapAsync: tapable.AsyncSeriesHook["tapAsync"] = (options, fn) => { + processAssetsHooks.tapAsync(getOptions(options), (assets, callback) => + (fn as any)(...getArgs(), callback) + ); + }; + const tapPromise: tapable.AsyncSeriesHook["tapPromise"] = ( + options, + fn + ) => { + processAssetsHooks.tapPromise(getOptions(options), () => fn(...getArgs())); + }; + return createFakeHook({ + name, + intercept() { + throw new Error(errorMessage("it's using 'intercept'")); + }, + tap, + tapAsync, + tapPromise + }); +}; + export function createFakeCompilationDependencies( getDeps: () => string[], addDeps: (deps: string[]) => void diff --git a/packages/rspack/src/util/hash/index.js b/packages/rspack/src/util/hash/index.js index e7f00f9e666..08c103aa184 100644 --- a/packages/rspack/src/util/hash/index.js +++ b/packages/rspack/src/util/hash/index.js @@ -19,7 +19,7 @@ class Hash { * @returns {this} updated hash */ update(data, inputEncoding) { - const AbstractMethodError = require("../AbstractMethodError"); + const AbstractMethodError = require("../../lib/AbstractMethodError"); throw new AbstractMethodError(); } @@ -31,7 +31,7 @@ class Hash { * @returns {string|Buffer} digest */ digest(encoding) { - const AbstractMethodError = require("../AbstractMethodError"); + const AbstractMethodError = require("../../lib/AbstractMethodError"); throw new AbstractMethodError(); } } diff --git a/packages/rspack/src/util/index.ts b/packages/rspack/src/util/index.ts index 346ec580e18..e2a50e94adf 100644 --- a/packages/rspack/src/util/index.ts +++ b/packages/rspack/src/util/index.ts @@ -107,10 +107,19 @@ export function toJsAssetInfo(info?: AssetInfo): JsAssetInfo { ...info }; } - +const getDeprecationStatus = () => { + const defaultEnableDeprecatedWarning = false; + return ( + (process.env.RSPACK_BUILTINS_DEPRECATED ?? + `${defaultEnableDeprecatedWarning}`) !== "false" + ); +}; const yellow = (content: string) => `\u001b[1m\u001b[33m${content}\u001b[39m\u001b[22m`; -export const deprecatedWarn = (content: string, enable = true) => { +export const deprecatedWarn = ( + content: string, + enable = getDeprecationStatus() +) => { if (enable) { console.warn(yellow(content)); } diff --git a/packages/rspack/tests/ConfigCase.template.ts b/packages/rspack/tests/ConfigCase.template.ts index 4cc23fa0d54..54ef2fdae3e 100644 --- a/packages/rspack/tests/ConfigCase.template.ts +++ b/packages/rspack/tests/ConfigCase.template.ts @@ -538,13 +538,7 @@ export const describeCases = config => { __dirname: path.dirname(p), __filename: p, _globalAssign: { expect }, - define, - // TODO support __non_webpack_require__ - __non_webpack_require__: _require.bind( - null, - path.dirname(p), - options - ) + define }; if (testConfig.moduleScope) { testConfig.moduleScope(moduleScope); diff --git a/packages/rspack/tests/Defaults.unittest.ts b/packages/rspack/tests/Defaults.unittest.ts index e6296e41230..5194ba92168 100644 --- a/packages/rspack/tests/Defaults.unittest.ts +++ b/packages/rspack/tests/Defaults.unittest.ts @@ -112,8 +112,9 @@ describe("snapshots", () => { + "minimize": true, @@ ... @@ - "moduleIds": "named", - - "realContentHash": false, + "moduleIds": "deterministic", + @@ ... @@ + - "realContentHash": false, + "realContentHash": true, @@ ... @@ - "sideEffects": "flag", @@ -127,6 +128,9 @@ describe("snapshots", () => { - "minSize": 10000, + "minSize": 20000, @@ ... @@ + - "usedExports": false, + + "usedExports": true, + @@ ... @@ - "hash": false, + "hash": true, @@ ... @@ @@ -147,8 +151,9 @@ describe("snapshots", () => { + "minimize": true, @@ ... @@ - "moduleIds": "named", - - "realContentHash": false, + "moduleIds": "deterministic", + @@ ... @@ + - "realContentHash": false, + "realContentHash": true, @@ ... @@ - "sideEffects": "flag", @@ -162,6 +167,9 @@ describe("snapshots", () => { - "minSize": 10000, + "minSize": 20000, @@ ... @@ + - "usedExports": false, + + "usedExports": true, + @@ ... @@ - "hash": false, + "hash": true, @@ ... @@ @@ -929,6 +937,9 @@ describe("snapshots", () => { - "chunkLoadingGlobal": "webpackChunk@rspack/core", + "chunkLoadingGlobal": "webpackChunk@@@Hello World!", @@ ... @@ + - "hotUpdateGlobal": "webpackHotUpdate@rspack/core", + + "hotUpdateGlobal": "webpackHotUpdate@@@Hello World!", + @@ ... @@ - "trustedTypes": undefined, - "uniqueName": "@rspack/core", + "trustedTypes": Object { @@ -992,6 +1003,9 @@ describe("snapshots", () => { - "chunkLoadingGlobal": "webpackChunk@rspack/core", + "chunkLoadingGlobal": "webpackChunkbrowserslist-test", @@ ... @@ + - "hotUpdateGlobal": "webpackHotUpdate@rspack/core", + + "hotUpdateGlobal": "webpackHotUpdatebrowserslist-test", + @@ ... @@ - "uniqueName": "@rspack/core", + "uniqueName": "browserslist-test", `) @@ -1023,6 +1037,9 @@ describe("snapshots", () => { - "chunkLoadingGlobal": "webpackChunk@rspack/core", + "chunkLoadingGlobal": "webpackChunk", @@ ... @@ + - "hotUpdateGlobal": "webpackHotUpdate@rspack/core", + + "hotUpdateGlobal": "webpackHotUpdate", + @@ ... @@ - "path": "/dist", + "path": "/tests/fixtures/dist", @@ ... @@ diff --git a/packages/rspack/tests/HotTestCases.template.ts b/packages/rspack/tests/HotTestCases.template.ts index d9c038da5d6..bfa897cd8a0 100644 --- a/packages/rspack/tests/HotTestCases.template.ts +++ b/packages/rspack/tests/HotTestCases.template.ts @@ -4,7 +4,12 @@ import vm from "vm"; import rimraf from "rimraf"; import checkArrayExpectation from "./checkArrayExpectation"; import createLazyTestEnv from "./helpers/createLazyTestEnv"; -import { Compiler, rspack, Stats } from "@rspack/core"; +import { + Compiler, + rspack, + Stats, + HotModuleReplacementPlugin +} from "@rspack/core"; export function describeCases(config: { name: string; @@ -460,5 +465,8 @@ function getOptions( ...options.devServer, hot }; + if (hot) { + options.plugins.push(new HotModuleReplacementPlugin()); + } return options; } diff --git a/packages/rspack/tests/Stats.test.ts b/packages/rspack/tests/Stats.test.ts index dff1a5fd2f5..fceedfa6fb0 100644 --- a/packages/rspack/tests/Stats.test.ts +++ b/packages/rspack/tests/Stats.test.ts @@ -34,7 +34,7 @@ describe("Stats", () => { entry ./fixtures/a ./fixtures/a.js [876] {main} entry ./fixtures/a - rspack compiled successfully (31124a919605602fc9ae)" + Rspack compiled successfully (224575f0bba4bc71b95f)" `); }); @@ -79,7 +79,7 @@ describe("Stats", () => { - rspack compiled with 1 error (18c9b1da202481673984)" + Rspack compiled with 1 error (51da9544767033575b9e)" `); }); @@ -144,6 +144,7 @@ describe("Stats", () => { module build task: X ms finish modules: X ms optimize dependencies: X ms + optimize dependencies: X ms create chunks: X ms optimize: X ms module ids: X ms diff --git a/packages/rspack/tests/__snapshots__/Defaults.unittest.ts.snap b/packages/rspack/tests/__snapshots__/Defaults.unittest.ts.snap index 728f86b31f8..679f21564e7 100644 --- a/packages/rspack/tests/__snapshots__/Defaults.unittest.ts.snap +++ b/packages/rspack/tests/__snapshots__/Defaults.unittest.ts.snap @@ -25,7 +25,9 @@ exports[`snapshots should have the correct base config 1`] = ` "lazyCompilation": false, "newSplitChunks": true, "rspackFuture": { + "disableTransformByDefault": false, "newResolver": false, + "newTreeshaking": false, }, }, "externals": undefined, @@ -187,6 +189,7 @@ exports[`snapshots should have the correct base config 1`] = ` "minimize": false, "minimizer": [], "moduleIds": "named", + "providedExports": true, "realContentHash": false, "removeAvailableModules": true, "removeEmptyChunks": true, @@ -213,6 +216,7 @@ exports[`snapshots should have the correct base config 1`] = ` "minChunks": 1, "minSize": 10000, }, + "usedExports": false, }, "output": { "assetModuleFilename": "[hash][ext][query]", @@ -240,6 +244,7 @@ exports[`snapshots should have the correct base config 1`] = ` "hashFunction": "md4", "hashSalt": undefined, "hotUpdateChunkFilename": "[id].[fullhash].hot-update.js", + "hotUpdateGlobal": "webpackHotUpdate@rspack/core", "hotUpdateMainFilename": "[runtime].[fullhash].hot-update.json", "iife": true, "importFunctionName": "import", diff --git a/packages/rspack/tests/__snapshots__/Stats.test.ts.snap b/packages/rspack/tests/__snapshots__/Stats.test.ts.snap index 1f265223833..ec8f4679e40 100644 --- a/packages/rspack/tests/__snapshots__/Stats.test.ts.snap +++ b/packages/rspack/tests/__snapshots__/Stats.test.ts.snap @@ -156,7 +156,7 @@ exports[`Stats should have stats 1`] = ` "errors": [], "errorsCount": 0, "filteredModules": undefined, - "hash": "31124a919605602fc9ae", + "hash": "224575f0bba4bc71b95f", "logging": {}, "modules": [ { @@ -416,7 +416,7 @@ exports.c = require("./c?c=3"); "errors": [], "errorsCount": 0, "filteredModules": undefined, - "hash": "089a36c7767bb55f0574", + "hash": "833faf822e0c01d589e7", "logging": {}, "modules": [ { diff --git a/packages/rspack/tests/__snapshots__/StatsTestCases.test.ts.snap b/packages/rspack/tests/__snapshots__/StatsTestCases.test.ts.snap index d121012c97a..dcfd6a96118 100644 --- a/packages/rspack/tests/__snapshots__/StatsTestCases.test.ts.snap +++ b/packages/rspack/tests/__snapshots__/StatsTestCases.test.ts.snap @@ -188,7 +188,7 @@ import rawModule from './raw.png'", "errors": [], "errorsCount": 0, "filteredModules": undefined, - "hash": "94f12aa69d3989830e25", + "hash": "7a935a9f14af6fedd836", "logging": {}, "modules": [ { @@ -337,7 +337,7 @@ chunk {main} bundle.js (main) [entry] entry ./index ./stringModule.js [363] {main} esm import ./stringModule [10] -rspack compiled successfully (94f12aa69d3989830e25)" +Rspack compiled successfully (7a935a9f14af6fedd836)" `; exports[`StatsTestCases should print correct stats for filename 1`] = ` @@ -500,7 +500,7 @@ exports[`StatsTestCases should print correct stats for filename 1`] = ` "errors": [], "errorsCount": 0, "filteredModules": undefined, - "hash": "b1dbe683f73e6b1f7f2c", + "hash": "6d7c52e50cefca7d30c4", "logging": {}, "modules": [ { @@ -602,7 +602,7 @@ chunk {main} main.xxxx.js (main) >{dynamic_js}< [entry] entry ./index ./dynamic.js [426] {dynamic_js} dynamic import ./dynamic [10] -rspack compiled successfully (b1dbe683f73e6b1f7f2c)" +Rspack compiled successfully (6d7c52e50cefca7d30c4)" `; exports[`StatsTestCases should print correct stats for hot+production 1`] = ` @@ -697,7 +697,7 @@ exports[`StatsTestCases should print correct stats for hot+production 1`] = ` "errors": [], "errorsCount": 0, "filteredModules": undefined, - "hash": "86548123ac24bd06a6bf", + "hash": "8b17e56c72949ef15048", "logging": {}, "modules": [ { @@ -760,7 +760,7 @@ chunk {main} bundle.js (main) [entry] entry ./index.js ./index.js [10] {main} entry ./index.js -rspack compiled successfully (86548123ac24bd06a6bf)" +Rspack compiled successfully (8b17e56c72949ef15048)" `; exports[`StatsTestCases should print correct stats for identifier-let-strict-mode 1`] = ` @@ -817,7 +817,7 @@ error[javascript]: JavaScript parsing error -rspack compiled with 2 errors" +Rspack compiled with 2 errors" `; exports[`StatsTestCases should print correct stats for ignore-plugin 1`] = ` @@ -929,7 +929,7 @@ exports[`StatsTestCases should print correct stats for ignore-warning 1`] = ` } `; -exports[`StatsTestCases should print correct stats for ignore-warning 2`] = `"rspack compiled successfully"`; +exports[`StatsTestCases should print correct stats for ignore-warning 2`] = `"Rspack compiled successfully"`; exports[`StatsTestCases should print correct stats for issue-3558 1`] = ` { @@ -941,7 +941,7 @@ exports[`StatsTestCases should print correct stats for issue-3558 1`] = ` } `; -exports[`StatsTestCases should print correct stats for issue-3558 2`] = `"rspack compiled successfully"`; +exports[`StatsTestCases should print correct stats for issue-3558 2`] = `"Rspack compiled successfully"`; exports[`StatsTestCases should print correct stats for legacy-ie-css-warning 1`] = ` { @@ -953,7 +953,7 @@ exports[`StatsTestCases should print correct stats for legacy-ie-css-warning 1`] } `; -exports[`StatsTestCases should print correct stats for legacy-ie-css-warning 2`] = `"rspack compiled successfully"`; +exports[`StatsTestCases should print correct stats for legacy-ie-css-warning 2`] = `"Rspack compiled successfully"`; exports[`StatsTestCases should print correct stats for loader-builtin-swc-plugin-warn 1`] = ` { @@ -977,7 +977,7 @@ exports[`StatsTestCases should print correct stats for loader-builtin-swc-plugin -rspack compiled with 1 warning" +Rspack compiled with 1 warning" `; exports[`StatsTestCases should print correct stats for logging 1`] = ` @@ -1066,7 +1066,7 @@ exports[`StatsTestCases should print correct stats for minify-error-recovery 2`] -rspack compiled with 1 error" +Rspack compiled with 1 error" `; exports[`StatsTestCases should print correct stats for named-chunk-group 1`] = ` @@ -1155,7 +1155,7 @@ exports[`StatsTestCases should print correct stats for normal-errors 2`] = ` -rspack compiled with 1 error" +Rspack compiled with 1 error" `; exports[`StatsTestCases should print correct stats for optimization-runtime-chunk 1`] = ` @@ -1771,7 +1771,7 @@ exports[`StatsTestCases should print correct stats for parse-error 2`] = ` -rspack compiled with 1 error" +Rspack compiled with 1 error" `; exports[`StatsTestCases should print correct stats for parse-error-builtin-swc-loader 1`] = ` @@ -1815,7 +1815,7 @@ exports[`StatsTestCases should print correct stats for parse-error-builtin-swc-l -rspack compiled with 1 error" +Rspack compiled with 1 error" `; exports[`StatsTestCases should print correct stats for reasons 1`] = ` @@ -2023,7 +2023,7 @@ console.log(a); ], "errorsCount": 1, "filteredModules": undefined, - "hash": "6ca407f06f94c982125d", + "hash": "745b7086c5177811e94a", "logging": {}, "modules": [ { @@ -2144,7 +2144,7 @@ error[internal]: Resolve error -rspack compiled with 1 error (6ca407f06f94c982125d)" +Rspack compiled with 1 error (745b7086c5177811e94a)" `; exports[`StatsTestCases should print correct stats for resolve-unexpected-exports-in-pkg 1`] = ` @@ -2288,7 +2288,7 @@ console.log(a); ], "errorsCount": 1, "filteredModules": undefined, - "hash": "a9093cd411993b4b9c01", + "hash": "4e3ebc05601fcb8c4e16", "logging": {}, "modules": [ { @@ -2403,7 +2403,7 @@ error[internal]: Export should be relative path and start with "./", but got ../ -rspack compiled with 1 error (a9093cd411993b4b9c01)" +Rspack compiled with 1 error (4e3ebc05601fcb8c4e16)" `; exports[`StatsTestCases should print correct stats for simple 1`] = ` @@ -2498,7 +2498,7 @@ exports[`StatsTestCases should print correct stats for simple 1`] = ` "errors": [], "errorsCount": 0, "filteredModules": undefined, - "hash": "7a27fed57156f35cc7b2", + "hash": "96a5acbdbd5061c8e5ac", "logging": {}, "modules": [ { @@ -2561,7 +2561,7 @@ chunk {main} bundle.js (main) [entry] entry ./index ./index.js [10] {main} entry ./index -rspack compiled successfully (7a27fed57156f35cc7b2)" +Rspack compiled successfully (96a5acbdbd5061c8e5ac)" `; exports[`StatsTestCases should print correct stats for simple-module-source 1`] = ` @@ -2722,7 +2722,7 @@ import rawModule from './raw.png'", "errors": [], "errorsCount": 0, "filteredModules": undefined, - "hash": "ef78d0d53e6750a65525", + "hash": "58ffc7a5ede4848a7209", "logging": {}, "modules": [ { @@ -2849,7 +2849,7 @@ Entrypoint main 631 bytes = bundle.js ./raw.png ./index.js ./stringModule.js -rspack compiled successfully (ef78d0d53e6750a65525)" +Rspack compiled successfully (58ffc7a5ede4848a7209)" `; exports[`StatsTestCases should print correct stats for stats-hooks 1`] = ` @@ -2943,7 +2943,7 @@ exports[`StatsTestCases should print correct stats for stats-hooks 1`] = ` "errors": [], "errorsCount": 0, "filteredModules": undefined, - "hash": "7a27fed57156f35cc7b2", + "hash": "96a5acbdbd5061c8e5ac", "logging": {}, "modules": [ { @@ -3000,7 +3000,7 @@ exports[`StatsTestCases should print correct stats for stats-hooks 2`] = ` asset bundle.js 589 bytes [emitted111] (name: main) [testA: aaaaaa] Entrypoint main 589 bytes = bundle.js ./index.js -rspack compiled successfully (7a27fed57156f35cc7b2)" +Rspack compiled successfully (96a5acbdbd5061c8e5ac)" `; exports[`StatsTestCases should print correct stats for try-require--module 1`] = ` @@ -3045,7 +3045,7 @@ exports[`StatsTestCases should print correct stats for try-require--module 2`] = -rspack compiled with 1 warning" +Rspack compiled with 1 warning" `; exports[`StatsTestCases should print correct stats for try-require-resolve-module 1`] = ` @@ -3090,7 +3090,7 @@ exports[`StatsTestCases should print correct stats for try-require-resolve-modul -rspack compiled with 1 warning" +Rspack compiled with 1 warning" `; exports[`StatsTestCases should print correct stats for try-require-resolve-weak-module 1`] = ` @@ -3135,5 +3135,5 @@ exports[`StatsTestCases should print correct stats for try-require-resolve-weak- -rspack compiled with 1 warning" +Rspack compiled with 1 warning" `; diff --git a/packages/rspack/tests/cases/css/rewrite-url-auto-public-path/webpack.config.js b/packages/rspack/tests/cases/css/rewrite-url-auto-public-path/webpack.config.js index b6e795dcc02..52fbe979782 100644 --- a/packages/rspack/tests/cases/css/rewrite-url-auto-public-path/webpack.config.js +++ b/packages/rspack/tests/cases/css/rewrite-url-auto-public-path/webpack.config.js @@ -35,7 +35,7 @@ module.exports = { "main.js", new ConcatSource( new RawSource( - `self = { document: { currentScript: { src: "/" } } };\n` + `globalThis = { document: { currentScript: { src: "/" } } };\n` ), assets["main.js"] ) diff --git a/packages/rspack/tests/configCases/builtin-swc-loader/react-refresh-false/webpack.config.js b/packages/rspack/tests/configCases/builtin-swc-loader/react-refresh-false/webpack.config.js index 12de81331dc..4c0b434b2d1 100644 --- a/packages/rspack/tests/configCases/builtin-swc-loader/react-refresh-false/webpack.config.js +++ b/packages/rspack/tests/configCases/builtin-swc-loader/react-refresh-false/webpack.config.js @@ -5,11 +5,12 @@ module.exports = { test: /\.js$/, loader: "builtin:swc-loader", options: { - rspackExperiments: { - react: { - refresh: false - } - } + // TODO: add back this until `@rspack/plugin-react-refresh` is finished + // rspackExperiments: { + // react: { + // refresh: false + // } + // } } } ] diff --git a/packages/rspack/tests/configCases/builtin-swc-loader/react-runtime-classic/webpack.config.js b/packages/rspack/tests/configCases/builtin-swc-loader/react-runtime-classic/webpack.config.js index f260c6f55f4..0a7fb2be2c3 100644 --- a/packages/rspack/tests/configCases/builtin-swc-loader/react-runtime-classic/webpack.config.js +++ b/packages/rspack/tests/configCases/builtin-swc-loader/react-runtime-classic/webpack.config.js @@ -5,9 +5,11 @@ module.exports = { test: /\.js$/, loader: "builtin:swc-loader", options: { - rspackExperiments: { - react: { - runtime: "classic" + jsc: { + transform: { + react: { + runtime: "classic" + } } } } diff --git a/packages/rspack/tests/configCases/builtins/decorator/foo.ts b/packages/rspack/tests/configCases/builtins/decorator/foo.ts new file mode 100644 index 00000000000..40677afef65 --- /dev/null +++ b/packages/rspack/tests/configCases/builtins/decorator/foo.ts @@ -0,0 +1,20 @@ +function methodDecorator(target, name, descriptor) { + const fn = descriptor.value; + descriptor.value = function (...args) { + const res = fn.call(this, ...args); + if (res === undefined) { + return 2; + } + return res; + }; +} +class B { + @methodDecorator + test_return_2() {} + + @methodDecorator + test_return_3() { + return 3; + } +} +export { B }; diff --git a/packages/rspack/tests/configCases/builtins/decorator/index.js b/packages/rspack/tests/configCases/builtins/decorator/index.js index 846633a1c95..ccf40ff1f3f 100644 --- a/packages/rspack/tests/configCases/builtins/decorator/index.js +++ b/packages/rspack/tests/configCases/builtins/decorator/index.js @@ -1,29 +1,11 @@ +import { B } from "./foo"; + function clsDecorator(cls) { cls.prototype.a = 1; } @clsDecorator class A {} -function methodDecorator(target, name, descriptor) { - const fn = descriptor.value; - descriptor.value = function (...args) { - const res = fn.call(this, ...args); - if (res === undefined) { - return 2; - } - return res; - }; -} -class B { - @methodDecorator - test_return_2() {} - - @methodDecorator - test_return_3() { - return 3; - } -} - it("should decorator be transformed", () => { const a = new A(); expect(a.a).toBe(1); diff --git a/packages/rspack/tests/configCases/builtins/decorator/tsconfig.json b/packages/rspack/tests/configCases/builtins/decorator/tsconfig.json new file mode 100644 index 00000000000..504cd646e14 --- /dev/null +++ b/packages/rspack/tests/configCases/builtins/decorator/tsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "experimentalDecorators": true + } +} diff --git a/packages/rspack/tests/configCases/builtins/define-disable-transform-by-default/index.js b/packages/rspack/tests/configCases/builtins/define-disable-transform-by-default/index.js new file mode 100644 index 00000000000..a52812e0156 --- /dev/null +++ b/packages/rspack/tests/configCases/builtins/define-disable-transform-by-default/index.js @@ -0,0 +1,3 @@ +it("should builtins define works even with `disableTransformByDefault` is on", () => { + expect(TRUE).toBe(true); +}); diff --git a/packages/rspack/tests/configCases/builtins/define-disable-transform-by-default/webpack.config.js b/packages/rspack/tests/configCases/builtins/define-disable-transform-by-default/webpack.config.js new file mode 100644 index 00000000000..49a31bffb65 --- /dev/null +++ b/packages/rspack/tests/configCases/builtins/define-disable-transform-by-default/webpack.config.js @@ -0,0 +1,15 @@ +module.exports = { + entry: { + main: ["./index.js"] + }, + builtins: { + define: { + TRUE: true + } + }, + experiments: { + rspackFuture: { + disableTransformByDefault: true + } + } +}; diff --git a/packages/rspack/tests/configCases/builtins/html-inject/index.js b/packages/rspack/tests/configCases/builtins/html-inject/index.js new file mode 100644 index 00000000000..1d427ecf57e --- /dev/null +++ b/packages/rspack/tests/configCases/builtins/html-inject/index.js @@ -0,0 +1,40 @@ +const fs = require("fs"); +const path = require("path"); + +it("body-index.html inject", () => { + const htmlPath = path.join(__dirname, "./body-index.html"); + const htmlContent = fs.readFileSync(htmlPath, "utf-8"); + expect( + htmlContent.includes('') + ).toBe(true); +}); + +it("head-index.html inject", () => { + const htmlPath = path.join(__dirname, "./head-index.html"); + const htmlContent = fs.readFileSync(htmlPath, "utf-8"); + expect( + htmlContent.includes('') + ).toBe(true); +}); + +it("true-blocking-index.html inject", () => { + const htmlPath = path.join(__dirname, "./true-blocking-index.html"); + const htmlContent = fs.readFileSync(htmlPath, "utf-8"); + expect(htmlContent.includes('')).toBe( + true + ); +}); + +it("true-defer-index.html inject", () => { + const htmlPath = path.join(__dirname, "./true-defer-index.html"); + const htmlContent = fs.readFileSync(htmlPath, "utf-8"); + expect( + htmlContent.includes('') + ).toBe(true); +}); + +it("false-index.html inject", () => { + const htmlPath = path.join(__dirname, "./false-index.html"); + const htmlContent = fs.readFileSync(htmlPath, "utf-8"); + expect(htmlContent.includes('