From 898f7851a2fb1b3f58822c605d5473e561baf83b Mon Sep 17 00:00:00 2001 From: xusd320 Date: Thu, 21 Nov 2024 18:39:25 +0800 Subject: [PATCH 01/68] feat: support module federation --- crates/mako/src/compiler.rs | 5 ++ crates/mako/src/config.rs | 3 ++ crates/mako/src/config/module_federation.rs | 31 ++++++++++++ crates/mako/src/plugins.rs | 1 + crates/mako/src/plugins/module_federation.rs | 49 +++++++++++++++++++ .../plugins/module_federation/container.rs | 0 .../container/container_options.rs | 18 +++++++ .../shared/shared_options.rs | 20 ++++++++ .../src/plugins/module_federation/sharing.rs | 0 .../consumer/mako.config.json | 14 ++++++ .../consumer/src/bootstrap.ts | 4 ++ .../module-federation/consumer/src/index.ts | 1 + .../provider/mako.config.json | 14 ++++++ .../provider/src/bootstrap.ts | 4 ++ .../module-federation/provider/src/index.ts | 1 + .../provider/src/provider.ts | 1 + 16 files changed, 166 insertions(+) create mode 100644 crates/mako/src/config/module_federation.rs create mode 100644 crates/mako/src/plugins/module_federation.rs create mode 100644 crates/mako/src/plugins/module_federation/container.rs create mode 100644 crates/mako/src/plugins/module_federation/container/container_options.rs create mode 100644 crates/mako/src/plugins/module_federation/shared/shared_options.rs create mode 100644 crates/mako/src/plugins/module_federation/sharing.rs create mode 100644 examples/module-federation/consumer/mako.config.json create mode 100644 examples/module-federation/consumer/src/bootstrap.ts create mode 100644 examples/module-federation/consumer/src/index.ts create mode 100644 examples/module-federation/provider/mako.config.json create mode 100644 examples/module-federation/provider/src/bootstrap.ts create mode 100644 examples/module-federation/provider/src/index.ts create mode 100644 examples/module-federation/provider/src/provider.ts diff --git a/crates/mako/src/compiler.rs b/crates/mako/src/compiler.rs index fc124a87e..536f15d7a 100644 --- a/crates/mako/src/compiler.rs +++ b/crates/mako/src/compiler.rs @@ -21,6 +21,7 @@ use crate::generate::optimize_chunk::OptimizeChunksInfo; use crate::module_graph::ModuleGraph; use crate::plugin::{Plugin, PluginDriver, PluginGenerateEndParams}; use crate::plugins; +use crate::plugins::module_federation::ModuleFederationPlugin; use crate::resolve::{get_resolvers, Resolvers}; use crate::share::helpers::SWC_HELPERS; use crate::stats::StatsInfo; @@ -290,6 +291,10 @@ impl Compiler { ); } + if let Some(mf_cfg) = config.module_federation.as_ref() { + plugins.push(Arc::new(ModuleFederationPlugin::new(mf_cfg.clone()))); + } + if std::env::var("DEBUG_GRAPH").is_ok_and(|v| v == "true") { plugins.push(Arc::new(plugins::graphviz::Graphviz {})); } diff --git a/crates/mako/src/config.rs b/crates/mako/src/config.rs index 1dbc8c3ef..e1bc484c2 100644 --- a/crates/mako/src/config.rs +++ b/crates/mako/src/config.rs @@ -12,6 +12,7 @@ mod macros; mod manifest; mod minifish; mod mode; +mod module_federation; mod module_id_strategy; mod optimization; mod output; @@ -54,6 +55,7 @@ pub use manifest::{deserialize_manifest, ManifestConfig}; use miette::{miette, ByteOffset, Diagnostic, NamedSource, SourceOffset, SourceSpan}; pub use minifish::{deserialize_minifish, MinifishConfig}; pub use mode::Mode; +pub use module_federation::ModuleFederationConfig; pub use module_id_strategy::ModuleIdStrategy; pub use optimization::{deserialize_optimization, OptimizationConfig}; use output::get_default_chunk_loading_global; @@ -219,6 +221,7 @@ pub struct Config { default )] pub check_duplicate_package: Option, + pub module_federation: Option, } const CONFIG_FILE: &str = "mako.config.json"; diff --git a/crates/mako/src/config/module_federation.rs b/crates/mako/src/config/module_federation.rs new file mode 100644 index 000000000..efe91d82c --- /dev/null +++ b/crates/mako/src/config/module_federation.rs @@ -0,0 +1,31 @@ +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ModuleFederationConfig { + pub exposes: Option, + pub shared: Option, + pub remotes: Option, + #[serde(default)] + pub runtime_plugins: Vec, +} + +pub type ExposesConfig = HashMap; + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SharedConfig { + singleton: Option, + required_version: Option, + shared_scope: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum SharedVersion { + Version(String), + False, +} + +pub type RemotesConfig = HashMap; diff --git a/crates/mako/src/plugins.rs b/crates/mako/src/plugins.rs index b2c545d58..15a90ccc5 100644 --- a/crates/mako/src/plugins.rs +++ b/crates/mako/src/plugins.rs @@ -13,6 +13,7 @@ pub mod import; pub mod invalid_webpack_syntax; pub mod manifest; pub mod minifish; +pub mod module_federation; pub mod progress; pub mod require_context; pub mod runtime; diff --git a/crates/mako/src/plugins/module_federation.rs b/crates/mako/src/plugins/module_federation.rs new file mode 100644 index 000000000..16dd6f618 --- /dev/null +++ b/crates/mako/src/plugins/module_federation.rs @@ -0,0 +1,49 @@ +use std::collections::hash_map::Entry::{Occupied, Vacant}; + +use anyhow::{anyhow, Result}; +use tracing::warn; + +use crate::config::ModuleFederationConfig; +use crate::plugin::Plugin; + +pub struct ModuleFederationPlugin { + pub config: ModuleFederationConfig, +} + +impl ModuleFederationPlugin { + pub fn new(config: ModuleFederationConfig) -> Self { + Self { config } + } +} + +impl Plugin for ModuleFederationPlugin { + fn name(&self) -> &str { + "module_federation" + } + + fn modify_config( + &self, + config: &mut crate::config::Config, + root: &std::path::Path, + _args: &crate::compiler::Args, + ) -> Result<()> { + if let Some(exposes) = self.config.exposes.as_ref() { + for (name, import) in exposes.iter() { + match config.entry.entry(name.to_string()) { + Occupied(_) => { + warn!("mf exposed name {} is duplcated with entry.", name); + } + Vacant(vacant_entry) => { + if let Ok(entry_path) = root.join(import).canonicalize() { + vacant_entry.insert(entry_path); + } else { + return Err(anyhow!("mf exposed file :{} not found", import)); + } + } + } + } + } + + Ok(()) + } +} diff --git a/crates/mako/src/plugins/module_federation/container.rs b/crates/mako/src/plugins/module_federation/container.rs new file mode 100644 index 000000000..e69de29bb diff --git a/crates/mako/src/plugins/module_federation/container/container_options.rs b/crates/mako/src/plugins/module_federation/container/container_options.rs new file mode 100644 index 000000000..ec6536b35 --- /dev/null +++ b/crates/mako/src/plugins/module_federation/container/container_options.rs @@ -0,0 +1,18 @@ +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Serialize, Deserialize, Default)] +pub struct ExposesOption { + name: String, + import: String, + shared_scope: String, +} + +#[derive(Clone, Serialize, Deserialize)] +pub struct ContainerOptions { + name: String, + exposes: ExposesOption, + runtime_plugins: Vec, + shared_scope: String, +} diff --git a/crates/mako/src/plugins/module_federation/shared/shared_options.rs b/crates/mako/src/plugins/module_federation/shared/shared_options.rs new file mode 100644 index 000000000..23ad20400 --- /dev/null +++ b/crates/mako/src/plugins/module_federation/shared/shared_options.rs @@ -0,0 +1,20 @@ +#[derive(Clone, Serialize, Deserialize)] +pub struct SharedItem { + name: String, + version: Option, + required_version: Option, + strict_version: Option, + singleton: Option, +} + +#[derive(Clone, Serialize, Deserialize)] +pub enum SharedVersion { + Version(String), + False, +} + +#[derive(Clone, Serialize, Deserialize)] +pub struct SharedOption { + shared: HashMap, + shared_scope: String, +} diff --git a/crates/mako/src/plugins/module_federation/sharing.rs b/crates/mako/src/plugins/module_federation/sharing.rs new file mode 100644 index 000000000..e69de29bb diff --git a/examples/module-federation/consumer/mako.config.json b/examples/module-federation/consumer/mako.config.json new file mode 100644 index 000000000..156c5f729 --- /dev/null +++ b/examples/module-federation/consumer/mako.config.json @@ -0,0 +1,14 @@ +{ + "entry": { + "consumerHost": "./src/index.ts" + }, + "moduleFederation": { + "remotes": { + "provider": "provider@http://localhost:3000/mf-manifest.json" + } + }, + "optimization": { + "skipModules": false, + "concatenateModules": false + } +} diff --git a/examples/module-federation/consumer/src/bootstrap.ts b/examples/module-federation/consumer/src/bootstrap.ts new file mode 100644 index 000000000..d933c8d8e --- /dev/null +++ b/examples/module-federation/consumer/src/bootstrap.ts @@ -0,0 +1,4 @@ +import provider from 'provider/provider'; + +console.log('mf consomer host loaded.'); +console.log(`provider loaded ${provider}`); diff --git a/examples/module-federation/consumer/src/index.ts b/examples/module-federation/consumer/src/index.ts new file mode 100644 index 000000000..e59d6a0ad --- /dev/null +++ b/examples/module-federation/consumer/src/index.ts @@ -0,0 +1 @@ +import './bootstrap'; diff --git a/examples/module-federation/provider/mako.config.json b/examples/module-federation/provider/mako.config.json new file mode 100644 index 000000000..77b77d441 --- /dev/null +++ b/examples/module-federation/provider/mako.config.json @@ -0,0 +1,14 @@ +{ + "entry": { + "providerHost": "./src/index.ts" + }, + "moduleFederation": { + "exposes": { + "provider": "./src/provider.ts" + } + }, + "optimization": { + "skipModules": false, + "concatenateModules": false + } +} diff --git a/examples/module-federation/provider/src/bootstrap.ts b/examples/module-federation/provider/src/bootstrap.ts new file mode 100644 index 000000000..53eae7725 --- /dev/null +++ b/examples/module-federation/provider/src/bootstrap.ts @@ -0,0 +1,4 @@ +import provider from './provider'; + +console.log('mf provider host loaded.'); +console.log(`provider loaded ${provider}`); diff --git a/examples/module-federation/provider/src/index.ts b/examples/module-federation/provider/src/index.ts new file mode 100644 index 000000000..b93c7a026 --- /dev/null +++ b/examples/module-federation/provider/src/index.ts @@ -0,0 +1 @@ +import('./bootstrap'); diff --git a/examples/module-federation/provider/src/provider.ts b/examples/module-federation/provider/src/provider.ts new file mode 100644 index 000000000..6f06a2d88 --- /dev/null +++ b/examples/module-federation/provider/src/provider.ts @@ -0,0 +1 @@ +export default 'mf provder'; From 45c519ca6d600450f47769d437ceb365524ba751 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Sat, 23 Nov 2024 22:32:44 +0800 Subject: [PATCH 02/68] feat: mf exposes to remote entries --- crates/binding/src/js_plugin.rs | 1 + crates/mako/src/build.rs | 1 + crates/mako/src/config/module_federation.rs | 1 + crates/mako/src/module.rs | 2 +- crates/mako/src/plugin.rs | 4 +- crates/mako/src/plugins/module_federation.rs | 140 +++++++++++++++++- ...{container_options.rs => entry_runtime.rs} | 0 .../{sharing.rs => shared.rs} | 0 .../shared/{shared_options.rs => shared.rs} | 0 crates/mako/src/visitors/mako_require.rs | 2 +- .../module-federation/consumer/.gitignore | 2 + .../module-federation/provider/.gitignore | 2 + .../provider/mako.config.json | 3 +- packages/mako/package.json | 2 +- pnpm-lock.yaml | 32 ++++ 15 files changed, 186 insertions(+), 6 deletions(-) rename crates/mako/src/plugins/module_federation/container/{container_options.rs => entry_runtime.rs} (100%) rename crates/mako/src/plugins/module_federation/{sharing.rs => shared.rs} (100%) rename crates/mako/src/plugins/module_federation/shared/{shared_options.rs => shared.rs} (100%) create mode 100644 examples/module-federation/consumer/.gitignore create mode 100644 examples/module-federation/provider/.gitignore diff --git a/crates/binding/src/js_plugin.rs b/crates/binding/src/js_plugin.rs index b4d8a7443..0937bbfd1 100644 --- a/crates/binding/src/js_plugin.rs +++ b/crates/binding/src/js_plugin.rs @@ -155,6 +155,7 @@ impl Plugin for JsPlugin { &self, content: &mut Content, path: &str, + _is_entry: bool, _context: &Arc, ) -> Result> { if let Some(hook) = &self.hooks.transform_include { diff --git a/crates/mako/src/build.rs b/crates/mako/src/build.rs index b1af48f53..d03145b2f 100644 --- a/crates/mako/src/build.rs +++ b/crates/mako/src/build.rs @@ -275,6 +275,7 @@ __mako_require__.loadScript('{}', (e) => e.type === 'load' ? resolve() : reject( let content = context.plugin_driver.load_transform( &mut content, &file.path.to_string_lossy(), + file.is_entry, &context, )?; file.set_content(content); diff --git a/crates/mako/src/config/module_federation.rs b/crates/mako/src/config/module_federation.rs index efe91d82c..a89876a5a 100644 --- a/crates/mako/src/config/module_federation.rs +++ b/crates/mako/src/config/module_federation.rs @@ -10,6 +10,7 @@ pub struct ModuleFederationConfig { pub remotes: Option, #[serde(default)] pub runtime_plugins: Vec, + pub implementation: String, } pub type ExposesConfig = HashMap; diff --git a/crates/mako/src/module.rs b/crates/mako/src/module.rs index 3122ea00f..01c9e5fb7 100644 --- a/crates/mako/src/module.rs +++ b/crates/mako/src/module.rs @@ -212,7 +212,7 @@ impl Default for ModuleInfo { } } -fn md5_hash(source_str: &str, lens: usize) -> String { +pub fn md5_hash(source_str: &str, lens: usize) -> String { format!("{:x}", md5::compute(source_str)) .chars() .take(lens) diff --git a/crates/mako/src/plugin.rs b/crates/mako/src/plugin.rs index fe02b88fe..d1d3a12f2 100644 --- a/crates/mako/src/plugin.rs +++ b/crates/mako/src/plugin.rs @@ -66,6 +66,7 @@ pub trait Plugin: Any + Send + Sync { &self, _content: &mut Content, _path: &str, + _is_entry: bool, _context: &Arc, ) -> Result> { Ok(None) @@ -434,10 +435,11 @@ impl PluginDriver { &self, content: &mut Content, path: &str, + _is_entry: bool, context: &Arc, ) -> Result { for plugin in &self.plugins { - if let Some(transformed) = plugin.load_transform(content, path, context)? { + if let Some(transformed) = plugin.load_transform(content, path, _is_entry, context)? { *content = transformed; } } diff --git a/crates/mako/src/plugins/module_federation.rs b/crates/mako/src/plugins/module_federation.rs index 16dd6f618..ef7dbbef5 100644 --- a/crates/mako/src/plugins/module_federation.rs +++ b/crates/mako/src/plugins/module_federation.rs @@ -1,15 +1,24 @@ use std::collections::hash_map::Entry::{Occupied, Vacant}; +use std::fs; +use std::path::Path; +use std::sync::Arc; use anyhow::{anyhow, Result}; use tracing::warn; +use crate::ast::file::Content; +use crate::compiler::Context; use crate::config::ModuleFederationConfig; +use crate::module::md5_hash; use crate::plugin::Plugin; +use crate::visitors::mako_require::MAKO_REQUIRE; pub struct ModuleFederationPlugin { pub config: ModuleFederationConfig, } +const FEDERATION_GLOBAL: &str = "__mako_require__.federation"; + impl ModuleFederationPlugin { pub fn new(config: ModuleFederationConfig) -> Self { Self { config } @@ -31,7 +40,7 @@ impl Plugin for ModuleFederationPlugin { for (name, import) in exposes.iter() { match config.entry.entry(name.to_string()) { Occupied(_) => { - warn!("mf exposed name {} is duplcated with entry.", name); + warn!("mf exposed name {} is duplcated with entry config.", name); } Vacant(vacant_entry) => { if let Ok(entry_path) = root.join(import).canonicalize() { @@ -46,4 +55,133 @@ impl Plugin for ModuleFederationPlugin { Ok(()) } + + fn load_transform( + &self, + _content: &mut Content, + _path: &str, + _is_entry: bool, + _context: &Arc, + ) -> Result> { + if !_is_entry { + Ok(None) + } else { + match _content { + Content::Js(js_content) => { + let entry_runtime_dep_path = self.prepare_entry_runtime_dep(&_context.root); + js_content.content.insert_str( + 0, + format!(r#"import "{}";"#, entry_runtime_dep_path).as_str(), + ); + Ok(Some(_content.clone())) + } + _ => Ok(None), + } + } + } + + fn runtime_plugins(&self, _context: &Arc) -> Result> { + let code = r#" +/* mako/runtime/federation runtime */ +!(function() { + if(!requireModule.federation) { + requireModule.federation = { + initOptions: {}, + chunkMatcher: undefined, + rootOutputDir: "", + initialConsumes: undefined, + bundlerRuntimeOptions: {} + }; + } +})();"# + .to_string(); + Ok(vec![code]) + } +} + +impl ModuleFederationPlugin { + fn prepare_entry_runtime_dep(&self, root: &Path) -> String { + let entry_runtime_code = self.get_entry_runtime_code(); + + let content_hash = md5_hash(&entry_runtime_code, 32); + let dep_path = root.join(format!("node_modules/.entry.{}.js", content_hash)); + let dep_parent_path = dep_path.parent().unwrap(); + if !fs::exists(dep_parent_path).unwrap() { + fs::create_dir(dep_parent_path).unwrap(); + } + if !fs::exists(&dep_path).unwrap() { + fs::write(&dep_path, entry_runtime_code).unwrap(); + } + + dep_path.to_string_lossy().to_string() + } + + fn get_entry_runtime_code(&self) -> String { + let embed_runtime_codes = format!( + r#"if(!{federation_global}.runtime) {{ + var preFederation = {federation_global}; + {federation_global} = {{}}; + for(var key in federation) {{ + {federation_global}[key] = federation[key]; + }} + for(var key in preFederation) {{ + {federation_global}[key] = preFederation[key]; + }} +}}"#, + federation_global = FEDERATION_GLOBAL + ); + + let (imported_plugin_names, import_plugin_stmts) = + self.config.runtime_plugins.iter().enumerate().fold( + (Vec::new(), Vec::new()), + |(mut names, mut stmts), (plugin, index)| { + names.push(format!("plugin_{}", index)); + stmts.push(format!(r#"import plugin_{} from "{}""#, index, plugin)); + (names, stmts) + }, + ); + + let plugins_imports = import_plugin_stmts.join(";"); + + let plugins_collection = if imported_plugin_names.is_empty() { + "".to_string() + } else { + format!( + r#"var pluginsToAdd = [{plugins_to_add}].filter(Boolean); + {federation_global}.initOptions.plugins = {federation_global}.initOptions.plugins ? + {federation_global}.initOptions.plugins.concat(pluginsToAdd) : pluginsToAdd; +"#, + plugins_to_add = imported_plugin_names + .iter() + .map(|item| format!(r#"{item} ? (item.default || item)() : false"#)) + .collect::>() + .join(","), + federation_global = FEDERATION_GLOBAL + ) + }; + + format!( + r#"import federation from "{federation_impl}"; +{plugins_imports} +{embed_runtime_codes} + +if(!{federation_global}.instance) {{ + {plugins_collection} + {federation_global}.instance = {federation_global}.runtime.init({federation_global}.initOptions); + if({federation_global}.attachShareScopeMap) {{ + {federation_global}.attachShareScopeMap({mako_require}); + }} + if({federation_global}.installInitialConsumes) {{ + {federation_global}.installInitialConsumes(); + }} +}} +"#, + embed_runtime_codes = embed_runtime_codes, + plugins_imports = plugins_imports, + plugins_collection = plugins_collection, + federation_impl = self.config.implementation, + federation_global = FEDERATION_GLOBAL, + mako_require = MAKO_REQUIRE + ) + } } diff --git a/crates/mako/src/plugins/module_federation/container/container_options.rs b/crates/mako/src/plugins/module_federation/container/entry_runtime.rs similarity index 100% rename from crates/mako/src/plugins/module_federation/container/container_options.rs rename to crates/mako/src/plugins/module_federation/container/entry_runtime.rs diff --git a/crates/mako/src/plugins/module_federation/sharing.rs b/crates/mako/src/plugins/module_federation/shared.rs similarity index 100% rename from crates/mako/src/plugins/module_federation/sharing.rs rename to crates/mako/src/plugins/module_federation/shared.rs diff --git a/crates/mako/src/plugins/module_federation/shared/shared_options.rs b/crates/mako/src/plugins/module_federation/shared/shared.rs similarity index 100% rename from crates/mako/src/plugins/module_federation/shared/shared_options.rs rename to crates/mako/src/plugins/module_federation/shared/shared.rs diff --git a/crates/mako/src/visitors/mako_require.rs b/crates/mako/src/visitors/mako_require.rs index 4929c9cde..701be9d39 100644 --- a/crates/mako/src/visitors/mako_require.rs +++ b/crates/mako/src/visitors/mako_require.rs @@ -9,7 +9,7 @@ use crate::ast::utils::is_ident_undefined; use crate::compiler::Context; use crate::config::Platform; -const MAKO_REQUIRE: &str = "__mako_require__"; +pub const MAKO_REQUIRE: &str = "__mako_require__"; pub struct MakoRequire { pub unresolved_mark: Mark, diff --git a/examples/module-federation/consumer/.gitignore b/examples/module-federation/consumer/.gitignore new file mode 100644 index 000000000..de4d1f007 --- /dev/null +++ b/examples/module-federation/consumer/.gitignore @@ -0,0 +1,2 @@ +dist +node_modules diff --git a/examples/module-federation/provider/.gitignore b/examples/module-federation/provider/.gitignore new file mode 100644 index 000000000..de4d1f007 --- /dev/null +++ b/examples/module-federation/provider/.gitignore @@ -0,0 +1,2 @@ +dist +node_modules diff --git a/examples/module-federation/provider/mako.config.json b/examples/module-federation/provider/mako.config.json index 77b77d441..4dea996d6 100644 --- a/examples/module-federation/provider/mako.config.json +++ b/examples/module-federation/provider/mako.config.json @@ -5,7 +5,8 @@ "moduleFederation": { "exposes": { "provider": "./src/provider.ts" - } + }, + "implementation": "/Users/xusd/codes/github/mako/packages/mako/node_modules/@module-federation/webpack-bundler-runtime" }, "optimization": { "skipModules": false, diff --git a/packages/mako/package.json b/packages/mako/package.json index 7ec1f7a8e..3dac21e82 100644 --- a/packages/mako/package.json +++ b/packages/mako/package.json @@ -85,4 +85,4 @@ "@umijs/mako-linux-x64-musl": "0.9.6" }, "repository": "git@github.com:umijs/mako.git" -} \ No newline at end of file +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4c616c68c..06a0a91c7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -496,6 +496,9 @@ importers: packages/mako: dependencies: + '@module-federation/webpack-bundler-runtime': + specifier: ^0.7.6 + version: 0.7.6 '@swc/helpers': specifier: 0.5.1 version: 0.5.1 @@ -4941,6 +4944,30 @@ packages: resolution: {integrity: sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==} dev: true + /@module-federation/error-codes@0.7.6: + resolution: {integrity: sha512-XVzX/sRFj1h5JvOOVMoFppxq0t1t3o/AlEICHgWX+dybIwJgz9g4gihZOWVZfz5/xsKGcUwdH5X7Z2nkuYhJEw==} + dev: false + + /@module-federation/runtime@0.7.6: + resolution: {integrity: sha512-TEEDbGwaohZ2dMa+Sk/Igq8XpcyfjqJfbL20mdAZeifSFVZYRSCaTd/xIXP7pEw8+5BaCMc4YfCf/XcjFAUrVA==} + dependencies: + '@module-federation/error-codes': 0.7.6 + '@module-federation/sdk': 0.7.6 + dev: false + + /@module-federation/sdk@0.7.6: + resolution: {integrity: sha512-MFE+RtsHnutZOCp2eKpa3A/yzZ8tOPmjX7QRdVnB2qqR9JA2SH3ZP5+cYq76tzFQZvU1BCWAQVNMvqGOW2yVZQ==} + dependencies: + isomorphic-rslog: 0.0.6 + dev: false + + /@module-federation/webpack-bundler-runtime@0.7.6: + resolution: {integrity: sha512-kB9hQ0BfwNAcQWGskDEOxYP2z2bB/1ABXKr8MDomCFl2mbW3vvfYMQrb8UhJmJvE3rbGI/iXhJUdgBLNREnjUg==} + dependencies: + '@module-federation/runtime': 0.7.6 + '@module-federation/sdk': 0.7.6 + dev: false + /@monaco-editor/loader@1.3.3(monaco-editor@0.38.0): resolution: {integrity: sha512-6KKF4CTzcJiS8BJwtxtfyYt9shBiEv32ateQ9T4UVogwn4HM/uPo9iJd2Dmbkpz8CM6Y0PDUpjnZzCwC+eYo2Q==} peerDependencies: @@ -11625,6 +11652,11 @@ packages: whatwg-fetch: 3.6.2 dev: true + /isomorphic-rslog@0.0.6: + resolution: {integrity: sha512-HM0q6XqQ93psDlqvuViNs/Ea3hAyGDkIdVAHlrEocjjAwGrs1fZ+EdQjS9eUPacnYB7Y8SoDdSY3H8p3ce205A==} + engines: {node: '>=14.17.6'} + dev: false + /isomorphic-unfetch@4.0.2: resolution: {integrity: sha512-1Yd+CF/7al18/N2BDbsLBcp6RO3tucSW+jcLq24dqdX5MNbCNTw1z4BsGsp4zNmjr/Izm2cs/cEqZPp4kvWSCA==} dependencies: From aebf286c17cd94d6c31a9e45b453cd4f5618d423 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Sat, 23 Nov 2024 23:04:48 +0800 Subject: [PATCH 03/68] chore: code styles --- crates/mako/src/plugins/module_federation.rs | 67 ++++++++++--------- .../provider/mako.config.json | 1 + 2 files changed, 35 insertions(+), 33 deletions(-) diff --git a/crates/mako/src/plugins/module_federation.rs b/crates/mako/src/plugins/module_federation.rs index ef7dbbef5..49c4a6cbb 100644 --- a/crates/mako/src/plugins/module_federation.rs +++ b/crates/mako/src/plugins/module_federation.rs @@ -104,6 +104,7 @@ impl ModuleFederationPlugin { let entry_runtime_code = self.get_entry_runtime_code(); let content_hash = md5_hash(&entry_runtime_code, 32); + let dep_path = root.join(format!("node_modules/.entry.{}.js", content_hash)); let dep_parent_path = dep_path.parent().unwrap(); if !fs::exists(dep_parent_path).unwrap() { @@ -117,8 +118,13 @@ impl ModuleFederationPlugin { } fn get_entry_runtime_code(&self) -> String { - let embed_runtime_codes = format!( - r#"if(!{federation_global}.runtime) {{ + let (plugins_imports, plugins_instantiations) = self.get_mf_runtime_plugins_code(); + + format!( + r#"import federation from "{federation_impl}"; +{plugins_imports} + +if(!{federation_global}.runtime) {{ var preFederation = {federation_global}; {federation_global} = {{}}; for(var key in federation) {{ @@ -127,23 +133,41 @@ impl ModuleFederationPlugin { for(var key in preFederation) {{ {federation_global}[key] = preFederation[key]; }} -}}"#, - federation_global = FEDERATION_GLOBAL - ); +}} + +if(!{federation_global}.instance) {{ + {plugins_instantiations} + {federation_global}.instance = {federation_global}.runtime.init({federation_global}.initOptions); + if({federation_global}.attachShareScopeMap) {{ + {federation_global}.attachShareScopeMap({mako_require}); + }} + if({federation_global}.installInitialConsumes) {{ + {federation_global}.installInitialConsumes(); + }} +}} +"#, + plugins_imports = plugins_imports, + plugins_instantiations = plugins_instantiations, + federation_impl = self.config.implementation, + federation_global = FEDERATION_GLOBAL, + mako_require = MAKO_REQUIRE + ) + } + fn get_mf_runtime_plugins_code(&self) -> (String, String) { let (imported_plugin_names, import_plugin_stmts) = self.config.runtime_plugins.iter().enumerate().fold( (Vec::new(), Vec::new()), - |(mut names, mut stmts), (plugin, index)| { + |(mut names, mut stmts), (index, plugin)| { names.push(format!("plugin_{}", index)); - stmts.push(format!(r#"import plugin_{} from "{}""#, index, plugin)); + stmts.push(format!(r#"import plugin_{} from "{}";"#, index, plugin)); (names, stmts) }, ); - let plugins_imports = import_plugin_stmts.join(";"); + let plugins_imports = import_plugin_stmts.join("\n"); - let plugins_collection = if imported_plugin_names.is_empty() { + let plugins_instantiations = if imported_plugin_names.is_empty() { "".to_string() } else { format!( @@ -159,29 +183,6 @@ impl ModuleFederationPlugin { federation_global = FEDERATION_GLOBAL ) }; - - format!( - r#"import federation from "{federation_impl}"; -{plugins_imports} -{embed_runtime_codes} - -if(!{federation_global}.instance) {{ - {plugins_collection} - {federation_global}.instance = {federation_global}.runtime.init({federation_global}.initOptions); - if({federation_global}.attachShareScopeMap) {{ - {federation_global}.attachShareScopeMap({mako_require}); - }} - if({federation_global}.installInitialConsumes) {{ - {federation_global}.installInitialConsumes(); - }} -}} -"#, - embed_runtime_codes = embed_runtime_codes, - plugins_imports = plugins_imports, - plugins_collection = plugins_collection, - federation_impl = self.config.implementation, - federation_global = FEDERATION_GLOBAL, - mako_require = MAKO_REQUIRE - ) + (plugins_imports, plugins_instantiations) } } diff --git a/examples/module-federation/provider/mako.config.json b/examples/module-federation/provider/mako.config.json index 4dea996d6..d1d76f0c9 100644 --- a/examples/module-federation/provider/mako.config.json +++ b/examples/module-federation/provider/mako.config.json @@ -6,6 +6,7 @@ "exposes": { "provider": "./src/provider.ts" }, + "runtimePlugins": [], "implementation": "/Users/xusd/codes/github/mako/packages/mako/node_modules/@module-federation/webpack-bundler-runtime" }, "optimization": { From 2ec6a9f3ebf09d8d474db7e2aaa3938b35ceca67 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Sun, 24 Nov 2024 21:57:11 +0800 Subject: [PATCH 04/68] feat: mf container entry impl --- crates/mako/src/config.rs | 4 +- crates/mako/src/config/module_federation.rs | 25 +++- crates/mako/src/plugins/module_federation.rs | 109 ++++++++++++++---- .../provider/mako.config.json | 3 +- .../provider/public/index.html | 7 ++ 5 files changed, 123 insertions(+), 25 deletions(-) create mode 100644 examples/module-federation/provider/public/index.html diff --git a/crates/mako/src/config.rs b/crates/mako/src/config.rs index e1bc484c2..51a6c5ea8 100644 --- a/crates/mako/src/config.rs +++ b/crates/mako/src/config.rs @@ -12,7 +12,7 @@ mod macros; mod manifest; mod minifish; mod mode; -mod module_federation; +pub mod module_federation; mod module_id_strategy; mod optimization; mod output; @@ -55,7 +55,7 @@ pub use manifest::{deserialize_manifest, ManifestConfig}; use miette::{miette, ByteOffset, Diagnostic, NamedSource, SourceOffset, SourceSpan}; pub use minifish::{deserialize_minifish, MinifishConfig}; pub use mode::Mode; -pub use module_federation::ModuleFederationConfig; +use module_federation::ModuleFederationConfig; pub use module_id_strategy::ModuleIdStrategy; pub use optimization::{deserialize_optimization, OptimizationConfig}; use output::get_default_chunk_loading_global; diff --git a/crates/mako/src/config/module_federation.rs b/crates/mako/src/config/module_federation.rs index a89876a5a..126856215 100644 --- a/crates/mako/src/config/module_federation.rs +++ b/crates/mako/src/config/module_federation.rs @@ -5,17 +5,22 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ModuleFederationConfig { + pub name: String, pub exposes: Option, pub shared: Option, pub remotes: Option, #[serde(default)] pub runtime_plugins: Vec, pub implementation: String, + #[serde(default)] + pub share_strategy: SharedConfig, + #[serde(default = "default_share_scope")] + pub share_scope: String, } pub type ExposesConfig = HashMap; -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, Default)] #[serde(rename_all = "camelCase")] pub struct SharedConfig { singleton: Option, @@ -29,4 +34,22 @@ pub enum SharedVersion { False, } +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum ShareStrategy { + #[serde(rename = "version_first")] + VersionFirst, + #[serde(rename = "loaded_first")] + LoadedFirst, +} + +impl Default for ShareStrategy { + fn default() -> Self { + Self::LoadedFirst + } +} + pub type RemotesConfig = HashMap; + +fn default_share_scope() -> String { + "default".to_string() +} diff --git a/crates/mako/src/plugins/module_federation.rs b/crates/mako/src/plugins/module_federation.rs index 49c4a6cbb..512fdff12 100644 --- a/crates/mako/src/plugins/module_federation.rs +++ b/crates/mako/src/plugins/module_federation.rs @@ -3,12 +3,13 @@ use std::fs; use std::path::Path; use std::sync::Arc; -use anyhow::{anyhow, Result}; +use anyhow::Result; use tracing::warn; use crate::ast::file::Content; -use crate::compiler::Context; -use crate::config::ModuleFederationConfig; +use crate::compiler::{Args, Context}; +use crate::config::module_federation::ModuleFederationConfig; +use crate::config::Config; use crate::module::md5_hash; use crate::plugin::Plugin; use crate::visitors::mako_require::MAKO_REQUIRE; @@ -30,24 +31,30 @@ impl Plugin for ModuleFederationPlugin { "module_federation" } - fn modify_config( - &self, - config: &mut crate::config::Config, - root: &std::path::Path, - _args: &crate::compiler::Args, - ) -> Result<()> { + fn modify_config(&self, config: &mut Config, root: &Path, _args: &Args) -> Result<()> { if let Some(exposes) = self.config.exposes.as_ref() { - for (name, import) in exposes.iter() { - match config.entry.entry(name.to_string()) { + let container_entry_name = &self.config.name; + if !exposes.is_empty() { + match config.entry.entry(container_entry_name.clone()) { Occupied(_) => { - warn!("mf exposed name {} is duplcated with entry config.", name); + warn!( + "mf exposed name {} is duplcated with entry config.", + container_entry_name + ); } Vacant(vacant_entry) => { - if let Ok(entry_path) = root.join(import).canonicalize() { - vacant_entry.insert(entry_path); - } else { - return Err(anyhow!("mf exposed file :{} not found", import)); + let container_entry_code = self.get_container_entry_code(root); + let container_entry_path = root.join(format!( + "node_modules/.federation/.entry.container.{}.js", + container_entry_name + )); + let container_entry_parent_path = container_entry_path.parent().unwrap(); + if !fs::exists(container_entry_parent_path).unwrap() { + fs::create_dir(container_entry_parent_path).unwrap(); } + fs::write(&container_entry_path, container_entry_code).unwrap(); + + vacant_entry.insert(container_entry_path); } } } @@ -71,7 +78,12 @@ impl Plugin for ModuleFederationPlugin { let entry_runtime_dep_path = self.prepare_entry_runtime_dep(&_context.root); js_content.content.insert_str( 0, - format!(r#"import "{}";"#, entry_runtime_dep_path).as_str(), + format!( + r#"import "{}"; +"#, + entry_runtime_dep_path + ) + .as_str(), ); Ok(Some(_content.clone())) } @@ -105,10 +117,13 @@ impl ModuleFederationPlugin { let content_hash = md5_hash(&entry_runtime_code, 32); - let dep_path = root.join(format!("node_modules/.entry.{}.js", content_hash)); + let dep_path = root.join(format!( + "node_modules/.federation/.entry.{}.js", + content_hash + )); let dep_parent_path = dep_path.parent().unwrap(); if !fs::exists(dep_parent_path).unwrap() { - fs::create_dir(dep_parent_path).unwrap(); + fs::create_dir_all(dep_parent_path).unwrap(); } if !fs::exists(&dep_path).unwrap() { fs::write(&dep_path, entry_runtime_code).unwrap(); @@ -155,7 +170,7 @@ if(!{federation_global}.instance) {{ } fn get_mf_runtime_plugins_code(&self) -> (String, String) { - let (imported_plugin_names, import_plugin_stmts) = + let (imported_plugin_names, import_plugin_instantiations) = self.config.runtime_plugins.iter().enumerate().fold( (Vec::new(), Vec::new()), |(mut names, mut stmts), (index, plugin)| { @@ -165,7 +180,7 @@ if(!{federation_global}.instance) {{ }, ); - let plugins_imports = import_plugin_stmts.join("\n"); + let plugins_imports = import_plugin_instantiations.join("\n"); let plugins_instantiations = if imported_plugin_names.is_empty() { "".to_string() @@ -185,4 +200,56 @@ if(!{federation_global}.instance) {{ }; (plugins_imports, plugins_instantiations) } + + fn get_container_entry_code(&self, root: &Path) -> String { + let exposes_modules_code = self + .config + .exposes + .as_ref() + .unwrap() + .iter() + .map(|(name, module)| { + format!( + r#""{name}": () => import("{module}"),"#, + module = root.join(module).to_string_lossy() + ) + }) + .collect::>() + .join("\n"); + + format!( + r#"var moduleMap = {{ + {exposes_modules_code} +}}; + +var get = (module, getScope) => {{ + {mako_require}.R = getScope; + getScope = ( + Object.prototype.hasOwnProperty.call(moduleMap, module) + ? moduleMap[module]() + : Promise.resolve().then(() => {{ + throw new Error('Module "' + module + '" does not exist in container.'); + }}) + ); + {mako_require}.R = undefined; + return getScope; +}}; + +var init = (shareScope, initScope, remoteEntryInitOptions) => {{ + return {mako_require}.federation.bundlerRuntime.initContainerEntry({{ + webpackRequire: {mako_require}, + shareScope: shareScope, + initScope: initScope, + remoteEntryInitOptions: remoteEntryInitOptions, + shareScopeKey: "{share_scope}" + }}) +}}; + +export {{ get, init }}; +"#, + exposes_modules_code = exposes_modules_code, + mako_require = MAKO_REQUIRE, + share_scope = self.config.share_scope + ) + } } diff --git a/examples/module-federation/provider/mako.config.json b/examples/module-federation/provider/mako.config.json index d1d76f0c9..3e4d4d133 100644 --- a/examples/module-federation/provider/mako.config.json +++ b/examples/module-federation/provider/mako.config.json @@ -3,8 +3,9 @@ "providerHost": "./src/index.ts" }, "moduleFederation": { + "name": "provider", "exposes": { - "provider": "./src/provider.ts" + "./provider": "./src/provider.ts" }, "runtimePlugins": [], "implementation": "/Users/xusd/codes/github/mako/packages/mako/node_modules/@module-federation/webpack-bundler-runtime" diff --git a/examples/module-federation/provider/public/index.html b/examples/module-federation/provider/public/index.html new file mode 100644 index 000000000..78d2edd80 --- /dev/null +++ b/examples/module-federation/provider/public/index.html @@ -0,0 +1,7 @@ + + + +
+ + + From 768259eeb251299e6451b3d7bdc92f743bed7011 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Sun, 24 Nov 2024 22:16:29 +0800 Subject: [PATCH 05/68] fix: mf container entry --- crates/mako/src/plugins/module_federation.rs | 21 ++++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/crates/mako/src/plugins/module_federation.rs b/crates/mako/src/plugins/module_federation.rs index 512fdff12..600d12c3a 100644 --- a/crates/mako/src/plugins/module_federation.rs +++ b/crates/mako/src/plugins/module_federation.rs @@ -161,8 +161,6 @@ if(!{federation_global}.instance) {{ }} }} "#, - plugins_imports = plugins_imports, - plugins_instantiations = plugins_instantiations, federation_impl = self.config.implementation, federation_global = FEDERATION_GLOBAL, mako_require = MAKO_REQUIRE @@ -174,14 +172,20 @@ if(!{federation_global}.instance) {{ self.config.runtime_plugins.iter().enumerate().fold( (Vec::new(), Vec::new()), |(mut names, mut stmts), (index, plugin)| { - names.push(format!("plugin_{}", index)); - stmts.push(format!(r#"import plugin_{} from "{}";"#, index, plugin)); + names.push(format!("plugin_{index}")); + stmts.push(format!(r#"import plugin_{index} from "{plugin}";"#)); (names, stmts) }, ); let plugins_imports = import_plugin_instantiations.join("\n"); + let plugins_to_add = imported_plugin_names + .iter() + .map(|item| format!(r#"{item} ? (item.default || item)() : false"#)) + .collect::>() + .join(","); + let plugins_instantiations = if imported_plugin_names.is_empty() { "".to_string() } else { @@ -190,11 +194,6 @@ if(!{federation_global}.instance) {{ {federation_global}.initOptions.plugins = {federation_global}.initOptions.plugins ? {federation_global}.initOptions.plugins.concat(pluginsToAdd) : pluginsToAdd; "#, - plugins_to_add = imported_plugin_names - .iter() - .map(|item| format!(r#"{item} ? (item.default || item)() : false"#)) - .collect::>() - .join(","), federation_global = FEDERATION_GLOBAL ) }; @@ -210,7 +209,8 @@ if(!{federation_global}.instance) {{ .iter() .map(|(name, module)| { format!( - r#""{name}": () => import("{module}"),"#, + r#""{name}": () => import(/* makoChunkName: "__mf_expose_{container_name}" */ "{module}"),"#, + container_name = self.config.name, module = root.join(module).to_string_lossy() ) }) @@ -247,7 +247,6 @@ var init = (shareScope, initScope, remoteEntryInitOptions) => {{ export {{ get, init }}; "#, - exposes_modules_code = exposes_modules_code, mako_require = MAKO_REQUIRE, share_scope = self.config.share_scope ) From 391a4fc9a00ac09e747239cc9247a8d0f612f795 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Mon, 25 Nov 2024 15:58:33 +0800 Subject: [PATCH 06/68] fix: mf runtime initOptions --- crates/mako/src/config/module_federation.rs | 2 +- crates/mako/src/plugins/module_federation.rs | 78 ++++++++++++++++--- .../consumer/mako.config.json | 4 +- .../consumer/public/index.html | 7 ++ .../consumer/src/bootstrap.ts | 4 +- 5 files changed, 79 insertions(+), 16 deletions(-) create mode 100644 examples/module-federation/consumer/public/index.html diff --git a/crates/mako/src/config/module_federation.rs b/crates/mako/src/config/module_federation.rs index 126856215..aeed03751 100644 --- a/crates/mako/src/config/module_federation.rs +++ b/crates/mako/src/config/module_federation.rs @@ -13,7 +13,7 @@ pub struct ModuleFederationConfig { pub runtime_plugins: Vec, pub implementation: String, #[serde(default)] - pub share_strategy: SharedConfig, + pub share_strategy: ShareStrategy, #[serde(default = "default_share_scope")] pub share_scope: String, } diff --git a/crates/mako/src/plugins/module_federation.rs b/crates/mako/src/plugins/module_federation.rs index 600d12c3a..ed9eb0de3 100644 --- a/crates/mako/src/plugins/module_federation.rs +++ b/crates/mako/src/plugins/module_federation.rs @@ -3,7 +3,8 @@ use std::fs; use std::path::Path; use std::sync::Arc; -use anyhow::Result; +use anyhow::{anyhow, Result}; +use serde::Serialize; use tracing::warn; use crate::ast::file::Content; @@ -93,20 +94,58 @@ impl Plugin for ModuleFederationPlugin { } fn runtime_plugins(&self, _context: &Arc) -> Result> { - let code = r#" + fn parse_remote(remote: &str) -> Result<(String, String)> { + let (left, right) = remote + .split_once('@') + .ok_or(anyhow!("invalid remote {}", remote))?; + if left.is_empty() || right.is_empty() { + Err(anyhow!("invalid remote {}", remote)) + } else { + Ok((left.to_string(), right.to_string())) + } + } + + let runtime_remotes = self.config.remotes.as_ref().map_or(Vec::new(), |remotes| { + remotes + .iter() + .map(|(alias, remote)| { + // FIXME: should not unwrap + let (name, entry) = parse_remote(remote).unwrap(); + RuntimeRemoteItem { + name, + alias: alias.clone(), + entry, + share_scope: self.config.share_scope.clone(), + } + }) + .collect() + }); + let init_options: RuntimeInitOptions = RuntimeInitOptions { + name: self.config.name.clone(), + remotes: runtime_remotes, + share_strategy: serde_json::to_value(&self.config.share_strategy) + .unwrap() + .as_str() + .unwrap() + .to_string(), + }; + let init_options_code = serde_json::to_string(&init_options).unwrap(); + + let code = format!( + r#" /* mako/runtime/federation runtime */ -!(function() { - if(!requireModule.federation) { - requireModule.federation = { - initOptions: {}, - chunkMatcher: undefined, +!(function() {{ + if(!requireModule.federation) {{ + requireModule.federation = {{ + initOptions: {init_options_code}, + chunkMatcher: () => true, rootOutputDir: "", initialConsumes: undefined, - bundlerRuntimeOptions: {} - }; - } -})();"# - .to_string(); + bundlerRuntimeOptions: {{}} + }}; + }} +}})();"# + ); Ok(vec![code]) } } @@ -252,3 +291,18 @@ export {{ get, init }}; ) } } + +#[derive(Serialize)] +struct RuntimeInitOptions { + name: String, + remotes: Vec, + share_strategy: String, +} + +#[derive(Serialize)] +struct RuntimeRemoteItem { + name: String, + alias: String, + entry: String, + share_scope: String, +} diff --git a/examples/module-federation/consumer/mako.config.json b/examples/module-federation/consumer/mako.config.json index 156c5f729..9edacd83c 100644 --- a/examples/module-federation/consumer/mako.config.json +++ b/examples/module-federation/consumer/mako.config.json @@ -3,9 +3,11 @@ "consumerHost": "./src/index.ts" }, "moduleFederation": { + "name": "consumer", "remotes": { "provider": "provider@http://localhost:3000/mf-manifest.json" - } + }, + "implementation": "/Users/xusd/codes/github/mako/packages/mako/node_modules/@module-federation/webpack-bundler-runtime" }, "optimization": { "skipModules": false, diff --git a/examples/module-federation/consumer/public/index.html b/examples/module-federation/consumer/public/index.html new file mode 100644 index 000000000..a85a3c710 --- /dev/null +++ b/examples/module-federation/consumer/public/index.html @@ -0,0 +1,7 @@ + + + +
+ + + diff --git a/examples/module-federation/consumer/src/bootstrap.ts b/examples/module-federation/consumer/src/bootstrap.ts index d933c8d8e..5da57036c 100644 --- a/examples/module-federation/consumer/src/bootstrap.ts +++ b/examples/module-federation/consumer/src/bootstrap.ts @@ -1,4 +1,4 @@ -import provider from 'provider/provider'; +// import provider from 'provider/provider'; console.log('mf consomer host loaded.'); -console.log(`provider loaded ${provider}`); +// console.log(`provider loaded ${provider}`); From d98c303c393818915942bf1cbabfccf0e73aac0e Mon Sep 17 00:00:00 2001 From: xusd320 Date: Tue, 26 Nov 2024 13:52:04 +0800 Subject: [PATCH 07/68] feat: add containter references --- crates/mako/src/plugins/module_federation.rs | 121 +++++++++++-------- 1 file changed, 69 insertions(+), 52 deletions(-) diff --git a/crates/mako/src/plugins/module_federation.rs b/crates/mako/src/plugins/module_federation.rs index ed9eb0de3..f85a2ea86 100644 --- a/crates/mako/src/plugins/module_federation.rs +++ b/crates/mako/src/plugins/module_federation.rs @@ -33,6 +33,7 @@ impl Plugin for ModuleFederationPlugin { } fn modify_config(&self, config: &mut Config, root: &Path, _args: &Args) -> Result<()> { + // add containter entry if let Some(exposes) = self.config.exposes.as_ref() { let container_entry_name = &self.config.name; if !exposes.is_empty() { @@ -71,6 +72,7 @@ impl Plugin for ModuleFederationPlugin { _is_entry: bool, _context: &Arc, ) -> Result> { + // add containter entry runtime dependency if !_is_entry { Ok(None) } else { @@ -94,59 +96,13 @@ impl Plugin for ModuleFederationPlugin { } fn runtime_plugins(&self, _context: &Arc) -> Result> { - fn parse_remote(remote: &str) -> Result<(String, String)> { - let (left, right) = remote - .split_once('@') - .ok_or(anyhow!("invalid remote {}", remote))?; - if left.is_empty() || right.is_empty() { - Err(anyhow!("invalid remote {}", remote)) - } else { - Ok((left.to_string(), right.to_string())) - } - } + let federation_runtime_code = self.get_federation_runtime_code(); + let federation_container_references_code = self.get_container_references_code(); - let runtime_remotes = self.config.remotes.as_ref().map_or(Vec::new(), |remotes| { - remotes - .iter() - .map(|(alias, remote)| { - // FIXME: should not unwrap - let (name, entry) = parse_remote(remote).unwrap(); - RuntimeRemoteItem { - name, - alias: alias.clone(), - entry, - share_scope: self.config.share_scope.clone(), - } - }) - .collect() - }); - let init_options: RuntimeInitOptions = RuntimeInitOptions { - name: self.config.name.clone(), - remotes: runtime_remotes, - share_strategy: serde_json::to_value(&self.config.share_strategy) - .unwrap() - .as_str() - .unwrap() - .to_string(), - }; - let init_options_code = serde_json::to_string(&init_options).unwrap(); - - let code = format!( - r#" -/* mako/runtime/federation runtime */ -!(function() {{ - if(!requireModule.federation) {{ - requireModule.federation = {{ - initOptions: {init_options_code}, - chunkMatcher: () => true, - rootOutputDir: "", - initialConsumes: undefined, - bundlerRuntimeOptions: {{}} - }}; - }} -}})();"# - ); - Ok(vec![code]) + Ok(vec![ + federation_runtime_code, + federation_container_references_code, + ]) } } @@ -290,6 +246,67 @@ export {{ get, init }}; share_scope = self.config.share_scope ) } + + fn get_federation_runtime_code(&self) -> String { + fn parse_remote(remote: &str) -> Result<(String, String)> { + let (left, right) = remote + .split_once('@') + .ok_or(anyhow!("invalid remote {}", remote))?; + if left.is_empty() || right.is_empty() { + Err(anyhow!("invalid remote {}", remote)) + } else { + Ok((left.to_string(), right.to_string())) + } + } + + let runtime_remotes = self.config.remotes.as_ref().map_or(Vec::new(), |remotes| { + remotes + .iter() + .map(|(alias, remote)| { + // FIXME: should not unwrap + let (name, entry) = parse_remote(remote).unwrap(); + RuntimeRemoteItem { + name, + alias: alias.clone(), + entry, + share_scope: self.config.share_scope.clone(), + } + }) + .collect() + }); + let init_options: RuntimeInitOptions = RuntimeInitOptions { + name: self.config.name.clone(), + remotes: runtime_remotes, + share_strategy: serde_json::to_value(&self.config.share_strategy) + .unwrap() + .as_str() + .unwrap() + .to_string(), + }; + let init_options_code = serde_json::to_string(&init_options).unwrap(); + + let federation_runtime_code = format!( + r#" +/* mako/runtime/federation runtime */ +!(function() {{ + if(!requireModule.federation) {{ + requireModule.federation = {{ + initOptions: {init_options_code}, + chunkMatcher: () => true, + rootOutputDir: "", + initialConsumes: undefined, + bundlerRuntimeOptions: {{}} + }}; + }} +}})();"# + ); + federation_runtime_code + } + + // TODO: impl remote module + fn get_container_references_code(&self) -> String { + "".to_string() + } } #[derive(Serialize)] From aac2c2d3386c3511d3736a5d3cc5b433c8169c8a Mon Sep 17 00:00:00 2001 From: xusd320 Date: Fri, 29 Nov 2024 14:36:48 +0800 Subject: [PATCH 08/68] feat: impl mf remote --- crates/mako/src/build.rs | 3 + crates/mako/src/compiler.rs | 16 +- crates/mako/src/module.rs | 3 + .../src/plugins/hmr_runtime/hmr_runtime.js | 21 +- crates/mako/src/plugins/module_federation.rs | 361 +++++++++++++----- .../tree_shaking/shake/find_export_source.rs | 1 + crates/mako/src/resolve.rs | 2 +- crates/mako/src/resolve/resource.rs | 27 +- crates/mako/templates/app_runtime.stpl | 9 +- .../consumer/mako.config.json | 3 + .../consumer/src/bootstrap.ts | 4 +- .../module-federation/consumer/src/index.ts | 2 +- 12 files changed, 342 insertions(+), 110 deletions(-) diff --git a/crates/mako/src/build.rs b/crates/mako/src/build.rs index d03145b2f..e93491fd9 100644 --- a/crates/mako/src/build.rs +++ b/crates/mako/src/build.rs @@ -126,6 +126,9 @@ impl Compiler { ResolverResource::Ignored(_) => { Self::create_ignored_module(&path, self.context.clone()) } + ResolverResource::Remote(remote_into) => { + Self::create_remote_module(remote_into) + } }; // 拿到依赖之后需要直接添加 module 到 module_graph 里,不能等依赖 build 完再添加 diff --git a/crates/mako/src/compiler.rs b/crates/mako/src/compiler.rs index 536f15d7a..8a74907d7 100644 --- a/crates/mako/src/compiler.rs +++ b/crates/mako/src/compiler.rs @@ -18,11 +18,12 @@ use crate::ast::file::win_path; use crate::config::{Config, ModuleIdStrategy, OutputMode}; use crate::generate::chunk_graph::ChunkGraph; use crate::generate::optimize_chunk::OptimizeChunksInfo; +use crate::module::{Module, ModuleInfo}; use crate::module_graph::ModuleGraph; use crate::plugin::{Plugin, PluginDriver, PluginGenerateEndParams}; use crate::plugins; use crate::plugins::module_federation::ModuleFederationPlugin; -use crate::resolve::{get_resolvers, Resolvers}; +use crate::resolve::{get_resolvers, RemoteInfo, ResolverResource, Resolvers}; use crate::share::helpers::SWC_HELPERS; use crate::stats::StatsInfo; use crate::utils::id_helper::{assign_numeric_ids, compare_modules_by_incoming_edges}; @@ -494,4 +495,17 @@ impl Compiler { } Ok(()) } + + pub(crate) fn create_remote_module(remote_info: RemoteInfo) -> Module { + Module { + is_remote: true, + is_entry: false, + id: remote_info.module_id.as_str().into(), + info: Some(ModuleInfo { + resolved_resource: Some(ResolverResource::Remote(remote_info.clone())), + ..Default::default() + }), + side_effects: true, + } + } } diff --git a/crates/mako/src/module.rs b/crates/mako/src/module.rs index 01c9e5fb7..348a50b88 100644 --- a/crates/mako/src/module.rs +++ b/crates/mako/src/module.rs @@ -381,6 +381,8 @@ pub enum ModuleType { pub struct Module { pub id: ModuleId, pub is_entry: bool, + // only module federation remote module + pub is_remote: bool, pub info: Option, pub side_effects: bool, } @@ -390,6 +392,7 @@ impl Module { Self { id, is_entry, + is_remote: false, info, side_effects: is_entry, } diff --git a/crates/mako/src/plugins/hmr_runtime/hmr_runtime.js b/crates/mako/src/plugins/hmr_runtime/hmr_runtime.js index 0227be6a5..ce4afc957 100644 --- a/crates/mako/src/plugins/hmr_runtime/hmr_runtime.js +++ b/crates/mako/src/plugins/hmr_runtime/hmr_runtime.js @@ -30,7 +30,26 @@ } return require(request); }; - Object.assign(fn, require); + + var createPropertyDescriptor = function (name) { + return { + configurable: true, + enumerable: true, + get: function () { + return require[name]; + }, + set: function (value) { + require[name] = value; + }, + }; + }; + + for (var name in require) { + if (Object.prototype.hasOwnProperty.call(require, name)) { + Object.defineProperty(fn, name, createPropertyDescriptor(name)); + } + } + return fn; }; const applyHotUpdate = (_chunkId, update) => { diff --git a/crates/mako/src/plugins/module_federation.rs b/crates/mako/src/plugins/module_federation.rs index f85a2ea86..98c484af3 100644 --- a/crates/mako/src/plugins/module_federation.rs +++ b/crates/mako/src/plugins/module_federation.rs @@ -1,4 +1,5 @@ use std::collections::hash_map::Entry::{Occupied, Vacant}; +use std::collections::HashMap; use std::fs; use std::path::Path; use std::sync::Arc; @@ -7,12 +8,16 @@ use anyhow::{anyhow, Result}; use serde::Serialize; use tracing::warn; -use crate::ast::file::Content; +use crate::ast::file::{Content, JsContent}; use crate::compiler::{Args, Context}; use crate::config::module_federation::ModuleFederationConfig; -use crate::config::Config; +use crate::config::{ + Config, ExternalAdvanced, ExternalAdvancedSubpath, ExternalAdvancedSubpathRule, + ExternalAdvancedSubpathTarget, ExternalConfig, +}; use crate::module::md5_hash; -use crate::plugin::Plugin; +use crate::plugin::{Plugin, PluginResolveIdParams}; +use crate::resolve::{RemoteInfo, ResolverResource}; use crate::visitors::mako_require::MAKO_REQUIRE; pub struct ModuleFederationPlugin { @@ -21,92 +26,17 @@ pub struct ModuleFederationPlugin { const FEDERATION_GLOBAL: &str = "__mako_require__.federation"; -impl ModuleFederationPlugin { - pub fn new(config: ModuleFederationConfig) -> Self { - Self { config } - } -} +const FEDERATION_REMOTE_MODULE_PREFIX: &str = "mako/container/remote/"; -impl Plugin for ModuleFederationPlugin { - fn name(&self) -> &str { - "module_federation" - } +const FEDERATION_REMOTE_REFERENCE_PREFIX: &str = "mako/container/reference/"; - fn modify_config(&self, config: &mut Config, root: &Path, _args: &Args) -> Result<()> { - // add containter entry - if let Some(exposes) = self.config.exposes.as_ref() { - let container_entry_name = &self.config.name; - if !exposes.is_empty() { - match config.entry.entry(container_entry_name.clone()) { - Occupied(_) => { - warn!( - "mf exposed name {} is duplcated with entry config.", - container_entry_name - ); - } - Vacant(vacant_entry) => { - let container_entry_code = self.get_container_entry_code(root); - let container_entry_path = root.join(format!( - "node_modules/.federation/.entry.container.{}.js", - container_entry_name - )); - let container_entry_parent_path = container_entry_path.parent().unwrap(); - if !fs::exists(container_entry_parent_path).unwrap() { - fs::create_dir(container_entry_parent_path).unwrap(); - } - fs::write(&container_entry_path, container_entry_code).unwrap(); +const FEDERATION_SHARED_REFERENCE_PREFIX: &str = "mako/sharing/consume/"; - vacant_entry.insert(container_entry_path); - } - } - } - } - - Ok(()) - } - - fn load_transform( - &self, - _content: &mut Content, - _path: &str, - _is_entry: bool, - _context: &Arc, - ) -> Result> { - // add containter entry runtime dependency - if !_is_entry { - Ok(None) - } else { - match _content { - Content::Js(js_content) => { - let entry_runtime_dep_path = self.prepare_entry_runtime_dep(&_context.root); - js_content.content.insert_str( - 0, - format!( - r#"import "{}"; -"#, - entry_runtime_dep_path - ) - .as_str(), - ); - Ok(Some(_content.clone())) - } - _ => Ok(None), - } - } - } - - fn runtime_plugins(&self, _context: &Arc) -> Result> { - let federation_runtime_code = self.get_federation_runtime_code(); - let federation_container_references_code = self.get_container_references_code(); - - Ok(vec![ - federation_runtime_code, - federation_container_references_code, - ]) +impl ModuleFederationPlugin { + pub fn new(config: ModuleFederationConfig) -> Self { + Self { config } } -} -impl ModuleFederationPlugin { fn prepare_entry_runtime_dep(&self, root: &Path) -> String { let entry_runtime_code = self.get_entry_runtime_code(); @@ -248,17 +178,6 @@ export {{ get, init }}; } fn get_federation_runtime_code(&self) -> String { - fn parse_remote(remote: &str) -> Result<(String, String)> { - let (left, right) = remote - .split_once('@') - .ok_or(anyhow!("invalid remote {}", remote))?; - if left.is_empty() || right.is_empty() { - Err(anyhow!("invalid remote {}", remote)) - } else { - Ok((left.to_string(), right.to_string())) - } - } - let runtime_remotes = self.config.remotes.as_ref().map_or(Vec::new(), |remotes| { remotes .iter() @@ -304,8 +223,236 @@ export {{ get, init }}; } // TODO: impl remote module - fn get_container_references_code(&self) -> String { - "".to_string() + fn get_container_references_code(&self, context: &Arc) -> String { + let module_graph = context.module_graph.read().unwrap(); + let chunk_graph = context.chunk_graph.read().unwrap(); + let all_chunks = chunk_graph.get_all_chunks(); + + let mut chunk_mapping: HashMap<&str, Vec<&str>> = HashMap::new(); + let mut id_to_external_and_name_mapping: HashMap<&str, Vec<&str>> = HashMap::new(); + let mut id_to_remote_map: HashMap<&str, Vec> = HashMap::new(); + all_chunks.iter().for_each(|c| { + c.modules.iter().for_each(|m| { + if let Some(m) = module_graph.get_module(m) { + if m.is_remote { + { + chunk_mapping + .entry(c.id.id.as_str()) + .or_default() + .push(m.id.id.as_str()); + } + + { + let remote_module = m + .info + .as_ref() + .unwrap() + .resolved_resource + .as_ref() + .unwrap() + .get_remote_info() + .unwrap(); + let remote_info = id_to_external_and_name_mapping + .entry(m.id.id.as_str()) + .or_default(); + remote_info.push(&remote_module.share_scope); + remote_info.push(&remote_module.sub_path); + remote_info.push(&remote_module.external_refenrence_id); + + let external_info = + id_to_remote_map.entry(m.id.id.as_str()).or_default(); + + external_info.push(RemoteExternal { + name: remote_module.name.clone(), + external_type: remote_module.external_type.clone(), + external_module_id: remote_module.external_refenrence_id.clone(), + }); + } + } + } + }); + }); + + let chunk_mapping = serde_json::to_string(&chunk_mapping).unwrap(); + let id_to_external_and_name_mapping = + serde_json::to_string(&id_to_external_and_name_mapping).unwrap(); + let id_to_remote_map = serde_json::to_string(&id_to_remote_map).unwrap(); + + format!( + r#" +/* mako/runtime/federation remotes consume */ +!(function() {{ + var chunkMapping = {chunk_mapping}; + var idToExternalAndNameMapping = {id_to_external_and_name_mapping}; + var idToRemoteMap = {id_to_remote_map}; + requireModule.federation.bundlerRuntimeOptions.remotes = {{idToRemoteMap, chunkMapping, idToExternalAndNameMapping, webpackRequire: requireModule}}; + requireModule.chunkEnsures.remotes = (chunkId, promises) => {{ + requireModule.federation.bundlerRuntime.remotes({{ idToRemoteMap,chunkMapping, idToExternalAndNameMapping, chunkId, promises, webpackRequire: requireModule}}); + }} +}} +)()"#, + ) + } + + fn add_container_entry(&self, config: &mut Config, root: &Path) { + // add containter entry + if let Some(exposes) = self.config.exposes.as_ref() { + let container_entry_name = &self.config.name; + if !exposes.is_empty() { + match config.entry.entry(container_entry_name.clone()) { + Occupied(_) => { + warn!( + "mf exposed name {} is duplcated with entry config.", + container_entry_name + ); + } + Vacant(vacant_entry) => { + let container_entry_code = self.get_container_entry_code(root); + let container_entry_path = root.join(format!( + "node_modules/.federation/.entry.container.{}.js", + container_entry_name + )); + let container_entry_parent_path = container_entry_path.parent().unwrap(); + if !fs::exists(container_entry_parent_path).unwrap() { + fs::create_dir(container_entry_parent_path).unwrap(); + } + fs::write(&container_entry_path, container_entry_code).unwrap(); + + vacant_entry.insert(container_entry_path); + } + } + } + } + } + + fn append_remotes_externals(&self, config: &mut Config) { + if let Some(remotes) = &self.config.remotes { + remotes.iter().for_each(|remote| { + config.externals.insert( + format!("{}{}", FEDERATION_REMOTE_REFERENCE_PREFIX, remote.0), + ExternalConfig::Advanced(ExternalAdvanced { + root: remote.0.clone(), + script: parse_remote(remote.1).ok().map(|(_, url)| url.clone()), + module_type: None, + subpath: Some(ExternalAdvancedSubpath { + exclude: None, + rules: vec![ExternalAdvancedSubpathRule { + regex: "/.*".to_string(), + target: ExternalAdvancedSubpathTarget::Empty, + target_converter: None, + }], + }), + }), + ); + }); + } + } +} + +impl Plugin for ModuleFederationPlugin { + fn name(&self) -> &str { + "module_federation" + } + + fn modify_config(&self, config: &mut Config, root: &Path, _args: &Args) -> Result<()> { + self.add_container_entry(config, root); + + self.append_remotes_externals(config); + + Ok(()) + } + + fn load( + &self, + _param: &crate::plugin::PluginLoadParam, + _context: &Arc, + ) -> Result> { + Ok(_param.file.path().map_or_else( + || None, + |path| { + if path.starts_with(FEDERATION_REMOTE_MODULE_PREFIX) { + Some(Content::Js(JsContent { + is_jsx: false, + content: "".to_string(), + })) + } else { + None + } + }, + )) + } + + fn load_transform( + &self, + _content: &mut Content, + _path: &str, + _is_entry: bool, + _context: &Arc, + ) -> Result> { + // add containter entry runtime dependency + if !_is_entry { + Ok(None) + } else { + match _content { + Content::Js(js_content) => { + let entry_runtime_dep_path = self.prepare_entry_runtime_dep(&_context.root); + js_content.content.insert_str( + 0, + format!( + r#"import "{}"; +"#, + entry_runtime_dep_path + ) + .as_str(), + ); + Ok(Some(_content.clone())) + } + _ => Ok(None), + } + } + } + + fn runtime_plugins(&self, context: &Arc) -> Result> { + let federation_runtime_code = self.get_federation_runtime_code(); + let federation_container_references_code = self.get_container_references_code(context); + + Ok(vec![ + federation_runtime_code, + federation_container_references_code, + ]) + } + + fn resolve_id( + &self, + source: &str, + _importer: &str, + _params: &PluginResolveIdParams, + _context: &Arc, + ) -> Result> { + let source_parts = source + .split_once("/") + .map_or((source.to_string(), ".".to_string()), |(part_0, part_1)| { + (part_0.to_string(), part_1.to_string()) + }); + Ok(self.config.remotes.as_ref().map_or_else( + || None, + |remotes| { + remotes.get(&source_parts.0).map(|_remote| { + ResolverResource::Remote(RemoteInfo { + module_id: format!("{}{}", FEDERATION_REMOTE_MODULE_PREFIX, source), + external_refenrence_id: format!( + "{}{}", + FEDERATION_REMOTE_REFERENCE_PREFIX, source_parts.0 + ), + // FIXME: hard code now + external_type: "script".to_string(), + sub_path: format!("./{}", source_parts.1), + name: source_parts.0.to_string(), + share_scope: self.config.share_scope.clone(), + }) + }) + }, + )) } } @@ -317,9 +464,29 @@ struct RuntimeInitOptions { } #[derive(Serialize)] +#[serde(rename_all = "camelCase")] struct RuntimeRemoteItem { name: String, alias: String, entry: String, share_scope: String, } + +fn parse_remote(remote: &str) -> Result<(String, String)> { + let (left, right) = remote + .split_once('@') + .ok_or(anyhow!("invalid remote {}", remote))?; + if left.is_empty() || right.is_empty() { + Err(anyhow!("invalid remote {}", remote)) + } else { + Ok((left.to_string(), right.to_string())) + } +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct RemoteExternal { + external_type: String, + name: String, + external_module_id: String, +} diff --git a/crates/mako/src/plugins/tree_shaking/shake/find_export_source.rs b/crates/mako/src/plugins/tree_shaking/shake/find_export_source.rs index 66913341f..cf52ec06d 100644 --- a/crates/mako/src/plugins/tree_shaking/shake/find_export_source.rs +++ b/crates/mako/src/plugins/tree_shaking/shake/find_export_source.rs @@ -470,6 +470,7 @@ mod tests { let mako_module = Module { id: "test.js".into(), is_entry: false, + is_remote: false, info: Some(ModuleInfo { ast: ModuleAst::Script(ast), file, diff --git a/crates/mako/src/resolve.rs b/crates/mako/src/resolve.rs index f283eba13..bcc5cb4dc 100644 --- a/crates/mako/src/resolve.rs +++ b/crates/mako/src/resolve.rs @@ -13,7 +13,7 @@ use tracing::debug; mod resolution; mod resource; pub use resolution::Resolution; -pub use resource::{ExternalResource, ResolvedResource, ResolverResource}; +pub use resource::{ExternalResource, RemoteInfo, ResolvedResource, ResolverResource}; use crate::ast::file::parse_path; use crate::compiler::Context; diff --git a/crates/mako/src/resolve/resource.rs b/crates/mako/src/resolve/resource.rs index 6e9219481..870661004 100644 --- a/crates/mako/src/resolve/resource.rs +++ b/crates/mako/src/resolve/resource.rs @@ -2,6 +2,16 @@ use std::path::PathBuf; use crate::resolve::Resolution; +#[derive(Debug, Clone)] +pub struct RemoteInfo { + pub module_id: String, + pub external_refenrence_id: String, + pub external_type: String, + pub sub_path: String, + pub name: String, + pub share_scope: String, +} + #[derive(Debug, Clone)] pub struct ExternalResource { pub source: String, @@ -18,6 +28,7 @@ pub enum ResolverResource { Resolved(ResolvedResource), Ignored(PathBuf), Virtual(PathBuf), + Remote(RemoteInfo), } impl ResolverResource { @@ -29,22 +40,26 @@ impl ResolverResource { } ResolverResource::Ignored(path) => path.to_string_lossy().to_string(), ResolverResource::Virtual(path) => path.to_string_lossy().to_string(), + ResolverResource::Remote(info) => info.module_id.to_string(), } } pub fn get_external(&self) -> Option { match self { ResolverResource::External(ExternalResource { external, .. }) => Some(external.clone()), - ResolverResource::Resolved(_) => None, - ResolverResource::Ignored(_) => None, - ResolverResource::Virtual(_) => None, + _ => None, } } pub fn get_script(&self) -> Option { match self { ResolverResource::External(ExternalResource { script, .. }) => script.clone(), - ResolverResource::Resolved(_) => None, - ResolverResource::Ignored(_) => None, - ResolverResource::Virtual(_) => None, + _ => None, + } + } + + pub fn get_remote_info(&self) -> Option<&RemoteInfo> { + match &self { + ResolverResource::Remote(remote_info) => Some(remote_info), + _ => None, } } } diff --git a/crates/mako/templates/app_runtime.stpl b/crates/mako/templates/app_runtime.stpl index 002c0019c..ed29c0e9f 100644 --- a/crates/mako/templates/app_runtime.stpl +++ b/crates/mako/templates/app_runtime.stpl @@ -64,11 +64,18 @@ function createRuntime(makoModules, entryModuleId, global) { get: all[name], }); }; + + // hasOwnProperty shorthand + requireModule.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)); + + // required modules + requireModule.m = makoModules; + <% if concatenate_enabled { %> // Export Star util for concatenated modules requireModule.es = function(to, from) { Object.keys(from).forEach(function(k) { - if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) { + if (k !== "default" && !requireModule.o(to, k)) { Object.defineProperty(to, k, { enumerable: true, get: from[k] diff --git a/examples/module-federation/consumer/mako.config.json b/examples/module-federation/consumer/mako.config.json index 9edacd83c..7e2dbca56 100644 --- a/examples/module-federation/consumer/mako.config.json +++ b/examples/module-federation/consumer/mako.config.json @@ -12,5 +12,8 @@ "optimization": { "skipModules": false, "concatenateModules": false + }, + "experimental": { + "centralEnsure": false } } diff --git a/examples/module-federation/consumer/src/bootstrap.ts b/examples/module-federation/consumer/src/bootstrap.ts index 5da57036c..d933c8d8e 100644 --- a/examples/module-federation/consumer/src/bootstrap.ts +++ b/examples/module-federation/consumer/src/bootstrap.ts @@ -1,4 +1,4 @@ -// import provider from 'provider/provider'; +import provider from 'provider/provider'; console.log('mf consomer host loaded.'); -// console.log(`provider loaded ${provider}`); +console.log(`provider loaded ${provider}`); diff --git a/examples/module-federation/consumer/src/index.ts b/examples/module-federation/consumer/src/index.ts index e59d6a0ad..b93c7a026 100644 --- a/examples/module-federation/consumer/src/index.ts +++ b/examples/module-federation/consumer/src/index.ts @@ -1 +1 @@ -import './bootstrap'; +import('./bootstrap'); From 7a61e418c53b275cd1a17b338da660b68fc0bd38 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Tue, 3 Dec 2024 19:34:34 +0800 Subject: [PATCH 09/68] feat: improve mf exposes --- crates/mako/src/compiler.rs | 1 + crates/mako/src/generate/transform.rs | 4 + crates/mako/src/module.rs | 1 + crates/mako/src/plugins/bundless_compiler.rs | 1 + crates/mako/src/plugins/module_federation.rs | 107 ++++++++++++- crates/mako/src/visitors/dep_analyzer.rs | 18 ++- crates/mako/src/visitors/dep_replacer.rs | 2 + crates/mako/src/visitors/dynamic_import.rs | 21 ++- .../consumer/src/bootstrap.ts | 4 - .../{consumer => host}/.gitignore | 0 .../{consumer => host}/mako.config.json | 6 +- examples/module-federation/host/package.json | 4 + .../{provider => host}/public/index.html | 2 +- .../module-federation/host/src/bootstrap.ts | 4 + .../{consumer => host}/src/index.ts | 0 .../provider/src/bootstrap.ts | 4 - .../provider/src/provider.ts | 1 - .../{provider => widget}/.gitignore | 0 .../{provider => widget}/mako.config.json | 6 +- .../module-federation/widget/package.json | 4 + .../{consumer => widget}/public/index.html | 2 +- examples/module-federation/widget/src/App.ts | 1 + .../module-federation/widget/src/bootstrap.ts | 4 + .../{provider => widget}/src/index.ts | 0 packages/mako/src/index.ts | 10 ++ packages/mako/src/mf/index.ts | 15 ++ packages/mako/src/mf/manifest.ts | 142 ++++++++++++++++++ 27 files changed, 337 insertions(+), 27 deletions(-) delete mode 100644 examples/module-federation/consumer/src/bootstrap.ts rename examples/module-federation/{consumer => host}/.gitignore (100%) rename examples/module-federation/{consumer => host}/mako.config.json (72%) create mode 100644 examples/module-federation/host/package.json rename examples/module-federation/{provider => host}/public/index.html (68%) create mode 100644 examples/module-federation/host/src/bootstrap.ts rename examples/module-federation/{consumer => host}/src/index.ts (100%) delete mode 100644 examples/module-federation/provider/src/bootstrap.ts delete mode 100644 examples/module-federation/provider/src/provider.ts rename examples/module-federation/{provider => widget}/.gitignore (100%) rename examples/module-federation/{provider => widget}/mako.config.json (75%) create mode 100644 examples/module-federation/widget/package.json rename examples/module-federation/{consumer => widget}/public/index.html (66%) create mode 100644 examples/module-federation/widget/src/App.ts create mode 100644 examples/module-federation/widget/src/bootstrap.ts rename examples/module-federation/{provider => widget}/src/index.ts (100%) create mode 100644 packages/mako/src/mf/index.ts create mode 100644 packages/mako/src/mf/manifest.ts diff --git a/crates/mako/src/compiler.rs b/crates/mako/src/compiler.rs index 8a74907d7..46132a941 100644 --- a/crates/mako/src/compiler.rs +++ b/crates/mako/src/compiler.rs @@ -473,6 +473,7 @@ impl Compiler { self.context .plugin_driver .generate_end(¶ms, &self.context)?; + self.context.plugin_driver.write_bundle(&self.context)?; Ok(()) } diff --git a/crates/mako/src/generate/transform.rs b/crates/mako/src/generate/transform.rs index 8cc2dfeb2..4e927091e 100644 --- a/crates/mako/src/generate/transform.rs +++ b/crates/mako/src/generate/transform.rs @@ -100,6 +100,7 @@ pub fn transform_modules_in_thread( chunk_id: None, to_replace_source: chunk_name, resolved_module_id: id.clone(), + _is_federation_expose: false, } } ResolveType::DynamicImport(import_options) => { @@ -112,12 +113,14 @@ pub fn transform_modules_in_thread( chunk_id, to_replace_source: id.generate(&context), resolved_module_id: id.clone(), + _is_federation_expose: import_options._is_federation_expose, } } _ => ResolvedReplaceInfo { chunk_id: None, to_replace_source: id.generate(&context), resolved_module_id: id.clone(), + _is_federation_expose: false, }, }; @@ -189,6 +192,7 @@ fn insert_swc_helper_replace( chunk_id: None, to_replace_source: m_id.generate(context), resolved_module_id: m_id, + _is_federation_expose: false, }, ); }); diff --git a/crates/mako/src/module.rs b/crates/mako/src/module.rs index 348a50b88..687a38cb2 100644 --- a/crates/mako/src/module.rs +++ b/crates/mako/src/module.rs @@ -130,6 +130,7 @@ impl From<&NamedExport> for NamedExportType { pub struct ImportOptions { pub chunk_name: Option, pub ignore: bool, + pub _is_federation_expose: bool, } impl ImportOptions { diff --git a/crates/mako/src/plugins/bundless_compiler.rs b/crates/mako/src/plugins/bundless_compiler.rs index e93aa3412..328a71d70 100644 --- a/crates/mako/src/plugins/bundless_compiler.rs +++ b/crates/mako/src/plugins/bundless_compiler.rs @@ -86,6 +86,7 @@ impl BundlessCompiler { chunk_id: None, to_replace_source: replacement, resolved_module_id: id.clone(), + _is_federation_expose: false, }, )) }) diff --git a/crates/mako/src/plugins/module_federation.rs b/crates/mako/src/plugins/module_federation.rs index 98c484af3..32cb2e655 100644 --- a/crates/mako/src/plugins/module_federation.rs +++ b/crates/mako/src/plugins/module_federation.rs @@ -16,7 +16,7 @@ use crate::config::{ ExternalAdvancedSubpathTarget, ExternalConfig, }; use crate::module::md5_hash; -use crate::plugin::{Plugin, PluginResolveIdParams}; +use crate::plugin::{Plugin, PluginGenerateEndParams, PluginResolveIdParams}; use crate::resolve::{RemoteInfo, ResolverResource}; use crate::visitors::mako_require::MAKO_REQUIRE; @@ -134,9 +134,13 @@ if(!{federation_global}.instance) {{ .iter() .map(|(name, module)| { format!( - r#""{name}": () => import(/* makoChunkName: "__mf_expose_{container_name}" */ "{module}"),"#, - container_name = self.config.name, - module = root.join(module).to_string_lossy() + r#""{name}": () => import( + /* makoChunkName: "__mf_expose_{striped_name}" */ + /* federationExpose: true */ + "{module}" +),"#, + module = root.join(module).canonicalize().unwrap().to_string_lossy(), + striped_name = name.replace("./", "") ) }) .collect::>() @@ -314,7 +318,7 @@ export {{ get, init }}; )); let container_entry_parent_path = container_entry_path.parent().unwrap(); if !fs::exists(container_entry_parent_path).unwrap() { - fs::create_dir(container_entry_parent_path).unwrap(); + fs::create_dir_all(container_entry_parent_path).unwrap(); } fs::write(&container_entry_path, container_entry_code).unwrap(); @@ -347,6 +351,22 @@ export {{ get, init }}; }); } } + + fn get_federation_exposes_library_code(&self) -> String { + if let Some(exposes) = self.config.exposes.as_ref() { + if !exposes.is_empty() { + format!( + r#"global["{}"] = requireModule(entryModuleId); +"#, + self.config.name + ) + } else { + "".to_string() + } + } else { + "".to_string() + } + } } impl Plugin for ModuleFederationPlugin { @@ -414,11 +434,13 @@ impl Plugin for ModuleFederationPlugin { fn runtime_plugins(&self, context: &Arc) -> Result> { let federation_runtime_code = self.get_federation_runtime_code(); + let federation_exposes_library_code = self.get_federation_exposes_library_code(); let federation_container_references_code = self.get_container_references_code(context); Ok(vec![ federation_runtime_code, federation_container_references_code, + federation_exposes_library_code, ]) } @@ -454,6 +476,17 @@ impl Plugin for ModuleFederationPlugin { }, )) } + + fn generate_end( + &self, + _params: &PluginGenerateEndParams, + _context: &Arc, + ) -> Result<()> { + // println!("----------"); + // println!("{:#?}", _params.stats); + // println!("----------"); + Ok(()) + } } #[derive(Serialize)] @@ -490,3 +523,67 @@ struct RemoteExternal { name: String, external_module_id: String, } + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct FederationManifestTypes { + path: String, + name: String, + zip: String, + api: String, +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct FederationManifestMetaData { + name: String, + #[serde(rename = "type")] + type_: String, + build_info: FederationManifestBuildInfo, + remote_entry: FederationManifestRemoteEntry, + types: FederationManifestTypes, + global_name: String, + plugin_version: String, + public_path: String, +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct FederationManifestBuildInfo { + build_version: String, + build_name: String, +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct FederationManifestRemoteEntry { + name: String, + path: String, + #[serde(rename = "type")] + type_: String, +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct FederationManifestShared { + id: String, +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct FederationManifestRemote {} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct FederationManifestExpose {} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct FederationManifest { + id: String, + name: String, + meta_data: FederationManifestMetaData, + shared: Vec, + remotes: Vec, + exposes: Vec, +} diff --git a/crates/mako/src/visitors/dep_analyzer.rs b/crates/mako/src/visitors/dep_analyzer.rs index ca3f89295..c6c7efc2c 100644 --- a/crates/mako/src/visitors/dep_analyzer.rs +++ b/crates/mako/src/visitors/dep_analyzer.rs @@ -66,7 +66,19 @@ impl DepAnalyzer { }) }); - ImportOptions { chunk_name, ignore } + let _is_federation_expose = comments_texts.iter().any(|t| { + get_magic_federation_expose_regex() + .captures(t.trim()) + .map_or(false, |cap| { + cap.get(2).map_or(false, |m| m.as_str() == "true") + }) + }); + + ImportOptions { + chunk_name, + ignore, + _is_federation_expose, + } } } @@ -241,6 +253,10 @@ fn get_magic_comment_ignore_regex() -> Regex { create_cached_regex(r#"(makoIgnore|webpackIgnore):\s*(true|false)"#) } +fn get_magic_federation_expose_regex() -> Regex { + create_cached_regex(r#"(federationExpose):\s*(true|false)"#) +} + #[cfg(test)] mod tests { use swc_core::common::GLOBALS; diff --git a/crates/mako/src/visitors/dep_replacer.rs b/crates/mako/src/visitors/dep_replacer.rs index 47167f6e7..272783551 100644 --- a/crates/mako/src/visitors/dep_replacer.rs +++ b/crates/mako/src/visitors/dep_replacer.rs @@ -28,6 +28,7 @@ pub struct ResolvedReplaceInfo { pub chunk_id: Option, pub to_replace_source: String, pub resolved_module_id: ModuleId, + pub _is_federation_expose: bool, } #[derive(Debug, Clone)] @@ -351,6 +352,7 @@ try { chunk_id: None, to_replace_source: module_id.into(), resolved_module_id: "".into(), + _is_federation_expose: false, } } } diff --git a/crates/mako/src/visitors/dynamic_import.rs b/crates/mako/src/visitors/dynamic_import.rs index b8cd66ac9..cb0beb1fd 100644 --- a/crates/mako/src/visitors/dynamic_import.rs +++ b/crates/mako/src/visitors/dynamic_import.rs @@ -2,7 +2,8 @@ use std::sync::Arc; use swc_core::common::DUMMY_SP; use swc_core::ecma::ast::{ - ArrayLit, Expr, ExprOrSpread, Ident, Lit, MemberExpr, Module, Stmt, VarDeclKind, + ArrayLit, ArrowExpr, BlockStmtOrExpr, Expr, ExprOrSpread, Ident, Lit, MemberExpr, Module, Stmt, + VarDeclKind, }; use swc_core::ecma::utils::{ member_expr, private_ident, quote_ident, quote_str, ExprFactory, IsDirective, @@ -135,8 +136,18 @@ impl<'a> VisitMut for DynamicImport<'a> { vec![self.interop.clone().as_arg(), lazy_require_call.as_arg()], ); + let dr_call_arg = if resolved_info._is_federation_expose { + Expr::Arrow(ArrowExpr { + body: Box::new(BlockStmtOrExpr::Expr(dr_call.into())), + ..Default::default() + }) + .as_arg() + } else { + dr_call.as_arg() + }; + member_expr!(@EXT, DUMMY_SP, load_promise.into(), then) - .as_call(call_expr.span, vec![dr_call.as_arg()]) + .as_call(call_expr.span, vec![dr_call_arg]) }; } } @@ -250,12 +261,14 @@ Promise.all([ "@swc/helpers/_/_interop_require_wildcard".to_string() => ResolvedReplaceInfo { chunk_id: None, to_replace_source: "hashed_helper".to_string(), - resolved_module_id:"dummy".into() + resolved_module_id:"dummy".into(), + _is_federation_expose: false, }, "foo".to_string() => ResolvedReplaceInfo { chunk_id: Some("foo".into()), to_replace_source: "foo".into(), - resolved_module_id: "foo".into() + resolved_module_id: "foo".into(), + _is_federation_expose: false, } }, missing: HashMap::new(), diff --git a/examples/module-federation/consumer/src/bootstrap.ts b/examples/module-federation/consumer/src/bootstrap.ts deleted file mode 100644 index d933c8d8e..000000000 --- a/examples/module-federation/consumer/src/bootstrap.ts +++ /dev/null @@ -1,4 +0,0 @@ -import provider from 'provider/provider'; - -console.log('mf consomer host loaded.'); -console.log(`provider loaded ${provider}`); diff --git a/examples/module-federation/consumer/.gitignore b/examples/module-federation/host/.gitignore similarity index 100% rename from examples/module-federation/consumer/.gitignore rename to examples/module-federation/host/.gitignore diff --git a/examples/module-federation/consumer/mako.config.json b/examples/module-federation/host/mako.config.json similarity index 72% rename from examples/module-federation/consumer/mako.config.json rename to examples/module-federation/host/mako.config.json index 7e2dbca56..1d7a18342 100644 --- a/examples/module-federation/consumer/mako.config.json +++ b/examples/module-federation/host/mako.config.json @@ -1,11 +1,11 @@ { "entry": { - "consumerHost": "./src/index.ts" + "app1": "./src/index.ts" }, "moduleFederation": { - "name": "consumer", + "name": "mfHost", "remotes": { - "provider": "provider@http://localhost:3000/mf-manifest.json" + "widget": "widget@http://localhost:3000/mf-manifest.json" }, "implementation": "/Users/xusd/codes/github/mako/packages/mako/node_modules/@module-federation/webpack-bundler-runtime" }, diff --git a/examples/module-federation/host/package.json b/examples/module-federation/host/package.json new file mode 100644 index 000000000..468626cbf --- /dev/null +++ b/examples/module-federation/host/package.json @@ -0,0 +1,4 @@ +{ + "name": "mf-host", + "version": "0.0.1" +} diff --git a/examples/module-federation/provider/public/index.html b/examples/module-federation/host/public/index.html similarity index 68% rename from examples/module-federation/provider/public/index.html rename to examples/module-federation/host/public/index.html index 78d2edd80..7e0bd8d29 100644 --- a/examples/module-federation/provider/public/index.html +++ b/examples/module-federation/host/public/index.html @@ -2,6 +2,6 @@
- + diff --git a/examples/module-federation/host/src/bootstrap.ts b/examples/module-federation/host/src/bootstrap.ts new file mode 100644 index 000000000..8a4681fd5 --- /dev/null +++ b/examples/module-federation/host/src/bootstrap.ts @@ -0,0 +1,4 @@ +import widget from 'widget/App'; + +console.log('mf host loaded.'); +console.log(`remote loaded ${widget}`); diff --git a/examples/module-federation/consumer/src/index.ts b/examples/module-federation/host/src/index.ts similarity index 100% rename from examples/module-federation/consumer/src/index.ts rename to examples/module-federation/host/src/index.ts diff --git a/examples/module-federation/provider/src/bootstrap.ts b/examples/module-federation/provider/src/bootstrap.ts deleted file mode 100644 index 53eae7725..000000000 --- a/examples/module-federation/provider/src/bootstrap.ts +++ /dev/null @@ -1,4 +0,0 @@ -import provider from './provider'; - -console.log('mf provider host loaded.'); -console.log(`provider loaded ${provider}`); diff --git a/examples/module-federation/provider/src/provider.ts b/examples/module-federation/provider/src/provider.ts deleted file mode 100644 index 6f06a2d88..000000000 --- a/examples/module-federation/provider/src/provider.ts +++ /dev/null @@ -1 +0,0 @@ -export default 'mf provder'; diff --git a/examples/module-federation/provider/.gitignore b/examples/module-federation/widget/.gitignore similarity index 100% rename from examples/module-federation/provider/.gitignore rename to examples/module-federation/widget/.gitignore diff --git a/examples/module-federation/provider/mako.config.json b/examples/module-federation/widget/mako.config.json similarity index 75% rename from examples/module-federation/provider/mako.config.json rename to examples/module-federation/widget/mako.config.json index 3e4d4d133..e7adc55b2 100644 --- a/examples/module-federation/provider/mako.config.json +++ b/examples/module-federation/widget/mako.config.json @@ -1,11 +1,11 @@ { "entry": { - "providerHost": "./src/index.ts" + "app2": "./src/index.ts" }, "moduleFederation": { - "name": "provider", + "name": "mfWidget", "exposes": { - "./provider": "./src/provider.ts" + "./App": "./src/App.ts" }, "runtimePlugins": [], "implementation": "/Users/xusd/codes/github/mako/packages/mako/node_modules/@module-federation/webpack-bundler-runtime" diff --git a/examples/module-federation/widget/package.json b/examples/module-federation/widget/package.json new file mode 100644 index 000000000..38254ca92 --- /dev/null +++ b/examples/module-federation/widget/package.json @@ -0,0 +1,4 @@ +{ + "name": "mf-widget", + "version": "0.0.1" +} diff --git a/examples/module-federation/consumer/public/index.html b/examples/module-federation/widget/public/index.html similarity index 66% rename from examples/module-federation/consumer/public/index.html rename to examples/module-federation/widget/public/index.html index a85a3c710..5de48ef2f 100644 --- a/examples/module-federation/consumer/public/index.html +++ b/examples/module-federation/widget/public/index.html @@ -2,6 +2,6 @@
- + diff --git a/examples/module-federation/widget/src/App.ts b/examples/module-federation/widget/src/App.ts new file mode 100644 index 000000000..1466d00b8 --- /dev/null +++ b/examples/module-federation/widget/src/App.ts @@ -0,0 +1 @@ +export default 'widget app'; diff --git a/examples/module-federation/widget/src/bootstrap.ts b/examples/module-federation/widget/src/bootstrap.ts new file mode 100644 index 000000000..0e2be7f0e --- /dev/null +++ b/examples/module-federation/widget/src/bootstrap.ts @@ -0,0 +1,4 @@ +import App from './App'; + +console.log('widget belonging app loaded.'); +console.log(`widget loaded ${App}`); diff --git a/examples/module-federation/provider/src/index.ts b/examples/module-federation/widget/src/index.ts similarity index 100% rename from examples/module-federation/provider/src/index.ts rename to examples/module-federation/widget/src/index.ts diff --git a/packages/mako/src/index.ts b/packages/mako/src/index.ts index 34c770dbe..244c7a62e 100644 --- a/packages/mako/src/index.ts +++ b/packages/mako/src/index.ts @@ -6,6 +6,7 @@ import { type Options } from 'sass'; import * as binding from '../binding'; import { ForkTSChecker as ForkTSChecker } from './forkTSChecker'; import { LessLoaderOpts, lessLoader } from './lessLoader'; +import { generateMFManifest } from './mf/manifest'; import { sassLoader } from './sassLoader'; type Config = binding.BuildParams['config'] & { @@ -134,6 +135,15 @@ export async function build(params: BuildParams) { }, }); } + + if (makoConfig?.moduleFederation) { + params.config.plugins.push({ + name: 'mf-manifest', + generateEnd(data) { + generateMFManifest(params.root, makoConfig.moduleFederation, data); + }, + }); + } // support dump mako config if (process.env.DUMP_MAKO_CONFIG) { const configFile = path.join(params.root, 'mako.config.json'); diff --git a/packages/mako/src/mf/index.ts b/packages/mako/src/mf/index.ts new file mode 100644 index 000000000..a0c37c69d --- /dev/null +++ b/packages/mako/src/mf/index.ts @@ -0,0 +1,15 @@ +export interface SharedConfig { + singleton?: boolean; + strictVersion?: boolean; + requiredVersion?: string; + version?: string; + eager?: boolean; +} + +export interface FederationConfig { + name: string; + filename?: string; + exposes?: Record; + shared?: Record; + remotes?: Record; +} diff --git a/packages/mako/src/mf/manifest.ts b/packages/mako/src/mf/manifest.ts new file mode 100644 index 000000000..8dc342c5f --- /dev/null +++ b/packages/mako/src/mf/manifest.ts @@ -0,0 +1,142 @@ +import fs from 'fs'; +import path from 'path'; +import { FederationConfig } from '.'; +import { JsHooks } from '../../binding'; + +interface Assets { + js: { async: string[]; sync: string[] }; + css: { async: string[]; sync: string[] }; +} + +interface SharedConfig { + id: string; + name: string; + version: string; + singleton: boolean; + requiredVersion: string; + assets: Assets; +} + +interface RemoteConfig { + federationContainerName: string; + moduleName: string; + alias: string; + entry: string; +} + +interface ExposeConfig { + id: string; + name: string; + assets: Assets; + path: string; +} + +interface TypesConfig { + path: string; + name: string; + zip: string; + api: string; +} + +interface Manifest { + id: string; + name: string; + metaData: { + name: string; + type: string; + buildInfo: { + buildVersion: string; + buildName: string; + }; + remoteEntry: { + name: string; + path: string; + type: string; + }; + types: TypesConfig; + globalName: string; + pluginVersion: string; + publicPath: string; + }; + shared: SharedConfig[]; + remotes: RemoteConfig[]; + exposes: ExposeConfig[]; +} + +export function generateMFManifest( + root: string, + federationConfig: FederationConfig, + bundlerStats: Parameters['generateEnd']>[0], +) { + let pkgJson = JSON.parse( + fs.readFileSync(path.join(root, 'package.json'), 'utf8'), + ); + let manifest: Manifest = { + id: pkgJson.name || '', + name: pkgJson.name || '', + metaData: { + name: pkgJson.name || '', + type: 'app', + buildInfo: { + buildVersion: pkgJson.version || '', + buildName: pkgJson.name || '', + }, + remoteEntry: { + name: + typeof federationConfig.exposes === 'object' && + Object.keys(federationConfig.exposes).length > 0 + ? `${federationConfig.name}.js` + : '', + path: '', + type: 'global', + }, + types: { + path: '', + name: '', + zip: '@mf-types.zip', + api: '@mf-types.d.ts', + }, + globalName: federationConfig.name, + pluginVersion: '0.0.0', + publicPath: 'auto', + }, + exposes: federationConfig.exposes + ? Object.entries(federationConfig.exposes).map(([name, path]) => ({ + id: `${federationConfig.name}:${name.replace(/^\.\//, '')}`, + name: name.replace(/^\.\//, ''), + path, + assets: { + js: { + sync: ['__mf_expose_App-async.js'], + async: [], + }, + css: { + sync: [], + async: [], + }, + }, + })) + : [], + shared: [], + remotes: bundlerStats.stats.chunkModules + .filter((m) => m.id.startsWith('mako/container/remote')) + .map((m) => { + const data = m.id.split('/'); + return { + moduleName: data[4], + federationContainerName: data[3], + alias: data[3], + entry: federationConfig.remotes![data[3]].split('@')[1], + }; + }), + }; + fs.writeFileSync( + path.join(root, './dist/mf-manifest.json'), + JSON.stringify(manifest, null, 2), + ); + + fs.writeFileSync( + path.join(root, './dist/stats.json'), + JSON.stringify(bundlerStats.stats, null, 2), + ); +} From d15d7c66a31d45661a53bc45103be397d3f7110d Mon Sep 17 00:00:00 2001 From: xusd320 Date: Wed, 4 Dec 2024 10:27:59 +0800 Subject: [PATCH 10/68] fix: mf exposes runtime factory --- crates/mako/src/visitors/dynamic_import.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/crates/mako/src/visitors/dynamic_import.rs b/crates/mako/src/visitors/dynamic_import.rs index cb0beb1fd..aa3200607 100644 --- a/crates/mako/src/visitors/dynamic_import.rs +++ b/crates/mako/src/visitors/dynamic_import.rs @@ -2,8 +2,7 @@ use std::sync::Arc; use swc_core::common::DUMMY_SP; use swc_core::ecma::ast::{ - ArrayLit, ArrowExpr, BlockStmtOrExpr, Expr, ExprOrSpread, Ident, Lit, MemberExpr, Module, Stmt, - VarDeclKind, + ArrayLit, Expr, ExprOrSpread, Ident, Lit, MemberExpr, Module, Stmt, VarDeclKind, }; use swc_core::ecma::utils::{ member_expr, private_ident, quote_ident, quote_str, ExprFactory, IsDirective, @@ -137,11 +136,11 @@ impl<'a> VisitMut for DynamicImport<'a> { ); let dr_call_arg = if resolved_info._is_federation_expose { - Expr::Arrow(ArrowExpr { - body: Box::new(BlockStmtOrExpr::Expr(dr_call.into())), - ..Default::default() - }) - .as_arg() + dr_call + .as_call(call_expr.span, Vec::new()) + .into_lazy_fn(Vec::new()) + .into_lazy_fn(Vec::new()) + .as_arg() } else { dr_call.as_arg() }; From 7d801e337dc8e426a481ca7b5058e836d712bc9c Mon Sep 17 00:00:00 2001 From: xusd320 Date: Wed, 4 Dec 2024 11:07:13 +0800 Subject: [PATCH 11/68] fix: mf plugin execution order --- crates/mako/src/compiler.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/crates/mako/src/compiler.rs b/crates/mako/src/compiler.rs index 46132a941..abe2618cf 100644 --- a/crates/mako/src/compiler.rs +++ b/crates/mako/src/compiler.rs @@ -291,11 +291,6 @@ impl Compiler { Arc::new(plugins::bundless_compiler::BundlessCompilerPlugin {}), ); } - - if let Some(mf_cfg) = config.module_federation.as_ref() { - plugins.push(Arc::new(ModuleFederationPlugin::new(mf_cfg.clone()))); - } - if std::env::var("DEBUG_GRAPH").is_ok_and(|v| v == "true") { plugins.push(Arc::new(plugins::graphviz::Graphviz {})); } @@ -308,6 +303,10 @@ impl Compiler { plugins.push(Arc::new(plugins::central_ensure::CentralChunkEnsure {})); } + if let Some(mf_cfg) = config.module_federation.as_ref() { + plugins.push(Arc::new(ModuleFederationPlugin::new(mf_cfg.clone()))); + } + if let Some(minifish_config) = &config._minifish { let inject = if let Some(inject) = &minifish_config.inject { let mut map = HashMap::new(); From b450d8927e3b5b2a9e2e394016e8f5135866bc36 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Wed, 4 Dec 2024 14:32:55 +0800 Subject: [PATCH 12/68] chore: update mf demo --- .../module-federation/host/mako.config.json | 6 +--- examples/module-federation/host/package.json | 6 +++- examples/module-federation/host/src/App.tsx | 24 ++++++++++++++++ .../module-federation/host/src/bootstrap.ts | 4 --- .../module-federation/host/src/bootstrap.tsx | 5 ++++ .../module-federation/widget/mako.config.json | 6 ++-- .../module-federation/widget/package.json | 6 +++- examples/module-federation/widget/src/App.ts | 1 - .../module-federation/widget/src/App1.tsx | 18 ++++++++++++ .../module-federation/widget/src/App2.tsx | 18 ++++++++++++ .../module-federation/widget/src/bootstrap.ts | 4 --- .../widget/src/bootstrap.tsx | 6 ++++ packages/mako/package.json | 3 +- packages/mako/src/index.ts | 9 ++++++ pnpm-lock.yaml | 28 +++++++++---------- 15 files changed, 110 insertions(+), 34 deletions(-) create mode 100644 examples/module-federation/host/src/App.tsx delete mode 100644 examples/module-federation/host/src/bootstrap.ts create mode 100644 examples/module-federation/host/src/bootstrap.tsx delete mode 100644 examples/module-federation/widget/src/App.ts create mode 100644 examples/module-federation/widget/src/App1.tsx create mode 100644 examples/module-federation/widget/src/App2.tsx delete mode 100644 examples/module-federation/widget/src/bootstrap.ts create mode 100644 examples/module-federation/widget/src/bootstrap.tsx diff --git a/examples/module-federation/host/mako.config.json b/examples/module-federation/host/mako.config.json index 1d7a18342..5bfe266de 100644 --- a/examples/module-federation/host/mako.config.json +++ b/examples/module-federation/host/mako.config.json @@ -6,14 +6,10 @@ "name": "mfHost", "remotes": { "widget": "widget@http://localhost:3000/mf-manifest.json" - }, - "implementation": "/Users/xusd/codes/github/mako/packages/mako/node_modules/@module-federation/webpack-bundler-runtime" + } }, "optimization": { "skipModules": false, "concatenateModules": false - }, - "experimental": { - "centralEnsure": false } } diff --git a/examples/module-federation/host/package.json b/examples/module-federation/host/package.json index 468626cbf..6035f9496 100644 --- a/examples/module-federation/host/package.json +++ b/examples/module-federation/host/package.json @@ -1,4 +1,8 @@ { "name": "mf-host", - "version": "0.0.1" + "version": "0.0.1", + "dependencies": { + "react": "18.2.0", + "react-dom": "18.2.0" + } } diff --git a/examples/module-federation/host/src/App.tsx b/examples/module-federation/host/src/App.tsx new file mode 100644 index 000000000..b0db6db67 --- /dev/null +++ b/examples/module-federation/host/src/App.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import Widget1 from 'widget/App1'; +import Widget2 from 'widget/App2'; + +const App = () => { + return ( +
+
+

Host App

+
+ + +
+ ); +}; + +export default App; diff --git a/examples/module-federation/host/src/bootstrap.ts b/examples/module-federation/host/src/bootstrap.ts deleted file mode 100644 index 8a4681fd5..000000000 --- a/examples/module-federation/host/src/bootstrap.ts +++ /dev/null @@ -1,4 +0,0 @@ -import widget from 'widget/App'; - -console.log('mf host loaded.'); -console.log(`remote loaded ${widget}`); diff --git a/examples/module-federation/host/src/bootstrap.tsx b/examples/module-federation/host/src/bootstrap.tsx new file mode 100644 index 000000000..b597a4423 --- /dev/null +++ b/examples/module-federation/host/src/bootstrap.tsx @@ -0,0 +1,5 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App'; + +ReactDOM.render(, document.getElementById('root')); diff --git a/examples/module-federation/widget/mako.config.json b/examples/module-federation/widget/mako.config.json index e7adc55b2..3cca45359 100644 --- a/examples/module-federation/widget/mako.config.json +++ b/examples/module-federation/widget/mako.config.json @@ -5,10 +5,10 @@ "moduleFederation": { "name": "mfWidget", "exposes": { - "./App": "./src/App.ts" + "./App1": "./src/App1.tsx", + "./App2": "./src/App2.tsx" }, - "runtimePlugins": [], - "implementation": "/Users/xusd/codes/github/mako/packages/mako/node_modules/@module-federation/webpack-bundler-runtime" + "runtimePlugins": [] }, "optimization": { "skipModules": false, diff --git a/examples/module-federation/widget/package.json b/examples/module-federation/widget/package.json index 38254ca92..716e343bf 100644 --- a/examples/module-federation/widget/package.json +++ b/examples/module-federation/widget/package.json @@ -1,4 +1,8 @@ { "name": "mf-widget", - "version": "0.0.1" + "version": "0.0.1", + "dependencies": { + "react": "18.2.0", + "react-dom": "18.2.0" + } } diff --git a/examples/module-federation/widget/src/App.ts b/examples/module-federation/widget/src/App.ts deleted file mode 100644 index 1466d00b8..000000000 --- a/examples/module-federation/widget/src/App.ts +++ /dev/null @@ -1 +0,0 @@ -export default 'widget app'; diff --git a/examples/module-federation/widget/src/App1.tsx b/examples/module-federation/widget/src/App1.tsx new file mode 100644 index 000000000..d6b4757c6 --- /dev/null +++ b/examples/module-federation/widget/src/App1.tsx @@ -0,0 +1,18 @@ +import React from 'react'; + +const App = () => { + return ( +
+

Widget App1

+
+ ); +}; + +export default App; diff --git a/examples/module-federation/widget/src/App2.tsx b/examples/module-federation/widget/src/App2.tsx new file mode 100644 index 000000000..2a1875c7f --- /dev/null +++ b/examples/module-federation/widget/src/App2.tsx @@ -0,0 +1,18 @@ +import React from 'react'; + +const App = () => { + return ( +
+

Widget App2

+
+ ); +}; + +export default App; diff --git a/examples/module-federation/widget/src/bootstrap.ts b/examples/module-federation/widget/src/bootstrap.ts deleted file mode 100644 index 0e2be7f0e..000000000 --- a/examples/module-federation/widget/src/bootstrap.ts +++ /dev/null @@ -1,4 +0,0 @@ -import App from './App'; - -console.log('widget belonging app loaded.'); -console.log(`widget loaded ${App}`); diff --git a/examples/module-federation/widget/src/bootstrap.tsx b/examples/module-federation/widget/src/bootstrap.tsx new file mode 100644 index 000000000..39c8c02eb --- /dev/null +++ b/examples/module-federation/widget/src/bootstrap.tsx @@ -0,0 +1,6 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +import App from './App1'; + +ReactDOM.render(, document.getElementById('root')); diff --git a/packages/mako/package.json b/packages/mako/package.json index 3dac21e82..9fefdfe16 100644 --- a/packages/mako/package.json +++ b/packages/mako/package.json @@ -36,7 +36,8 @@ "react-refresh": "^0.14.0", "resolve": "^1.22.8", "semver": "^7.6.2", - "yargs-parser": "^21.1.1" + "yargs-parser": "^21.1.1", + "@module-federation/webpack-bundler-runtime": "^0.8.0" }, "devDependencies": { "@napi-rs/cli": "^2.18.0", diff --git a/packages/mako/src/index.ts b/packages/mako/src/index.ts index 244c7a62e..4f0bfb122 100644 --- a/packages/mako/src/index.ts +++ b/packages/mako/src/index.ts @@ -137,6 +137,15 @@ export async function build(params: BuildParams) { } if (makoConfig?.moduleFederation) { + // @ts-ignore + params.config.moduleFederation = makoConfig.moduleFederation; + // @ts-ignore + if (!params.config.moduleFederation.implementation) { + // @ts-ignore + params.config.moduleFederation.implementation = require.resolve( + '@module-federation/webpack-bundler-runtime', + ); + } params.config.plugins.push({ name: 'mf-manifest', generateEnd(data) { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 06a0a91c7..cd4d47ed7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -497,8 +497,8 @@ importers: packages/mako: dependencies: '@module-federation/webpack-bundler-runtime': - specifier: ^0.7.6 - version: 0.7.6 + specifier: ^0.8.0 + version: 0.8.0 '@swc/helpers': specifier: 0.5.1 version: 0.5.1 @@ -4944,28 +4944,28 @@ packages: resolution: {integrity: sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==} dev: true - /@module-federation/error-codes@0.7.6: - resolution: {integrity: sha512-XVzX/sRFj1h5JvOOVMoFppxq0t1t3o/AlEICHgWX+dybIwJgz9g4gihZOWVZfz5/xsKGcUwdH5X7Z2nkuYhJEw==} + /@module-federation/error-codes@0.8.0: + resolution: {integrity: sha512-xU0eUA0xTUx93Li/eYCZ+kuGP9qt+8fEaOu+i6U9jJP1RYONvPifibfLNo4SQszQTzqfGViyrx1O3uiA7XUYQQ==} dev: false - /@module-federation/runtime@0.7.6: - resolution: {integrity: sha512-TEEDbGwaohZ2dMa+Sk/Igq8XpcyfjqJfbL20mdAZeifSFVZYRSCaTd/xIXP7pEw8+5BaCMc4YfCf/XcjFAUrVA==} + /@module-federation/runtime@0.8.0: + resolution: {integrity: sha512-UfDsJYAFOyJoErpmjf1sy8d2WXHGitFsSQrIiDzNpDHv4SzHgjuhWQeAuJKlQq2zdE/F4IPhkHgTatQigRKZCA==} dependencies: - '@module-federation/error-codes': 0.7.6 - '@module-federation/sdk': 0.7.6 + '@module-federation/error-codes': 0.8.0 + '@module-federation/sdk': 0.8.0 dev: false - /@module-federation/sdk@0.7.6: - resolution: {integrity: sha512-MFE+RtsHnutZOCp2eKpa3A/yzZ8tOPmjX7QRdVnB2qqR9JA2SH3ZP5+cYq76tzFQZvU1BCWAQVNMvqGOW2yVZQ==} + /@module-federation/sdk@0.8.0: + resolution: {integrity: sha512-V2cNGO//sWCyHTaQ0iTcoslolqVgdBIBOkZVLyk9AkZ4B3CO49pe/TmIIaVs9jVg3GO+ZmmazBFKRkqdn2PdRg==} dependencies: isomorphic-rslog: 0.0.6 dev: false - /@module-federation/webpack-bundler-runtime@0.7.6: - resolution: {integrity: sha512-kB9hQ0BfwNAcQWGskDEOxYP2z2bB/1ABXKr8MDomCFl2mbW3vvfYMQrb8UhJmJvE3rbGI/iXhJUdgBLNREnjUg==} + /@module-federation/webpack-bundler-runtime@0.8.0: + resolution: {integrity: sha512-NwkQbgUgh0ubwmPR/36YNuOaITkWPTYnJyYqi9vgxHBDp4tURnRI2b1ocG2Gw8c9sEW88ImWYMeF1qT58hQ32w==} dependencies: - '@module-federation/runtime': 0.7.6 - '@module-federation/sdk': 0.7.6 + '@module-federation/runtime': 0.8.0 + '@module-federation/sdk': 0.8.0 dev: false /@monaco-editor/loader@1.3.3(monaco-editor@0.38.0): From 5f629448c48062bdc2e4428293c4f7b52fa582a1 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Thu, 5 Dec 2024 17:21:29 +0800 Subject: [PATCH 13/68] feat: generate mf manifest in rust --- crates/mako/src/compiler.rs | 2 +- crates/mako/src/config/output.rs | 4 +- crates/mako/src/generate/chunk_pot/util.rs | 4 +- crates/mako/src/plugins/module_federation.rs | 246 +++++++++++------- .../plugins/module_federation/container.rs | 0 .../container/entry_runtime.rs | 18 -- .../src/plugins/module_federation/manifest.rs | 90 +++++++ .../src/plugins/module_federation/shared.rs | 0 .../module_federation/shared/shared.rs | 20 -- crates/mako/src/stats.rs | 4 +- crates/mako/src/utils.rs | 15 +- .../module-federation/host/mako.config.json | 9 +- .../module-federation/widget/mako.config.json | 7 +- packages/mako/src/index.ts | 7 - packages/mako/src/mf/manifest.ts | 142 ---------- 15 files changed, 261 insertions(+), 307 deletions(-) delete mode 100644 crates/mako/src/plugins/module_federation/container.rs delete mode 100644 crates/mako/src/plugins/module_federation/container/entry_runtime.rs create mode 100644 crates/mako/src/plugins/module_federation/manifest.rs delete mode 100644 crates/mako/src/plugins/module_federation/shared.rs delete mode 100644 crates/mako/src/plugins/module_federation/shared/shared.rs delete mode 100644 packages/mako/src/mf/manifest.ts diff --git a/crates/mako/src/compiler.rs b/crates/mako/src/compiler.rs index abe2618cf..1459dfee7 100644 --- a/crates/mako/src/compiler.rs +++ b/crates/mako/src/compiler.rs @@ -505,7 +505,7 @@ impl Compiler { resolved_resource: Some(ResolverResource::Remote(remote_info.clone())), ..Default::default() }), - side_effects: true, + side_effects: false, } } } diff --git a/crates/mako/src/config/output.rs b/crates/mako/src/config/output.rs index da3edb041..09973df85 100644 --- a/crates/mako/src/config/output.rs +++ b/crates/mako/src/config/output.rs @@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize}; use swc_core::ecma::ast::EsVersion; use crate::create_deserialize_fn; -use crate::utils::get_pkg_name; +use crate::utils::get_app_info; #[derive(Deserialize, Serialize, Debug)] #[serde(rename_all = "camelCase")] @@ -50,7 +50,7 @@ impl fmt::Display for CrossOriginLoading { } pub fn get_default_chunk_loading_global(umd: Option, root: &Path) -> String { - let unique_name = umd.unwrap_or_else(|| get_pkg_name(root).unwrap_or("global".to_string())); + let unique_name = umd.unwrap_or_else(|| get_app_info(root).0.unwrap_or("global".to_string())); format!("makoChunk_{}", unique_name) } diff --git a/crates/mako/src/generate/chunk_pot/util.rs b/crates/mako/src/generate/chunk_pot/util.rs index b0c0966d2..13576f080 100644 --- a/crates/mako/src/generate/chunk_pot/util.rs +++ b/crates/mako/src/generate/chunk_pot/util.rs @@ -25,7 +25,7 @@ use crate::config::Mode; use crate::generate::chunk_pot::ChunkPot; use crate::generate::runtime::AppRuntimeTemplate; use crate::module::{relative_to_root, Module, ModuleAst}; -use crate::utils::get_pkg_name; +use crate::utils::get_app_info; pub(crate) fn render_module_js( ast: &SwcModule, @@ -113,7 +113,7 @@ pub(crate) fn runtime_code(context: &Arc) -> Result { .cross_origin_loading .clone() .map(|s| s.to_string()), - pkg_name: get_pkg_name(&context.root), + pkg_name: get_app_info(&context.root).0, concatenate_enabled: context .config .optimization diff --git a/crates/mako/src/plugins/module_federation.rs b/crates/mako/src/plugins/module_federation.rs index 32cb2e655..344a557df 100644 --- a/crates/mako/src/plugins/module_federation.rs +++ b/crates/mako/src/plugins/module_federation.rs @@ -5,21 +5,28 @@ use std::path::Path; use std::sync::Arc; use anyhow::{anyhow, Result}; +use manifest::{ + Manifest, ManifestAssets, ManifestAssetsItem, ManifestExpose, ManifestMetaBuildInfo, + ManifestMetaData, ManifestMetaRemoteEntry, ManifestRemote, +}; use serde::Serialize; use tracing::warn; -use crate::ast::file::{Content, JsContent}; +use crate::ast::file::Content; use crate::compiler::{Args, Context}; use crate::config::module_federation::ModuleFederationConfig; use crate::config::{ Config, ExternalAdvanced, ExternalAdvancedSubpath, ExternalAdvancedSubpathRule, ExternalAdvancedSubpathTarget, ExternalConfig, }; -use crate::module::md5_hash; +use crate::module::{md5_hash, ModuleId}; use crate::plugin::{Plugin, PluginGenerateEndParams, PluginResolveIdParams}; use crate::resolve::{RemoteInfo, ResolverResource}; +use crate::utils::get_app_info; use crate::visitors::mako_require::MAKO_REQUIRE; +mod manifest; + pub struct ModuleFederationPlugin { pub config: ModuleFederationConfig, } @@ -32,6 +39,8 @@ const FEDERATION_REMOTE_REFERENCE_PREFIX: &str = "mako/container/reference/"; const FEDERATION_SHARED_REFERENCE_PREFIX: &str = "mako/sharing/consume/"; +const FEDERATION_EXPOSE_CHUNK_PREFIX: &str = "__mf_expose_"; + impl ModuleFederationPlugin { pub fn new(config: ModuleFederationConfig) -> Self { Self { config } @@ -135,10 +144,11 @@ if(!{federation_global}.instance) {{ .map(|(name, module)| { format!( r#""{name}": () => import( - /* makoChunkName: "__mf_expose_{striped_name}" */ + /* makoChunkName: "{prefix}{striped_name}" */ /* federationExpose: true */ "{module}" ),"#, + prefix = FEDERATION_EXPOSE_CHUNK_PREFIX, module = root.join(module).canonicalize().unwrap().to_string_lossy(), striped_name = name.replace("./", "") ) @@ -226,7 +236,6 @@ export {{ get, init }}; federation_runtime_code } - // TODO: impl remote module fn get_container_references_code(&self, context: &Arc) -> String { let module_graph = context.module_graph.read().unwrap(); let chunk_graph = context.chunk_graph.read().unwrap(); @@ -306,7 +315,7 @@ export {{ get, init }}; match config.entry.entry(container_entry_name.clone()) { Occupied(_) => { warn!( - "mf exposed name {} is duplcated with entry config.", + "mf exposed name {} is conflicting with entry config.", container_entry_name ); } @@ -382,26 +391,6 @@ impl Plugin for ModuleFederationPlugin { Ok(()) } - fn load( - &self, - _param: &crate::plugin::PluginLoadParam, - _context: &Arc, - ) -> Result> { - Ok(_param.file.path().map_or_else( - || None, - |path| { - if path.starts_with(FEDERATION_REMOTE_MODULE_PREFIX) { - Some(Content::Js(JsContent { - is_jsx: false, - content: "".to_string(), - })) - } else { - None - } - }, - )) - } - fn load_transform( &self, _content: &mut Content, @@ -477,14 +466,141 @@ impl Plugin for ModuleFederationPlugin { )) } - fn generate_end( - &self, - _params: &PluginGenerateEndParams, - _context: &Arc, - ) -> Result<()> { - // println!("----------"); - // println!("{:#?}", _params.stats); - // println!("----------"); + fn generate_end(&self, params: &PluginGenerateEndParams, context: &Arc) -> Result<()> { + fs::write( + context.root.join("./dist/stats.json"), + serde_json::to_string_pretty(¶ms.stats)?, + ) + .unwrap(); + let chunk_graph = context.chunk_graph.read().unwrap(); + let app_info = get_app_info(&context.root); + let manifest = Manifest { + id: self.config.name.clone(), + name: self.config.name.clone(), + exposes: self.config.exposes.as_ref().map_or(Vec::new(), |exposes| { + exposes + .iter() + .map(|(path, module)| { + let name = path.replace("./", ""); + let remote_module_id: ModuleId = context + .root + .join(module) + .canonicalize() + .unwrap() + .to_string_lossy() + .to_string() + .into(); + let exposes_sync_chunks = chunk_graph + .graph + .node_weights() + .filter_map(|c| { + if c.id.id.starts_with(FEDERATION_EXPOSE_CHUNK_PREFIX) + && c.has_module(&remote_module_id) + { + Some(c.id.clone()) + } else { + None + } + }) + .collect::>(); + + let exposes_sync_chunk_dependencies = + exposes_sync_chunks.iter().fold(Vec::new(), |mut acc, cur| { + let sync_deps = chunk_graph.sync_dependencies_chunk(cur); + acc.splice(0..sync_deps.len(), sync_deps); + acc + }); + let (sync_js_files, sync_css_files) = + [exposes_sync_chunk_dependencies, exposes_sync_chunks] + .concat() + .iter() + .fold( + (Vec::::new(), Vec::::new()), + |mut acc, cur| { + if let Some(c) = + params.stats.chunks.iter().find(|c| c.id == cur.id) + { + c.files.iter().for_each(|f| { + if f.ends_with(".js") { + acc.0.push(f.clone()); + } + if f.ends_with(".css") { + acc.1.push(f.clone()); + } + }); + } + acc + }, + ); + ManifestExpose { + id: format!("{}:{}", self.config.name, name), + name, + path: path.clone(), + assets: ManifestAssets { + js: ManifestAssetsItem { + sync: sync_js_files, + r#async: Vec::new(), + }, + css: ManifestAssetsItem { + sync: sync_css_files, + r#async: Vec::new(), + }, + }, + } + }) + .collect() + }), + shared: Vec::new(), + remotes: params + .stats + .chunk_modules + .iter() + .filter_map(|cm| { + if cm.id.starts_with(FEDERATION_REMOTE_MODULE_PREFIX) { + let data = cm.id.split('/').collect::>(); + Some(ManifestRemote { + entry: parse_remote( + self.config.remotes.as_ref().unwrap().get(data[3]).unwrap(), + ) + .unwrap() + .1, + module_name: data[4].to_string(), + alias: data[3].to_string(), + federation_container_name: data[3].to_string(), + }) + } else { + None + } + }) + .collect(), + meta_data: ManifestMetaData { + name: self.config.name.clone(), + build_info: ManifestMetaBuildInfo { + build_name: app_info.0.unwrap_or("default".to_string()), + build_version: app_info.1.unwrap_or("".to_string()), + }, + global_name: self.config.name.clone(), + public_path: "auto".to_string(), + r#type: "global".to_string(), + remote_entry: self.config.exposes.as_ref().and_then(|exposes| { + if exposes.is_empty() { + None + } else { + Some(ManifestMetaRemoteEntry { + name: format!("{}.js", self.config.name), + path: "".to_string(), + r#type: "global".to_string(), + }) + } + }), + ..Default::default() + }, + }; + fs::write( + context.root.join("./dist/mf-manifest.json"), + serde_json::to_string_pretty(&manifest)?, + ) + .unwrap(); Ok(()) } } @@ -523,67 +639,3 @@ struct RemoteExternal { name: String, external_module_id: String, } - -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -struct FederationManifestTypes { - path: String, - name: String, - zip: String, - api: String, -} - -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -struct FederationManifestMetaData { - name: String, - #[serde(rename = "type")] - type_: String, - build_info: FederationManifestBuildInfo, - remote_entry: FederationManifestRemoteEntry, - types: FederationManifestTypes, - global_name: String, - plugin_version: String, - public_path: String, -} - -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -struct FederationManifestBuildInfo { - build_version: String, - build_name: String, -} - -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -struct FederationManifestRemoteEntry { - name: String, - path: String, - #[serde(rename = "type")] - type_: String, -} - -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -struct FederationManifestShared { - id: String, -} - -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -struct FederationManifestRemote {} - -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -struct FederationManifestExpose {} - -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -struct FederationManifest { - id: String, - name: String, - meta_data: FederationManifestMetaData, - shared: Vec, - remotes: Vec, - exposes: Vec, -} diff --git a/crates/mako/src/plugins/module_federation/container.rs b/crates/mako/src/plugins/module_federation/container.rs deleted file mode 100644 index e69de29bb..000000000 diff --git a/crates/mako/src/plugins/module_federation/container/entry_runtime.rs b/crates/mako/src/plugins/module_federation/container/entry_runtime.rs deleted file mode 100644 index ec6536b35..000000000 --- a/crates/mako/src/plugins/module_federation/container/entry_runtime.rs +++ /dev/null @@ -1,18 +0,0 @@ -use std::collections::HashMap; - -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Serialize, Deserialize, Default)] -pub struct ExposesOption { - name: String, - import: String, - shared_scope: String, -} - -#[derive(Clone, Serialize, Deserialize)] -pub struct ContainerOptions { - name: String, - exposes: ExposesOption, - runtime_plugins: Vec, - shared_scope: String, -} diff --git a/crates/mako/src/plugins/module_federation/manifest.rs b/crates/mako/src/plugins/module_federation/manifest.rs new file mode 100644 index 000000000..d1705d375 --- /dev/null +++ b/crates/mako/src/plugins/module_federation/manifest.rs @@ -0,0 +1,90 @@ +use serde::Serialize; + +#[derive(Serialize, Default)] +pub struct ManifestAssetsItem { + pub sync: Vec, + pub r#async: Vec, +} + +#[derive(Serialize, Default)] +pub struct ManifestAssets { + pub js: ManifestAssetsItem, + pub css: ManifestAssetsItem, +} + +#[derive(Serialize, Default)] +#[serde(rename_all = "camelCase")] +pub struct ManifestExpose { + pub id: String, + pub name: String, + pub assets: ManifestAssets, + pub path: String, +} + +#[derive(Serialize, Default)] +#[serde(rename_all = "camelCase")] +pub struct ManifestShared { + id: String, + name: String, + assets: ManifestAssets, + version: String, + require_version: String, + singleton: bool, +} + +#[derive(Serialize, Default)] +#[serde(rename_all = "camelCase")] +pub struct ManifestRemote { + pub entry: String, + pub alias: String, + pub module_name: String, + pub federation_container_name: String, +} + +#[derive(Serialize, Default)] +#[serde(rename_all = "camelCase")] +pub struct ManifestMetaTypes { + path: String, + name: String, + zip: String, + api: String, +} + +#[derive(Serialize, Default)] +#[serde(rename_all = "camelCase")] +pub struct ManifestMetaData { + pub remote_entry: Option, + pub global_name: String, + pub public_path: String, + pub r#type: String, + pub build_info: ManifestMetaBuildInfo, + pub name: String, + pub types: ManifestMetaTypes, + pub plugin_version: String, +} + +#[derive(Serialize, Default)] +#[serde(rename_all = "camelCase")] +pub struct ManifestMetaBuildInfo { + pub build_version: String, + pub build_name: String, +} + +#[derive(Serialize, Default)] +#[serde(rename_all = "camelCase")] +pub struct ManifestMetaRemoteEntry { + pub name: String, + pub path: String, + pub r#type: String, +} + +#[derive(Serialize, Default)] +#[serde(rename_all = "camelCase")] +pub struct Manifest { + pub id: String, + pub name: String, + pub meta_data: ManifestMetaData, + pub shared: Vec, + pub remotes: Vec, + pub exposes: Vec, +} diff --git a/crates/mako/src/plugins/module_federation/shared.rs b/crates/mako/src/plugins/module_federation/shared.rs deleted file mode 100644 index e69de29bb..000000000 diff --git a/crates/mako/src/plugins/module_federation/shared/shared.rs b/crates/mako/src/plugins/module_federation/shared/shared.rs deleted file mode 100644 index 23ad20400..000000000 --- a/crates/mako/src/plugins/module_federation/shared/shared.rs +++ /dev/null @@ -1,20 +0,0 @@ -#[derive(Clone, Serialize, Deserialize)] -pub struct SharedItem { - name: String, - version: Option, - required_version: Option, - strict_version: Option, - singleton: Option, -} - -#[derive(Clone, Serialize, Deserialize)] -pub enum SharedVersion { - Version(String), - False, -} - -#[derive(Clone, Serialize, Deserialize)] -pub struct SharedOption { - shared: HashMap, - shared_scope: String, -} diff --git a/crates/mako/src/stats.rs b/crates/mako/src/stats.rs index 48da7b61f..42db0f836 100644 --- a/crates/mako/src/stats.rs +++ b/crates/mako/src/stats.rs @@ -505,9 +505,9 @@ pub struct StatsJsonMap { root_path: String, output_path: String, assets: Vec, - chunk_modules: Vec, + pub chunk_modules: Vec, modules: HashMap, - chunks: Vec, + pub chunks: Vec, entrypoints: HashMap, rsc_client_components: Vec, #[serde(rename = "rscCSSModules")] diff --git a/crates/mako/src/utils.rs b/crates/mako/src/utils.rs index a469dd3a8..0dc917b6b 100644 --- a/crates/mako/src/utils.rs +++ b/crates/mako/src/utils.rs @@ -53,18 +53,23 @@ pub fn process_req_url(public_path: &str, req_url: &str) -> Result { Ok(req_url.to_string()) } -pub(crate) fn get_pkg_name(root: &Path) -> Option { +pub(crate) fn get_app_info(root: &Path) -> (Option, Option) { let pkg_json_path = root.join("package.json"); if pkg_json_path.exists() { let pkg_json = std::fs::read_to_string(pkg_json_path).unwrap(); let pkg_json: serde_json::Value = serde_json::from_str(&pkg_json).unwrap(); - pkg_json - .get("name") - .map(|name| name.as_str().unwrap().to_string()) + ( + pkg_json + .get("name") + .map(|name| name.as_str().unwrap().to_string()), + pkg_json + .get("version") + .map(|name| name.as_str().unwrap().to_string()), + ) } else { - None + (None, None) } } diff --git a/examples/module-federation/host/mako.config.json b/examples/module-federation/host/mako.config.json index 5bfe266de..c212abf00 100644 --- a/examples/module-federation/host/mako.config.json +++ b/examples/module-federation/host/mako.config.json @@ -5,11 +5,8 @@ "moduleFederation": { "name": "mfHost", "remotes": { - "widget": "widget@http://localhost:3000/mf-manifest.json" - } - }, - "optimization": { - "skipModules": false, - "concatenateModules": false + "widget": "mfWidget@http://localhost:3000/mf-manifest.json" + }, + "implementation": "/Users/xusd/codes/github/mako/packages/mako/node_modules/@module-federation/webpack-bundler-runtime" } } diff --git a/examples/module-federation/widget/mako.config.json b/examples/module-federation/widget/mako.config.json index 3cca45359..22f503e25 100644 --- a/examples/module-federation/widget/mako.config.json +++ b/examples/module-federation/widget/mako.config.json @@ -8,10 +8,7 @@ "./App1": "./src/App1.tsx", "./App2": "./src/App2.tsx" }, - "runtimePlugins": [] - }, - "optimization": { - "skipModules": false, - "concatenateModules": false + "runtimePlugins": [], + "implementation": "/Users/xusd/codes/github/mako/packages/mako/node_modules/@module-federation/webpack-bundler-runtime" } } diff --git a/packages/mako/src/index.ts b/packages/mako/src/index.ts index 4f0bfb122..1742fb599 100644 --- a/packages/mako/src/index.ts +++ b/packages/mako/src/index.ts @@ -6,7 +6,6 @@ import { type Options } from 'sass'; import * as binding from '../binding'; import { ForkTSChecker as ForkTSChecker } from './forkTSChecker'; import { LessLoaderOpts, lessLoader } from './lessLoader'; -import { generateMFManifest } from './mf/manifest'; import { sassLoader } from './sassLoader'; type Config = binding.BuildParams['config'] & { @@ -146,12 +145,6 @@ export async function build(params: BuildParams) { '@module-federation/webpack-bundler-runtime', ); } - params.config.plugins.push({ - name: 'mf-manifest', - generateEnd(data) { - generateMFManifest(params.root, makoConfig.moduleFederation, data); - }, - }); } // support dump mako config if (process.env.DUMP_MAKO_CONFIG) { diff --git a/packages/mako/src/mf/manifest.ts b/packages/mako/src/mf/manifest.ts deleted file mode 100644 index 8dc342c5f..000000000 --- a/packages/mako/src/mf/manifest.ts +++ /dev/null @@ -1,142 +0,0 @@ -import fs from 'fs'; -import path from 'path'; -import { FederationConfig } from '.'; -import { JsHooks } from '../../binding'; - -interface Assets { - js: { async: string[]; sync: string[] }; - css: { async: string[]; sync: string[] }; -} - -interface SharedConfig { - id: string; - name: string; - version: string; - singleton: boolean; - requiredVersion: string; - assets: Assets; -} - -interface RemoteConfig { - federationContainerName: string; - moduleName: string; - alias: string; - entry: string; -} - -interface ExposeConfig { - id: string; - name: string; - assets: Assets; - path: string; -} - -interface TypesConfig { - path: string; - name: string; - zip: string; - api: string; -} - -interface Manifest { - id: string; - name: string; - metaData: { - name: string; - type: string; - buildInfo: { - buildVersion: string; - buildName: string; - }; - remoteEntry: { - name: string; - path: string; - type: string; - }; - types: TypesConfig; - globalName: string; - pluginVersion: string; - publicPath: string; - }; - shared: SharedConfig[]; - remotes: RemoteConfig[]; - exposes: ExposeConfig[]; -} - -export function generateMFManifest( - root: string, - federationConfig: FederationConfig, - bundlerStats: Parameters['generateEnd']>[0], -) { - let pkgJson = JSON.parse( - fs.readFileSync(path.join(root, 'package.json'), 'utf8'), - ); - let manifest: Manifest = { - id: pkgJson.name || '', - name: pkgJson.name || '', - metaData: { - name: pkgJson.name || '', - type: 'app', - buildInfo: { - buildVersion: pkgJson.version || '', - buildName: pkgJson.name || '', - }, - remoteEntry: { - name: - typeof federationConfig.exposes === 'object' && - Object.keys(federationConfig.exposes).length > 0 - ? `${federationConfig.name}.js` - : '', - path: '', - type: 'global', - }, - types: { - path: '', - name: '', - zip: '@mf-types.zip', - api: '@mf-types.d.ts', - }, - globalName: federationConfig.name, - pluginVersion: '0.0.0', - publicPath: 'auto', - }, - exposes: federationConfig.exposes - ? Object.entries(federationConfig.exposes).map(([name, path]) => ({ - id: `${federationConfig.name}:${name.replace(/^\.\//, '')}`, - name: name.replace(/^\.\//, ''), - path, - assets: { - js: { - sync: ['__mf_expose_App-async.js'], - async: [], - }, - css: { - sync: [], - async: [], - }, - }, - })) - : [], - shared: [], - remotes: bundlerStats.stats.chunkModules - .filter((m) => m.id.startsWith('mako/container/remote')) - .map((m) => { - const data = m.id.split('/'); - return { - moduleName: data[4], - federationContainerName: data[3], - alias: data[3], - entry: federationConfig.remotes![data[3]].split('@')[1], - }; - }), - }; - fs.writeFileSync( - path.join(root, './dist/mf-manifest.json'), - JSON.stringify(manifest, null, 2), - ); - - fs.writeFileSync( - path.join(root, './dist/stats.json'), - JSON.stringify(bundlerStats.stats, null, 2), - ); -} From a842cbd4871945668b03c7d5c6afcdd693ad6011 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Thu, 5 Dec 2024 17:22:54 +0800 Subject: [PATCH 14/68] fix: remote stats.json --- crates/mako/src/plugins/module_federation.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/crates/mako/src/plugins/module_federation.rs b/crates/mako/src/plugins/module_federation.rs index 344a557df..6ae6d3c04 100644 --- a/crates/mako/src/plugins/module_federation.rs +++ b/crates/mako/src/plugins/module_federation.rs @@ -467,11 +467,6 @@ impl Plugin for ModuleFederationPlugin { } fn generate_end(&self, params: &PluginGenerateEndParams, context: &Arc) -> Result<()> { - fs::write( - context.root.join("./dist/stats.json"), - serde_json::to_string_pretty(¶ms.stats)?, - ) - .unwrap(); let chunk_graph = context.chunk_graph.read().unwrap(); let app_info = get_app_info(&context.root); let manifest = Manifest { From 5044465ff4406494cc50e7aa7f938559dda12c50 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Thu, 5 Dec 2024 17:24:36 +0800 Subject: [PATCH 15/68] refactor: code styles --- crates/mako/src/plugins/module_federation.rs | 187 ++++++++++--------- 1 file changed, 98 insertions(+), 89 deletions(-) diff --git a/crates/mako/src/plugins/module_federation.rs b/crates/mako/src/plugins/module_federation.rs index 6ae6d3c04..bc38fb517 100644 --- a/crates/mako/src/plugins/module_federation.rs +++ b/crates/mako/src/plugins/module_federation.rs @@ -376,97 +376,12 @@ export {{ get, init }}; "".to_string() } } -} - -impl Plugin for ModuleFederationPlugin { - fn name(&self) -> &str { - "module_federation" - } - fn modify_config(&self, config: &mut Config, root: &Path, _args: &Args) -> Result<()> { - self.add_container_entry(config, root); - - self.append_remotes_externals(config); - - Ok(()) - } - - fn load_transform( + fn generate_federation_manifest( &self, - _content: &mut Content, - _path: &str, - _is_entry: bool, - _context: &Arc, - ) -> Result> { - // add containter entry runtime dependency - if !_is_entry { - Ok(None) - } else { - match _content { - Content::Js(js_content) => { - let entry_runtime_dep_path = self.prepare_entry_runtime_dep(&_context.root); - js_content.content.insert_str( - 0, - format!( - r#"import "{}"; -"#, - entry_runtime_dep_path - ) - .as_str(), - ); - Ok(Some(_content.clone())) - } - _ => Ok(None), - } - } - } - - fn runtime_plugins(&self, context: &Arc) -> Result> { - let federation_runtime_code = self.get_federation_runtime_code(); - let federation_exposes_library_code = self.get_federation_exposes_library_code(); - let federation_container_references_code = self.get_container_references_code(context); - - Ok(vec![ - federation_runtime_code, - federation_container_references_code, - federation_exposes_library_code, - ]) - } - - fn resolve_id( - &self, - source: &str, - _importer: &str, - _params: &PluginResolveIdParams, - _context: &Arc, - ) -> Result> { - let source_parts = source - .split_once("/") - .map_or((source.to_string(), ".".to_string()), |(part_0, part_1)| { - (part_0.to_string(), part_1.to_string()) - }); - Ok(self.config.remotes.as_ref().map_or_else( - || None, - |remotes| { - remotes.get(&source_parts.0).map(|_remote| { - ResolverResource::Remote(RemoteInfo { - module_id: format!("{}{}", FEDERATION_REMOTE_MODULE_PREFIX, source), - external_refenrence_id: format!( - "{}{}", - FEDERATION_REMOTE_REFERENCE_PREFIX, source_parts.0 - ), - // FIXME: hard code now - external_type: "script".to_string(), - sub_path: format!("./{}", source_parts.1), - name: source_parts.0.to_string(), - share_scope: self.config.share_scope.clone(), - }) - }) - }, - )) - } - - fn generate_end(&self, params: &PluginGenerateEndParams, context: &Arc) -> Result<()> { + context: &Arc, + params: &PluginGenerateEndParams, + ) -> Result<(), anyhow::Error> { let chunk_graph = context.chunk_graph.read().unwrap(); let app_info = get_app_info(&context.root); let manifest = Manifest { @@ -600,6 +515,100 @@ impl Plugin for ModuleFederationPlugin { } } +impl Plugin for ModuleFederationPlugin { + fn name(&self) -> &str { + "module_federation" + } + + fn modify_config(&self, config: &mut Config, root: &Path, _args: &Args) -> Result<()> { + self.add_container_entry(config, root); + + self.append_remotes_externals(config); + + Ok(()) + } + + fn load_transform( + &self, + _content: &mut Content, + _path: &str, + _is_entry: bool, + _context: &Arc, + ) -> Result> { + // add containter entry runtime dependency + if !_is_entry { + Ok(None) + } else { + match _content { + Content::Js(js_content) => { + let entry_runtime_dep_path = self.prepare_entry_runtime_dep(&_context.root); + js_content.content.insert_str( + 0, + format!( + r#"import "{}"; +"#, + entry_runtime_dep_path + ) + .as_str(), + ); + Ok(Some(_content.clone())) + } + _ => Ok(None), + } + } + } + + fn runtime_plugins(&self, context: &Arc) -> Result> { + let federation_runtime_code = self.get_federation_runtime_code(); + let federation_exposes_library_code = self.get_federation_exposes_library_code(); + let federation_container_references_code = self.get_container_references_code(context); + + Ok(vec![ + federation_runtime_code, + federation_container_references_code, + federation_exposes_library_code, + ]) + } + + fn resolve_id( + &self, + source: &str, + _importer: &str, + _params: &PluginResolveIdParams, + _context: &Arc, + ) -> Result> { + let source_parts = source + .split_once("/") + .map_or((source.to_string(), ".".to_string()), |(part_0, part_1)| { + (part_0.to_string(), part_1.to_string()) + }); + Ok(self.config.remotes.as_ref().map_or_else( + || None, + |remotes| { + remotes.get(&source_parts.0).map(|_remote| { + ResolverResource::Remote(RemoteInfo { + module_id: format!("{}{}", FEDERATION_REMOTE_MODULE_PREFIX, source), + external_refenrence_id: format!( + "{}{}", + FEDERATION_REMOTE_REFERENCE_PREFIX, source_parts.0 + ), + // FIXME: hard code now + external_type: "script".to_string(), + sub_path: format!("./{}", source_parts.1), + name: source_parts.0.to_string(), + share_scope: self.config.share_scope.clone(), + }) + }) + }, + )) + } + + fn generate_end(&self, params: &PluginGenerateEndParams, context: &Arc) -> Result<()> { + self.generate_federation_manifest(context, params)?; + Ok(()) + } +} + #[derive(Serialize)] struct RuntimeInitOptions { name: String, From d67f7925fc49364c52b68145ff37b3999e1b0673 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Thu, 5 Dec 2024 17:26:40 +0800 Subject: [PATCH 16/68] chore: add some FIXME --- crates/mako/src/plugins/module_federation.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/mako/src/plugins/module_federation.rs b/crates/mako/src/plugins/module_federation.rs index bc38fb517..830ea64f7 100644 --- a/crates/mako/src/plugins/module_federation.rs +++ b/crates/mako/src/plugins/module_federation.rs @@ -400,6 +400,7 @@ export {{ get, init }}; .to_string_lossy() .to_string() .into(); + // FIXME: this may be slow let exposes_sync_chunks = chunk_graph .graph .node_weights() From 609e94fa6904631172a729b0c25ad45a0ea88f9d Mon Sep 17 00:00:00 2001 From: xusd320 Date: Fri, 6 Dec 2024 11:19:47 +0800 Subject: [PATCH 17/68] refactor: mf plugin mods files --- crates/mako/src/plugins/module_federation.rs | 529 +----------------- .../plugins/module_federation/constants.rs | 9 + .../plugins/module_federation/container.rs | 296 ++++++++++ .../module_federation/container_reference.rs | 79 +++ .../src/plugins/module_federation/manifest.rs | 154 +++++ .../src/plugins/module_federation/util.rs | 12 + 6 files changed, 557 insertions(+), 522 deletions(-) create mode 100644 crates/mako/src/plugins/module_federation/constants.rs create mode 100644 crates/mako/src/plugins/module_federation/container.rs create mode 100644 crates/mako/src/plugins/module_federation/container_reference.rs create mode 100644 crates/mako/src/plugins/module_federation/util.rs diff --git a/crates/mako/src/plugins/module_federation.rs b/crates/mako/src/plugins/module_federation.rs index 830ea64f7..b9e480d8f 100644 --- a/crates/mako/src/plugins/module_federation.rs +++ b/crates/mako/src/plugins/module_federation.rs @@ -1,519 +1,31 @@ -use std::collections::hash_map::Entry::{Occupied, Vacant}; -use std::collections::HashMap; -use std::fs; use std::path::Path; use std::sync::Arc; -use anyhow::{anyhow, Result}; -use manifest::{ - Manifest, ManifestAssets, ManifestAssetsItem, ManifestExpose, ManifestMetaBuildInfo, - ManifestMetaData, ManifestMetaRemoteEntry, ManifestRemote, -}; +use anyhow::Result; +use constants::{FEDERATION_REMOTE_MODULE_PREFIX, FEDERATION_REMOTE_REFERENCE_PREFIX}; use serde::Serialize; -use tracing::warn; use crate::ast::file::Content; use crate::compiler::{Args, Context}; use crate::config::module_federation::ModuleFederationConfig; -use crate::config::{ - Config, ExternalAdvanced, ExternalAdvancedSubpath, ExternalAdvancedSubpathRule, - ExternalAdvancedSubpathTarget, ExternalConfig, -}; -use crate::module::{md5_hash, ModuleId}; +use crate::config::Config; use crate::plugin::{Plugin, PluginGenerateEndParams, PluginResolveIdParams}; use crate::resolve::{RemoteInfo, ResolverResource}; -use crate::utils::get_app_info; -use crate::visitors::mako_require::MAKO_REQUIRE; +mod constants; +mod container; +mod container_reference; mod manifest; +mod util; pub struct ModuleFederationPlugin { pub config: ModuleFederationConfig, } -const FEDERATION_GLOBAL: &str = "__mako_require__.federation"; - -const FEDERATION_REMOTE_MODULE_PREFIX: &str = "mako/container/remote/"; - -const FEDERATION_REMOTE_REFERENCE_PREFIX: &str = "mako/container/reference/"; - -const FEDERATION_SHARED_REFERENCE_PREFIX: &str = "mako/sharing/consume/"; - -const FEDERATION_EXPOSE_CHUNK_PREFIX: &str = "__mf_expose_"; - impl ModuleFederationPlugin { pub fn new(config: ModuleFederationConfig) -> Self { Self { config } } - - fn prepare_entry_runtime_dep(&self, root: &Path) -> String { - let entry_runtime_code = self.get_entry_runtime_code(); - - let content_hash = md5_hash(&entry_runtime_code, 32); - - let dep_path = root.join(format!( - "node_modules/.federation/.entry.{}.js", - content_hash - )); - let dep_parent_path = dep_path.parent().unwrap(); - if !fs::exists(dep_parent_path).unwrap() { - fs::create_dir_all(dep_parent_path).unwrap(); - } - if !fs::exists(&dep_path).unwrap() { - fs::write(&dep_path, entry_runtime_code).unwrap(); - } - - dep_path.to_string_lossy().to_string() - } - - fn get_entry_runtime_code(&self) -> String { - let (plugins_imports, plugins_instantiations) = self.get_mf_runtime_plugins_code(); - - format!( - r#"import federation from "{federation_impl}"; -{plugins_imports} - -if(!{federation_global}.runtime) {{ - var preFederation = {federation_global}; - {federation_global} = {{}}; - for(var key in federation) {{ - {federation_global}[key] = federation[key]; - }} - for(var key in preFederation) {{ - {federation_global}[key] = preFederation[key]; - }} -}} - -if(!{federation_global}.instance) {{ - {plugins_instantiations} - {federation_global}.instance = {federation_global}.runtime.init({federation_global}.initOptions); - if({federation_global}.attachShareScopeMap) {{ - {federation_global}.attachShareScopeMap({mako_require}); - }} - if({federation_global}.installInitialConsumes) {{ - {federation_global}.installInitialConsumes(); - }} -}} -"#, - federation_impl = self.config.implementation, - federation_global = FEDERATION_GLOBAL, - mako_require = MAKO_REQUIRE - ) - } - - fn get_mf_runtime_plugins_code(&self) -> (String, String) { - let (imported_plugin_names, import_plugin_instantiations) = - self.config.runtime_plugins.iter().enumerate().fold( - (Vec::new(), Vec::new()), - |(mut names, mut stmts), (index, plugin)| { - names.push(format!("plugin_{index}")); - stmts.push(format!(r#"import plugin_{index} from "{plugin}";"#)); - (names, stmts) - }, - ); - - let plugins_imports = import_plugin_instantiations.join("\n"); - - let plugins_to_add = imported_plugin_names - .iter() - .map(|item| format!(r#"{item} ? (item.default || item)() : false"#)) - .collect::>() - .join(","); - - let plugins_instantiations = if imported_plugin_names.is_empty() { - "".to_string() - } else { - format!( - r#"var pluginsToAdd = [{plugins_to_add}].filter(Boolean); - {federation_global}.initOptions.plugins = {federation_global}.initOptions.plugins ? - {federation_global}.initOptions.plugins.concat(pluginsToAdd) : pluginsToAdd; -"#, - federation_global = FEDERATION_GLOBAL - ) - }; - (plugins_imports, plugins_instantiations) - } - - fn get_container_entry_code(&self, root: &Path) -> String { - let exposes_modules_code = self - .config - .exposes - .as_ref() - .unwrap() - .iter() - .map(|(name, module)| { - format!( - r#""{name}": () => import( - /* makoChunkName: "{prefix}{striped_name}" */ - /* federationExpose: true */ - "{module}" -),"#, - prefix = FEDERATION_EXPOSE_CHUNK_PREFIX, - module = root.join(module).canonicalize().unwrap().to_string_lossy(), - striped_name = name.replace("./", "") - ) - }) - .collect::>() - .join("\n"); - - format!( - r#"var moduleMap = {{ - {exposes_modules_code} -}}; - -var get = (module, getScope) => {{ - {mako_require}.R = getScope; - getScope = ( - Object.prototype.hasOwnProperty.call(moduleMap, module) - ? moduleMap[module]() - : Promise.resolve().then(() => {{ - throw new Error('Module "' + module + '" does not exist in container.'); - }}) - ); - {mako_require}.R = undefined; - return getScope; -}}; - -var init = (shareScope, initScope, remoteEntryInitOptions) => {{ - return {mako_require}.federation.bundlerRuntime.initContainerEntry({{ - webpackRequire: {mako_require}, - shareScope: shareScope, - initScope: initScope, - remoteEntryInitOptions: remoteEntryInitOptions, - shareScopeKey: "{share_scope}" - }}) -}}; - -export {{ get, init }}; -"#, - mako_require = MAKO_REQUIRE, - share_scope = self.config.share_scope - ) - } - - fn get_federation_runtime_code(&self) -> String { - let runtime_remotes = self.config.remotes.as_ref().map_or(Vec::new(), |remotes| { - remotes - .iter() - .map(|(alias, remote)| { - // FIXME: should not unwrap - let (name, entry) = parse_remote(remote).unwrap(); - RuntimeRemoteItem { - name, - alias: alias.clone(), - entry, - share_scope: self.config.share_scope.clone(), - } - }) - .collect() - }); - let init_options: RuntimeInitOptions = RuntimeInitOptions { - name: self.config.name.clone(), - remotes: runtime_remotes, - share_strategy: serde_json::to_value(&self.config.share_strategy) - .unwrap() - .as_str() - .unwrap() - .to_string(), - }; - let init_options_code = serde_json::to_string(&init_options).unwrap(); - - let federation_runtime_code = format!( - r#" -/* mako/runtime/federation runtime */ -!(function() {{ - if(!requireModule.federation) {{ - requireModule.federation = {{ - initOptions: {init_options_code}, - chunkMatcher: () => true, - rootOutputDir: "", - initialConsumes: undefined, - bundlerRuntimeOptions: {{}} - }}; - }} -}})();"# - ); - federation_runtime_code - } - - fn get_container_references_code(&self, context: &Arc) -> String { - let module_graph = context.module_graph.read().unwrap(); - let chunk_graph = context.chunk_graph.read().unwrap(); - let all_chunks = chunk_graph.get_all_chunks(); - - let mut chunk_mapping: HashMap<&str, Vec<&str>> = HashMap::new(); - let mut id_to_external_and_name_mapping: HashMap<&str, Vec<&str>> = HashMap::new(); - let mut id_to_remote_map: HashMap<&str, Vec> = HashMap::new(); - all_chunks.iter().for_each(|c| { - c.modules.iter().for_each(|m| { - if let Some(m) = module_graph.get_module(m) { - if m.is_remote { - { - chunk_mapping - .entry(c.id.id.as_str()) - .or_default() - .push(m.id.id.as_str()); - } - - { - let remote_module = m - .info - .as_ref() - .unwrap() - .resolved_resource - .as_ref() - .unwrap() - .get_remote_info() - .unwrap(); - let remote_info = id_to_external_and_name_mapping - .entry(m.id.id.as_str()) - .or_default(); - remote_info.push(&remote_module.share_scope); - remote_info.push(&remote_module.sub_path); - remote_info.push(&remote_module.external_refenrence_id); - - let external_info = - id_to_remote_map.entry(m.id.id.as_str()).or_default(); - - external_info.push(RemoteExternal { - name: remote_module.name.clone(), - external_type: remote_module.external_type.clone(), - external_module_id: remote_module.external_refenrence_id.clone(), - }); - } - } - } - }); - }); - - let chunk_mapping = serde_json::to_string(&chunk_mapping).unwrap(); - let id_to_external_and_name_mapping = - serde_json::to_string(&id_to_external_and_name_mapping).unwrap(); - let id_to_remote_map = serde_json::to_string(&id_to_remote_map).unwrap(); - - format!( - r#" -/* mako/runtime/federation remotes consume */ -!(function() {{ - var chunkMapping = {chunk_mapping}; - var idToExternalAndNameMapping = {id_to_external_and_name_mapping}; - var idToRemoteMap = {id_to_remote_map}; - requireModule.federation.bundlerRuntimeOptions.remotes = {{idToRemoteMap, chunkMapping, idToExternalAndNameMapping, webpackRequire: requireModule}}; - requireModule.chunkEnsures.remotes = (chunkId, promises) => {{ - requireModule.federation.bundlerRuntime.remotes({{ idToRemoteMap,chunkMapping, idToExternalAndNameMapping, chunkId, promises, webpackRequire: requireModule}}); - }} -}} -)()"#, - ) - } - - fn add_container_entry(&self, config: &mut Config, root: &Path) { - // add containter entry - if let Some(exposes) = self.config.exposes.as_ref() { - let container_entry_name = &self.config.name; - if !exposes.is_empty() { - match config.entry.entry(container_entry_name.clone()) { - Occupied(_) => { - warn!( - "mf exposed name {} is conflicting with entry config.", - container_entry_name - ); - } - Vacant(vacant_entry) => { - let container_entry_code = self.get_container_entry_code(root); - let container_entry_path = root.join(format!( - "node_modules/.federation/.entry.container.{}.js", - container_entry_name - )); - let container_entry_parent_path = container_entry_path.parent().unwrap(); - if !fs::exists(container_entry_parent_path).unwrap() { - fs::create_dir_all(container_entry_parent_path).unwrap(); - } - fs::write(&container_entry_path, container_entry_code).unwrap(); - - vacant_entry.insert(container_entry_path); - } - } - } - } - } - - fn append_remotes_externals(&self, config: &mut Config) { - if let Some(remotes) = &self.config.remotes { - remotes.iter().for_each(|remote| { - config.externals.insert( - format!("{}{}", FEDERATION_REMOTE_REFERENCE_PREFIX, remote.0), - ExternalConfig::Advanced(ExternalAdvanced { - root: remote.0.clone(), - script: parse_remote(remote.1).ok().map(|(_, url)| url.clone()), - module_type: None, - subpath: Some(ExternalAdvancedSubpath { - exclude: None, - rules: vec![ExternalAdvancedSubpathRule { - regex: "/.*".to_string(), - target: ExternalAdvancedSubpathTarget::Empty, - target_converter: None, - }], - }), - }), - ); - }); - } - } - - fn get_federation_exposes_library_code(&self) -> String { - if let Some(exposes) = self.config.exposes.as_ref() { - if !exposes.is_empty() { - format!( - r#"global["{}"] = requireModule(entryModuleId); -"#, - self.config.name - ) - } else { - "".to_string() - } - } else { - "".to_string() - } - } - - fn generate_federation_manifest( - &self, - context: &Arc, - params: &PluginGenerateEndParams, - ) -> Result<(), anyhow::Error> { - let chunk_graph = context.chunk_graph.read().unwrap(); - let app_info = get_app_info(&context.root); - let manifest = Manifest { - id: self.config.name.clone(), - name: self.config.name.clone(), - exposes: self.config.exposes.as_ref().map_or(Vec::new(), |exposes| { - exposes - .iter() - .map(|(path, module)| { - let name = path.replace("./", ""); - let remote_module_id: ModuleId = context - .root - .join(module) - .canonicalize() - .unwrap() - .to_string_lossy() - .to_string() - .into(); - // FIXME: this may be slow - let exposes_sync_chunks = chunk_graph - .graph - .node_weights() - .filter_map(|c| { - if c.id.id.starts_with(FEDERATION_EXPOSE_CHUNK_PREFIX) - && c.has_module(&remote_module_id) - { - Some(c.id.clone()) - } else { - None - } - }) - .collect::>(); - - let exposes_sync_chunk_dependencies = - exposes_sync_chunks.iter().fold(Vec::new(), |mut acc, cur| { - let sync_deps = chunk_graph.sync_dependencies_chunk(cur); - acc.splice(0..sync_deps.len(), sync_deps); - acc - }); - let (sync_js_files, sync_css_files) = - [exposes_sync_chunk_dependencies, exposes_sync_chunks] - .concat() - .iter() - .fold( - (Vec::::new(), Vec::::new()), - |mut acc, cur| { - if let Some(c) = - params.stats.chunks.iter().find(|c| c.id == cur.id) - { - c.files.iter().for_each(|f| { - if f.ends_with(".js") { - acc.0.push(f.clone()); - } - if f.ends_with(".css") { - acc.1.push(f.clone()); - } - }); - } - acc - }, - ); - ManifestExpose { - id: format!("{}:{}", self.config.name, name), - name, - path: path.clone(), - assets: ManifestAssets { - js: ManifestAssetsItem { - sync: sync_js_files, - r#async: Vec::new(), - }, - css: ManifestAssetsItem { - sync: sync_css_files, - r#async: Vec::new(), - }, - }, - } - }) - .collect() - }), - shared: Vec::new(), - remotes: params - .stats - .chunk_modules - .iter() - .filter_map(|cm| { - if cm.id.starts_with(FEDERATION_REMOTE_MODULE_PREFIX) { - let data = cm.id.split('/').collect::>(); - Some(ManifestRemote { - entry: parse_remote( - self.config.remotes.as_ref().unwrap().get(data[3]).unwrap(), - ) - .unwrap() - .1, - module_name: data[4].to_string(), - alias: data[3].to_string(), - federation_container_name: data[3].to_string(), - }) - } else { - None - } - }) - .collect(), - meta_data: ManifestMetaData { - name: self.config.name.clone(), - build_info: ManifestMetaBuildInfo { - build_name: app_info.0.unwrap_or("default".to_string()), - build_version: app_info.1.unwrap_or("".to_string()), - }, - global_name: self.config.name.clone(), - public_path: "auto".to_string(), - r#type: "global".to_string(), - remote_entry: self.config.exposes.as_ref().and_then(|exposes| { - if exposes.is_empty() { - None - } else { - Some(ManifestMetaRemoteEntry { - name: format!("{}.js", self.config.name), - path: "".to_string(), - r#type: "global".to_string(), - }) - } - }), - ..Default::default() - }, - }; - fs::write( - context.root.join("./dist/mf-manifest.json"), - serde_json::to_string_pretty(&manifest)?, - ) - .unwrap(); - Ok(()) - } } impl Plugin for ModuleFederationPlugin { @@ -610,33 +122,6 @@ impl Plugin for ModuleFederationPlugin { } } -#[derive(Serialize)] -struct RuntimeInitOptions { - name: String, - remotes: Vec, - share_strategy: String, -} - -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -struct RuntimeRemoteItem { - name: String, - alias: String, - entry: String, - share_scope: String, -} - -fn parse_remote(remote: &str) -> Result<(String, String)> { - let (left, right) = remote - .split_once('@') - .ok_or(anyhow!("invalid remote {}", remote))?; - if left.is_empty() || right.is_empty() { - Err(anyhow!("invalid remote {}", remote)) - } else { - Ok((left.to_string(), right.to_string())) - } -} - #[derive(Serialize)] #[serde(rename_all = "camelCase")] struct RemoteExternal { diff --git a/crates/mako/src/plugins/module_federation/constants.rs b/crates/mako/src/plugins/module_federation/constants.rs new file mode 100644 index 000000000..ebe18c9b4 --- /dev/null +++ b/crates/mako/src/plugins/module_federation/constants.rs @@ -0,0 +1,9 @@ +pub(crate) const FEDERATION_GLOBAL: &str = "__mako_require__.federation"; + +pub(crate) const FEDERATION_REMOTE_MODULE_PREFIX: &str = "mako/container/remote/"; + +pub(crate) const FEDERATION_REMOTE_REFERENCE_PREFIX: &str = "mako/container/reference/"; + +pub(crate) const FEDERATION_SHARED_REFERENCE_PREFIX: &str = "mako/sharing/consume/"; + +pub(crate) const FEDERATION_EXPOSE_CHUNK_PREFIX: &str = "__mf_expose_"; diff --git a/crates/mako/src/plugins/module_federation/container.rs b/crates/mako/src/plugins/module_federation/container.rs new file mode 100644 index 000000000..7ef248ef5 --- /dev/null +++ b/crates/mako/src/plugins/module_federation/container.rs @@ -0,0 +1,296 @@ +use std::collections::hash_map::Entry::{Occupied, Vacant}; +use std::fs; +use std::path::Path; + +use serde::Serialize; +use tracing::warn; + +use super::constants::{ + FEDERATION_EXPOSE_CHUNK_PREFIX, FEDERATION_GLOBAL, FEDERATION_REMOTE_REFERENCE_PREFIX, +}; +use super::util::parse_remote; +use super::ModuleFederationPlugin; +use crate::config::{ + Config, ExternalAdvanced, ExternalAdvancedSubpath, ExternalAdvancedSubpathRule, + ExternalAdvancedSubpathTarget, ExternalConfig, +}; +use crate::module::md5_hash; +use crate::visitors::mako_require::MAKO_REQUIRE; + +impl ModuleFederationPlugin { + pub(super) fn prepare_entry_runtime_dep(&self, root: &Path) -> String { + let entry_runtime_code = self.get_entry_runtime_code(); + + let content_hash = md5_hash(&entry_runtime_code, 32); + + let dep_path = root.join(format!( + "node_modules/.federation/.entry.{}.js", + content_hash + )); + let dep_parent_path = dep_path.parent().unwrap(); + if !fs::exists(dep_parent_path).unwrap() { + fs::create_dir_all(dep_parent_path).unwrap(); + } + if !fs::exists(&dep_path).unwrap() { + fs::write(&dep_path, entry_runtime_code).unwrap(); + } + + dep_path.to_string_lossy().to_string() + } + + pub(super) fn get_entry_runtime_code(&self) -> String { + let (plugins_imports, plugins_instantiations) = self.get_mf_runtime_plugins_code(); + + format!( + r#"import federation from "{federation_impl}"; +{plugins_imports} + +if(!{federation_global}.runtime) {{ + var preFederation = {federation_global}; + {federation_global} = {{}}; + for(var key in federation) {{ + {federation_global}[key] = federation[key]; + }} + for(var key in preFederation) {{ + {federation_global}[key] = preFederation[key]; + }} +}} + +if(!{federation_global}.instance) {{ + {plugins_instantiations} + {federation_global}.instance = {federation_global}.runtime.init({federation_global}.initOptions); + if({federation_global}.attachShareScopeMap) {{ + {federation_global}.attachShareScopeMap({mako_require}); + }} + if({federation_global}.installInitialConsumes) {{ + {federation_global}.installInitialConsumes(); + }} +}} +"#, + federation_impl = self.config.implementation, + federation_global = FEDERATION_GLOBAL, + mako_require = MAKO_REQUIRE + ) + } + + pub(super) fn get_mf_runtime_plugins_code(&self) -> (String, String) { + let (imported_plugin_names, import_plugin_instantiations) = + self.config.runtime_plugins.iter().enumerate().fold( + (Vec::new(), Vec::new()), + |(mut names, mut stmts), (index, plugin)| { + names.push(format!("plugin_{index}")); + stmts.push(format!(r#"import plugin_{index} from "{plugin}";"#)); + (names, stmts) + }, + ); + + let plugins_imports = import_plugin_instantiations.join("\n"); + + let plugins_to_add = imported_plugin_names + .iter() + .map(|item| format!(r#"{item} ? (item.default || item)() : false"#)) + .collect::>() + .join(","); + + let plugins_instantiations = if imported_plugin_names.is_empty() { + "".to_string() + } else { + format!( + r#"var pluginsToAdd = [{plugins_to_add}].filter(Boolean); + {federation_global}.initOptions.plugins = {federation_global}.initOptions.plugins ? + {federation_global}.initOptions.plugins.concat(pluginsToAdd) : pluginsToAdd; +"#, + federation_global = FEDERATION_GLOBAL + ) + }; + (plugins_imports, plugins_instantiations) + } + + pub(super) fn add_container_entry(&self, config: &mut Config, root: &Path) { + // add containter entry + if let Some(exposes) = self.config.exposes.as_ref() { + let container_entry_name = &self.config.name; + if !exposes.is_empty() { + match config.entry.entry(container_entry_name.clone()) { + Occupied(_) => { + warn!( + "mf exposed name {} is conflicting with entry config.", + container_entry_name + ); + } + Vacant(vacant_entry) => { + let container_entry_code = self.get_container_entry_code(root); + let container_entry_path = root.join(format!( + "node_modules/.federation/.entry.container.{}.js", + container_entry_name + )); + let container_entry_parent_path = container_entry_path.parent().unwrap(); + if !fs::exists(container_entry_parent_path).unwrap() { + fs::create_dir_all(container_entry_parent_path).unwrap(); + } + fs::write(&container_entry_path, container_entry_code).unwrap(); + + vacant_entry.insert(container_entry_path); + } + } + } + } + } + + pub(super) fn get_container_entry_code(&self, root: &Path) -> String { + let exposes_modules_code = self + .config + .exposes + .as_ref() + .unwrap() + .iter() + .map(|(name, module)| { + format!( + r#""{name}": () => import( + /* makoChunkName: "{prefix}{striped_name}" */ + /* federationExpose: true */ + "{module}" +),"#, + prefix = FEDERATION_EXPOSE_CHUNK_PREFIX, + module = root.join(module).canonicalize().unwrap().to_string_lossy(), + striped_name = name.replace("./", "") + ) + }) + .collect::>() + .join("\n"); + + format!( + r#"var moduleMap = {{ + {exposes_modules_code} +}}; + +var get = (module, getScope) => {{ + {mako_require}.R = getScope; + getScope = ( + Object.prototype.hasOwnProperty.call(moduleMap, module) + ? moduleMap[module]() + : Promise.resolve().then(() => {{ + throw new Error('Module "' + module + '" does not exist in container.'); + }}) + ); + {mako_require}.R = undefined; + return getScope; +}}; + +var init = (shareScope, initScope, remoteEntryInitOptions) => {{ + return {mako_require}.federation.bundlerRuntime.initContainerEntry({{ + webpackRequire: {mako_require}, + shareScope: shareScope, + initScope: initScope, + remoteEntryInitOptions: remoteEntryInitOptions, + shareScopeKey: "{share_scope}" + }}) +}}; + +export {{ get, init }}; +"#, + mako_require = MAKO_REQUIRE, + share_scope = self.config.share_scope + ) + } + + pub(super) fn get_federation_runtime_code(&self) -> String { + let runtime_remotes = self.config.remotes.as_ref().map_or(Vec::new(), |remotes| { + remotes + .iter() + .map(|(alias, remote)| { + // FIXME: should not unwrap + let (name, entry) = parse_remote(remote).unwrap(); + RuntimeRemoteItem { + name, + alias: alias.clone(), + entry, + share_scope: self.config.share_scope.clone(), + } + }) + .collect() + }); + let init_options: RuntimeInitOptions = RuntimeInitOptions { + name: self.config.name.clone(), + remotes: runtime_remotes, + share_strategy: serde_json::to_value(&self.config.share_strategy) + .unwrap() + .as_str() + .unwrap() + .to_string(), + }; + let init_options_code = serde_json::to_string(&init_options).unwrap(); + + let federation_runtime_code = format!( + r#" +/* mako/runtime/federation runtime */ +!(function() {{ + if(!requireModule.federation) {{ + requireModule.federation = {{ + initOptions: {init_options_code}, + chunkMatcher: () => true, + rootOutputDir: "", + initialConsumes: undefined, + bundlerRuntimeOptions: {{}} + }}; + }} +}})();"# + ); + federation_runtime_code + } + + pub(super) fn get_federation_exposes_library_code(&self) -> String { + if let Some(exposes) = self.config.exposes.as_ref() { + if !exposes.is_empty() { + format!( + r#"global["{}"] = requireModule(entryModuleId); +"#, + self.config.name + ) + } else { + "".to_string() + } + } else { + "".to_string() + } + } + + pub(super) fn append_remotes_externals(&self, config: &mut Config) { + if let Some(remotes) = &self.config.remotes { + remotes.iter().for_each(|remote| { + config.externals.insert( + format!("{}{}", FEDERATION_REMOTE_REFERENCE_PREFIX, remote.0), + ExternalConfig::Advanced(ExternalAdvanced { + root: remote.0.clone(), + script: parse_remote(remote.1).ok().map(|(_, url)| url.clone()), + module_type: None, + subpath: Some(ExternalAdvancedSubpath { + exclude: None, + rules: vec![ExternalAdvancedSubpathRule { + regex: "/.*".to_string(), + target: ExternalAdvancedSubpathTarget::Empty, + target_converter: None, + }], + }), + }), + ); + }); + } + } +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct RuntimeRemoteItem { + name: String, + alias: String, + entry: String, + share_scope: String, +} + +#[derive(Serialize)] +struct RuntimeInitOptions { + name: String, + remotes: Vec, + share_strategy: String, +} diff --git a/crates/mako/src/plugins/module_federation/container_reference.rs b/crates/mako/src/plugins/module_federation/container_reference.rs new file mode 100644 index 000000000..32b0ab6b4 --- /dev/null +++ b/crates/mako/src/plugins/module_federation/container_reference.rs @@ -0,0 +1,79 @@ +use std::collections::HashMap; +use std::sync::Arc; + +use super::ModuleFederationPlugin; +use crate::compiler::Context; +use crate::plugins::module_federation::RemoteExternal; + +impl ModuleFederationPlugin { + pub(super) fn get_container_references_code(&self, context: &Arc) -> String { + let module_graph = context.module_graph.read().unwrap(); + let chunk_graph = context.chunk_graph.read().unwrap(); + let all_chunks = chunk_graph.get_all_chunks(); + + let mut chunk_mapping: HashMap<&str, Vec<&str>> = HashMap::new(); + let mut id_to_external_and_name_mapping: HashMap<&str, Vec<&str>> = HashMap::new(); + let mut id_to_remote_map: HashMap<&str, Vec> = HashMap::new(); + all_chunks.iter().for_each(|c| { + c.modules.iter().for_each(|m| { + if let Some(m) = module_graph.get_module(m) { + if m.is_remote { + { + chunk_mapping + .entry(c.id.id.as_str()) + .or_default() + .push(m.id.id.as_str()); + } + + { + let remote_module = m + .info + .as_ref() + .unwrap() + .resolved_resource + .as_ref() + .unwrap() + .get_remote_info() + .unwrap(); + let remote_info = id_to_external_and_name_mapping + .entry(m.id.id.as_str()) + .or_default(); + remote_info.push(&remote_module.share_scope); + remote_info.push(&remote_module.sub_path); + remote_info.push(&remote_module.external_refenrence_id); + + let external_info = + id_to_remote_map.entry(m.id.id.as_str()).or_default(); + + external_info.push(RemoteExternal { + name: remote_module.name.clone(), + external_type: remote_module.external_type.clone(), + external_module_id: remote_module.external_refenrence_id.clone(), + }); + } + } + } + }); + }); + + let chunk_mapping = serde_json::to_string(&chunk_mapping).unwrap(); + let id_to_external_and_name_mapping = + serde_json::to_string(&id_to_external_and_name_mapping).unwrap(); + let id_to_remote_map = serde_json::to_string(&id_to_remote_map).unwrap(); + + format!( + r#" +/* mako/runtime/federation remotes consume */ +!(function() {{ + var chunkMapping = {chunk_mapping}; + var idToExternalAndNameMapping = {id_to_external_and_name_mapping}; + var idToRemoteMap = {id_to_remote_map}; + requireModule.federation.bundlerRuntimeOptions.remotes = {{idToRemoteMap, chunkMapping, idToExternalAndNameMapping, webpackRequire: requireModule}}; + requireModule.chunkEnsures.remotes = (chunkId, promises) => {{ + requireModule.federation.bundlerRuntime.remotes({{ idToRemoteMap,chunkMapping, idToExternalAndNameMapping, chunkId, promises, webpackRequire: requireModule}}); + }} +}} +)()"#, + ) + } +} diff --git a/crates/mako/src/plugins/module_federation/manifest.rs b/crates/mako/src/plugins/module_federation/manifest.rs index d1705d375..943924ab9 100644 --- a/crates/mako/src/plugins/module_federation/manifest.rs +++ b/crates/mako/src/plugins/module_federation/manifest.rs @@ -1,5 +1,159 @@ +use std::fs; +use std::sync::Arc; + use serde::Serialize; +use super::constants::FEDERATION_EXPOSE_CHUNK_PREFIX; +use super::util::parse_remote; +use super::{constants, ModuleFederationPlugin}; +use crate::compiler::Context; +use crate::module::ModuleId; +use crate::plugin::PluginGenerateEndParams; +use crate::utils::get_app_info; + +impl ModuleFederationPlugin { + pub(super) fn generate_federation_manifest( + &self, + context: &Arc, + params: &PluginGenerateEndParams, + ) -> Result<(), anyhow::Error> { + let chunk_graph = context.chunk_graph.read().unwrap(); + let app_info = get_app_info(&context.root); + let manifest = Manifest { + id: self.config.name.clone(), + name: self.config.name.clone(), + exposes: self.config.exposes.as_ref().map_or(Vec::new(), |exposes| { + exposes + .iter() + .map(|(path, module)| { + let name = path.replace("./", ""); + let remote_module_id: ModuleId = context + .root + .join(module) + .canonicalize() + .unwrap() + .to_string_lossy() + .to_string() + .into(); + // FIXME: this may be slow + let exposes_sync_chunks = chunk_graph + .graph + .node_weights() + .filter_map(|c| { + if c.id.id.starts_with(FEDERATION_EXPOSE_CHUNK_PREFIX) + && c.has_module(&remote_module_id) + { + Some(c.id.clone()) + } else { + None + } + }) + .collect::>(); + + let exposes_sync_chunk_dependencies = + exposes_sync_chunks.iter().fold(Vec::new(), |mut acc, cur| { + let sync_deps = chunk_graph.sync_dependencies_chunk(cur); + acc.splice(0..sync_deps.len(), sync_deps); + acc + }); + let (sync_js_files, sync_css_files) = + [exposes_sync_chunk_dependencies, exposes_sync_chunks] + .concat() + .iter() + .fold( + (Vec::::new(), Vec::::new()), + |mut acc, cur| { + if let Some(c) = + params.stats.chunks.iter().find(|c| c.id == cur.id) + { + c.files.iter().for_each(|f| { + if f.ends_with(".js") { + acc.0.push(f.clone()); + } + if f.ends_with(".css") { + acc.1.push(f.clone()); + } + }); + } + acc + }, + ); + ManifestExpose { + id: format!("{}:{}", self.config.name, name), + name, + path: path.clone(), + assets: ManifestAssets { + js: ManifestAssetsItem { + sync: sync_js_files, + r#async: Vec::new(), + }, + css: ManifestAssetsItem { + sync: sync_css_files, + r#async: Vec::new(), + }, + }, + } + }) + .collect() + }), + shared: Vec::new(), + remotes: params + .stats + .chunk_modules + .iter() + .filter_map(|cm| { + if cm + .id + .starts_with(constants::FEDERATION_REMOTE_MODULE_PREFIX) + { + let data = cm.id.split('/').collect::>(); + Some(ManifestRemote { + entry: parse_remote( + self.config.remotes.as_ref().unwrap().get(data[3]).unwrap(), + ) + .unwrap() + .1, + module_name: data[4].to_string(), + alias: data[3].to_string(), + federation_container_name: data[3].to_string(), + }) + } else { + None + } + }) + .collect(), + meta_data: ManifestMetaData { + name: self.config.name.clone(), + build_info: ManifestMetaBuildInfo { + build_name: app_info.0.unwrap_or("default".to_string()), + build_version: app_info.1.unwrap_or("".to_string()), + }, + global_name: self.config.name.clone(), + public_path: "auto".to_string(), + r#type: "global".to_string(), + remote_entry: self.config.exposes.as_ref().and_then(|exposes| { + if exposes.is_empty() { + None + } else { + Some(ManifestMetaRemoteEntry { + name: format!("{}.js", self.config.name), + path: "".to_string(), + r#type: "global".to_string(), + }) + } + }), + ..Default::default() + }, + }; + fs::write( + context.root.join("./dist/mf-manifest.json"), + serde_json::to_string_pretty(&manifest)?, + ) + .unwrap(); + Ok(()) + } +} + #[derive(Serialize, Default)] pub struct ManifestAssetsItem { pub sync: Vec, diff --git a/crates/mako/src/plugins/module_federation/util.rs b/crates/mako/src/plugins/module_federation/util.rs new file mode 100644 index 000000000..2ad8d2801 --- /dev/null +++ b/crates/mako/src/plugins/module_federation/util.rs @@ -0,0 +1,12 @@ +use anyhow::{anyhow, Result}; + +pub(super) fn parse_remote(remote: &str) -> Result<(String, String)> { + let (left, right) = remote + .split_once('@') + .ok_or(anyhow!("invalid remote {}", remote))?; + if left.is_empty() || right.is_empty() { + Err(anyhow!("invalid remote {}", remote)) + } else { + Ok((left.to_string(), right.to_string())) + } +} From 528f8cc5f35eec91cd52c05a9288688b58247d8e Mon Sep 17 00:00:00 2001 From: xusd320 Date: Fri, 6 Dec 2024 13:41:40 +0800 Subject: [PATCH 18/68] refactor: mf plugin mods files --- crates/mako/src/plugins/module_federation.rs | 2 +- .../plugins/module_federation/container.rs | 67 ++++++++++--------- .../module_federation/container_reference.rs | 11 ++- 3 files changed, 45 insertions(+), 35 deletions(-) diff --git a/crates/mako/src/plugins/module_federation.rs b/crates/mako/src/plugins/module_federation.rs index b9e480d8f..bba1754bc 100644 --- a/crates/mako/src/plugins/module_federation.rs +++ b/crates/mako/src/plugins/module_federation.rs @@ -36,7 +36,7 @@ impl Plugin for ModuleFederationPlugin { fn modify_config(&self, config: &mut Config, root: &Path, _args: &Args) -> Result<()> { self.add_container_entry(config, root); - self.append_remotes_externals(config); + // self.append_remotes_externals(config); Ok(()) } diff --git a/crates/mako/src/plugins/module_federation/container.rs b/crates/mako/src/plugins/module_federation/container.rs index 7ef248ef5..5d870cf51 100644 --- a/crates/mako/src/plugins/module_federation/container.rs +++ b/crates/mako/src/plugins/module_federation/container.rs @@ -73,39 +73,6 @@ if(!{federation_global}.instance) {{ ) } - pub(super) fn get_mf_runtime_plugins_code(&self) -> (String, String) { - let (imported_plugin_names, import_plugin_instantiations) = - self.config.runtime_plugins.iter().enumerate().fold( - (Vec::new(), Vec::new()), - |(mut names, mut stmts), (index, plugin)| { - names.push(format!("plugin_{index}")); - stmts.push(format!(r#"import plugin_{index} from "{plugin}";"#)); - (names, stmts) - }, - ); - - let plugins_imports = import_plugin_instantiations.join("\n"); - - let plugins_to_add = imported_plugin_names - .iter() - .map(|item| format!(r#"{item} ? (item.default || item)() : false"#)) - .collect::>() - .join(","); - - let plugins_instantiations = if imported_plugin_names.is_empty() { - "".to_string() - } else { - format!( - r#"var pluginsToAdd = [{plugins_to_add}].filter(Boolean); - {federation_global}.initOptions.plugins = {federation_global}.initOptions.plugins ? - {federation_global}.initOptions.plugins.concat(pluginsToAdd) : pluginsToAdd; -"#, - federation_global = FEDERATION_GLOBAL - ) - }; - (plugins_imports, plugins_instantiations) - } - pub(super) fn add_container_entry(&self, config: &mut Config, root: &Path) { // add containter entry if let Some(exposes) = self.config.exposes.as_ref() { @@ -255,6 +222,7 @@ export {{ get, init }}; } } + #[allow(dead_code)] pub(super) fn append_remotes_externals(&self, config: &mut Config) { if let Some(remotes) = &self.config.remotes { remotes.iter().for_each(|remote| { @@ -277,6 +245,39 @@ export {{ get, init }}; }); } } + + pub(super) fn get_mf_runtime_plugins_code(&self) -> (String, String) { + let (imported_plugin_names, import_plugin_instantiations) = + self.config.runtime_plugins.iter().enumerate().fold( + (Vec::new(), Vec::new()), + |(mut names, mut stmts), (index, plugin)| { + names.push(format!("plugin_{index}")); + stmts.push(format!(r#"import plugin_{index} from "{plugin}";"#)); + (names, stmts) + }, + ); + + let plugins_imports = import_plugin_instantiations.join("\n"); + + let plugins_to_add = imported_plugin_names + .iter() + .map(|item| format!(r#"{item} ? (item.default || item)() : false"#)) + .collect::>() + .join(","); + + let plugins_instantiations = if imported_plugin_names.is_empty() { + "".to_string() + } else { + format!( + r#"var pluginsToAdd = [{plugins_to_add}].filter(Boolean); + {federation_global}.initOptions.plugins = {federation_global}.initOptions.plugins ? + {federation_global}.initOptions.plugins.concat(pluginsToAdd) : pluginsToAdd; +"#, + federation_global = FEDERATION_GLOBAL + ) + }; + (plugins_imports, plugins_instantiations) + } } #[derive(Serialize)] diff --git a/crates/mako/src/plugins/module_federation/container_reference.rs b/crates/mako/src/plugins/module_federation/container_reference.rs index 32b0ab6b4..73b2a2662 100644 --- a/crates/mako/src/plugins/module_federation/container_reference.rs +++ b/crates/mako/src/plugins/module_federation/container_reference.rs @@ -1,9 +1,10 @@ use std::collections::HashMap; use std::sync::Arc; +use serde::Serialize; + use super::ModuleFederationPlugin; use crate::compiler::Context; -use crate::plugins::module_federation::RemoteExternal; impl ModuleFederationPlugin { pub(super) fn get_container_references_code(&self, context: &Arc) -> String { @@ -77,3 +78,11 @@ impl ModuleFederationPlugin { ) } } + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct RemoteExternal { + external_type: String, + name: String, + external_module_id: String, +} From 60452a3376ce63b088b1b9119af6ec07604e884f Mon Sep 17 00:00:00 2001 From: xusd320 Date: Fri, 6 Dec 2024 17:12:47 +0800 Subject: [PATCH 19/68] chore: remove dead code --- crates/mako/src/plugins/module_federation.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/crates/mako/src/plugins/module_federation.rs b/crates/mako/src/plugins/module_federation.rs index bba1754bc..6f28acfa4 100644 --- a/crates/mako/src/plugins/module_federation.rs +++ b/crates/mako/src/plugins/module_federation.rs @@ -3,7 +3,6 @@ use std::sync::Arc; use anyhow::Result; use constants::{FEDERATION_REMOTE_MODULE_PREFIX, FEDERATION_REMOTE_REFERENCE_PREFIX}; -use serde::Serialize; use crate::ast::file::Content; use crate::compiler::{Args, Context}; @@ -121,11 +120,3 @@ impl Plugin for ModuleFederationPlugin { Ok(()) } } - -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -struct RemoteExternal { - external_type: String, - name: String, - external_module_id: String, -} From 71ff5b85289a42cdff53651535986a3c9db67589 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Tue, 10 Dec 2024 11:35:23 +0800 Subject: [PATCH 20/68] --wip-- [skip ci] --- examples/module-federation/widget/src/App1.tsx | 9 ++++++++- examples/module-federation/widget/src/lazy.tsx | 3 +++ 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 examples/module-federation/widget/src/lazy.tsx diff --git a/examples/module-federation/widget/src/App1.tsx b/examples/module-federation/widget/src/App1.tsx index d6b4757c6..66fb59110 100644 --- a/examples/module-federation/widget/src/App1.tsx +++ b/examples/module-federation/widget/src/App1.tsx @@ -1,4 +1,6 @@ -import React from 'react'; +import React, { Suspense } from 'react'; + +const Lazy = React.lazy(() => import('./lazy')); const App = () => { return ( @@ -11,6 +13,11 @@ const App = () => { }} >

Widget App1

+

+ + + +

); }; diff --git a/examples/module-federation/widget/src/lazy.tsx b/examples/module-federation/widget/src/lazy.tsx new file mode 100644 index 000000000..0b10b38bb --- /dev/null +++ b/examples/module-federation/widget/src/lazy.tsx @@ -0,0 +1,3 @@ +import React from 'react'; + +export default () =>
Lazy
; From 1f75e1790c84ec9de493024c670acd13d35e8bdf Mon Sep 17 00:00:00 2001 From: xusd320 Date: Tue, 10 Dec 2024 16:56:26 +0800 Subject: [PATCH 21/68] fix: remote stats.json --- .../src/plugins/module_federation/manifest.rs | 67 ++++++++++++------- .../module-federation/host/mako.config.json | 2 +- .../module-federation/widget/mako.config.json | 1 + .../module-federation/widget/src/lazy.less | 3 + .../module-federation/widget/src/lazy.tsx | 3 +- 5 files changed, 51 insertions(+), 25 deletions(-) create mode 100644 examples/module-federation/widget/src/lazy.less diff --git a/crates/mako/src/plugins/module_federation/manifest.rs b/crates/mako/src/plugins/module_federation/manifest.rs index 943924ab9..719878b07 100644 --- a/crates/mako/src/plugins/module_federation/manifest.rs +++ b/crates/mako/src/plugins/module_federation/manifest.rs @@ -9,6 +9,7 @@ use super::{constants, ModuleFederationPlugin}; use crate::compiler::Context; use crate::module::ModuleId; use crate::plugin::PluginGenerateEndParams; +use crate::stats::StatsJsonMap; use crate::utils::get_app_info; impl ModuleFederationPlugin { @@ -56,28 +57,26 @@ impl ModuleFederationPlugin { acc.splice(0..sync_deps.len(), sync_deps); acc }); + let all_exposes_sync_chunks = + [exposes_sync_chunk_dependencies, exposes_sync_chunks].concat(); + let all_exposes_async_chunks: Vec = + all_exposes_sync_chunks.iter().fold(vec![], |mut acc, cur| { + acc.extend(chunk_graph.installable_descendants_chunk(cur)); + acc + }); let (sync_js_files, sync_css_files) = - [exposes_sync_chunk_dependencies, exposes_sync_chunks] - .concat() - .iter() - .fold( - (Vec::::new(), Vec::::new()), - |mut acc, cur| { - if let Some(c) = - params.stats.chunks.iter().find(|c| c.id == cur.id) - { - c.files.iter().for_each(|f| { - if f.ends_with(".js") { - acc.0.push(f.clone()); - } - if f.ends_with(".css") { - acc.1.push(f.clone()); - } - }); - } - acc - }, - ); + extrac_assets(all_exposes_sync_chunks, ¶ms.stats); + + let (async_js_files, async_css_files) = + extrac_assets(all_exposes_async_chunks, ¶ms.stats); + let async_js_files = async_js_files + .into_iter() + .filter(|f| !sync_js_files.contains(f)) + .collect(); + let async_css_files = async_css_files + .into_iter() + .filter(|f| !sync_js_files.contains(f)) + .collect(); ManifestExpose { id: format!("{}:{}", self.config.name, name), name, @@ -85,11 +84,11 @@ impl ModuleFederationPlugin { assets: ManifestAssets { js: ManifestAssetsItem { sync: sync_js_files, - r#async: Vec::new(), + r#async: async_js_files, }, css: ManifestAssetsItem { sync: sync_css_files, - r#async: Vec::new(), + r#async: async_css_files, }, }, } @@ -154,6 +153,28 @@ impl ModuleFederationPlugin { } } +fn extrac_assets( + all_exposes_sync_chunks: Vec, + stats: &StatsJsonMap, +) -> (Vec, Vec) { + all_exposes_sync_chunks.iter().fold( + (Vec::::new(), Vec::::new()), + |mut acc, cur| { + if let Some(c) = stats.chunks.iter().find(|c| c.id == cur.id) { + c.files.iter().for_each(|f| { + if f.ends_with(".js") { + acc.0.push(f.clone()); + } + if f.ends_with(".css") { + acc.1.push(f.clone()); + } + }); + } + acc + }, + ) +} + #[derive(Serialize, Default)] pub struct ManifestAssetsItem { pub sync: Vec, diff --git a/examples/module-federation/host/mako.config.json b/examples/module-federation/host/mako.config.json index c212abf00..01f656beb 100644 --- a/examples/module-federation/host/mako.config.json +++ b/examples/module-federation/host/mako.config.json @@ -5,7 +5,7 @@ "moduleFederation": { "name": "mfHost", "remotes": { - "widget": "mfWidget@http://localhost:3000/mf-manifest.json" + "widget": "mfWidget@http://localhost:3000/mfWidget.js" }, "implementation": "/Users/xusd/codes/github/mako/packages/mako/node_modules/@module-federation/webpack-bundler-runtime" } diff --git a/examples/module-federation/widget/mako.config.json b/examples/module-federation/widget/mako.config.json index 22f503e25..b2423d109 100644 --- a/examples/module-federation/widget/mako.config.json +++ b/examples/module-federation/widget/mako.config.json @@ -2,6 +2,7 @@ "entry": { "app2": "./src/index.ts" }, + "publicPath": "auto", "moduleFederation": { "name": "mfWidget", "exposes": { diff --git a/examples/module-federation/widget/src/lazy.less b/examples/module-federation/widget/src/lazy.less new file mode 100644 index 000000000..7e30e7dbb --- /dev/null +++ b/examples/module-federation/widget/src/lazy.less @@ -0,0 +1,3 @@ +.lazy { + color: green; +} diff --git a/examples/module-federation/widget/src/lazy.tsx b/examples/module-federation/widget/src/lazy.tsx index 0b10b38bb..e0edcac47 100644 --- a/examples/module-federation/widget/src/lazy.tsx +++ b/examples/module-federation/widget/src/lazy.tsx @@ -1,3 +1,4 @@ import React from 'react'; +import './lazy.less'; -export default () =>
Lazy
; +export default () =>
Lazy
; From 6fc54c9685c09e9c933c6c63b4ae83f14ed1a76c Mon Sep 17 00:00:00 2001 From: xusd320 Date: Wed, 11 Dec 2024 14:22:45 +0800 Subject: [PATCH 22/68] fix: typos --- crates/mako/src/plugins/module_federation.rs | 2 +- crates/mako/src/plugins/module_federation/container.rs | 2 +- crates/mako/src/plugins/module_federation/manifest.rs | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/mako/src/plugins/module_federation.rs b/crates/mako/src/plugins/module_federation.rs index 6f28acfa4..24e858952 100644 --- a/crates/mako/src/plugins/module_federation.rs +++ b/crates/mako/src/plugins/module_federation.rs @@ -47,7 +47,7 @@ impl Plugin for ModuleFederationPlugin { _is_entry: bool, _context: &Arc, ) -> Result> { - // add containter entry runtime dependency + // add container entry runtime dependency if !_is_entry { Ok(None) } else { diff --git a/crates/mako/src/plugins/module_federation/container.rs b/crates/mako/src/plugins/module_federation/container.rs index 5d870cf51..1b5d6f4b6 100644 --- a/crates/mako/src/plugins/module_federation/container.rs +++ b/crates/mako/src/plugins/module_federation/container.rs @@ -74,7 +74,7 @@ if(!{federation_global}.instance) {{ } pub(super) fn add_container_entry(&self, config: &mut Config, root: &Path) { - // add containter entry + // add container entry if let Some(exposes) = self.config.exposes.as_ref() { let container_entry_name = &self.config.name; if !exposes.is_empty() { diff --git a/crates/mako/src/plugins/module_federation/manifest.rs b/crates/mako/src/plugins/module_federation/manifest.rs index 719878b07..c461e98f5 100644 --- a/crates/mako/src/plugins/module_federation/manifest.rs +++ b/crates/mako/src/plugins/module_federation/manifest.rs @@ -65,10 +65,10 @@ impl ModuleFederationPlugin { acc }); let (sync_js_files, sync_css_files) = - extrac_assets(all_exposes_sync_chunks, ¶ms.stats); + extract_assets(all_exposes_sync_chunks, ¶ms.stats); let (async_js_files, async_css_files) = - extrac_assets(all_exposes_async_chunks, ¶ms.stats); + extract_assets(all_exposes_async_chunks, ¶ms.stats); let async_js_files = async_js_files .into_iter() .filter(|f| !sync_js_files.contains(f)) @@ -153,7 +153,7 @@ impl ModuleFederationPlugin { } } -fn extrac_assets( +fn extract_assets( all_exposes_sync_chunks: Vec, stats: &StatsJsonMap, ) -> (Vec, Vec) { From 367561bd014266b57d459381e6d09757dd6121cd Mon Sep 17 00:00:00 2001 From: xusd320 Date: Fri, 13 Dec 2024 14:21:56 +0800 Subject: [PATCH 23/68] chore: simpify mf runtime codes fmt --- crates/mako/src/dev.rs | 1 - .../plugins/module_federation/container.rs | 41 ++++++++----------- 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/crates/mako/src/dev.rs b/crates/mako/src/dev.rs index 0dae20352..3db00ff71 100644 --- a/crates/mako/src/dev.rs +++ b/crates/mako/src/dev.rs @@ -85,7 +85,6 @@ impl DevServer { let server = Server::bind(&addr).serve(make_svc); // TODO: print when mako is run standalone if std::env::var("MAKO_CLI").is_ok() { - println!(); if config_port != port { println!( "{}", diff --git a/crates/mako/src/plugins/module_federation/container.rs b/crates/mako/src/plugins/module_federation/container.rs index 1b5d6f4b6..518987aa1 100644 --- a/crates/mako/src/plugins/module_federation/container.rs +++ b/crates/mako/src/plugins/module_federation/container.rs @@ -45,31 +45,29 @@ impl ModuleFederationPlugin { r#"import federation from "{federation_impl}"; {plugins_imports} -if(!{federation_global}.runtime) {{ - var preFederation = {federation_global}; - {federation_global} = {{}}; +if(!{FEDERATION_GLOBAL}.runtime) {{ + var preFederation = {FEDERATION_GLOBAL}; + {FEDERATION_GLOBAL} = {{}}; for(var key in federation) {{ - {federation_global}[key] = federation[key]; + {FEDERATION_GLOBAL}[key] = federation[key]; }} for(var key in preFederation) {{ - {federation_global}[key] = preFederation[key]; + {FEDERATION_GLOBAL}[key] = preFederation[key]; }} }} -if(!{federation_global}.instance) {{ +if(!{FEDERATION_GLOBAL}.instance) {{ {plugins_instantiations} - {federation_global}.instance = {federation_global}.runtime.init({federation_global}.initOptions); - if({federation_global}.attachShareScopeMap) {{ - {federation_global}.attachShareScopeMap({mako_require}); + {FEDERATION_GLOBAL}.instance = {FEDERATION_GLOBAL}.runtime.init({FEDERATION_GLOBAL}.initOptions); + if({FEDERATION_GLOBAL}.attachShareScopeMap) {{ + {FEDERATION_GLOBAL}.attachShareScopeMap({MAKO_REQUIRE}); }} - if({federation_global}.installInitialConsumes) {{ - {federation_global}.installInitialConsumes(); + if({FEDERATION_GLOBAL}.installInitialConsumes) {{ + {FEDERATION_GLOBAL}.installInitialConsumes(); }} }} "#, federation_impl = self.config.implementation, - federation_global = FEDERATION_GLOBAL, - mako_require = MAKO_REQUIRE ) } @@ -114,11 +112,10 @@ if(!{federation_global}.instance) {{ .map(|(name, module)| { format!( r#""{name}": () => import( - /* makoChunkName: "{prefix}{striped_name}" */ + /* makoChunkName: "{FEDERATION_EXPOSE_CHUNK_PREFIX}{striped_name}" */ /* federationExpose: true */ "{module}" ),"#, - prefix = FEDERATION_EXPOSE_CHUNK_PREFIX, module = root.join(module).canonicalize().unwrap().to_string_lossy(), striped_name = name.replace("./", "") ) @@ -132,7 +129,7 @@ if(!{federation_global}.instance) {{ }}; var get = (module, getScope) => {{ - {mako_require}.R = getScope; + {MAKO_REQUIRE}.R = getScope; getScope = ( Object.prototype.hasOwnProperty.call(moduleMap, module) ? moduleMap[module]() @@ -140,13 +137,13 @@ var get = (module, getScope) => {{ throw new Error('Module "' + module + '" does not exist in container.'); }}) ); - {mako_require}.R = undefined; + {MAKO_REQUIRE}.R = undefined; return getScope; }}; var init = (shareScope, initScope, remoteEntryInitOptions) => {{ - return {mako_require}.federation.bundlerRuntime.initContainerEntry({{ - webpackRequire: {mako_require}, + return {FEDERATION_GLOBAL}bundlerRuntime.initContainerEntry({{ + webpackRequire: {MAKO_REQUIRE}, shareScope: shareScope, initScope: initScope, remoteEntryInitOptions: remoteEntryInitOptions, @@ -156,7 +153,6 @@ var init = (shareScope, initScope, remoteEntryInitOptions) => {{ export {{ get, init }}; "#, - mako_require = MAKO_REQUIRE, share_scope = self.config.share_scope ) } @@ -270,10 +266,9 @@ export {{ get, init }}; } else { format!( r#"var pluginsToAdd = [{plugins_to_add}].filter(Boolean); - {federation_global}.initOptions.plugins = {federation_global}.initOptions.plugins ? - {federation_global}.initOptions.plugins.concat(pluginsToAdd) : pluginsToAdd; + {FEDERATION_GLOBAL}.initOptions.plugins = {FEDERATION_GLOBAL}.initOptions.plugins ? + {FEDERATION_GLOBAL}.initOptions.plugins.concat(pluginsToAdd) : pluginsToAdd; "#, - federation_global = FEDERATION_GLOBAL ) }; (plugins_imports, plugins_instantiations) From b7c9136ccfbfa76add573f999842ec5b6ddb9f3b Mon Sep 17 00:00:00 2001 From: xusd320 Date: Fri, 13 Dec 2024 14:45:09 +0800 Subject: [PATCH 24/68] refactor: mf containter plugin --- crates/mako/src/plugins/module_federation.rs | 37 ++++--------------- .../module_federation/container_reference.rs | 35 +++++++++++++++++- 2 files changed, 41 insertions(+), 31 deletions(-) diff --git a/crates/mako/src/plugins/module_federation.rs b/crates/mako/src/plugins/module_federation.rs index 24e858952..d12d01a11 100644 --- a/crates/mako/src/plugins/module_federation.rs +++ b/crates/mako/src/plugins/module_federation.rs @@ -9,7 +9,7 @@ use crate::compiler::{Args, Context}; use crate::config::module_federation::ModuleFederationConfig; use crate::config::Config; use crate::plugin::{Plugin, PluginGenerateEndParams, PluginResolveIdParams}; -use crate::resolve::{RemoteInfo, ResolverResource}; +use crate::resolve::ResolverResource; mod constants; mod container; @@ -42,18 +42,18 @@ impl Plugin for ModuleFederationPlugin { fn load_transform( &self, - _content: &mut Content, + content: &mut Content, _path: &str, _is_entry: bool, - _context: &Arc, + context: &Arc, ) -> Result> { // add container entry runtime dependency if !_is_entry { Ok(None) } else { - match _content { + match content { Content::Js(js_content) => { - let entry_runtime_dep_path = self.prepare_entry_runtime_dep(&_context.root); + let entry_runtime_dep_path = self.prepare_entry_runtime_dep(&context.root); js_content.content.insert_str( 0, format!( @@ -63,7 +63,7 @@ impl Plugin for ModuleFederationPlugin { ) .as_str(), ); - Ok(Some(_content.clone())) + Ok(Some(content.clone())) } _ => Ok(None), } @@ -89,30 +89,7 @@ impl Plugin for ModuleFederationPlugin { _params: &PluginResolveIdParams, _context: &Arc, ) -> Result> { - let source_parts = source - .split_once("/") - .map_or((source.to_string(), ".".to_string()), |(part_0, part_1)| { - (part_0.to_string(), part_1.to_string()) - }); - Ok(self.config.remotes.as_ref().map_or_else( - || None, - |remotes| { - remotes.get(&source_parts.0).map(|_remote| { - ResolverResource::Remote(RemoteInfo { - module_id: format!("{}{}", FEDERATION_REMOTE_MODULE_PREFIX, source), - external_refenrence_id: format!( - "{}{}", - FEDERATION_REMOTE_REFERENCE_PREFIX, source_parts.0 - ), - // FIXME: hard code now - external_type: "script".to_string(), - sub_path: format!("./{}", source_parts.1), - name: source_parts.0.to_string(), - share_scope: self.config.share_scope.clone(), - }) - }) - }, - )) + self.resolve_remote(source) } fn generate_end(&self, params: &PluginGenerateEndParams, context: &Arc) -> Result<()> { diff --git a/crates/mako/src/plugins/module_federation/container_reference.rs b/crates/mako/src/plugins/module_federation/container_reference.rs index 73b2a2662..5bcdb7fed 100644 --- a/crates/mako/src/plugins/module_federation/container_reference.rs +++ b/crates/mako/src/plugins/module_federation/container_reference.rs @@ -3,8 +3,11 @@ use std::sync::Arc; use serde::Serialize; -use super::ModuleFederationPlugin; +use super::{ + ModuleFederationPlugin, FEDERATION_REMOTE_MODULE_PREFIX, FEDERATION_REMOTE_REFERENCE_PREFIX, +}; use crate::compiler::Context; +use crate::resolve::{RemoteInfo, ResolverResource}; impl ModuleFederationPlugin { pub(super) fn get_container_references_code(&self, context: &Arc) -> String { @@ -77,6 +80,36 @@ impl ModuleFederationPlugin { )()"#, ) } + + pub(super) fn resolve_remote( + &self, + source: &str, + ) -> std::result::Result, anyhow::Error> { + let source_parts = source + .split_once("/") + .map_or((source.to_string(), ".".to_string()), |(part_0, part_1)| { + (part_0.to_string(), part_1.to_string()) + }); + Ok(self.config.remotes.as_ref().map_or_else( + || None, + |remotes| { + remotes.get(&source_parts.0).map(|_remote| { + ResolverResource::Remote(RemoteInfo { + module_id: format!("{}{}", FEDERATION_REMOTE_MODULE_PREFIX, source), + external_refenrence_id: format!( + "{}{}", + FEDERATION_REMOTE_REFERENCE_PREFIX, source_parts.0 + ), + // FIXME: hard code now + external_type: "script".to_string(), + sub_path: format!("./{}", source_parts.1), + name: source_parts.0.to_string(), + share_scope: self.config.share_scope.clone(), + }) + }) + }, + )) + } } #[derive(Serialize)] From 606ca185f7ed3429004f4d1b90fc4392898d13af Mon Sep 17 00:00:00 2001 From: xusd320 Date: Wed, 8 Jan 2025 18:19:44 +0800 Subject: [PATCH 25/68] feat: mf shared workaround --- crates/mako/src/build.rs | 60 +++- crates/mako/src/build/analyze_deps.rs | 8 +- crates/mako/src/compiler.rs | 16 +- crates/mako/src/config/module_federation.rs | 17 +- crates/mako/src/module.rs | 21 +- crates/mako/src/plugin.rs | 15 +- crates/mako/src/plugins/module_federation.rs | 41 ++- .../plugins/module_federation/container.rs | 3 +- .../module_federation/container_reference.rs | 8 +- .../module_federation/provide_shared.rs | 306 ++++++++++++++++++ .../mako/src/plugins/tree_shaking/module.rs | 2 +- crates/mako/src/plugins/tree_shaking/shake.rs | 4 +- .../tree_shaking/shake/find_export_source.rs | 1 - crates/mako/src/resolve.rs | 15 +- crates/mako/src/resolve/resource.rs | 63 ++++ crates/mako/templates/app_runtime.stpl | 3 + .../module-federation/host/mako.config.json | 4 + .../widget/mako.config.bk.json | 29 ++ .../module-federation/widget/mako.config.json | 4 + 19 files changed, 569 insertions(+), 51 deletions(-) create mode 100644 crates/mako/src/plugins/module_federation/provide_shared.rs create mode 100644 examples/module-federation/widget/mako.config.bk.json diff --git a/crates/mako/src/build.rs b/crates/mako/src/build.rs index b5935c1a8..a789a42d6 100644 --- a/crates/mako/src/build.rs +++ b/crates/mako/src/build.rs @@ -16,9 +16,9 @@ use crate::ast::file::{Content, File, JsContent}; use crate::ast::utils::get_module_system; use crate::compiler::{Compiler, Context}; use crate::generate::chunk_pot::util::hash_hashmap; -use crate::module::{Module, ModuleAst, ModuleId, ModuleInfo}; +use crate::module::{FedereationModuleType, Module, ModuleAst, ModuleId, ModuleInfo}; use crate::plugin::NextBuildParam; -use crate::resolve::ResolverResource; +use crate::resolve::{ConsumeShareInfo, ProvideShareInfo, RemoteInfo, ResolverResource}; use crate::utils::thread_pool; #[derive(Debug, Error)] @@ -46,6 +46,15 @@ impl Compiler { rs.send(result).unwrap(); }); }; + + let build_provide_share_with_pool = |provide_share_info: ConsumeShareInfo| { + let rs = rs.clone(); + let context = self.context.clone(); + thread_pool::spawn(move || { + let result = Self::build_provide_share_module(provide_share_info, context.clone()); + rs.send(result).unwrap(); + }); + }; let mut count = 0; for file in files { count += 1; @@ -130,6 +139,14 @@ impl Compiler { ResolverResource::Remote(remote_into) => { Self::create_remote_module(remote_into) } + ResolverResource::ProviderShare(provide_share_info) => { + Self::create_consume_share_module(provide_share_info) + } + ResolverResource::ConsumeShare(consume_share_info) => { + count += 1; + build_provide_share_with_pool(consume_share_info.clone()); + Self::create_empty_module(&dep_module_id) + } }; // 拿到依赖之后需要直接添加 module 到 module_graph 里,不能等依赖 build 完再添加 @@ -137,6 +154,7 @@ impl Compiler { module_ids.insert(module.id.clone()); module_graph.add_module(module); } + module_graph.add_dependency(&module_id, &dep_module_id, dep.dependency); } if count == 0 { @@ -270,6 +288,12 @@ __mako_require__.loadScript('{}', (e) => e.type === 'load' ? resolve() : reject( result } } + pub fn build_provide_share_module( + provide_share_info: ConsumeShareInfo, + context: Arc, + ) -> Result { + Ok(Self::create_provide_share_module(provide_share_info)) + } pub fn build_module( file: &File, @@ -333,4 +357,36 @@ __mako_require__.loadScript('{}', (e) => e.type === 'load' ? resolve() : reject( let module = Module::new(module_id, is_entry, Some(info)); Ok(module) } + + pub(crate) fn create_remote_module(remote_info: RemoteInfo) -> Module { + Module { + is_entry: false, + id: remote_info.module_id.as_str().into(), + info: Some(ModuleInfo { + resolved_resource: Some(ResolverResource::Remote(remote_info.clone())), + federation: Some(FedereationModuleType::Remote), + ..Default::default() + }), + side_effects: true, + } + } + + pub(crate) fn create_provide_share_module(provide_share_info: ConsumeShareInfo) -> Module { + Module { + is_entry: false, + id: provide_share_info.module_id.as_str().into(), + info: Some(ModuleInfo { + deps: provide_share_info.deps.clone(), + resolved_resource: Some(ResolverResource::ConsumeShare(provide_share_info.clone())), + federation: Some(FedereationModuleType::ConsumeShare), + module_system: crate::module::ModuleSystem::Custom, + ..Default::default() + }), + side_effects: true, + } + } + + pub(crate) fn create_consume_share_module(consume_share_info: ProvideShareInfo) -> Module { + todo!() + } } diff --git a/crates/mako/src/build/analyze_deps.rs b/crates/mako/src/build/analyze_deps.rs index 1bb374aa5..2f7b5eb11 100644 --- a/crates/mako/src/build/analyze_deps.rs +++ b/crates/mako/src/build/analyze_deps.rs @@ -59,10 +59,14 @@ impl AnalyzeDeps { ); match result { Ok(resolver_resource) => { - resolved_deps.push(ResolvedDep { + let resolved_dep = ResolvedDep { resolver_resource, dependency: dep, - }); + }; + context + .plugin_driver + .after_resolve(&resolved_dep, &context)?; + resolved_deps.push(resolved_dep); } Err(_err) => { missing_deps.insert(dep.source.clone(), dep); diff --git a/crates/mako/src/compiler.rs b/crates/mako/src/compiler.rs index 44f9f70cc..901e3924b 100644 --- a/crates/mako/src/compiler.rs +++ b/crates/mako/src/compiler.rs @@ -18,12 +18,11 @@ use crate::ast::file::win_path; use crate::config::{Config, Mode, ModuleIdStrategy, OutputMode}; use crate::generate::chunk_graph::ChunkGraph; use crate::generate::optimize_chunk::OptimizeChunksInfo; -use crate::module::{Module, ModuleInfo}; use crate::module_graph::ModuleGraph; use crate::plugin::{Plugin, PluginDriver, PluginGenerateEndParams}; use crate::plugins; use crate::plugins::module_federation::ModuleFederationPlugin; -use crate::resolve::{get_resolvers, RemoteInfo, ResolverResource, Resolvers}; +use crate::resolve::{get_resolvers, Resolvers}; use crate::share::helpers::SWC_HELPERS; use crate::stats::StatsInfo; use crate::utils::id_helper::{assign_numeric_ids, compare_modules_by_incoming_edges}; @@ -499,17 +498,4 @@ impl Compiler { } Ok(()) } - - pub(crate) fn create_remote_module(remote_info: RemoteInfo) -> Module { - Module { - is_remote: true, - is_entry: false, - id: remote_info.module_id.as_str().into(), - info: Some(ModuleInfo { - resolved_resource: Some(ResolverResource::Remote(remote_info.clone())), - ..Default::default() - }), - side_effects: false, - } - } } diff --git a/crates/mako/src/config/module_federation.rs b/crates/mako/src/config/module_federation.rs index aeed03751..929c6a9ca 100644 --- a/crates/mako/src/config/module_federation.rs +++ b/crates/mako/src/config/module_federation.rs @@ -20,12 +20,21 @@ pub struct ModuleFederationConfig { pub type ExposesConfig = HashMap; +pub type SharedConfig = HashMap; + #[derive(Debug, Clone, Serialize, Deserialize, Default)] #[serde(rename_all = "camelCase")] -pub struct SharedConfig { - singleton: Option, - required_version: Option, - shared_scope: Option, +pub struct SharedItemConfig { + #[serde(default)] + pub eager: bool, + #[serde(default)] + pub singleton: bool, + #[serde(default)] + pub required_version: Option, + #[serde(default)] + pub strict_version: bool, + #[serde(default = "default_share_scope")] + pub shared_scope: String, } #[derive(Debug, Clone, Serialize, Deserialize)] diff --git a/crates/mako/src/module.rs b/crates/mako/src/module.rs index 7e471a314..8361aaac7 100644 --- a/crates/mako/src/module.rs +++ b/crates/mako/src/module.rs @@ -201,6 +201,7 @@ pub struct ModuleInfo { /// The transformed source map chain of this module pub source_map_chain: Vec>, pub module_system: ModuleSystem, + pub federation: Option, } impl Default for ModuleInfo { @@ -218,6 +219,7 @@ impl Default for ModuleInfo { resolved_resource: None, source_map_chain: vec![], is_ignored: false, + federation: None, } } } @@ -387,12 +389,18 @@ pub enum ModuleType { PlaceHolder, } +#[derive(Clone, Debug)] +pub enum FedereationModuleType { + Remote, + ConsumeShare, + ProvideShare, +} + #[derive(Clone)] pub struct Module { pub id: ModuleId, pub is_entry: bool, // only module federation remote module - pub is_remote: bool, pub info: Option, pub side_effects: bool, } @@ -402,7 +410,6 @@ impl Module { Self { id, is_entry, - is_remote: false, info, side_effects: is_entry, } @@ -426,6 +433,16 @@ impl Module { .map_or(false, |info| info.external.is_some()) } + pub fn is_provide_share(&self) -> bool { + if let Some(info) = self.info.as_ref() + && let Some(FedereationModuleType::ConsumeShare) = info.federation + { + true + } else { + false + } + } + pub fn is_placeholder(&self) -> bool { self.get_module_type() == ModuleType::PlaceHolder } diff --git a/crates/mako/src/plugin.rs b/crates/mako/src/plugin.rs index d1d3a12f2..092493317 100644 --- a/crates/mako/src/plugin.rs +++ b/crates/mako/src/plugin.rs @@ -9,6 +9,7 @@ use swc_core::common::Mark; use swc_core::ecma::ast::Module; use crate::ast::file::{Content, File}; +use crate::build::analyze_deps::ResolvedDep; use crate::compiler::{Args, Compiler, Context}; use crate::config::Config; use crate::generate::chunk_graph::ChunkGraph; @@ -24,8 +25,9 @@ pub struct PluginLoadParam<'a> { } #[derive(Debug)] -pub struct PluginResolveIdParams { +pub struct PluginResolveIdParams<'a> { pub is_entry: bool, + pub dep: &'a Dependency, } pub struct PluginParseParam<'a> { @@ -116,6 +118,10 @@ pub trait Plugin: Any + Send + Sync { Ok(()) } + fn after_resolve(&self, _resolved_dep: &ResolvedDep, _context: &Arc) -> Result<()> { + Ok(()) + } + fn after_build(&self, _context: &Arc, _compiler: &Compiler) -> Result<()> { Ok(()) } @@ -289,6 +295,13 @@ impl PluginDriver { Ok(()) } + pub fn after_resolve(&self, resolved_dep: &ResolvedDep, context: &Arc) -> Result<()> { + for plugin in &self.plugins { + plugin.after_resolve(resolved_dep, context)?; + } + Ok(()) + } + pub fn resolve_id( &self, source: &str, diff --git a/crates/mako/src/plugins/module_federation.rs b/crates/mako/src/plugins/module_federation.rs index d12d01a11..f0f129269 100644 --- a/crates/mako/src/plugins/module_federation.rs +++ b/crates/mako/src/plugins/module_federation.rs @@ -1,10 +1,12 @@ use std::path::Path; -use std::sync::Arc; +use std::sync::{Arc, RwLock}; use anyhow::Result; use constants::{FEDERATION_REMOTE_MODULE_PREFIX, FEDERATION_REMOTE_REFERENCE_PREFIX}; +use provide_shared::SharedDependencies; use crate::ast::file::Content; +use crate::build::analyze_deps::ResolvedDep; use crate::compiler::{Args, Context}; use crate::config::module_federation::ModuleFederationConfig; use crate::config::Config; @@ -15,15 +17,20 @@ mod constants; mod container; mod container_reference; mod manifest; +mod provide_shared; mod util; pub struct ModuleFederationPlugin { pub config: ModuleFederationConfig, + shared_dependencies: RwLock, } impl ModuleFederationPlugin { pub fn new(config: ModuleFederationConfig) -> Self { - Self { config } + Self { + config, + shared_dependencies: RwLock::new(SharedDependencies::new()), + } } } @@ -71,29 +78,37 @@ impl Plugin for ModuleFederationPlugin { } fn runtime_plugins(&self, context: &Arc) -> Result> { - let federation_runtime_code = self.get_federation_runtime_code(); - let federation_exposes_library_code = self.get_federation_exposes_library_code(); - let federation_container_references_code = self.get_container_references_code(context); - Ok(vec![ - federation_runtime_code, - federation_container_references_code, - federation_exposes_library_code, + self.get_federation_runtime_code(), + self.get_container_references_code(context), + self.get_provide_sharing_code(context), + self.get_consume_sharing_code(context), + self.get_federation_exposes_library_code(), ]) } fn resolve_id( &self, source: &str, - _importer: &str, - _params: &PluginResolveIdParams, - _context: &Arc, + importer: &str, + params: &PluginResolveIdParams, + context: &Arc, ) -> Result> { - self.resolve_remote(source) + let remote_module = self.resolve_remote(source); + if let Ok(Some(_)) = remote_module.as_ref() { + remote_module + } else { + self.resolve_provide_share(source, importer, params, context) + } } fn generate_end(&self, params: &PluginGenerateEndParams, context: &Arc) -> Result<()> { self.generate_federation_manifest(context, params)?; Ok(()) } + + fn after_resolve(&self, resolved_dep: &ResolvedDep, _context: &Arc) -> Result<()> { + self.collect_provide_shared_map(resolved_dep); + Ok(()) + } } diff --git a/crates/mako/src/plugins/module_federation/container.rs b/crates/mako/src/plugins/module_federation/container.rs index 518987aa1..f9dbebd7a 100644 --- a/crates/mako/src/plugins/module_federation/container.rs +++ b/crates/mako/src/plugins/module_federation/container.rs @@ -84,6 +84,7 @@ if(!{FEDERATION_GLOBAL}.instance) {{ ); } Vacant(vacant_entry) => { + // TODO: refactor with virtual entry let container_entry_code = self.get_container_entry_code(root); let container_entry_path = root.join(format!( "node_modules/.federation/.entry.container.{}.js", @@ -142,7 +143,7 @@ var get = (module, getScope) => {{ }}; var init = (shareScope, initScope, remoteEntryInitOptions) => {{ - return {FEDERATION_GLOBAL}bundlerRuntime.initContainerEntry({{ + return {FEDERATION_GLOBAL}.bundlerRuntime.initContainerEntry({{ webpackRequire: {MAKO_REQUIRE}, shareScope: shareScope, initScope: initScope, diff --git a/crates/mako/src/plugins/module_federation/container_reference.rs b/crates/mako/src/plugins/module_federation/container_reference.rs index 5bcdb7fed..adc6679b9 100644 --- a/crates/mako/src/plugins/module_federation/container_reference.rs +++ b/crates/mako/src/plugins/module_federation/container_reference.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use std::result::Result; use std::sync::Arc; use serde::Serialize; @@ -7,6 +8,7 @@ use super::{ ModuleFederationPlugin, FEDERATION_REMOTE_MODULE_PREFIX, FEDERATION_REMOTE_REFERENCE_PREFIX, }; use crate::compiler::Context; +use crate::module::FedereationModuleType; use crate::resolve::{RemoteInfo, ResolverResource}; impl ModuleFederationPlugin { @@ -21,7 +23,9 @@ impl ModuleFederationPlugin { all_chunks.iter().for_each(|c| { c.modules.iter().for_each(|m| { if let Some(m) = module_graph.get_module(m) { - if m.is_remote { + if let Some(info) = m.info.as_ref() + && let Some(FedereationModuleType::Remote) = info.federation.as_ref() + { { chunk_mapping .entry(c.id.id.as_str()) @@ -84,7 +88,7 @@ impl ModuleFederationPlugin { pub(super) fn resolve_remote( &self, source: &str, - ) -> std::result::Result, anyhow::Error> { + ) -> Result, anyhow::Error> { let source_parts = source .split_once("/") .map_or((source.to_string(), ".".to_string()), |(part_0, part_1)| { diff --git a/crates/mako/src/plugins/module_federation/provide_shared.rs b/crates/mako/src/plugins/module_federation/provide_shared.rs new file mode 100644 index 000000000..c445524ee --- /dev/null +++ b/crates/mako/src/plugins/module_federation/provide_shared.rs @@ -0,0 +1,306 @@ +use core::panic; +use std::collections::HashMap; +use std::sync::Arc; + +use pathdiff::diff_paths; +use serde::Serialize; + +use super::constants::FEDERATION_SHARED_REFERENCE_PREFIX; +use super::ModuleFederationPlugin; +use crate::build::analyze_deps::{AnalyzeDepsResult, ResolvedDep}; +use crate::compiler::Context; +use crate::generate::chunk::ChunkType; +use crate::module::{Dependency, ModuleId, ResolveType}; +use crate::plugin::PluginResolveIdParams; +use crate::resolve::{do_resolve, ConsumeShareInfo, ResolverResource, ResolverType}; + +impl ModuleFederationPlugin { + pub(super) fn get_provide_sharing_code(&self, context: &Context) -> String { + let provide_shared_map = self.shared_dependencies.read().unwrap(); + let chunk_graph = context.chunk_graph.read().unwrap(); + + if provide_shared_map.is_empty() { + return "".to_string(); + } + + let provide_shared_map_code = format!( + r#"{{{}}}"#, + provide_shared_map + .iter() + .map(|(_, items)| format!( + r#""{share_key}": [{infos}]"#, + infos = items + .iter() + .map(|share_item| { + let getter = { + let module_id: ModuleId = share_item.file_path.as_str().into(); + let module_in_chunk = + chunk_graph.get_chunk_for_module(&module_id).unwrap(); + let module_relative_path = + diff_paths(&share_item.file_path, &context.root) + .unwrap() + .to_string_lossy() + .to_string(); + + match &module_in_chunk.chunk_type { + ChunkType::Entry(_, _, false) | ChunkType::Worker(_) => { + format!( + r#"() => (() => requireModule("{module_relative_path}"))"# + ) + }, + ChunkType::Async + | ChunkType::Sync + | ChunkType::Entry(_, _, true) + => { + let dependency_chunks = chunk_graph.sync_dependencies_chunk(&module_in_chunk.id); + format!( + r#"() => (Promise.all([{}]).then(() => (() => requireModule("{module_relative_path}"))))"#, + [dependency_chunks, vec![module_in_chunk.id.clone()]].concat().iter().map(|e| format!(r#"requireModule.ensure("{}")"#, e.id)).collect::>().join(",") + ) + }, + // FIXME: + _ => panic!("mf shared dependency should not bundled to worker chunk, entries' shared chunk or runtime chunk") + } + }; + format!( + r#"{{ version: {version}, get: {getter}, scope: {scope}, shareConfig: {share_config} }}"#, + version = share_item + .version + .as_ref() + .map_or("false".to_string(), |v| format!(r#""{}""#, v)), + scope = serde_json::to_string(&share_item.scope).unwrap(), + share_config = serde_json::to_string(&share_item.shared_config).unwrap() + ) + }) + .collect::>() + .join(","), + share_key = items[0].share_key + )) + .collect::>() + .join(",") + ); + + if let Some(shared) = self.config.shared.as_ref() + && !shared.is_empty() + { + format!( + r#" +/* mako/runtime/federation sharing */ +!(function() {{ + requireModule.federation.initOptions.shared = {provide_shared_map_code}; + requireModule.S = {{}}; + var initPromises = {{}}; + var initTokens = {{}}; + requireModule.I = function(name, initScope) {{ + return requireModule.federation.bundlerRuntime.I({{ + shareScopeName: name, + webpackRequire: requireModule, + initPromises: initPromises, + initTokens: initTokens, + initScope: initScope + }}); + }}; +}})(); +"#, + ) + } else { + "".to_string() + } + } + + pub(super) fn get_consume_sharing_code(&self, context: &Context) -> String { + let module_graph = context.module_graph.read().unwrap(); + let chunk_graph = context.chunk_graph.read().unwrap(); + let share_dependencies = self.shared_dependencies.read().unwrap(); + let shared_modules = module_graph + .modules() + .into_iter() + .filter(|m| m.id.id.starts_with(FEDERATION_SHARED_REFERENCE_PREFIX)) + .collect::>(); + let mut shared_referenced_map: HashMap> = HashMap::new(); + let module_to_handler_mapping_code = shared_modules + .iter() + .map(|s| { + let resolved_resource = s.info.as_ref().unwrap().resolved_resource.as_ref().unwrap(); + let module_full_path = match resolved_resource { + ResolverResource::ConsumeShare(info) => info.deps.resolved_deps[0].resolver_resource.get_resolved_path(), + _ => panic!("{} is not a shared module", resolved_resource.get_resolved_path()) + }; + let module_relative_path = + diff_paths(&module_full_path, &context.root) + .unwrap() + .to_string_lossy() + .to_string(); + + let module_in_chunk = chunk_graph.get_chunk_for_module(&module_full_path.as_str().into()).unwrap(); + + chunk_graph.dependents_chunk(&module_in_chunk.id).iter().for_each(|c| { + let chunk = chunk_graph.chunk(c); + if let Some(chunk) = chunk.as_ref() && !matches!(chunk.chunk_type, ChunkType::Runtime | ChunkType::Entry(_, _, false)) { + let entry = shared_referenced_map.entry(c.id.clone()).or_default(); + entry.push(s.id.id.clone()); + } + }); + + let getter = match &module_in_chunk.chunk_type { + ChunkType::Entry(_, _, false) | ChunkType::Worker(_) => { + format!( + r#"() => (() => requireModule("{module_relative_path}"))"# + ) + }, + ChunkType::Async + | ChunkType::Sync + | ChunkType::Entry(_, _, true) + => { + let dependency_chunks = chunk_graph.sync_dependencies_chunk(&module_in_chunk.id); + format!( + r#"() => (Promise.all([{}]).then(() => requireModule("{module_relative_path}")))"#, + [dependency_chunks, vec![module_in_chunk.id.clone()]].concat().iter().map(|e| format!(r#"requireModule.ensure("{}")"#, e.id)).collect::>().join(",") + ) + }, + ChunkType::Runtime => panic!("mf shared dependency should not bundled to runtime chunk") + }; + + let share_dependency = share_dependencies.get(&s.id.id).unwrap().first().unwrap(); + format!( + r#""{shared_consume_id}": {{ + getter: {getter}, + shareInfo: {{ shareConfig: {share_config} }}, + shareKey: "{share_key}" + }}"#, + shared_consume_id = s.id.id, + share_config = serde_json::to_string(&share_dependency.shared_config).unwrap(), + share_key = share_dependency.share_key + + ) + }) + .collect::>() + .join(","); + let chunk_mapping_code = serde_json::to_string(&shared_referenced_map).unwrap(); + format!( + r#" +/* mako/runtime/federation consumes */ +!(() => {{ + var installedModules = {{}}; + var moduleToHandlerMapping = {{{module_to_handler_mapping_code}}}; + + var chunkMapping = {chunk_mapping_code}; + requireModule.chunkEnsures.consumes = (chunkId, promises) => {{ + requireModule.federation.bundlerRuntime.consumes({{ + chunkMapping: chunkMapping, + installedModules: installedModules, + chunkId: chunkId, + moduleToHandlerMapping: moduleToHandlerMapping, + promises: promises, + webpackRequire: requireModule + }}); + }} +}})();"# + ) + } + + pub(super) fn collect_provide_shared_map(&self, resolved_dep: &ResolvedDep) { + if let Some(shared) = self.config.shared.as_ref() + && let Some(pkg_info) = resolved_dep.resolver_resource.get_pkg_info() + && let Some(pkg_name) = pkg_info.name + && let Some(shared_info) = shared.get(&pkg_name) + && pkg_name == resolved_dep.dependency.source + { + let mut provide_shared_map = self.shared_dependencies.write().unwrap(); + let shared_items = provide_shared_map + .entry(resolved_dep.resolver_resource.get_resolved_path()) + .or_default(); + if shared_items.is_empty() { + shared_items.push(ProvideSharedItem { + share_key: pkg_name.clone(), + version: pkg_info.version.clone(), + scope: vec![shared_info.shared_scope.clone()], + file_path: pkg_info.file_path.clone(), + shared_config: SharedDepency { + eager: shared_info.eager, + strict_version: shared_info.strict_version, + singleton: shared_info.singleton, + required_version: pkg_info.version.clone(), + fixed_dependencies: false, + }, + }) + }; + } + } + + pub(super) fn resolve_provide_share( + &self, + source: &str, + importer: &str, + params: &PluginResolveIdParams, + context: &Arc, + ) -> Result, anyhow::Error> { + if let Some(shared) = self.config.shared.as_ref() + && let Some(shared_info) = shared.get(source) + { + let resolver = if params.dep.resolve_type == ResolveType::Require { + context.resolvers.get(&ResolverType::Cjs) + } else if params.dep.resolve_type == ResolveType::Css { + context.resolvers.get(&ResolverType::Css) + } else { + context.resolvers.get(&ResolverType::Esm) + } + .unwrap(); + let resolver_resource = + do_resolve(importer, source, resolver, Some(&context.config.externals))?; + return Ok(Some(ResolverResource::ConsumeShare(ConsumeShareInfo { + eager: shared_info.eager, + module_id: format!( + "{}{}/{}/{}", + FEDERATION_SHARED_REFERENCE_PREFIX, shared_info.shared_scope, source, source + ), + name: source.to_string(), + share_scope: shared_info.shared_scope.clone(), + version: resolver_resource.get_pkg_info().unwrap().version.unwrap(), + full_path: format!( + "{}{}/{}/{}", + FEDERATION_SHARED_REFERENCE_PREFIX, shared_info.shared_scope, source, source + ), + deps: AnalyzeDepsResult { + resolved_deps: vec![ResolvedDep { + resolver_resource, + dependency: Dependency { + source: params.dep.source.clone(), + resolve_as: None, + resolve_type: ResolveType::DynamicImport(Default::default()), + order: params.dep.order, + span: params.dep.span, + }, + }], + missing_deps: HashMap::new(), + }, + singletion: shared_info.singleton, + required_version: shared_info.required_version.clone(), + strict_version: shared_info.strict_version, + }))); + } + Ok(None) + } +} + +#[derive(Debug)] +pub(super) struct ProvideSharedItem { + pub(super) share_key: String, + pub(super) version: Option, + pub(super) scope: Vec, + pub(super) shared_config: SharedDepency, + pub(super) file_path: String, +} + +#[derive(Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub(super) struct SharedDepency { + #[serde(default)] + pub(super) fixed_dependencies: bool, + pub(super) eager: bool, + pub(super) strict_version: bool, + pub(super) singleton: bool, + pub(super) required_version: Option, +} + +pub(super) type SharedDependencies = HashMap>; diff --git a/crates/mako/src/plugins/tree_shaking/module.rs b/crates/mako/src/plugins/tree_shaking/module.rs index 4c449b9fb..7d2cbdec3 100644 --- a/crates/mako/src/plugins/tree_shaking/module.rs +++ b/crates/mako/src/plugins/tree_shaking/module.rs @@ -297,7 +297,7 @@ impl TreeShakeModule { crate::module::ModuleAst::None => StatementGraph::empty(), }; - let used_exports = if module.is_entry { + let used_exports = if module.is_entry || module.is_provide_share() { UsedExports::All } else { UsedExports::Partial(Default::default()) diff --git a/crates/mako/src/plugins/tree_shaking/shake.rs b/crates/mako/src/plugins/tree_shaking/shake.rs index 57d23a545..96262e1b4 100644 --- a/crates/mako/src/plugins/tree_shaking/shake.rs +++ b/crates/mako/src/plugins/tree_shaking/shake.rs @@ -38,7 +38,9 @@ pub fn optimize_modules(module_graph: &mut ModuleGraph, context: &Arc) let module_type = module.get_module_type(); // skip non script modules and external modules - if module_type != ModuleType::Script || module.is_external() { + if (module_type != ModuleType::Script && !module.is_provide_share()) + || module.is_external() + { if module_type != ModuleType::Script && !module.is_external() { // mark all non script modules' script dependencies as side_effects for dep_id in module_graph.dependence_module_ids(module_id) { diff --git a/crates/mako/src/plugins/tree_shaking/shake/find_export_source.rs b/crates/mako/src/plugins/tree_shaking/shake/find_export_source.rs index 214dd454f..030a92e10 100644 --- a/crates/mako/src/plugins/tree_shaking/shake/find_export_source.rs +++ b/crates/mako/src/plugins/tree_shaking/shake/find_export_source.rs @@ -470,7 +470,6 @@ mod tests { let mako_module = Module { id: "test.js".into(), is_entry: false, - is_remote: false, info: Some(ModuleInfo { module_system: get_module_system(&ast), ast, diff --git a/crates/mako/src/resolve.rs b/crates/mako/src/resolve.rs index bcc5cb4dc..e85c77568 100644 --- a/crates/mako/src/resolve.rs +++ b/crates/mako/src/resolve.rs @@ -13,7 +13,10 @@ use tracing::debug; mod resolution; mod resource; pub use resolution::Resolution; -pub use resource::{ExternalResource, RemoteInfo, ResolvedResource, ResolverResource}; +pub use resource::{ + ConsumeShareInfo, ExternalResource, ProvideShareInfo, RemoteInfo, ResolvedResource, + ResolverResource, +}; use crate::ast::file::parse_path; use crate::compiler::Context; @@ -49,9 +52,6 @@ pub fn resolve( resolvers: &Resolvers, context: &Arc, ) -> Result { - crate::mako_profile_function!(); - crate::mako_profile_scope!("resolve", &dep.source); - // plugin first if let Some(resolved) = context.plugin_driver.resolve_id( &dep.source, @@ -59,7 +59,10 @@ pub fn resolve( // it's a compatibility feature for unplugin hooks // is_entry is always false for dependencies // since entry file does not need be be resolved - &PluginResolveIdParams { is_entry: false }, + &PluginResolveIdParams { + is_entry: false, + dep, + }, context, )? { return Ok(resolved); @@ -231,7 +234,7 @@ fn get_external_target_from_global_obj(global_obj_name: &str, external: &str) -> format!("{}{}", global_obj_name, external) } -fn do_resolve( +pub fn do_resolve( path: &str, source: &str, resolver: &Resolver, diff --git a/crates/mako/src/resolve/resource.rs b/crates/mako/src/resolve/resource.rs index 870661004..04f02f2ec 100644 --- a/crates/mako/src/resolve/resource.rs +++ b/crates/mako/src/resolve/resource.rs @@ -1,5 +1,6 @@ use std::path::PathBuf; +use crate::build::analyze_deps::AnalyzeDepsResult; use crate::resolve::Resolution; #[derive(Debug, Clone)] @@ -12,6 +13,35 @@ pub struct RemoteInfo { pub share_scope: String, } +#[derive(Debug, Clone)] +pub struct ConsumeShareInfo { + pub module_id: String, + pub name: String, + pub share_scope: String, + pub version: String, + pub full_path: String, + pub eager: bool, + pub required_version: Option, + pub strict_version: bool, + pub singletion: bool, + pub deps: AnalyzeDepsResult, +} + +#[derive(Debug, Clone)] +pub struct ProvideShareInfo { + pub module_id: String, + pub name: String, + pub import: String, + pub import_resolved: String, + pub share_key: String, + pub share_scope: String, + pub required_version: Option, + pub package_name: String, + pub eager: bool, + pub strict_version: bool, + pub singletion: bool, +} + #[derive(Debug, Clone)] pub struct ExternalResource { pub source: String, @@ -29,6 +59,8 @@ pub enum ResolverResource { Ignored(PathBuf), Virtual(PathBuf), Remote(RemoteInfo), + ProviderShare(ProvideShareInfo), + ConsumeShare(ConsumeShareInfo), } impl ResolverResource { @@ -41,6 +73,8 @@ impl ResolverResource { ResolverResource::Ignored(path) => path.to_string_lossy().to_string(), ResolverResource::Virtual(path) => path.to_string_lossy().to_string(), ResolverResource::Remote(info) => info.module_id.to_string(), + ResolverResource::ProviderShare(info) => info.import_resolved.clone(), + ResolverResource::ConsumeShare(info) => info.full_path.clone(), } } pub fn get_external(&self) -> Option { @@ -62,4 +96,33 @@ impl ResolverResource { _ => None, } } + + pub fn get_pkg_info(&self) -> Option { + match self { + ResolverResource::Resolved(ResolvedResource(resolution)) => Some(PkgInfo { + file_path: resolution.full_path().to_string_lossy().to_string(), + name: resolution.package_json().and_then(|p| { + p.raw_json() + .get("name") + .and_then(|v| v.as_str().map(|v| v.to_string())) + }), + version: resolution.package_json().and_then(|p| { + p.raw_json() + .get("version") + .and_then(|v| v.as_str().map(|v| v.to_string())) + }), + }), + ResolverResource::ConsumeShare(info) => { + info.deps.resolved_deps[0].resolver_resource.get_pkg_info() + } + _ => None, + } + } +} + +#[derive(Debug)] +pub struct PkgInfo { + pub file_path: String, + pub name: Option, + pub version: Option, } diff --git a/crates/mako/templates/app_runtime.stpl b/crates/mako/templates/app_runtime.stpl index ed29c0e9f..c3785053e 100644 --- a/crates/mako/templates/app_runtime.stpl +++ b/crates/mako/templates/app_runtime.stpl @@ -71,6 +71,9 @@ function createRuntime(makoModules, entryModuleId, global) { // required modules requireModule.m = makoModules; + // required modules + requireModule.c = modulesRegistry; + <% if concatenate_enabled { %> // Export Star util for concatenated modules requireModule.es = function(to, from) { diff --git a/examples/module-federation/host/mako.config.json b/examples/module-federation/host/mako.config.json index 01f656beb..32613cfd2 100644 --- a/examples/module-federation/host/mako.config.json +++ b/examples/module-federation/host/mako.config.json @@ -7,6 +7,10 @@ "remotes": { "widget": "mfWidget@http://localhost:3000/mfWidget.js" }, + "shared": { "react": {}, "react-dom": {} }, "implementation": "/Users/xusd/codes/github/mako/packages/mako/node_modules/@module-federation/webpack-bundler-runtime" + }, + "experimental": { + "centralEnsure": false } } diff --git a/examples/module-federation/widget/mako.config.bk.json b/examples/module-federation/widget/mako.config.bk.json new file mode 100644 index 000000000..248058c4a --- /dev/null +++ b/examples/module-federation/widget/mako.config.bk.json @@ -0,0 +1,29 @@ +{ + "entry": { + "app2": "./src/index.ts" + }, + "publicPath": "auto", + "moduleFederation": { + "name": "mfWidget", + "exposes": { + "./App1": "./src/App1.tsx", + "./App2": "./src/App2.tsx" + }, + "shared": { "react": {}, "react-dom": {} }, + "runtimePlugins": [], + "implementation": "/Users/xusd/codes/github/mako/packages/mako/node_modules/@module-federation/webpack-bundler-runtime" + }, + "codeSplitting": { + "strategy": "advanced", + "options": { + "groups": [ + { + "name": "vendor", + "allowChunks": "all", + "minSize": 1, + "test": "node_modules" + } + ] + } + } +} diff --git a/examples/module-federation/widget/mako.config.json b/examples/module-federation/widget/mako.config.json index b2423d109..bf3264f13 100644 --- a/examples/module-federation/widget/mako.config.json +++ b/examples/module-federation/widget/mako.config.json @@ -9,7 +9,11 @@ "./App1": "./src/App1.tsx", "./App2": "./src/App2.tsx" }, + "shared": { "react": {}, "react-dom": {} }, "runtimePlugins": [], "implementation": "/Users/xusd/codes/github/mako/packages/mako/node_modules/@module-federation/webpack-bundler-runtime" + }, + "experimental": { + "centralEnsure": false } } From 465c32fff72c350e0198dfc73497019b87618270 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Thu, 9 Jan 2025 19:51:01 +0800 Subject: [PATCH 26/68] feat: mf shared workaround --- crates/mako/src/build.rs | 24 +-- .../mako/src/generate/chunk_pot/ast_impl.rs | 2 +- .../mako/src/generate/chunk_pot/str_impl.rs | 3 +- crates/mako/src/generate/chunk_pot/util.rs | 7 +- crates/mako/src/plugin.rs | 15 +- crates/mako/src/plugins/async_runtime.rs | 7 +- crates/mako/src/plugins/central_ensure.rs | 7 +- crates/mako/src/plugins/hmr_runtime.rs | 7 +- crates/mako/src/plugins/module_federation.rs | 29 ++- .../module_federation/consume_shared.rs | 187 +++++++++++++++++ .../module_federation/provide_shared.rs | 195 ++++-------------- crates/mako/src/plugins/progress.rs | 7 +- crates/mako/src/plugins/runtime.rs | 3 +- crates/mako/src/plugins/ssu.rs | 12 +- crates/mako/src/plugins/wasm_runtime.rs | 7 +- 15 files changed, 322 insertions(+), 190 deletions(-) create mode 100644 crates/mako/src/plugins/module_federation/consume_shared.rs diff --git a/crates/mako/src/build.rs b/crates/mako/src/build.rs index a789a42d6..5b463fb06 100644 --- a/crates/mako/src/build.rs +++ b/crates/mako/src/build.rs @@ -47,11 +47,11 @@ impl Compiler { }); }; - let build_provide_share_with_pool = |provide_share_info: ConsumeShareInfo| { + let build_consume_share_with_pool = |consume_share_info: ConsumeShareInfo| { let rs = rs.clone(); let context = self.context.clone(); thread_pool::spawn(move || { - let result = Self::build_provide_share_module(provide_share_info, context.clone()); + let result = Self::build_consume_share_module(consume_share_info, context.clone()); rs.send(result).unwrap(); }); }; @@ -140,11 +140,11 @@ impl Compiler { Self::create_remote_module(remote_into) } ResolverResource::ProviderShare(provide_share_info) => { - Self::create_consume_share_module(provide_share_info) + Self::create_provide_share_module(provide_share_info) } ResolverResource::ConsumeShare(consume_share_info) => { count += 1; - build_provide_share_with_pool(consume_share_info.clone()); + build_consume_share_with_pool(consume_share_info.clone()); Self::create_empty_module(&dep_module_id) } }; @@ -288,11 +288,11 @@ __mako_require__.loadScript('{}', (e) => e.type === 'load' ? resolve() : reject( result } } - pub fn build_provide_share_module( - provide_share_info: ConsumeShareInfo, + pub fn build_consume_share_module( + consume_share_info: ConsumeShareInfo, context: Arc, ) -> Result { - Ok(Self::create_provide_share_module(provide_share_info)) + Ok(Self::create_consume_share_module(consume_share_info)) } pub fn build_module( @@ -371,13 +371,13 @@ __mako_require__.loadScript('{}', (e) => e.type === 'load' ? resolve() : reject( } } - pub(crate) fn create_provide_share_module(provide_share_info: ConsumeShareInfo) -> Module { + pub(crate) fn create_consume_share_module(consume_share_info: ConsumeShareInfo) -> Module { Module { is_entry: false, - id: provide_share_info.module_id.as_str().into(), + id: consume_share_info.module_id.as_str().into(), info: Some(ModuleInfo { - deps: provide_share_info.deps.clone(), - resolved_resource: Some(ResolverResource::ConsumeShare(provide_share_info.clone())), + deps: consume_share_info.deps.clone(), + resolved_resource: Some(ResolverResource::ConsumeShare(consume_share_info.clone())), federation: Some(FedereationModuleType::ConsumeShare), module_system: crate::module::ModuleSystem::Custom, ..Default::default() @@ -386,7 +386,7 @@ __mako_require__.loadScript('{}', (e) => e.type === 'load' ? resolve() : reject( } } - pub(crate) fn create_consume_share_module(consume_share_info: ProvideShareInfo) -> Module { + pub(crate) fn create_provide_share_module(provide_share_info: ProvideShareInfo) -> Module { todo!() } } diff --git a/crates/mako/src/generate/chunk_pot/ast_impl.rs b/crates/mako/src/generate/chunk_pot/ast_impl.rs index 0c187d384..28939e061 100644 --- a/crates/mako/src/generate/chunk_pot/ast_impl.rs +++ b/crates/mako/src/generate/chunk_pot/ast_impl.rs @@ -288,7 +288,7 @@ fn render_entry_chunk_js_without_full_hash( let mut ast = { crate::mako_profile_scope!("parse_runtime_entry"); - let runtime_content = runtime_code(context)?; + let runtime_content = runtime_code(chunk, context)?; JsAst::build( "_mako_internal/runtime_entry.js", diff --git a/crates/mako/src/generate/chunk_pot/str_impl.rs b/crates/mako/src/generate/chunk_pot/str_impl.rs index 1cfa7edeb..e423be13c 100644 --- a/crates/mako/src/generate/chunk_pot/str_impl.rs +++ b/crates/mako/src/generate/chunk_pot/str_impl.rs @@ -76,7 +76,8 @@ pub(super) fn render_entry_js_chunk( lines.push(init_install_css_chunk); lines.push(format!("var e = \"{}\";", chunk_root_module_id)); - let runtime_content = runtime_code(context)?.replace("_%full_hash%_", &hmr_hash.to_string()); + let runtime_content = + runtime_code(chunk, context)?.replace("_%full_hash%_", &hmr_hash.to_string()); let entry_prefix_code = "!(function(){\n"; diff --git a/crates/mako/src/generate/chunk_pot/util.rs b/crates/mako/src/generate/chunk_pot/util.rs index 13576f080..9c7e4ff15 100644 --- a/crates/mako/src/generate/chunk_pot/util.rs +++ b/crates/mako/src/generate/chunk_pot/util.rs @@ -22,6 +22,7 @@ use twox_hash::XxHash64; use crate::ast::sourcemap::build_source_map_to_buf; use crate::compiler::Context; use crate::config::Mode; +use crate::generate::chunk::Chunk; use crate::generate::chunk_pot::ChunkPot; use crate::generate::runtime::AppRuntimeTemplate; use crate::module::{relative_to_root, Module, ModuleAst}; @@ -94,7 +95,7 @@ pub(crate) fn empty_module_fn_expr() -> FnExpr { } } -pub(crate) fn runtime_code(context: &Arc) -> Result { +pub(crate) fn runtime_code(entry_chunk: &Chunk, context: &Arc) -> Result { let umd = context.config.umd.clone(); let chunk_graph = context.chunk_graph.read().unwrap(); let has_dynamic_chunks = chunk_graph.get_all_chunks().len() > 1; @@ -124,7 +125,9 @@ pub(crate) fn runtime_code(context: &Arc) -> Result { let app_runtime = app_runtime.render_once()?; let app_runtime = app_runtime.replace( "// __inject_runtime_code__", - &context.plugin_driver.runtime_plugins_code(context)?, + &context + .plugin_driver + .runtime_plugins_code(entry_chunk, context)?, ); Ok(app_runtime) } diff --git a/crates/mako/src/plugin.rs b/crates/mako/src/plugin.rs index 092493317..6c2c842df 100644 --- a/crates/mako/src/plugin.rs +++ b/crates/mako/src/plugin.rs @@ -12,6 +12,7 @@ use crate::ast::file::{Content, File}; use crate::build::analyze_deps::ResolvedDep; use crate::compiler::{Args, Compiler, Context}; use crate::config::Config; +use crate::generate::chunk::Chunk; use crate::generate::chunk_graph::ChunkGraph; use crate::generate::generate_chunks::ChunkFile; use crate::module::{Dependency, ModuleAst, ModuleId}; @@ -162,7 +163,11 @@ pub trait Plugin: Any + Send + Sync { Ok(()) } - fn runtime_plugins(&self, _context: &Arc) -> Result> { + fn runtime_plugins( + &self, + _entry_chunk: &Chunk, + _context: &Arc, + ) -> Result> { Ok(Vec::new()) } @@ -383,10 +388,14 @@ impl PluginDriver { Ok(()) } - pub fn runtime_plugins_code(&self, context: &Arc) -> Result { + pub fn runtime_plugins_code( + &self, + entry_chunk: &Chunk, + context: &Arc, + ) -> Result { let mut plugins = Vec::new(); for plugin in &self.plugins { - plugins.extend(plugin.runtime_plugins(context)?); + plugins.extend(plugin.runtime_plugins(entry_chunk, context)?); } Ok(plugins.join("\n")) } diff --git a/crates/mako/src/plugins/async_runtime.rs b/crates/mako/src/plugins/async_runtime.rs index 02729e977..294d38d80 100644 --- a/crates/mako/src/plugins/async_runtime.rs +++ b/crates/mako/src/plugins/async_runtime.rs @@ -3,6 +3,7 @@ use std::sync::Arc; use anyhow; use crate::compiler::Context; +use crate::generate::chunk::Chunk; use crate::plugin::Plugin; pub struct AsyncRuntimePlugin {} @@ -12,7 +13,11 @@ impl Plugin for AsyncRuntimePlugin { "async_runtime" } - fn runtime_plugins(&self, context: &Arc) -> anyhow::Result> { + fn runtime_plugins( + &self, + _entry_chunk: &Chunk, + context: &Arc, + ) -> anyhow::Result> { if context .module_graph .read() diff --git a/crates/mako/src/plugins/central_ensure.rs b/crates/mako/src/plugins/central_ensure.rs index 6c2c31f5e..5b5f832f2 100644 --- a/crates/mako/src/plugins/central_ensure.rs +++ b/crates/mako/src/plugins/central_ensure.rs @@ -5,6 +5,7 @@ use std::sync::Arc; use anyhow::anyhow; use crate::compiler::Context; +use crate::generate::chunk::Chunk; use crate::module::generate_module_id; use crate::plugin::Plugin; @@ -51,7 +52,11 @@ impl Plugin for CentralChunkEnsure { fn name(&self) -> &str { "dev_ensure2" } - fn runtime_plugins(&self, context: &Arc) -> anyhow::Result> { + fn runtime_plugins( + &self, + _entry_chunk: &Chunk, + context: &Arc, + ) -> anyhow::Result> { let chunk_async_map = module_ensure_map(context)?; // TODO: compress the map to reduce duplicated chunk ids diff --git a/crates/mako/src/plugins/hmr_runtime.rs b/crates/mako/src/plugins/hmr_runtime.rs index 2ed9b9a20..32c60e694 100644 --- a/crates/mako/src/plugins/hmr_runtime.rs +++ b/crates/mako/src/plugins/hmr_runtime.rs @@ -3,6 +3,7 @@ use std::sync::Arc; use anyhow; use crate::compiler::Context; +use crate::generate::chunk::Chunk; use crate::plugin::Plugin; pub struct HMRRuntimePlugin {} @@ -12,7 +13,11 @@ impl Plugin for HMRRuntimePlugin { "hmr_runtime" } - fn runtime_plugins(&self, context: &Arc) -> anyhow::Result> { + fn runtime_plugins( + &self, + _entry_chunk: &Chunk, + context: &Arc, + ) -> anyhow::Result> { if context.args.watch { Ok(vec![include_str!("hmr_runtime/hmr_runtime.js").to_string()]) } else { diff --git a/crates/mako/src/plugins/module_federation.rs b/crates/mako/src/plugins/module_federation.rs index f0f129269..5f5fe3500 100644 --- a/crates/mako/src/plugins/module_federation.rs +++ b/crates/mako/src/plugins/module_federation.rs @@ -1,19 +1,24 @@ +use std::collections::HashMap; use std::path::Path; use std::sync::{Arc, RwLock}; use anyhow::Result; use constants::{FEDERATION_REMOTE_MODULE_PREFIX, FEDERATION_REMOTE_REFERENCE_PREFIX}; -use provide_shared::SharedDependencies; +use provide_shared::ProvideSharedItem; use crate::ast::file::Content; use crate::build::analyze_deps::ResolvedDep; use crate::compiler::{Args, Context}; use crate::config::module_federation::ModuleFederationConfig; use crate::config::Config; +use crate::generate::chunk::Chunk; +use crate::generate::chunk_graph::ChunkGraph; +use crate::module_graph::ModuleGraph; use crate::plugin::{Plugin, PluginGenerateEndParams, PluginResolveIdParams}; use crate::resolve::ResolverResource; mod constants; +mod consume_shared; mod container; mod container_reference; mod manifest; @@ -22,14 +27,14 @@ mod util; pub struct ModuleFederationPlugin { pub config: ModuleFederationConfig, - shared_dependencies: RwLock, + provide_shared_map: RwLock>>, } impl ModuleFederationPlugin { pub fn new(config: ModuleFederationConfig) -> Self { Self { config, - shared_dependencies: RwLock::new(SharedDependencies::new()), + provide_shared_map: RwLock::new(HashMap::new()), } } } @@ -77,12 +82,12 @@ impl Plugin for ModuleFederationPlugin { } } - fn runtime_plugins(&self, context: &Arc) -> Result> { + fn runtime_plugins(&self, entry_chunk: &Chunk, context: &Arc) -> Result> { Ok(vec![ self.get_federation_runtime_code(), self.get_container_references_code(context), self.get_provide_sharing_code(context), - self.get_consume_sharing_code(context), + self.get_consume_sharing_code(entry_chunk, context), self.get_federation_exposes_library_code(), ]) } @@ -98,7 +103,7 @@ impl Plugin for ModuleFederationPlugin { if let Ok(Some(_)) = remote_module.as_ref() { remote_module } else { - self.resolve_provide_share(source, importer, params, context) + self.resolve_to_consume_share(source, importer, params, context) } } @@ -108,7 +113,17 @@ impl Plugin for ModuleFederationPlugin { } fn after_resolve(&self, resolved_dep: &ResolvedDep, _context: &Arc) -> Result<()> { - self.collect_provide_shared_map(resolved_dep); + self.collect_provide_shared(resolved_dep); + Ok(()) + } + + fn optimize_chunk( + &self, + chunk_graph: &mut ChunkGraph, + module_graph: &mut ModuleGraph, + _context: &Arc, + ) -> Result<()> { + self.connect_provide_shared_to_container(chunk_graph, module_graph); Ok(()) } } diff --git a/crates/mako/src/plugins/module_federation/consume_shared.rs b/crates/mako/src/plugins/module_federation/consume_shared.rs new file mode 100644 index 000000000..51a5d8019 --- /dev/null +++ b/crates/mako/src/plugins/module_federation/consume_shared.rs @@ -0,0 +1,187 @@ +use std::collections::{HashMap, HashSet}; +use std::sync::Arc; + +use pathdiff::diff_paths; + +use super::constants::FEDERATION_SHARED_REFERENCE_PREFIX; +use super::ModuleFederationPlugin; +use crate::build::analyze_deps::{AnalyzeDepsResult, ResolvedDep}; +use crate::compiler::Context; +use crate::generate::chunk::{Chunk, ChunkType}; +use crate::module::{Dependency, ResolveType}; +use crate::plugin::PluginResolveIdParams; +use crate::resolve::{do_resolve, ConsumeShareInfo, ResolverResource, ResolverType}; + +impl ModuleFederationPlugin { + pub(super) fn get_consume_sharing_code( + &self, + entry_chunk: &Chunk, + context: &Context, + ) -> String { + let module_graph = context.module_graph.read().unwrap(); + let chunk_graph = context.chunk_graph.read().unwrap(); + let share_dependencies = self.provide_shared_map.read().unwrap(); + + let consume_modules_chunk_map: HashMap> = chunk_graph + .installable_descendants_chunk(&entry_chunk.id) + .into_iter() + .filter_map(|c| { + let modules = chunk_graph + .chunk(&c) + .unwrap() + .modules + .iter() + .filter_map(|m| { + if m.id.starts_with(FEDERATION_SHARED_REFERENCE_PREFIX) { + Some(m.id.clone()) + } else { + None + } + }) + .collect::>(); + if modules.is_empty() { + None + } else { + Some((c.id, modules)) + } + }) + .collect(); + let consume_shared_module_ids = + consume_modules_chunk_map + .iter() + .fold(HashSet::<&String>::new(), |mut acc, cur| { + acc.extend(cur.1.iter()); + acc + }); + let consume_shared_modules = consume_shared_module_ids + .iter() + .map(|id| module_graph.get_module(&id.as_str().into()).unwrap()) + .collect::>(); + let module_to_handler_mapping_code = consume_shared_modules + .iter() + .map(|s| { + let resolved_resource = s.info.as_ref().unwrap().resolved_resource.as_ref().unwrap(); + let module_full_path = match resolved_resource { + ResolverResource::ConsumeShare(info) => info.deps.resolved_deps[0].resolver_resource.get_resolved_path(), + _ => panic!("{} is not a shared module", resolved_resource.get_resolved_path()) + }; + let module_relative_path = + diff_paths(&module_full_path, &context.root) + .unwrap() + .to_string_lossy() + .to_string(); + + let module_in_chunk = chunk_graph.get_chunk_for_module(&module_full_path.as_str().into()).unwrap(); + + let getter = match &module_in_chunk.chunk_type { + ChunkType::Entry(_, _, false) | ChunkType::Worker(_) => { + format!( + r#"() => (() => requireModule("{module_relative_path}"))"# + ) + }, + ChunkType::Async + | ChunkType::Sync + | ChunkType::Entry(_, _, true) + => { + let dependency_chunks = chunk_graph.sync_dependencies_chunk(&module_in_chunk.id); + format!( + r#"() => (Promise.all([{}]).then(() => requireModule("{module_relative_path}")))"#, + [dependency_chunks, vec![module_in_chunk.id.clone()]].concat().iter().map(|e| format!(r#"requireModule.ensure("{}")"#, e.id)).collect::>().join(",") + ) + }, + ChunkType::Runtime => panic!("mf shared dependency should not bundled to runtime chunk") + }; + + let share_dependency = share_dependencies.get(&s.id.id).unwrap().first().unwrap(); + format!( + r#""{shared_consume_id}": {{ + getter: {getter}, + shareInfo: {{ shareConfig: {share_config} }}, + shareKey: "{share_key}" + }}"#, + shared_consume_id = s.id.id, + share_config = serde_json::to_string(&share_dependency.shared_config).unwrap(), + share_key = share_dependency.share_key + + ) + }) + .collect::>() + .join(","); + + let chunk_mapping_code = serde_json::to_string(&consume_modules_chunk_map).unwrap(); + format!( + r#" +/* mako/runtime/federation consumes */ +!(() => {{ + var installedModules = {{}}; + var moduleToHandlerMapping = {{{module_to_handler_mapping_code}}}; + + var chunkMapping = {chunk_mapping_code}; + requireModule.chunkEnsures.consumes = (chunkId, promises) => {{ + requireModule.federation.bundlerRuntime.consumes({{ + chunkMapping: chunkMapping, + installedModules: installedModules, + chunkId: chunkId, + moduleToHandlerMapping: moduleToHandlerMapping, + promises: promises, + webpackRequire: requireModule + }}); + }} +}})();"# + ) + } + + pub(super) fn resolve_to_consume_share( + &self, + source: &str, + importer: &str, + params: &PluginResolveIdParams, + context: &Arc, + ) -> Result, anyhow::Error> { + if let Some(shared) = self.config.shared.as_ref() + && let Some(shared_info) = shared.get(source) + { + let resolver = if params.dep.resolve_type == ResolveType::Require { + context.resolvers.get(&ResolverType::Cjs) + } else if params.dep.resolve_type == ResolveType::Css { + context.resolvers.get(&ResolverType::Css) + } else { + context.resolvers.get(&ResolverType::Esm) + } + .unwrap(); + let resolver_resource = + do_resolve(importer, source, resolver, Some(&context.config.externals))?; + return Ok(Some(ResolverResource::ConsumeShare(ConsumeShareInfo { + eager: shared_info.eager, + module_id: format!( + "{}{}/{}/{}", + FEDERATION_SHARED_REFERENCE_PREFIX, shared_info.shared_scope, source, source + ), + name: source.to_string(), + share_scope: shared_info.shared_scope.clone(), + version: resolver_resource.get_pkg_info().unwrap().version.unwrap(), + full_path: format!( + "{}{}/{}/{}", + FEDERATION_SHARED_REFERENCE_PREFIX, shared_info.shared_scope, source, source + ), + deps: AnalyzeDepsResult { + resolved_deps: vec![ResolvedDep { + resolver_resource, + dependency: Dependency { + source: params.dep.source.clone(), + resolve_as: None, + resolve_type: ResolveType::DynamicImport(Default::default()), + order: params.dep.order, + span: params.dep.span, + }, + }], + missing_deps: HashMap::new(), + }, + singletion: shared_info.singleton, + required_version: shared_info.required_version.clone(), + strict_version: shared_info.strict_version, + }))); + } + Ok(None) + } +} diff --git a/crates/mako/src/plugins/module_federation/provide_shared.rs b/crates/mako/src/plugins/module_federation/provide_shared.rs index c445524ee..ace468bf4 100644 --- a/crates/mako/src/plugins/module_federation/provide_shared.rs +++ b/crates/mako/src/plugins/module_federation/provide_shared.rs @@ -1,22 +1,19 @@ use core::panic; -use std::collections::HashMap; -use std::sync::Arc; use pathdiff::diff_paths; use serde::Serialize; -use super::constants::FEDERATION_SHARED_REFERENCE_PREFIX; use super::ModuleFederationPlugin; -use crate::build::analyze_deps::{AnalyzeDepsResult, ResolvedDep}; +use crate::build::analyze_deps::ResolvedDep; use crate::compiler::Context; use crate::generate::chunk::ChunkType; -use crate::module::{Dependency, ModuleId, ResolveType}; -use crate::plugin::PluginResolveIdParams; -use crate::resolve::{do_resolve, ConsumeShareInfo, ResolverResource, ResolverType}; +use crate::generate::chunk_graph::ChunkGraph; +use crate::module::ModuleId; +use crate::module_graph::ModuleGraph; impl ModuleFederationPlugin { pub(super) fn get_provide_sharing_code(&self, context: &Context) -> String { - let provide_shared_map = self.shared_dependencies.read().unwrap(); + let provide_shared_map = self.provide_shared_map.read().unwrap(); let chunk_graph = context.chunk_graph.read().unwrap(); if provide_shared_map.is_empty() { @@ -108,105 +105,14 @@ impl ModuleFederationPlugin { } } - pub(super) fn get_consume_sharing_code(&self, context: &Context) -> String { - let module_graph = context.module_graph.read().unwrap(); - let chunk_graph = context.chunk_graph.read().unwrap(); - let share_dependencies = self.shared_dependencies.read().unwrap(); - let shared_modules = module_graph - .modules() - .into_iter() - .filter(|m| m.id.id.starts_with(FEDERATION_SHARED_REFERENCE_PREFIX)) - .collect::>(); - let mut shared_referenced_map: HashMap> = HashMap::new(); - let module_to_handler_mapping_code = shared_modules - .iter() - .map(|s| { - let resolved_resource = s.info.as_ref().unwrap().resolved_resource.as_ref().unwrap(); - let module_full_path = match resolved_resource { - ResolverResource::ConsumeShare(info) => info.deps.resolved_deps[0].resolver_resource.get_resolved_path(), - _ => panic!("{} is not a shared module", resolved_resource.get_resolved_path()) - }; - let module_relative_path = - diff_paths(&module_full_path, &context.root) - .unwrap() - .to_string_lossy() - .to_string(); - - let module_in_chunk = chunk_graph.get_chunk_for_module(&module_full_path.as_str().into()).unwrap(); - - chunk_graph.dependents_chunk(&module_in_chunk.id).iter().for_each(|c| { - let chunk = chunk_graph.chunk(c); - if let Some(chunk) = chunk.as_ref() && !matches!(chunk.chunk_type, ChunkType::Runtime | ChunkType::Entry(_, _, false)) { - let entry = shared_referenced_map.entry(c.id.clone()).or_default(); - entry.push(s.id.id.clone()); - } - }); - - let getter = match &module_in_chunk.chunk_type { - ChunkType::Entry(_, _, false) | ChunkType::Worker(_) => { - format!( - r#"() => (() => requireModule("{module_relative_path}"))"# - ) - }, - ChunkType::Async - | ChunkType::Sync - | ChunkType::Entry(_, _, true) - => { - let dependency_chunks = chunk_graph.sync_dependencies_chunk(&module_in_chunk.id); - format!( - r#"() => (Promise.all([{}]).then(() => requireModule("{module_relative_path}")))"#, - [dependency_chunks, vec![module_in_chunk.id.clone()]].concat().iter().map(|e| format!(r#"requireModule.ensure("{}")"#, e.id)).collect::>().join(",") - ) - }, - ChunkType::Runtime => panic!("mf shared dependency should not bundled to runtime chunk") - }; - - let share_dependency = share_dependencies.get(&s.id.id).unwrap().first().unwrap(); - format!( - r#""{shared_consume_id}": {{ - getter: {getter}, - shareInfo: {{ shareConfig: {share_config} }}, - shareKey: "{share_key}" - }}"#, - shared_consume_id = s.id.id, - share_config = serde_json::to_string(&share_dependency.shared_config).unwrap(), - share_key = share_dependency.share_key - - ) - }) - .collect::>() - .join(","); - let chunk_mapping_code = serde_json::to_string(&shared_referenced_map).unwrap(); - format!( - r#" -/* mako/runtime/federation consumes */ -!(() => {{ - var installedModules = {{}}; - var moduleToHandlerMapping = {{{module_to_handler_mapping_code}}}; - - var chunkMapping = {chunk_mapping_code}; - requireModule.chunkEnsures.consumes = (chunkId, promises) => {{ - requireModule.federation.bundlerRuntime.consumes({{ - chunkMapping: chunkMapping, - installedModules: installedModules, - chunkId: chunkId, - moduleToHandlerMapping: moduleToHandlerMapping, - promises: promises, - webpackRequire: requireModule - }}); - }} -}})();"# - ) - } - - pub(super) fn collect_provide_shared_map(&self, resolved_dep: &ResolvedDep) { + pub(super) fn collect_provide_shared(&self, resolved_dep: &ResolvedDep) { if let Some(shared) = self.config.shared.as_ref() && let Some(pkg_info) = resolved_dep.resolver_resource.get_pkg_info() && let Some(pkg_name) = pkg_info.name && let Some(shared_info) = shared.get(&pkg_name) && pkg_name == resolved_dep.dependency.source { - let mut provide_shared_map = self.shared_dependencies.write().unwrap(); + let mut provide_shared_map = self.provide_shared_map.write().unwrap(); let shared_items = provide_shared_map .entry(resolved_dep.resolver_resource.get_resolved_path()) .or_default(); @@ -228,58 +134,41 @@ impl ModuleFederationPlugin { } } - pub(super) fn resolve_provide_share( + pub(super) fn connect_provide_shared_to_container( &self, - source: &str, - importer: &str, - params: &PluginResolveIdParams, - context: &Arc, - ) -> Result, anyhow::Error> { - if let Some(shared) = self.config.shared.as_ref() - && let Some(shared_info) = shared.get(source) - { - let resolver = if params.dep.resolve_type == ResolveType::Require { - context.resolvers.get(&ResolverType::Cjs) - } else if params.dep.resolve_type == ResolveType::Css { - context.resolvers.get(&ResolverType::Css) - } else { - context.resolvers.get(&ResolverType::Esm) - } - .unwrap(); - let resolver_resource = - do_resolve(importer, source, resolver, Some(&context.config.externals))?; - return Ok(Some(ResolverResource::ConsumeShare(ConsumeShareInfo { - eager: shared_info.eager, - module_id: format!( - "{}{}/{}/{}", - FEDERATION_SHARED_REFERENCE_PREFIX, shared_info.shared_scope, source, source - ), - name: source.to_string(), - share_scope: shared_info.shared_scope.clone(), - version: resolver_resource.get_pkg_info().unwrap().version.unwrap(), - full_path: format!( - "{}{}/{}/{}", - FEDERATION_SHARED_REFERENCE_PREFIX, shared_info.shared_scope, source, source - ), - deps: AnalyzeDepsResult { - resolved_deps: vec![ResolvedDep { - resolver_resource, - dependency: Dependency { - source: params.dep.source.clone(), - resolve_as: None, - resolve_type: ResolveType::DynamicImport(Default::default()), - order: params.dep.order, - span: params.dep.span, - }, - }], - missing_deps: HashMap::new(), - }, - singletion: shared_info.singleton, - required_version: shared_info.required_version.clone(), - strict_version: shared_info.strict_version, - }))); - } - Ok(None) + chunk_graph: &mut ChunkGraph, + module_graph: &mut ModuleGraph, + ) { + let entry_chunks = chunk_graph + .get_chunks() + .into_iter() + .filter_map(|c| { + if matches!(c.chunk_type, ChunkType::Entry(_, _, false)) { + Some(c.id.clone()) + } else { + None + } + }) + .collect::>(); + + let provide_shared_map = self.provide_shared_map.read().unwrap(); + + let provide_shared_in_chunks = provide_shared_map + .iter() + .map(|m| { + chunk_graph + .get_chunk_for_module(&m.0.as_str().into()) + .unwrap() + .id + .clone() + }) + .collect::>(); + + entry_chunks.iter().for_each(|ec| { + provide_shared_in_chunks.iter().for_each(|c| { + chunk_graph.add_edge(ec, c); + }); + }); } } @@ -302,5 +191,3 @@ pub(super) struct SharedDepency { pub(super) singleton: bool, pub(super) required_version: Option, } - -pub(super) type SharedDependencies = HashMap>; diff --git a/crates/mako/src/plugins/progress.rs b/crates/mako/src/plugins/progress.rs index b68d3b304..a5c8ec959 100644 --- a/crates/mako/src/plugins/progress.rs +++ b/crates/mako/src/plugins/progress.rs @@ -7,6 +7,7 @@ use parking_lot::Mutex; use crate::ast::file::Content; use crate::compiler::Context; +use crate::generate::chunk::Chunk; use crate::plugin::{Plugin, PluginLoadParam}; /* @@ -278,7 +279,11 @@ impl Plugin for ProgressPlugin { Ok(()) } - fn runtime_plugins(&self, _context: &Arc) -> anyhow::Result> { + fn runtime_plugins( + &self, + _entry_chunk: &Chunk, + _context: &Arc, + ) -> anyhow::Result> { self.handler( 0.9, "runtime plugins".to_string(), diff --git a/crates/mako/src/plugins/runtime.rs b/crates/mako/src/plugins/runtime.rs index dedd7d18a..7bc787ba3 100644 --- a/crates/mako/src/plugins/runtime.rs +++ b/crates/mako/src/plugins/runtime.rs @@ -3,6 +3,7 @@ use std::sync::Arc; use anyhow::{anyhow, Result}; use crate::compiler::Context; +use crate::generate::chunk::Chunk; use crate::generate::swc_helpers::SwcHelpers; use crate::module::ModuleId; use crate::plugin::Plugin; @@ -14,7 +15,7 @@ impl Plugin for MakoRuntime { "mako/runtime" } - fn runtime_plugins(&self, context: &Arc) -> Result> { + fn runtime_plugins(&self, _entry_chunk: &Chunk, context: &Arc) -> Result> { let plugins = vec![ self.public_path(context), self.helper_runtime(context).unwrap(), diff --git a/crates/mako/src/plugins/ssu.rs b/crates/mako/src/plugins/ssu.rs index 83a683c13..cf0c10307 100644 --- a/crates/mako/src/plugins/ssu.rs +++ b/crates/mako/src/plugins/ssu.rs @@ -18,7 +18,7 @@ use crate::config::{ AllowChunks, ChunkGroup, CodeSplitting, CodeSplittingAdvancedOptions, CodeSplittingStrategy, CodeSplittingStrategyOptions, Config, }; -use crate::generate::chunk::ChunkType; +use crate::generate::chunk::{Chunk, ChunkType}; use crate::generate::chunk_pot::util::{hash_hashmap, hash_vec}; use crate::generate::generate_chunks::{ChunkFile, ChunkFileType}; use crate::generate::transform::transform_modules; @@ -258,8 +258,8 @@ let patch = require._su_patch(); console.log(patch); try{{ {} -}}catch(e){{ -//ignore the error +}}catch(e){{ +//ignore the error }} module.export = Promise.all( patch.map((d)=>__mako_require__.ensure(d)) @@ -554,7 +554,11 @@ module.export = Promise.all( Ok(()) } - fn runtime_plugins(&self, _context: &Arc) -> Result> { + fn runtime_plugins( + &self, + _entry_chunk: &Chunk, + _context: &Arc, + ) -> Result> { if *self.cache_valid.lock().unwrap() { let cache = self.cached_state.lock().unwrap(); diff --git a/crates/mako/src/plugins/wasm_runtime.rs b/crates/mako/src/plugins/wasm_runtime.rs index 9feb48973..cdd9bfef1 100644 --- a/crates/mako/src/plugins/wasm_runtime.rs +++ b/crates/mako/src/plugins/wasm_runtime.rs @@ -3,6 +3,7 @@ use std::sync::Arc; use anyhow; use crate::compiler::Context; +use crate::generate::chunk::Chunk; use crate::plugin::Plugin; pub struct WasmRuntimePlugin {} @@ -12,7 +13,11 @@ impl Plugin for WasmRuntimePlugin { "wasm_runtime" } - fn runtime_plugins(&self, context: &Arc) -> anyhow::Result> { + fn runtime_plugins( + &self, + _entry_chunk: &Chunk, + context: &Arc, + ) -> anyhow::Result> { if context .assets_info .lock() From 9f3ef7800932bc3b3264b91be8e2c3ae39479393 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Fri, 10 Jan 2025 11:13:03 +0800 Subject: [PATCH 27/68] fix: runtime template and remove some useless codes --- crates/mako/src/build.rs | 25 +++---- crates/mako/src/plugins/module_federation.rs | 3 +- .../module_federation/consume_shared.rs | 8 +-- .../module_federation/container_reference.rs | 6 +- .../module_federation/provide_for_consume.rs | 43 ++++++++++++ .../module_federation/provide_shared.rs | 67 +++---------------- crates/mako/src/resolve.rs | 3 +- crates/mako/src/resolve/resource.rs | 27 ++------ crates/mako/templates/app_runtime.stpl | 2 +- .../javascript.require-context/lazy-case.js | 2 +- .../javascript.require-context/sync-case.js | 2 +- 11 files changed, 81 insertions(+), 107 deletions(-) create mode 100644 crates/mako/src/plugins/module_federation/provide_for_consume.rs diff --git a/crates/mako/src/build.rs b/crates/mako/src/build.rs index 5b463fb06..b1dff558b 100644 --- a/crates/mako/src/build.rs +++ b/crates/mako/src/build.rs @@ -18,7 +18,7 @@ use crate::compiler::{Compiler, Context}; use crate::generate::chunk_pot::util::hash_hashmap; use crate::module::{FedereationModuleType, Module, ModuleAst, ModuleId, ModuleInfo}; use crate::plugin::NextBuildParam; -use crate::resolve::{ConsumeShareInfo, ProvideShareInfo, RemoteInfo, ResolverResource}; +use crate::resolve::{ConsumeSharedInfo, RemoteInfo, ResolverResource}; use crate::utils::thread_pool; #[derive(Debug, Error)] @@ -47,11 +47,11 @@ impl Compiler { }); }; - let build_consume_share_with_pool = |consume_share_info: ConsumeShareInfo| { + let build_consume_share_with_pool = |consume_share_info: ConsumeSharedInfo| { let rs = rs.clone(); let context = self.context.clone(); thread_pool::spawn(move || { - let result = Self::build_consume_share_module(consume_share_info, context.clone()); + let result = Self::build_shared_module(consume_share_info, context.clone()); rs.send(result).unwrap(); }); }; @@ -139,10 +139,7 @@ impl Compiler { ResolverResource::Remote(remote_into) => { Self::create_remote_module(remote_into) } - ResolverResource::ProviderShare(provide_share_info) => { - Self::create_provide_share_module(provide_share_info) - } - ResolverResource::ConsumeShare(consume_share_info) => { + ResolverResource::Shared(consume_share_info) => { count += 1; build_consume_share_with_pool(consume_share_info.clone()); Self::create_empty_module(&dep_module_id) @@ -288,9 +285,9 @@ __mako_require__.loadScript('{}', (e) => e.type === 'load' ? resolve() : reject( result } } - pub fn build_consume_share_module( - consume_share_info: ConsumeShareInfo, - context: Arc, + pub fn build_shared_module( + consume_share_info: ConsumeSharedInfo, + _context: Arc, ) -> Result { Ok(Self::create_consume_share_module(consume_share_info)) } @@ -371,13 +368,13 @@ __mako_require__.loadScript('{}', (e) => e.type === 'load' ? resolve() : reject( } } - pub(crate) fn create_consume_share_module(consume_share_info: ConsumeShareInfo) -> Module { + pub(crate) fn create_consume_share_module(consume_share_info: ConsumeSharedInfo) -> Module { Module { is_entry: false, id: consume_share_info.module_id.as_str().into(), info: Some(ModuleInfo { deps: consume_share_info.deps.clone(), - resolved_resource: Some(ResolverResource::ConsumeShare(consume_share_info.clone())), + resolved_resource: Some(ResolverResource::Shared(consume_share_info.clone())), federation: Some(FedereationModuleType::ConsumeShare), module_system: crate::module::ModuleSystem::Custom, ..Default::default() @@ -385,8 +382,4 @@ __mako_require__.loadScript('{}', (e) => e.type === 'load' ? resolve() : reject( side_effects: true, } } - - pub(crate) fn create_provide_share_module(provide_share_info: ProvideShareInfo) -> Module { - todo!() - } } diff --git a/crates/mako/src/plugins/module_federation.rs b/crates/mako/src/plugins/module_federation.rs index 5f5fe3500..4d458218a 100644 --- a/crates/mako/src/plugins/module_federation.rs +++ b/crates/mako/src/plugins/module_federation.rs @@ -22,12 +22,13 @@ mod consume_shared; mod container; mod container_reference; mod manifest; +mod provide_for_consume; mod provide_shared; mod util; pub struct ModuleFederationPlugin { pub config: ModuleFederationConfig, - provide_shared_map: RwLock>>, + provide_shared_map: RwLock>, } impl ModuleFederationPlugin { diff --git a/crates/mako/src/plugins/module_federation/consume_shared.rs b/crates/mako/src/plugins/module_federation/consume_shared.rs index 51a5d8019..a172d8a88 100644 --- a/crates/mako/src/plugins/module_federation/consume_shared.rs +++ b/crates/mako/src/plugins/module_federation/consume_shared.rs @@ -10,7 +10,7 @@ use crate::compiler::Context; use crate::generate::chunk::{Chunk, ChunkType}; use crate::module::{Dependency, ResolveType}; use crate::plugin::PluginResolveIdParams; -use crate::resolve::{do_resolve, ConsumeShareInfo, ResolverResource, ResolverType}; +use crate::resolve::{do_resolve, ConsumeSharedInfo, ResolverResource, ResolverType}; impl ModuleFederationPlugin { pub(super) fn get_consume_sharing_code( @@ -62,7 +62,7 @@ impl ModuleFederationPlugin { .map(|s| { let resolved_resource = s.info.as_ref().unwrap().resolved_resource.as_ref().unwrap(); let module_full_path = match resolved_resource { - ResolverResource::ConsumeShare(info) => info.deps.resolved_deps[0].resolver_resource.get_resolved_path(), + ResolverResource::Shared(info) => info.deps.resolved_deps[0].resolver_resource.get_resolved_path(), _ => panic!("{} is not a shared module", resolved_resource.get_resolved_path()) }; let module_relative_path = @@ -92,7 +92,7 @@ impl ModuleFederationPlugin { ChunkType::Runtime => panic!("mf shared dependency should not bundled to runtime chunk") }; - let share_dependency = share_dependencies.get(&s.id.id).unwrap().first().unwrap(); + let share_dependency = share_dependencies.get(&s.id.id).unwrap(); format!( r#""{shared_consume_id}": {{ getter: {getter}, @@ -151,7 +151,7 @@ impl ModuleFederationPlugin { .unwrap(); let resolver_resource = do_resolve(importer, source, resolver, Some(&context.config.externals))?; - return Ok(Some(ResolverResource::ConsumeShare(ConsumeShareInfo { + return Ok(Some(ResolverResource::Shared(ConsumeSharedInfo { eager: shared_info.eager, module_id: format!( "{}{}/{}/{}", diff --git a/crates/mako/src/plugins/module_federation/container_reference.rs b/crates/mako/src/plugins/module_federation/container_reference.rs index adc6679b9..bd36e2c67 100644 --- a/crates/mako/src/plugins/module_federation/container_reference.rs +++ b/crates/mako/src/plugins/module_federation/container_reference.rs @@ -48,7 +48,7 @@ impl ModuleFederationPlugin { .or_default(); remote_info.push(&remote_module.share_scope); remote_info.push(&remote_module.sub_path); - remote_info.push(&remote_module.external_refenrence_id); + remote_info.push(&remote_module.external_reference_id); let external_info = id_to_remote_map.entry(m.id.id.as_str()).or_default(); @@ -56,7 +56,7 @@ impl ModuleFederationPlugin { external_info.push(RemoteExternal { name: remote_module.name.clone(), external_type: remote_module.external_type.clone(), - external_module_id: remote_module.external_refenrence_id.clone(), + external_module_id: remote_module.external_reference_id.clone(), }); } } @@ -100,7 +100,7 @@ impl ModuleFederationPlugin { remotes.get(&source_parts.0).map(|_remote| { ResolverResource::Remote(RemoteInfo { module_id: format!("{}{}", FEDERATION_REMOTE_MODULE_PREFIX, source), - external_refenrence_id: format!( + external_reference_id: format!( "{}{}", FEDERATION_REMOTE_REFERENCE_PREFIX, source_parts.0 ), diff --git a/crates/mako/src/plugins/module_federation/provide_for_consume.rs b/crates/mako/src/plugins/module_federation/provide_for_consume.rs new file mode 100644 index 000000000..b26b15347 --- /dev/null +++ b/crates/mako/src/plugins/module_federation/provide_for_consume.rs @@ -0,0 +1,43 @@ +use super::ModuleFederationPlugin; +use crate::generate::chunk::ChunkType; +use crate::generate::chunk_graph::ChunkGraph; +use crate::module_graph::ModuleGraph; + +impl ModuleFederationPlugin { + pub(super) fn connect_provide_shared_to_container( + &self, + chunk_graph: &mut ChunkGraph, + _module_graph: &mut ModuleGraph, + ) { + let entry_chunks = chunk_graph + .get_chunks() + .into_iter() + .filter_map(|c| { + if matches!(c.chunk_type, ChunkType::Entry(_, _, false)) { + Some(c.id.clone()) + } else { + None + } + }) + .collect::>(); + + let provide_shared_map = self.provide_shared_map.read().unwrap(); + + let provide_shared_in_chunks = provide_shared_map + .iter() + .map(|m| { + chunk_graph + .get_chunk_for_module(&m.0.as_str().into()) + .unwrap() + .id + .clone() + }) + .collect::>(); + + entry_chunks.iter().for_each(|ec| { + provide_shared_in_chunks.iter().for_each(|c| { + chunk_graph.add_edge(ec, c); + }); + }); + } +} diff --git a/crates/mako/src/plugins/module_federation/provide_shared.rs b/crates/mako/src/plugins/module_federation/provide_shared.rs index ace468bf4..6fd73c41c 100644 --- a/crates/mako/src/plugins/module_federation/provide_shared.rs +++ b/crates/mako/src/plugins/module_federation/provide_shared.rs @@ -7,9 +7,7 @@ use super::ModuleFederationPlugin; use crate::build::analyze_deps::ResolvedDep; use crate::compiler::Context; use crate::generate::chunk::ChunkType; -use crate::generate::chunk_graph::ChunkGraph; use crate::module::ModuleId; -use crate::module_graph::ModuleGraph; impl ModuleFederationPlugin { pub(super) fn get_provide_sharing_code(&self, context: &Context) -> String { @@ -24,11 +22,9 @@ impl ModuleFederationPlugin { r#"{{{}}}"#, provide_shared_map .iter() - .map(|(_, items)| format!( + .map(|(_, share_item)| format!( r#""{share_key}": [{infos}]"#, - infos = items - .iter() - .map(|share_item| { + infos = { let getter = { let module_id: ModuleId = share_item.file_path.as_str().into(); let module_in_chunk = @@ -68,10 +64,9 @@ impl ModuleFederationPlugin { scope = serde_json::to_string(&share_item.scope).unwrap(), share_config = serde_json::to_string(&share_item.shared_config).unwrap() ) - }) - .collect::>() - .join(","), - share_key = items[0].share_key + } +, + share_key = share_item.share_key )) .collect::>() .join(",") @@ -113,63 +108,23 @@ impl ModuleFederationPlugin { && pkg_name == resolved_dep.dependency.source { let mut provide_shared_map = self.provide_shared_map.write().unwrap(); - let shared_items = provide_shared_map + provide_shared_map .entry(resolved_dep.resolver_resource.get_resolved_path()) - .or_default(); - if shared_items.is_empty() { - shared_items.push(ProvideSharedItem { + .or_insert(ProvideSharedItem { share_key: pkg_name.clone(), version: pkg_info.version.clone(), scope: vec![shared_info.shared_scope.clone()], file_path: pkg_info.file_path.clone(), - shared_config: SharedDepency { + shared_config: SharedConfig { eager: shared_info.eager, strict_version: shared_info.strict_version, singleton: shared_info.singleton, required_version: pkg_info.version.clone(), fixed_dependencies: false, }, - }) - }; + }); } } - - pub(super) fn connect_provide_shared_to_container( - &self, - chunk_graph: &mut ChunkGraph, - module_graph: &mut ModuleGraph, - ) { - let entry_chunks = chunk_graph - .get_chunks() - .into_iter() - .filter_map(|c| { - if matches!(c.chunk_type, ChunkType::Entry(_, _, false)) { - Some(c.id.clone()) - } else { - None - } - }) - .collect::>(); - - let provide_shared_map = self.provide_shared_map.read().unwrap(); - - let provide_shared_in_chunks = provide_shared_map - .iter() - .map(|m| { - chunk_graph - .get_chunk_for_module(&m.0.as_str().into()) - .unwrap() - .id - .clone() - }) - .collect::>(); - - entry_chunks.iter().for_each(|ec| { - provide_shared_in_chunks.iter().for_each(|c| { - chunk_graph.add_edge(ec, c); - }); - }); - } } #[derive(Debug)] @@ -177,13 +132,13 @@ pub(super) struct ProvideSharedItem { pub(super) share_key: String, pub(super) version: Option, pub(super) scope: Vec, - pub(super) shared_config: SharedDepency, + pub(super) shared_config: SharedConfig, pub(super) file_path: String, } #[derive(Serialize, Debug)] #[serde(rename_all = "camelCase")] -pub(super) struct SharedDepency { +pub(super) struct SharedConfig { #[serde(default)] pub(super) fixed_dependencies: bool, pub(super) eager: bool, diff --git a/crates/mako/src/resolve.rs b/crates/mako/src/resolve.rs index e85c77568..20cb5259a 100644 --- a/crates/mako/src/resolve.rs +++ b/crates/mako/src/resolve.rs @@ -14,8 +14,7 @@ mod resolution; mod resource; pub use resolution::Resolution; pub use resource::{ - ConsumeShareInfo, ExternalResource, ProvideShareInfo, RemoteInfo, ResolvedResource, - ResolverResource, + ConsumeSharedInfo, ExternalResource, RemoteInfo, ResolvedResource, ResolverResource, }; use crate::ast::file::parse_path; diff --git a/crates/mako/src/resolve/resource.rs b/crates/mako/src/resolve/resource.rs index 04f02f2ec..fa7858dc3 100644 --- a/crates/mako/src/resolve/resource.rs +++ b/crates/mako/src/resolve/resource.rs @@ -6,7 +6,7 @@ use crate::resolve::Resolution; #[derive(Debug, Clone)] pub struct RemoteInfo { pub module_id: String, - pub external_refenrence_id: String, + pub external_reference_id: String, pub external_type: String, pub sub_path: String, pub name: String, @@ -14,7 +14,7 @@ pub struct RemoteInfo { } #[derive(Debug, Clone)] -pub struct ConsumeShareInfo { +pub struct ConsumeSharedInfo { pub module_id: String, pub name: String, pub share_scope: String, @@ -27,21 +27,6 @@ pub struct ConsumeShareInfo { pub deps: AnalyzeDepsResult, } -#[derive(Debug, Clone)] -pub struct ProvideShareInfo { - pub module_id: String, - pub name: String, - pub import: String, - pub import_resolved: String, - pub share_key: String, - pub share_scope: String, - pub required_version: Option, - pub package_name: String, - pub eager: bool, - pub strict_version: bool, - pub singletion: bool, -} - #[derive(Debug, Clone)] pub struct ExternalResource { pub source: String, @@ -59,8 +44,7 @@ pub enum ResolverResource { Ignored(PathBuf), Virtual(PathBuf), Remote(RemoteInfo), - ProviderShare(ProvideShareInfo), - ConsumeShare(ConsumeShareInfo), + Shared(ConsumeSharedInfo), } impl ResolverResource { @@ -73,8 +57,7 @@ impl ResolverResource { ResolverResource::Ignored(path) => path.to_string_lossy().to_string(), ResolverResource::Virtual(path) => path.to_string_lossy().to_string(), ResolverResource::Remote(info) => info.module_id.to_string(), - ResolverResource::ProviderShare(info) => info.import_resolved.clone(), - ResolverResource::ConsumeShare(info) => info.full_path.clone(), + ResolverResource::Shared(info) => info.full_path.clone(), } } pub fn get_external(&self) -> Option { @@ -112,7 +95,7 @@ impl ResolverResource { .and_then(|v| v.as_str().map(|v| v.to_string())) }), }), - ResolverResource::ConsumeShare(info) => { + ResolverResource::Shared(info) => { info.deps.resolved_deps[0].resolver_resource.get_pkg_info() } _ => None, diff --git a/crates/mako/templates/app_runtime.stpl b/crates/mako/templates/app_runtime.stpl index c3785053e..4e8b7f115 100644 --- a/crates/mako/templates/app_runtime.stpl +++ b/crates/mako/templates/app_runtime.stpl @@ -66,7 +66,7 @@ function createRuntime(makoModules, entryModuleId, global) { }; // hasOwnProperty shorthand - requireModule.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)); + requireModule.o = function (obj, prop) { return (Object.prototype.hasOwnProperty.call(obj, prop));}; // required modules requireModule.m = makoModules; diff --git a/e2e/fixtures/javascript.require-context/lazy-case.js b/e2e/fixtures/javascript.require-context/lazy-case.js index 0bf50b04c..a7a909610 100644 --- a/e2e/fixtures/javascript.require-context/lazy-case.js +++ b/e2e/fixtures/javascript.require-context/lazy-case.js @@ -5,7 +5,7 @@ let context = require.context( "lazy", ); -it("lazy: no sub directorie", () => { +it("lazy: no sub directories", () => { it(" should get list of context files", () => { expect(context.keys().sort()).toStrictEqual(["./a.js", "./b.js"]); }); diff --git a/e2e/fixtures/javascript.require-context/sync-case.js b/e2e/fixtures/javascript.require-context/sync-case.js index 1f5778722..a2c100f64 100644 --- a/e2e/fixtures/javascript.require-context/sync-case.js +++ b/e2e/fixtures/javascript.require-context/sync-case.js @@ -1,6 +1,6 @@ let context = require.context("./context", false, /^\.\/(A|B)\.js$/i, "sync"); -it("sync: no sub directorie", () => { +it("sync: no sub directories", () => { it(" should get list of context files", () => { expect(context.keys().sort()).toStrictEqual(["./a.js", "./b.js"]); }); From 76ae8842ef2729490666e512eeb1042bf007fe95 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Mon, 13 Jan 2025 10:11:26 +0800 Subject: [PATCH 28/68] fix: mf dev server --- crates/mako/src/dev.rs | 9 ++++++++- examples/module-federation/host/mako.config.json | 3 +++ examples/module-federation/widget/mako.config.json | 3 +++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/crates/mako/src/dev.rs b/crates/mako/src/dev.rs index 3db00ff71..e88db069a 100644 --- a/crates/mako/src/dev.rs +++ b/crates/mako/src/dev.rs @@ -213,7 +213,14 @@ impl DevServer { .body(hyper::Body::empty()) .unwrap(); let res = staticfile.serve(req).await; - res.map_err(anyhow::Error::from) + res.map_or_else( + |e| Err(anyhow::Error::from(e)), + |mut res| { + res.headers_mut() + .insert(ACCESS_CONTROL_ALLOW_ORIGIN, "*".parse().unwrap()); + Ok(res) + }, + ) } } } diff --git a/examples/module-federation/host/mako.config.json b/examples/module-federation/host/mako.config.json index 32613cfd2..b051e4e7a 100644 --- a/examples/module-federation/host/mako.config.json +++ b/examples/module-federation/host/mako.config.json @@ -12,5 +12,8 @@ }, "experimental": { "centralEnsure": false + }, + "define": { + "process.env.SOCKET_SERVER": "\"http://localhost:3001\"" } } diff --git a/examples/module-federation/widget/mako.config.json b/examples/module-federation/widget/mako.config.json index bf3264f13..5640c758b 100644 --- a/examples/module-federation/widget/mako.config.json +++ b/examples/module-federation/widget/mako.config.json @@ -15,5 +15,8 @@ }, "experimental": { "centralEnsure": false + }, + "define": { + "process.env.SOCKET_SERVER": "\"http://localhost:3000\"" } } From d78087d3c9507978b6d74be54d33c851b8366a68 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Wed, 15 Jan 2025 10:47:13 +0800 Subject: [PATCH 29/68] fix: mf shared config --- crates/mako/src/config/module_federation.rs | 6 - crates/mako/src/plugins/module_federation.rs | 12 +- .../plugins/module_federation/container.rs | 52 ++------ .../module_federation/provide_shared.rs | 123 ++++++++++-------- 4 files changed, 82 insertions(+), 111 deletions(-) diff --git a/crates/mako/src/config/module_federation.rs b/crates/mako/src/config/module_federation.rs index 929c6a9ca..4b707cc30 100644 --- a/crates/mako/src/config/module_federation.rs +++ b/crates/mako/src/config/module_federation.rs @@ -37,12 +37,6 @@ pub struct SharedItemConfig { pub shared_scope: String, } -#[derive(Debug, Clone, Serialize, Deserialize)] -pub enum SharedVersion { - Version(String), - False, -} - #[derive(Debug, Clone, Serialize, Deserialize)] pub enum ShareStrategy { #[serde(rename = "version_first")] diff --git a/crates/mako/src/plugins/module_federation.rs b/crates/mako/src/plugins/module_federation.rs index 4d458218a..cbae1de94 100644 --- a/crates/mako/src/plugins/module_federation.rs +++ b/crates/mako/src/plugins/module_federation.rs @@ -47,9 +47,6 @@ impl Plugin for ModuleFederationPlugin { fn modify_config(&self, config: &mut Config, root: &Path, _args: &Args) -> Result<()> { self.add_container_entry(config, root); - - // self.append_remotes_externals(config); - Ok(()) } @@ -66,15 +63,10 @@ impl Plugin for ModuleFederationPlugin { } else { match content { Content::Js(js_content) => { - let entry_runtime_dep_path = self.prepare_entry_runtime_dep(&context.root); + let entry_runtime_dep_path = self.prepare_container_entry_dep(&context.root); js_content.content.insert_str( 0, - format!( - r#"import "{}"; -"#, - entry_runtime_dep_path - ) - .as_str(), + format!(r#"import "{}";"#, entry_runtime_dep_path).as_str(), ); Ok(Some(content.clone())) } diff --git a/crates/mako/src/plugins/module_federation/container.rs b/crates/mako/src/plugins/module_federation/container.rs index f9dbebd7a..939bff149 100644 --- a/crates/mako/src/plugins/module_federation/container.rs +++ b/crates/mako/src/plugins/module_federation/container.rs @@ -5,23 +5,18 @@ use std::path::Path; use serde::Serialize; use tracing::warn; -use super::constants::{ - FEDERATION_EXPOSE_CHUNK_PREFIX, FEDERATION_GLOBAL, FEDERATION_REMOTE_REFERENCE_PREFIX, -}; +use super::constants::{FEDERATION_EXPOSE_CHUNK_PREFIX, FEDERATION_GLOBAL}; use super::util::parse_remote; use super::ModuleFederationPlugin; -use crate::config::{ - Config, ExternalAdvanced, ExternalAdvancedSubpath, ExternalAdvancedSubpathRule, - ExternalAdvancedSubpathTarget, ExternalConfig, -}; +use crate::config::Config; use crate::module::md5_hash; use crate::visitors::mako_require::MAKO_REQUIRE; impl ModuleFederationPlugin { - pub(super) fn prepare_entry_runtime_dep(&self, root: &Path) -> String { - let entry_runtime_code = self.get_entry_runtime_code(); + pub(super) fn prepare_container_entry_dep(&self, root: &Path) -> String { + let container_content = self.get_container_content(); - let content_hash = md5_hash(&entry_runtime_code, 32); + let content_hash = md5_hash(&container_content, 32); let dep_path = root.join(format!( "node_modules/.federation/.entry.{}.js", @@ -32,14 +27,14 @@ impl ModuleFederationPlugin { fs::create_dir_all(dep_parent_path).unwrap(); } if !fs::exists(&dep_path).unwrap() { - fs::write(&dep_path, entry_runtime_code).unwrap(); + fs::write(&dep_path, container_content).unwrap(); } dep_path.to_string_lossy().to_string() } - pub(super) fn get_entry_runtime_code(&self) -> String { - let (plugins_imports, plugins_instantiations) = self.get_mf_runtime_plugins_code(); + pub(super) fn get_container_content(&self) -> String { + let (plugins_imports, plugins_instantiations) = self.get_mf_runtime_plugins_content(); format!( r#"import federation from "{federation_impl}"; @@ -163,7 +158,6 @@ export {{ get, init }}; remotes .iter() .map(|(alias, remote)| { - // FIXME: should not unwrap let (name, entry) = parse_remote(remote).unwrap(); RuntimeRemoteItem { name, @@ -207,8 +201,7 @@ export {{ get, init }}; if let Some(exposes) = self.config.exposes.as_ref() { if !exposes.is_empty() { format!( - r#"global["{}"] = requireModule(entryModuleId); -"#, + r#"global["{}"] = requireModule(entryModuleId);"#, self.config.name ) } else { @@ -219,31 +212,7 @@ export {{ get, init }}; } } - #[allow(dead_code)] - pub(super) fn append_remotes_externals(&self, config: &mut Config) { - if let Some(remotes) = &self.config.remotes { - remotes.iter().for_each(|remote| { - config.externals.insert( - format!("{}{}", FEDERATION_REMOTE_REFERENCE_PREFIX, remote.0), - ExternalConfig::Advanced(ExternalAdvanced { - root: remote.0.clone(), - script: parse_remote(remote.1).ok().map(|(_, url)| url.clone()), - module_type: None, - subpath: Some(ExternalAdvancedSubpath { - exclude: None, - rules: vec![ExternalAdvancedSubpathRule { - regex: "/.*".to_string(), - target: ExternalAdvancedSubpathTarget::Empty, - target_converter: None, - }], - }), - }), - ); - }); - } - } - - pub(super) fn get_mf_runtime_plugins_code(&self) -> (String, String) { + pub(super) fn get_mf_runtime_plugins_content(&self) -> (String, String) { let (imported_plugin_names, import_plugin_instantiations) = self.config.runtime_plugins.iter().enumerate().fold( (Vec::new(), Vec::new()), @@ -272,6 +241,7 @@ export {{ get, init }}; "#, ) }; + (plugins_imports, plugins_instantiations) } } diff --git a/crates/mako/src/plugins/module_federation/provide_shared.rs b/crates/mako/src/plugins/module_federation/provide_shared.rs index 6fd73c41c..3b5b10f4b 100644 --- a/crates/mako/src/plugins/module_federation/provide_shared.rs +++ b/crates/mako/src/plugins/module_federation/provide_shared.rs @@ -1,7 +1,7 @@ use core::panic; use pathdiff::diff_paths; -use serde::Serialize; +use serde::{Serialize, Serializer}; use super::ModuleFederationPlugin; use crate::build::analyze_deps::ResolvedDep; @@ -18,59 +18,62 @@ impl ModuleFederationPlugin { return "".to_string(); } - let provide_shared_map_code = format!( - r#"{{{}}}"#, - provide_shared_map - .iter() - .map(|(_, share_item)| format!( - r#""{share_key}": [{infos}]"#, - infos = { - let getter = { - let module_id: ModuleId = share_item.file_path.as_str().into(); - let module_in_chunk = - chunk_graph.get_chunk_for_module(&module_id).unwrap(); - let module_relative_path = - diff_paths(&share_item.file_path, &context.root) - .unwrap() - .to_string_lossy() - .to_string(); + let provide_shared_map_code = format!( + r#"{{{}}}"#, + provide_shared_map + .iter() + .filter_map(|(_, share_item)| { + let module_id: ModuleId = share_item.file_path.as_str().into(); + let module_in_chunk = chunk_graph.get_chunk_for_module(&module_id)?; + + let share_item_code = format!(r#""{share_key}": [{infos}]"#, + share_key = share_item.share_key, + infos = { + let getter = { + let module_relative_path = + diff_paths(&share_item.file_path, &context.root) + .unwrap() + .to_string_lossy() + .to_string(); - match &module_in_chunk.chunk_type { - ChunkType::Entry(_, _, false) | ChunkType::Worker(_) => { - format!( - r#"() => (() => requireModule("{module_relative_path}"))"# - ) - }, - ChunkType::Async - | ChunkType::Sync - | ChunkType::Entry(_, _, true) - => { - let dependency_chunks = chunk_graph.sync_dependencies_chunk(&module_in_chunk.id); - format!( - r#"() => (Promise.all([{}]).then(() => (() => requireModule("{module_relative_path}"))))"#, - [dependency_chunks, vec![module_in_chunk.id.clone()]].concat().iter().map(|e| format!(r#"requireModule.ensure("{}")"#, e.id)).collect::>().join(",") - ) - }, - // FIXME: - _ => panic!("mf shared dependency should not bundled to worker chunk, entries' shared chunk or runtime chunk") - } - }; - format!( - r#"{{ version: {version}, get: {getter}, scope: {scope}, shareConfig: {share_config} }}"#, - version = share_item - .version - .as_ref() - .map_or("false".to_string(), |v| format!(r#""{}""#, v)), - scope = serde_json::to_string(&share_item.scope).unwrap(), - share_config = serde_json::to_string(&share_item.shared_config).unwrap() - ) - } -, - share_key = share_item.share_key - )) - .collect::>() - .join(",") - ); + match &module_in_chunk.chunk_type { + ChunkType::Entry(_, _, false) | ChunkType::Worker(_) => { + format!( + r#"() => (() => requireModule("{module_relative_path}"))"# + ) + }, + ChunkType::Async + | ChunkType::Sync + | ChunkType::Entry(_, _, true) + => { + let dependency_chunks = chunk_graph.sync_dependencies_chunk(&module_in_chunk.id); + format!( + r#"() => (Promise.all([{}]).then(() => (() => requireModule("{module_relative_path}"))))"#, + [dependency_chunks, vec![module_in_chunk.id.clone()]] + .concat().iter().map(|e| format!(r#"requireModule.ensure("{}")"#, e.id)) + .collect::>().join(",") + ) + }, + // FIXME: + _ => panic!("mf shared dependency should not bundled to worker chunk, entries' shared chunk or runtime chunk") + } + }; + format!( + r#"{{ version: {version}, get: {getter}, scope: {scope}, shareConfig: {share_config} }}"#, + version = share_item + .version + .as_ref() + .map_or("false".to_string(), |v| format!(r#""{}""#, v)), + scope = serde_json::to_string(&share_item.scope).unwrap(), + share_config = serde_json::to_string(&share_item.shared_config).unwrap() + ) + }, + ); + Some(share_item_code)} + ) + .collect::>() + .join(",") + ); if let Some(shared) = self.config.shared.as_ref() && !shared.is_empty() @@ -119,7 +122,8 @@ impl ModuleFederationPlugin { eager: shared_info.eager, strict_version: shared_info.strict_version, singleton: shared_info.singleton, - required_version: pkg_info.version.clone(), + required_version: shared_info.required_version.clone(), + // FIXME: hard code now fixed_dependencies: false, }, }); @@ -144,5 +148,16 @@ pub(super) struct SharedConfig { pub(super) eager: bool, pub(super) strict_version: bool, pub(super) singleton: bool, + #[serde(serialize_with = "serialize_none_to_false")] pub(super) required_version: Option, } + +fn serialize_none_to_false( + t: &Option, + s: S, +) -> Result { + match t { + Some(t) => t.serialize(s), + None => s.serialize_bool(false), + } +} From dbd6a382b663a04d2add7c8e2bc9b7648162b70b Mon Sep 17 00:00:00 2001 From: xusd320 Date: Thu, 16 Jan 2025 15:02:13 +0800 Subject: [PATCH 30/68] feat: supports chunk group exclude --- crates/mako/src/config/code_splitting.rs | 4 ++++ crates/mako/src/generate/optimize_chunk.rs | 7 +++++++ crates/mako/src/plugins/ssu.rs | 1 + 3 files changed, 12 insertions(+) diff --git a/crates/mako/src/config/code_splitting.rs b/crates/mako/src/config/code_splitting.rs index d1175d72f..8411cafe0 100644 --- a/crates/mako/src/config/code_splitting.rs +++ b/crates/mako/src/config/code_splitting.rs @@ -91,6 +91,9 @@ pub struct ChunkGroup { #[serde(default)] // A string raw of regex pub test: Option, + // A string raw of regex + #[serde(default)] + pub exclude: Option, } impl Default for ChunkGroup { @@ -104,6 +107,7 @@ impl Default for ChunkGroup { name_suffix: None, min_package_size: None, test: None, + exclude: None, priority: i8::default(), } } diff --git a/crates/mako/src/generate/optimize_chunk.rs b/crates/mako/src/generate/optimize_chunk.rs index f37897402..1c4c9e2c6 100644 --- a/crates/mako/src/generate/optimize_chunk.rs +++ b/crates/mako/src/generate/optimize_chunk.rs @@ -175,6 +175,13 @@ impl Compiler { } } + // check exclude regex + if let Some(exclude) = &optimize_info.group_options.exclude { + if create_cached_regex(exclude).is_match(&module_id.id) { + continue; + } + } + // check min shared count of chunks if optimize_info.group_options.min_chunks > 1 && chunks diff --git a/crates/mako/src/plugins/ssu.rs b/crates/mako/src/plugins/ssu.rs index cf0c10307..6df62ef3e 100644 --- a/crates/mako/src/plugins/ssu.rs +++ b/crates/mako/src/plugins/ssu.rs @@ -185,6 +185,7 @@ impl Plugin for SUPlus { min_package_size: None, priority: 10, test: Some(r"[/\\]node_modules[/\\]".to_string()), + ..Default::default() }, ChunkGroup { name: "common".to_string(), From 4ba5bb3523c28c65916aaf12d62ecb5c368a8218 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Mon, 20 Jan 2025 14:43:35 +0800 Subject: [PATCH 31/68] feat: mf patch code splitting --- crates/mako/src/config/code_splitting.rs | 4 --- crates/mako/src/generate/optimize_chunk.rs | 13 ++++----- crates/mako/src/plugin.rs | 20 ++++++++++++- crates/mako/src/plugins/module_federation.rs | 8 +++++ .../plugins/module_federation/container.rs | 11 ++++++- .../src/plugins/module_federation/manifest.rs | 2 +- crates/mako/src/plugins/ssu.rs | 1 - .../module-federation/host/mako.config.json | 16 ++++++++-- .../widget/mako.config.bk.json | 29 ------------------- .../module-federation/widget/mako.config.json | 16 ++++++++-- 10 files changed, 71 insertions(+), 49 deletions(-) delete mode 100644 examples/module-federation/widget/mako.config.bk.json diff --git a/crates/mako/src/config/code_splitting.rs b/crates/mako/src/config/code_splitting.rs index 8411cafe0..d1175d72f 100644 --- a/crates/mako/src/config/code_splitting.rs +++ b/crates/mako/src/config/code_splitting.rs @@ -91,9 +91,6 @@ pub struct ChunkGroup { #[serde(default)] // A string raw of regex pub test: Option, - // A string raw of regex - #[serde(default)] - pub exclude: Option, } impl Default for ChunkGroup { @@ -107,7 +104,6 @@ impl Default for ChunkGroup { name_suffix: None, min_package_size: None, test: None, - exclude: None, priority: i8::default(), } } diff --git a/crates/mako/src/generate/optimize_chunk.rs b/crates/mako/src/generate/optimize_chunk.rs index 1c4c9e2c6..d3f42822c 100644 --- a/crates/mako/src/generate/optimize_chunk.rs +++ b/crates/mako/src/generate/optimize_chunk.rs @@ -26,7 +26,11 @@ impl Compiler { pub fn optimize_chunk(&self) { crate::mako_profile_function!(); debug!("optimize chunk"); - if let Some(optimize_options) = self.get_optimize_chunk_options() { + if let Some(mut optimize_options) = self.get_optimize_chunk_options() { + self.context + .plugin_driver + .after_optimize_chunk_options(&mut optimize_options) + .unwrap(); debug!("optimize options: {:?}", optimize_options); // stage: prepare let mut optimize_chunks_infos = optimize_options @@ -175,13 +179,6 @@ impl Compiler { } } - // check exclude regex - if let Some(exclude) = &optimize_info.group_options.exclude { - if create_cached_regex(exclude).is_match(&module_id.id) { - continue; - } - } - // check min shared count of chunks if optimize_info.group_options.min_chunks > 1 && chunks diff --git a/crates/mako/src/plugin.rs b/crates/mako/src/plugin.rs index 6c2c842df..0552f11e0 100644 --- a/crates/mako/src/plugin.rs +++ b/crates/mako/src/plugin.rs @@ -11,7 +11,7 @@ use swc_core::ecma::ast::Module; use crate::ast::file::{Content, File}; use crate::build::analyze_deps::ResolvedDep; use crate::compiler::{Args, Compiler, Context}; -use crate::config::Config; +use crate::config::{CodeSplittingAdvancedOptions, Config}; use crate::generate::chunk::Chunk; use crate::generate::chunk_graph::ChunkGraph; use crate::generate::generate_chunks::ChunkFile; @@ -187,6 +187,13 @@ pub trait Plugin: Any + Send + Sync { Ok(()) } + fn after_optimize_chunk_options( + &self, + _optimize_chunk_options: &mut CodeSplittingAdvancedOptions, + ) -> Result<()> { + Ok(()) + } + fn optimize_chunk( &self, _chunk_graph: &mut ChunkGraph, @@ -428,6 +435,17 @@ impl PluginDriver { Ok(()) } + pub fn after_optimize_chunk_options( + &self, + optimize_chunk_options: &mut CodeSplittingAdvancedOptions, + ) -> Result<()> { + for p in &self.plugins { + p.after_optimize_chunk_options(optimize_chunk_options)?; + } + + Ok(()) + } + pub fn optimize_chunk( &self, chunk_graph: &mut ChunkGraph, diff --git a/crates/mako/src/plugins/module_federation.rs b/crates/mako/src/plugins/module_federation.rs index cbae1de94..807e4ad23 100644 --- a/crates/mako/src/plugins/module_federation.rs +++ b/crates/mako/src/plugins/module_federation.rs @@ -119,4 +119,12 @@ impl Plugin for ModuleFederationPlugin { self.connect_provide_shared_to_container(chunk_graph, module_graph); Ok(()) } + + fn after_optimize_chunk_options( + &self, + optimize_chunk_options: &mut crate::config::CodeSplittingAdvancedOptions, + ) -> Result<()> { + self.patch_code_splitting(optimize_chunk_options); + Ok(()) + } } diff --git a/crates/mako/src/plugins/module_federation/container.rs b/crates/mako/src/plugins/module_federation/container.rs index 939bff149..63d3d7120 100644 --- a/crates/mako/src/plugins/module_federation/container.rs +++ b/crates/mako/src/plugins/module_federation/container.rs @@ -8,7 +8,7 @@ use tracing::warn; use super::constants::{FEDERATION_EXPOSE_CHUNK_PREFIX, FEDERATION_GLOBAL}; use super::util::parse_remote; use super::ModuleFederationPlugin; -use crate::config::Config; +use crate::config::{AllowChunks, Config}; use crate::module::md5_hash; use crate::visitors::mako_require::MAKO_REQUIRE; @@ -244,6 +244,15 @@ export {{ get, init }}; (plugins_imports, plugins_instantiations) } + + pub(crate) fn patch_code_splitting( + &self, + optimize_chunk_options: &mut crate::config::CodeSplittingAdvancedOptions, + ) { + optimize_chunk_options.groups.iter_mut().for_each(|group| { + group.allow_chunks = AllowChunks::Async; + }); + } } #[derive(Serialize)] diff --git a/crates/mako/src/plugins/module_federation/manifest.rs b/crates/mako/src/plugins/module_federation/manifest.rs index c461e98f5..69978d765 100644 --- a/crates/mako/src/plugins/module_federation/manifest.rs +++ b/crates/mako/src/plugins/module_federation/manifest.rs @@ -54,7 +54,7 @@ impl ModuleFederationPlugin { let exposes_sync_chunk_dependencies = exposes_sync_chunks.iter().fold(Vec::new(), |mut acc, cur| { let sync_deps = chunk_graph.sync_dependencies_chunk(cur); - acc.splice(0..sync_deps.len(), sync_deps); + acc.splice(..0, sync_deps); acc }); let all_exposes_sync_chunks = diff --git a/crates/mako/src/plugins/ssu.rs b/crates/mako/src/plugins/ssu.rs index 6df62ef3e..cf0c10307 100644 --- a/crates/mako/src/plugins/ssu.rs +++ b/crates/mako/src/plugins/ssu.rs @@ -185,7 +185,6 @@ impl Plugin for SUPlus { min_package_size: None, priority: 10, test: Some(r"[/\\]node_modules[/\\]".to_string()), - ..Default::default() }, ChunkGroup { name: "common".to_string(), diff --git a/examples/module-federation/host/mako.config.json b/examples/module-federation/host/mako.config.json index b051e4e7a..ec9229851 100644 --- a/examples/module-federation/host/mako.config.json +++ b/examples/module-federation/host/mako.config.json @@ -7,13 +7,25 @@ "remotes": { "widget": "mfWidget@http://localhost:3000/mfWidget.js" }, - "shared": { "react": {}, "react-dom": {} }, - "implementation": "/Users/xusd/codes/github/mako/packages/mako/node_modules/@module-federation/webpack-bundler-runtime" + "shared": { "react": {}, "react-dom": {} } }, "experimental": { "centralEnsure": false }, "define": { "process.env.SOCKET_SERVER": "\"http://localhost:3001\"" + }, + "codeSplitting": { + "strategy": "advanced", + "options": { + "groups": [ + { + "name": "vendor", + "allowChunks": "all", + "minSize": 1, + "test": "node_modules" + } + ] + } } } diff --git a/examples/module-federation/widget/mako.config.bk.json b/examples/module-federation/widget/mako.config.bk.json deleted file mode 100644 index 248058c4a..000000000 --- a/examples/module-federation/widget/mako.config.bk.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "entry": { - "app2": "./src/index.ts" - }, - "publicPath": "auto", - "moduleFederation": { - "name": "mfWidget", - "exposes": { - "./App1": "./src/App1.tsx", - "./App2": "./src/App2.tsx" - }, - "shared": { "react": {}, "react-dom": {} }, - "runtimePlugins": [], - "implementation": "/Users/xusd/codes/github/mako/packages/mako/node_modules/@module-federation/webpack-bundler-runtime" - }, - "codeSplitting": { - "strategy": "advanced", - "options": { - "groups": [ - { - "name": "vendor", - "allowChunks": "all", - "minSize": 1, - "test": "node_modules" - } - ] - } - } -} diff --git a/examples/module-federation/widget/mako.config.json b/examples/module-federation/widget/mako.config.json index 5640c758b..d0a37f6ea 100644 --- a/examples/module-federation/widget/mako.config.json +++ b/examples/module-federation/widget/mako.config.json @@ -10,13 +10,25 @@ "./App2": "./src/App2.tsx" }, "shared": { "react": {}, "react-dom": {} }, - "runtimePlugins": [], - "implementation": "/Users/xusd/codes/github/mako/packages/mako/node_modules/@module-federation/webpack-bundler-runtime" + "runtimePlugins": [] }, "experimental": { "centralEnsure": false }, "define": { "process.env.SOCKET_SERVER": "\"http://localhost:3000\"" + }, + "codeSplitting": { + "strategy": "advanced", + "options": { + "groups": [ + { + "name": "vendor", + "allowChunks": "all", + "minSize": 1, + "test": "node_modules" + } + ] + } } } From fb15a731bdd3be9c050db9753aa240f03da3424c Mon Sep 17 00:00:00 2001 From: xusd320 Date: Mon, 20 Jan 2025 15:56:34 +0800 Subject: [PATCH 32/68] feat: mf shared manifest --- .../src/plugins/module_federation/manifest.rs | 112 +++++++++++------- .../module_federation/provide_shared.rs | 24 +--- .../src/plugins/module_federation/util.rs | 11 ++ .../module-federation/host/mako.config.json | 3 +- .../module-federation/widget/mako.config.json | 3 +- 5 files changed, 92 insertions(+), 61 deletions(-) diff --git a/crates/mako/src/plugins/module_federation/manifest.rs b/crates/mako/src/plugins/module_federation/manifest.rs index 69978d765..4435e9265 100644 --- a/crates/mako/src/plugins/module_federation/manifest.rs +++ b/crates/mako/src/plugins/module_federation/manifest.rs @@ -4,9 +4,10 @@ use std::sync::Arc; use serde::Serialize; use super::constants::FEDERATION_EXPOSE_CHUNK_PREFIX; -use super::util::parse_remote; +use super::util::{parse_remote, serialize_none_to_false}; use super::{constants, ModuleFederationPlugin}; use crate::compiler::Context; +use crate::generate::chunk_graph::ChunkGraph; use crate::module::ModuleId; use crate::plugin::PluginGenerateEndParams; use crate::stats::StatsJsonMap; @@ -18,7 +19,6 @@ impl ModuleFederationPlugin { context: &Arc, params: &PluginGenerateEndParams, ) -> Result<(), anyhow::Error> { - let chunk_graph = context.chunk_graph.read().unwrap(); let app_info = get_app_info(&context.root); let manifest = Manifest { id: self.config.name.clone(), @@ -37,7 +37,8 @@ impl ModuleFederationPlugin { .to_string() .into(); // FIXME: this may be slow - let exposes_sync_chunks = chunk_graph + let chunk_graph = context.chunk_graph.read().unwrap(); + let sync_chunks = chunk_graph .graph .node_weights() .filter_map(|c| { @@ -51,51 +52,41 @@ impl ModuleFederationPlugin { }) .collect::>(); - let exposes_sync_chunk_dependencies = - exposes_sync_chunks.iter().fold(Vec::new(), |mut acc, cur| { - let sync_deps = chunk_graph.sync_dependencies_chunk(cur); - acc.splice(..0, sync_deps); - acc - }); - let all_exposes_sync_chunks = - [exposes_sync_chunk_dependencies, exposes_sync_chunks].concat(); - let all_exposes_async_chunks: Vec = - all_exposes_sync_chunks.iter().fold(vec![], |mut acc, cur| { - acc.extend(chunk_graph.installable_descendants_chunk(cur)); - acc - }); - let (sync_js_files, sync_css_files) = - extract_assets(all_exposes_sync_chunks, ¶ms.stats); - - let (async_js_files, async_css_files) = - extract_assets(all_exposes_async_chunks, ¶ms.stats); - let async_js_files = async_js_files - .into_iter() - .filter(|f| !sync_js_files.contains(f)) - .collect(); - let async_css_files = async_css_files - .into_iter() - .filter(|f| !sync_js_files.contains(f)) - .collect(); + let assets = extrac_chunk_assets(sync_chunks, &chunk_graph, params); ManifestExpose { id: format!("{}:{}", self.config.name, name), name, path: path.clone(), - assets: ManifestAssets { - js: ManifestAssetsItem { - sync: sync_js_files, - r#async: async_js_files, - }, - css: ManifestAssetsItem { - sync: sync_css_files, - r#async: async_css_files, - }, - }, + assets, } }) .collect() }), - shared: Vec::new(), + shared: { + let chunk_graph = context.chunk_graph.read().unwrap(); + let provide_shared_map = self.provide_shared_map.read().unwrap(); + provide_shared_map + .iter() + .map(|(_, config)| { + let module_id: ModuleId = config.file_path.clone().into(); + let chunk_id = chunk_graph + .get_chunk_for_module(&module_id) + .as_ref() + .unwrap() + .id + .clone(); + let assets = extrac_chunk_assets(vec![chunk_id], &chunk_graph, params); + ManifestShared { + id: format!("{}:{}", self.config.name, config.share_key), + name: config.share_key.clone(), + require_version: config.shared_config.required_version.clone(), + version: config.version.clone(), + singleton: config.shared_config.singleton, + assets, + } + }) + .collect() + }, remotes: params .stats .chunk_modules @@ -153,6 +144,44 @@ impl ModuleFederationPlugin { } } +fn extrac_chunk_assets( + sync_chunks: Vec, + chunk_graph: &ChunkGraph, + params: &PluginGenerateEndParams, +) -> ManifestAssets { + let sync_chunk_dependencies = sync_chunks.iter().fold(Vec::new(), |mut acc, cur| { + let sync_deps = chunk_graph.sync_dependencies_chunk(cur); + acc.splice(..0, sync_deps); + acc + }); + let all_sync_chunks = [sync_chunk_dependencies, sync_chunks].concat(); + let all_async_chunks: Vec = all_sync_chunks.iter().fold(vec![], |mut acc, cur| { + acc.extend(chunk_graph.installable_descendants_chunk(cur)); + acc + }); + let (sync_js_files, sync_css_files) = extract_assets(all_sync_chunks, ¶ms.stats); + + let (async_js_files, async_css_files) = extract_assets(all_async_chunks, ¶ms.stats); + let async_js_files = async_js_files + .into_iter() + .filter(|f| !sync_js_files.contains(f)) + .collect(); + let async_css_files = async_css_files + .into_iter() + .filter(|f| !sync_js_files.contains(f)) + .collect(); + ManifestAssets { + js: ManifestAssetsItem { + sync: sync_js_files, + r#async: async_js_files, + }, + css: ManifestAssetsItem { + sync: sync_css_files, + r#async: async_css_files, + }, + } +} + fn extract_assets( all_exposes_sync_chunks: Vec, stats: &StatsJsonMap, @@ -203,7 +232,8 @@ pub struct ManifestShared { name: String, assets: ManifestAssets, version: String, - require_version: String, + #[serde(serialize_with = "serialize_none_to_false")] + require_version: Option, singleton: bool, } diff --git a/crates/mako/src/plugins/module_federation/provide_shared.rs b/crates/mako/src/plugins/module_federation/provide_shared.rs index 3b5b10f4b..cbba3c0ee 100644 --- a/crates/mako/src/plugins/module_federation/provide_shared.rs +++ b/crates/mako/src/plugins/module_federation/provide_shared.rs @@ -1,8 +1,9 @@ use core::panic; use pathdiff::diff_paths; -use serde::{Serialize, Serializer}; +use serde::Serialize; +use super::util::serialize_none_to_false; use super::ModuleFederationPlugin; use crate::build::analyze_deps::ResolvedDep; use crate::compiler::Context; @@ -59,11 +60,8 @@ impl ModuleFederationPlugin { } }; format!( - r#"{{ version: {version}, get: {getter}, scope: {scope}, shareConfig: {share_config} }}"#, - version = share_item - .version - .as_ref() - .map_or("false".to_string(), |v| format!(r#""{}""#, v)), + r#"{{ version: "{version}", get: {getter}, scope: {scope}, shareConfig: {share_config} }}"#, + version = share_item.version, scope = serde_json::to_string(&share_item.scope).unwrap(), share_config = serde_json::to_string(&share_item.shared_config).unwrap() ) @@ -115,7 +113,7 @@ impl ModuleFederationPlugin { .entry(resolved_dep.resolver_resource.get_resolved_path()) .or_insert(ProvideSharedItem { share_key: pkg_name.clone(), - version: pkg_info.version.clone(), + version: pkg_info.version.clone().unwrap(), scope: vec![shared_info.shared_scope.clone()], file_path: pkg_info.file_path.clone(), shared_config: SharedConfig { @@ -134,7 +132,7 @@ impl ModuleFederationPlugin { #[derive(Debug)] pub(super) struct ProvideSharedItem { pub(super) share_key: String, - pub(super) version: Option, + pub(super) version: String, pub(super) scope: Vec, pub(super) shared_config: SharedConfig, pub(super) file_path: String, @@ -151,13 +149,3 @@ pub(super) struct SharedConfig { #[serde(serialize_with = "serialize_none_to_false")] pub(super) required_version: Option, } - -fn serialize_none_to_false( - t: &Option, - s: S, -) -> Result { - match t { - Some(t) => t.serialize(s), - None => s.serialize_bool(false), - } -} diff --git a/crates/mako/src/plugins/module_federation/util.rs b/crates/mako/src/plugins/module_federation/util.rs index 2ad8d2801..110296416 100644 --- a/crates/mako/src/plugins/module_federation/util.rs +++ b/crates/mako/src/plugins/module_federation/util.rs @@ -1,4 +1,5 @@ use anyhow::{anyhow, Result}; +use serde::{Serialize, Serializer}; pub(super) fn parse_remote(remote: &str) -> Result<(String, String)> { let (left, right) = remote @@ -10,3 +11,13 @@ pub(super) fn parse_remote(remote: &str) -> Result<(String, String)> { Ok((left.to_string(), right.to_string())) } } + +pub(super) fn serialize_none_to_false( + t: &Option, + s: S, +) -> Result { + match t { + Some(t) => t.serialize(s), + None => s.serialize_bool(false), + } +} diff --git a/examples/module-federation/host/mako.config.json b/examples/module-federation/host/mako.config.json index ec9229851..aaf0d38a6 100644 --- a/examples/module-federation/host/mako.config.json +++ b/examples/module-federation/host/mako.config.json @@ -7,7 +7,8 @@ "remotes": { "widget": "mfWidget@http://localhost:3000/mfWidget.js" }, - "shared": { "react": {}, "react-dom": {} } + "shared": { "react": {}, "react-dom": {} }, + "implementation": "../../../../../packages/mako/node_modules/@module-federation/webpack-bundler-runtime" }, "experimental": { "centralEnsure": false diff --git a/examples/module-federation/widget/mako.config.json b/examples/module-federation/widget/mako.config.json index d0a37f6ea..c5576b24d 100644 --- a/examples/module-federation/widget/mako.config.json +++ b/examples/module-federation/widget/mako.config.json @@ -10,7 +10,8 @@ "./App2": "./src/App2.tsx" }, "shared": { "react": {}, "react-dom": {} }, - "runtimePlugins": [] + "runtimePlugins": [], + "implementation": "../../../../../packages/mako/node_modules/@module-federation/webpack-bundler-runtime" }, "experimental": { "centralEnsure": false From eeec6b5d46653aea2e241e5f76e4e59385b9978b Mon Sep 17 00:00:00 2001 From: xusd320 Date: Mon, 20 Jan 2025 16:48:44 +0800 Subject: [PATCH 33/68] feat: add config hash for mf shared module --- .../module_federation/consume_shared.rs | 28 ++++++++++++++----- crates/mako/src/resolve/resource.rs | 3 +- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/crates/mako/src/plugins/module_federation/consume_shared.rs b/crates/mako/src/plugins/module_federation/consume_shared.rs index a172d8a88..9cd0246d4 100644 --- a/crates/mako/src/plugins/module_federation/consume_shared.rs +++ b/crates/mako/src/plugins/module_federation/consume_shared.rs @@ -8,7 +8,7 @@ use super::ModuleFederationPlugin; use crate::build::analyze_deps::{AnalyzeDepsResult, ResolvedDep}; use crate::compiler::Context; use crate::generate::chunk::{Chunk, ChunkType}; -use crate::module::{Dependency, ResolveType}; +use crate::module::{md5_hash, Dependency, ResolveType}; use crate::plugin::PluginResolveIdParams; use crate::resolve::{do_resolve, ConsumeSharedInfo, ResolverResource, ResolverType}; @@ -151,19 +151,33 @@ impl ModuleFederationPlugin { .unwrap(); let resolver_resource = do_resolve(importer, source, resolver, Some(&context.config.externals))?; + let config_joined_str = format!( + "{}|{}|{}|{}|{}|{}|{}", + shared_info.shared_scope, + source, + shared_info + .required_version + .as_ref() + .map_or("", |v| v.as_str()), + shared_info.strict_version, + resolver_resource.get_resolved_path(), + shared_info.singleton, + shared_info.eager + ); + let hash = md5_hash(&config_joined_str, 4); return Ok(Some(ResolverResource::Shared(ConsumeSharedInfo { eager: shared_info.eager, module_id: format!( - "{}{}/{}/{}", - FEDERATION_SHARED_REFERENCE_PREFIX, shared_info.shared_scope, source, source + "{}{}/{}/{}?{}", + FEDERATION_SHARED_REFERENCE_PREFIX, + shared_info.shared_scope, + source, + source, + hash ), name: source.to_string(), share_scope: shared_info.shared_scope.clone(), version: resolver_resource.get_pkg_info().unwrap().version.unwrap(), - full_path: format!( - "{}{}/{}/{}", - FEDERATION_SHARED_REFERENCE_PREFIX, shared_info.shared_scope, source, source - ), deps: AnalyzeDepsResult { resolved_deps: vec![ResolvedDep { resolver_resource, diff --git a/crates/mako/src/resolve/resource.rs b/crates/mako/src/resolve/resource.rs index fa7858dc3..648c47628 100644 --- a/crates/mako/src/resolve/resource.rs +++ b/crates/mako/src/resolve/resource.rs @@ -19,7 +19,6 @@ pub struct ConsumeSharedInfo { pub name: String, pub share_scope: String, pub version: String, - pub full_path: String, pub eager: bool, pub required_version: Option, pub strict_version: bool, @@ -57,7 +56,7 @@ impl ResolverResource { ResolverResource::Ignored(path) => path.to_string_lossy().to_string(), ResolverResource::Virtual(path) => path.to_string_lossy().to_string(), ResolverResource::Remote(info) => info.module_id.to_string(), - ResolverResource::Shared(info) => info.full_path.clone(), + ResolverResource::Shared(info) => info.module_id.clone(), } } pub fn get_external(&self) -> Option { From ca5c7d5e46bb9757da3691d1e5c92027a7b8b175 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Tue, 21 Jan 2025 18:16:12 +0800 Subject: [PATCH 34/68] chore: update mako typings --- crates/binding/src/lib.rs | 20 +++++++++++++++++ crates/mako/src/config/module_federation.rs | 5 +++-- packages/mako/binding.d.ts | 24 +++++++++++++++++++++ packages/mako/src/index.ts | 8 +++---- packages/mako/src/mf/index.ts | 15 ------------- 5 files changed, 51 insertions(+), 21 deletions(-) delete mode 100644 packages/mako/src/mf/index.ts diff --git a/crates/binding/src/lib.rs b/crates/binding/src/lib.rs index 70d1776b1..e92bcf3ed 100644 --- a/crates/binding/src/lib.rs +++ b/crates/binding/src/lib.rs @@ -156,9 +156,29 @@ pub struct BuildParams { rscClient?: false | { "logServerComponent": "error" | "ignore"; }; + moduleFederation?: { + name: string; + // filename?: string; + exposes?: Record; + shared: Record; + remotes?: Record; + runtimePlugins?: string[]; + shareScope?: string; + shareStrategy?: "version-first" | "loaded-first"; + }; experimental?: { webpackSyntaxValidate?: string[]; + requireContext?: bool; + ignoreNonLiteralRequire?: bool; + magicComment?: bool; + detectCircularDependence?: { ignore?: string[] }; rustPlugins?: Array<[string, any]>; + centralEnsure?: bool, + importsChecker?: bool, }; watch?: { ignoredPaths?: string[]; diff --git a/crates/mako/src/config/module_federation.rs b/crates/mako/src/config/module_federation.rs index 4b707cc30..b21dc359f 100644 --- a/crates/mako/src/config/module_federation.rs +++ b/crates/mako/src/config/module_federation.rs @@ -26,6 +26,7 @@ pub type SharedConfig = HashMap; #[serde(rename_all = "camelCase")] pub struct SharedItemConfig { #[serde(default)] + /// not supported now pub eager: bool, #[serde(default)] pub singleton: bool, @@ -39,9 +40,9 @@ pub struct SharedItemConfig { #[derive(Debug, Clone, Serialize, Deserialize)] pub enum ShareStrategy { - #[serde(rename = "version_first")] + #[serde(rename = "version-first")] VersionFirst, - #[serde(rename = "loaded_first")] + #[serde(rename = "loaded-first")] LoadedFirst, } diff --git a/packages/mako/binding.d.ts b/packages/mako/binding.d.ts index 6d2753930..04ab6eac7 100644 --- a/packages/mako/binding.d.ts +++ b/packages/mako/binding.d.ts @@ -258,9 +258,33 @@ export interface BuildParams { | { logServerComponent: 'error' | 'ignore'; }; + moduleFederation?: { + name: string; + // filename?: string; + exposes?: Record; + shared: Record< + string, + { + singleton?: bool; + strictVersion?: bool; + requiredVersion?: string; + /* eager?: bool; */ /* shareScope?: string; */ + } + >; + remotes?: Record; + runtimePlugins?: string[]; + shareScope?: string; + shareStrategy?: 'version-first' | 'loaded-first'; + }; experimental?: { webpackSyntaxValidate?: string[]; + requireContext?: bool; + ignoreNonLiteralRequire?: bool; + magicComment?: bool; + detectCircularDependence?: { ignore?: string[] }; rustPlugins?: Array<[string, any]>; + centralEnsure?: bool; + importsChecker?: bool; }; watch?: { ignoredPaths?: string[]; diff --git a/packages/mako/src/index.ts b/packages/mako/src/index.ts index 01f198124..ca3435043 100644 --- a/packages/mako/src/index.ts +++ b/packages/mako/src/index.ts @@ -59,7 +59,7 @@ export async function build(params: BuildParams) { await rustPluginResolver(rustPlugins); } - let makoConfig: any = {}; + let makoConfig: binding.BuildParams['config'] = {}; let makoConfigPath = path.join(params.root, 'mako.config.json'); if (fs.existsSync(makoConfigPath)) { try { @@ -129,9 +129,9 @@ export async function build(params: BuildParams) { }, }); - if (makoConfig?.sass || params.config?.sass) { + if ((makoConfig as any)?.sass || params.config?.sass) { const sassOpts = { - ...(makoConfig?.sass || {}), + ...((makoConfig as any)?.sass || {}), ...(params.config?.sass || {}), }; let sass = sassLoader(null, sassOpts); @@ -199,7 +199,7 @@ export async function build(params: BuildParams) { return plugin; } }); - makoConfig.plugins?.forEach((plugin: any) => { + (makoConfig as any).plugins?.forEach((plugin: any) => { if (typeof plugin === 'string') { let fn = require( resolve.sync(plugin, { diff --git a/packages/mako/src/mf/index.ts b/packages/mako/src/mf/index.ts deleted file mode 100644 index a0c37c69d..000000000 --- a/packages/mako/src/mf/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -export interface SharedConfig { - singleton?: boolean; - strictVersion?: boolean; - requiredVersion?: string; - version?: string; - eager?: boolean; -} - -export interface FederationConfig { - name: string; - filename?: string; - exposes?: Record; - shared?: Record; - remotes?: Record; -} From 38dc51b8d27d52f3a47a587de156e5c1b8839e18 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Tue, 21 Jan 2025 18:56:36 +0800 Subject: [PATCH 35/68] chore: code styles --- crates/mako/src/plugins/module_federation.rs | 12 ++++++------ .../src/plugins/module_federation/consume_shared.rs | 12 ++++++------ .../plugins/module_federation/container_reference.rs | 1 + .../mako/src/plugins/module_federation/manifest.rs | 5 +++++ 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/crates/mako/src/plugins/module_federation.rs b/crates/mako/src/plugins/module_federation.rs index 807e4ad23..e9e4e7b03 100644 --- a/crates/mako/src/plugins/module_federation.rs +++ b/crates/mako/src/plugins/module_federation.rs @@ -10,7 +10,7 @@ use crate::ast::file::Content; use crate::build::analyze_deps::ResolvedDep; use crate::compiler::{Args, Context}; use crate::config::module_federation::ModuleFederationConfig; -use crate::config::Config; +use crate::config::{CodeSplittingAdvancedOptions, Config}; use crate::generate::chunk::Chunk; use crate::generate::chunk_graph::ChunkGraph; use crate::module_graph::ModuleGraph; @@ -54,11 +54,11 @@ impl Plugin for ModuleFederationPlugin { &self, content: &mut Content, _path: &str, - _is_entry: bool, + is_entry: bool, context: &Arc, ) -> Result> { // add container entry runtime dependency - if !_is_entry { + if !is_entry { Ok(None) } else { match content { @@ -79,9 +79,9 @@ impl Plugin for ModuleFederationPlugin { Ok(vec![ self.get_federation_runtime_code(), self.get_container_references_code(context), - self.get_provide_sharing_code(context), - self.get_consume_sharing_code(entry_chunk, context), self.get_federation_exposes_library_code(), + self.get_consume_sharing_code(entry_chunk, context), + self.get_provide_sharing_code(context), ]) } @@ -122,7 +122,7 @@ impl Plugin for ModuleFederationPlugin { fn after_optimize_chunk_options( &self, - optimize_chunk_options: &mut crate::config::CodeSplittingAdvancedOptions, + optimize_chunk_options: &mut CodeSplittingAdvancedOptions, ) -> Result<()> { self.patch_code_splitting(optimize_chunk_options); Ok(()) diff --git a/crates/mako/src/plugins/module_federation/consume_shared.rs b/crates/mako/src/plugins/module_federation/consume_shared.rs index 9cd0246d4..231b262cb 100644 --- a/crates/mako/src/plugins/module_federation/consume_shared.rs +++ b/crates/mako/src/plugins/module_federation/consume_shared.rs @@ -166,7 +166,13 @@ impl ModuleFederationPlugin { ); let hash = md5_hash(&config_joined_str, 4); return Ok(Some(ResolverResource::Shared(ConsumeSharedInfo { + name: source.to_string(), + version: resolver_resource.get_pkg_info().unwrap().version.unwrap(), + share_scope: shared_info.shared_scope.clone(), eager: shared_info.eager, + singletion: shared_info.singleton, + required_version: shared_info.required_version.clone(), + strict_version: shared_info.strict_version, module_id: format!( "{}{}/{}/{}?{}", FEDERATION_SHARED_REFERENCE_PREFIX, @@ -175,9 +181,6 @@ impl ModuleFederationPlugin { source, hash ), - name: source.to_string(), - share_scope: shared_info.shared_scope.clone(), - version: resolver_resource.get_pkg_info().unwrap().version.unwrap(), deps: AnalyzeDepsResult { resolved_deps: vec![ResolvedDep { resolver_resource, @@ -191,9 +194,6 @@ impl ModuleFederationPlugin { }], missing_deps: HashMap::new(), }, - singletion: shared_info.singleton, - required_version: shared_info.required_version.clone(), - strict_version: shared_info.strict_version, }))); } Ok(None) diff --git a/crates/mako/src/plugins/module_federation/container_reference.rs b/crates/mako/src/plugins/module_federation/container_reference.rs index bd36e2c67..06caa69ba 100644 --- a/crates/mako/src/plugins/module_federation/container_reference.rs +++ b/crates/mako/src/plugins/module_federation/container_reference.rs @@ -46,6 +46,7 @@ impl ModuleFederationPlugin { let remote_info = id_to_external_and_name_mapping .entry(m.id.id.as_str()) .or_default(); + remote_info.push(&remote_module.share_scope); remote_info.push(&remote_module.sub_path); remote_info.push(&remote_module.external_reference_id); diff --git a/crates/mako/src/plugins/module_federation/manifest.rs b/crates/mako/src/plugins/module_federation/manifest.rs index 4435e9265..7eff5e1df 100644 --- a/crates/mako/src/plugins/module_federation/manifest.rs +++ b/crates/mako/src/plugins/module_federation/manifest.rs @@ -154,22 +154,27 @@ fn extrac_chunk_assets( acc.splice(..0, sync_deps); acc }); + let all_sync_chunks = [sync_chunk_dependencies, sync_chunks].concat(); let all_async_chunks: Vec = all_sync_chunks.iter().fold(vec![], |mut acc, cur| { acc.extend(chunk_graph.installable_descendants_chunk(cur)); acc }); + let (sync_js_files, sync_css_files) = extract_assets(all_sync_chunks, ¶ms.stats); let (async_js_files, async_css_files) = extract_assets(all_async_chunks, ¶ms.stats); + let async_js_files = async_js_files .into_iter() .filter(|f| !sync_js_files.contains(f)) .collect(); + let async_css_files = async_css_files .into_iter() .filter(|f| !sync_js_files.contains(f)) .collect(); + ManifestAssets { js: ManifestAssetsItem { sync: sync_js_files, From bccb33eaea5cd2aa5030f23c2473440a546d31d4 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Tue, 21 Jan 2025 19:01:50 +0800 Subject: [PATCH 36/68] chore: fix typo --- crates/mako/src/plugins/module_federation/manifest.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/mako/src/plugins/module_federation/manifest.rs b/crates/mako/src/plugins/module_federation/manifest.rs index 7eff5e1df..806ef110a 100644 --- a/crates/mako/src/plugins/module_federation/manifest.rs +++ b/crates/mako/src/plugins/module_federation/manifest.rs @@ -52,7 +52,7 @@ impl ModuleFederationPlugin { }) .collect::>(); - let assets = extrac_chunk_assets(sync_chunks, &chunk_graph, params); + let assets = extract_chunk_assets(sync_chunks, &chunk_graph, params); ManifestExpose { id: format!("{}:{}", self.config.name, name), name, @@ -75,7 +75,7 @@ impl ModuleFederationPlugin { .unwrap() .id .clone(); - let assets = extrac_chunk_assets(vec![chunk_id], &chunk_graph, params); + let assets = extract_chunk_assets(vec![chunk_id], &chunk_graph, params); ManifestShared { id: format!("{}:{}", self.config.name, config.share_key), name: config.share_key.clone(), @@ -144,7 +144,7 @@ impl ModuleFederationPlugin { } } -fn extrac_chunk_assets( +fn extract_chunk_assets( sync_chunks: Vec, chunk_graph: &ChunkGraph, params: &PluginGenerateEndParams, From 5ff27c8757f11f8abdca25eb194c5e2eea6ab3af Mon Sep 17 00:00:00 2001 From: xusd320 Date: Wed, 22 Jan 2025 11:16:51 +0800 Subject: [PATCH 37/68] chore: code styles --- crates/mako/src/build.rs | 4 ++-- crates/mako/src/module.rs | 3 +-- crates/mako/src/plugins/module_federation/provide_shared.rs | 2 -- crates/mako/src/plugins/tree_shaking/module.rs | 2 +- crates/mako/src/plugins/tree_shaking/shake.rs | 2 +- 5 files changed, 5 insertions(+), 8 deletions(-) diff --git a/crates/mako/src/build.rs b/crates/mako/src/build.rs index b1dff558b..aa4be17b5 100644 --- a/crates/mako/src/build.rs +++ b/crates/mako/src/build.rs @@ -51,7 +51,7 @@ impl Compiler { let rs = rs.clone(); let context = self.context.clone(); thread_pool::spawn(move || { - let result = Self::build_shared_module(consume_share_info, context.clone()); + let result = Self::build_consume_shared_module(consume_share_info, context.clone()); rs.send(result).unwrap(); }); }; @@ -285,7 +285,7 @@ __mako_require__.loadScript('{}', (e) => e.type === 'load' ? resolve() : reject( result } } - pub fn build_shared_module( + pub fn build_consume_shared_module( consume_share_info: ConsumeSharedInfo, _context: Arc, ) -> Result { diff --git a/crates/mako/src/module.rs b/crates/mako/src/module.rs index 2a448b008..65f08bcad 100644 --- a/crates/mako/src/module.rs +++ b/crates/mako/src/module.rs @@ -397,7 +397,6 @@ pub enum ModuleType { pub enum FedereationModuleType { Remote, ConsumeShare, - ProvideShare, } #[derive(Clone)] @@ -437,7 +436,7 @@ impl Module { .map_or(false, |info| info.external.is_some()) } - pub fn is_provide_share(&self) -> bool { + pub fn is_consume_share(&self) -> bool { if let Some(info) = self.info.as_ref() && let Some(FedereationModuleType::ConsumeShare) = info.federation { diff --git a/crates/mako/src/plugins/module_federation/provide_shared.rs b/crates/mako/src/plugins/module_federation/provide_shared.rs index cbba3c0ee..2b232ad0a 100644 --- a/crates/mako/src/plugins/module_federation/provide_shared.rs +++ b/crates/mako/src/plugins/module_federation/provide_shared.rs @@ -1,5 +1,3 @@ -use core::panic; - use pathdiff::diff_paths; use serde::Serialize; diff --git a/crates/mako/src/plugins/tree_shaking/module.rs b/crates/mako/src/plugins/tree_shaking/module.rs index 7d2cbdec3..b401f2012 100644 --- a/crates/mako/src/plugins/tree_shaking/module.rs +++ b/crates/mako/src/plugins/tree_shaking/module.rs @@ -297,7 +297,7 @@ impl TreeShakeModule { crate::module::ModuleAst::None => StatementGraph::empty(), }; - let used_exports = if module.is_entry || module.is_provide_share() { + let used_exports = if module.is_entry || module.is_consume_share() { UsedExports::All } else { UsedExports::Partial(Default::default()) diff --git a/crates/mako/src/plugins/tree_shaking/shake.rs b/crates/mako/src/plugins/tree_shaking/shake.rs index 96262e1b4..52c4a0ba1 100644 --- a/crates/mako/src/plugins/tree_shaking/shake.rs +++ b/crates/mako/src/plugins/tree_shaking/shake.rs @@ -38,7 +38,7 @@ pub fn optimize_modules(module_graph: &mut ModuleGraph, context: &Arc) let module_type = module.get_module_type(); // skip non script modules and external modules - if (module_type != ModuleType::Script && !module.is_provide_share()) + if (module_type != ModuleType::Script && !module.is_consume_share()) || module.is_external() { if module_type != ModuleType::Script && !module.is_external() { From 441bed8637c40188bc6b64f0890b34c9efcdc8b6 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Thu, 23 Jan 2025 10:42:16 +0800 Subject: [PATCH 38/68] perf: improve performance --- crates/mako/src/module.rs | 10 ++ .../module_federation/consume_shared.rs | 6 +- .../plugins/module_federation/container.rs | 135 +++++++++--------- .../src/plugins/module_federation/manifest.rs | 54 +++---- 4 files changed, 109 insertions(+), 96 deletions(-) diff --git a/crates/mako/src/module.rs b/crates/mako/src/module.rs index 65f08bcad..662943ea6 100644 --- a/crates/mako/src/module.rs +++ b/crates/mako/src/module.rs @@ -436,6 +436,16 @@ impl Module { .map_or(false, |info| info.external.is_some()) } + pub fn is_remote(&self) -> bool { + if let Some(info) = self.info.as_ref() + && let Some(FedereationModuleType::Remote) = info.federation + { + true + } else { + false + } + } + pub fn is_consume_share(&self) -> bool { if let Some(info) = self.info.as_ref() && let Some(FedereationModuleType::ConsumeShare) = info.federation diff --git a/crates/mako/src/plugins/module_federation/consume_shared.rs b/crates/mako/src/plugins/module_federation/consume_shared.rs index 231b262cb..5002cd2d5 100644 --- a/crates/mako/src/plugins/module_federation/consume_shared.rs +++ b/crates/mako/src/plugins/module_federation/consume_shared.rs @@ -32,7 +32,9 @@ impl ModuleFederationPlugin { .modules .iter() .filter_map(|m| { - if m.id.starts_with(FEDERATION_SHARED_REFERENCE_PREFIX) { + if let Some(module) = module_graph.get_module(m) + && module.is_consume_share() + { Some(m.id.clone()) } else { None @@ -192,7 +194,7 @@ impl ModuleFederationPlugin { span: params.dep.span, }, }], - missing_deps: HashMap::new(), + ..Default::default() }, }))); } diff --git a/crates/mako/src/plugins/module_federation/container.rs b/crates/mako/src/plugins/module_federation/container.rs index 16e626283..e7795fd25 100644 --- a/crates/mako/src/plugins/module_federation/container.rs +++ b/crates/mako/src/plugins/module_federation/container.rs @@ -12,59 +12,6 @@ use crate::module::md5_hash; use crate::visitors::mako_require::MAKO_REQUIRE; impl ModuleFederationPlugin { - pub(super) fn prepare_container_entry_dep(&self, root: &Path) -> String { - let container_content = self.get_container_content(); - - let content_hash = md5_hash(&container_content, 32); - - let dep_path = root.join(format!( - "node_modules/.federation/.entry.{}.js", - content_hash - )); - let dep_parent_path = dep_path.parent().unwrap(); - if !fs::exists(dep_parent_path).unwrap() { - fs::create_dir_all(dep_parent_path).unwrap(); - } - if !fs::exists(&dep_path).unwrap() { - fs::write(&dep_path, container_content).unwrap(); - } - - dep_path.to_string_lossy().to_string() - } - - pub(super) fn get_container_content(&self) -> String { - let (plugins_imports, plugins_instantiations) = self.get_mf_runtime_plugins_content(); - - format!( - r#"import federation from "{federation_impl}"; -{plugins_imports} - -if(!{FEDERATION_GLOBAL}.runtime) {{ - var preFederation = {FEDERATION_GLOBAL}; - {FEDERATION_GLOBAL} = {{}}; - for(var key in federation) {{ - {FEDERATION_GLOBAL}[key] = federation[key]; - }} - for(var key in preFederation) {{ - {FEDERATION_GLOBAL}[key] = preFederation[key]; - }} -}} - -if(!{FEDERATION_GLOBAL}.instance) {{ - {plugins_instantiations} - {FEDERATION_GLOBAL}.instance = {FEDERATION_GLOBAL}.runtime.init({FEDERATION_GLOBAL}.initOptions); - if({FEDERATION_GLOBAL}.attachShareScopeMap) {{ - {FEDERATION_GLOBAL}.attachShareScopeMap({MAKO_REQUIRE}); - }} - if({FEDERATION_GLOBAL}.installInitialConsumes) {{ - {FEDERATION_GLOBAL}.installInitialConsumes(); - }} -}} -"#, - federation_impl = self.config.implementation, - ) - } - pub(super) fn add_container_entry(&self, config: &mut Config, root: &Path) { // add container entry if let Some(exposes) = self.config.exposes.as_ref() { @@ -152,6 +99,59 @@ export {{ get, init }}; ) } + pub(super) fn prepare_container_entry_dep(&self, root: &Path) -> String { + let container_content = self.get_federation_init_code(); + + let content_hash = md5_hash(&container_content, 32); + + let dep_path = root.join(format!( + "node_modules/.federation/.entry.{}.js", + content_hash + )); + let dep_parent_path = dep_path.parent().unwrap(); + if !fs::exists(dep_parent_path).unwrap() { + fs::create_dir_all(dep_parent_path).unwrap(); + } + if !fs::exists(&dep_path).unwrap() { + fs::write(&dep_path, container_content).unwrap(); + } + + dep_path.to_string_lossy().to_string() + } + + pub(super) fn get_federation_init_code(&self) -> String { + let (plugins_imports, plugins_instantiations) = self.get_mf_runtime_plugins_content(); + + format!( + r#"import federation from "{federation_impl}"; +{plugins_imports} + +if(!{FEDERATION_GLOBAL}.runtime) {{ + var preFederation = {FEDERATION_GLOBAL}; + {FEDERATION_GLOBAL} = {{}}; + for(var key in federation) {{ + {FEDERATION_GLOBAL}[key] = federation[key]; + }} + for(var key in preFederation) {{ + {FEDERATION_GLOBAL}[key] = preFederation[key]; + }} +}} + +if(!{FEDERATION_GLOBAL}.instance) {{ + {plugins_instantiations} + {FEDERATION_GLOBAL}.instance = {FEDERATION_GLOBAL}.runtime.init({FEDERATION_GLOBAL}.initOptions); + if({FEDERATION_GLOBAL}.attachShareScopeMap) {{ + {FEDERATION_GLOBAL}.attachShareScopeMap({MAKO_REQUIRE}); + }} + if({FEDERATION_GLOBAL}.installInitialConsumes) {{ + {FEDERATION_GLOBAL}.installInitialConsumes(); + }} +}} +"#, + federation_impl = self.config.implementation, + ) + } + pub(super) fn get_federation_runtime_code(&self) -> String { let runtime_remotes = self.config.remotes.as_ref().map_or(Vec::new(), |remotes| { remotes @@ -196,21 +196,6 @@ export {{ get, init }}; federation_runtime_code } - pub(super) fn get_federation_exposes_library_code(&self) -> String { - if let Some(exposes) = self.config.exposes.as_ref() { - if !exposes.is_empty() { - format!( - r#"global["{}"] = requireModule(entryModuleId);"#, - self.config.name - ) - } else { - "".to_string() - } - } else { - "".to_string() - } - } - pub(super) fn get_mf_runtime_plugins_content(&self) -> (String, String) { let (imported_plugin_names, import_plugin_instantiations) = self.config.runtime_plugins.iter().enumerate().fold( @@ -244,6 +229,20 @@ export {{ get, init }}; (plugins_imports, plugins_instantiations) } + pub(super) fn get_federation_exposes_library_code(&self) -> String { + if let Some(exposes) = self.config.exposes.as_ref() { + if !exposes.is_empty() { + format!( + r#"global["{}"] = requireModule(entryModuleId);"#, + self.config.name + ) + } else { + "".to_string() + } + } else { + "".to_string() + } + } pub(crate) fn patch_code_splitting( &self, optimize_chunk_options: &mut crate::config::CodeSplittingAdvancedOptions, diff --git a/crates/mako/src/plugins/module_federation/manifest.rs b/crates/mako/src/plugins/module_federation/manifest.rs index 806ef110a..de0a1bf4f 100644 --- a/crates/mako/src/plugins/module_federation/manifest.rs +++ b/crates/mako/src/plugins/module_federation/manifest.rs @@ -5,7 +5,7 @@ use serde::Serialize; use super::constants::FEDERATION_EXPOSE_CHUNK_PREFIX; use super::util::{parse_remote, serialize_none_to_false}; -use super::{constants, ModuleFederationPlugin}; +use super::ModuleFederationPlugin; use crate::compiler::Context; use crate::generate::chunk_graph::ChunkGraph; use crate::module::ModuleId; @@ -87,31 +87,33 @@ impl ModuleFederationPlugin { }) .collect() }, - remotes: params - .stats - .chunk_modules - .iter() - .filter_map(|cm| { - if cm - .id - .starts_with(constants::FEDERATION_REMOTE_MODULE_PREFIX) - { - let data = cm.id.split('/').collect::>(); - Some(ManifestRemote { - entry: parse_remote( - self.config.remotes.as_ref().unwrap().get(data[3]).unwrap(), - ) - .unwrap() - .1, - module_name: data[4].to_string(), - alias: data[3].to_string(), - federation_container_name: data[3].to_string(), - }) - } else { - None - } - }) - .collect(), + remotes: { + let module_graph = context.module_graph.read().unwrap(); + params + .stats + .chunk_modules + .iter() + .filter_map(|cm| { + if let Some(module) = module_graph.get_module(&cm.id.clone().into()) + && module.is_remote() + { + let data = cm.id.split('/').collect::>(); + Some(ManifestRemote { + entry: parse_remote( + self.config.remotes.as_ref().unwrap().get(data[3]).unwrap(), + ) + .unwrap() + .1, + module_name: data[4].to_string(), + alias: data[3].to_string(), + federation_container_name: data[3].to_string(), + }) + } else { + None + } + }) + .collect() + }, meta_data: ManifestMetaData { name: self.config.name.clone(), build_info: ManifestMetaBuildInfo { From e4b1d1ddd6cab5148e737aa3272a2049a4296c97 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Thu, 23 Jan 2025 11:12:08 +0800 Subject: [PATCH 39/68] chore: code styles --- crates/mako/src/plugins/module_federation.rs | 12 ++++++------ .../src/plugins/module_federation/consume_shared.rs | 2 +- .../mako/src/plugins/module_federation/container.rs | 4 ++-- .../plugins/module_federation/container_reference.rs | 2 +- .../src/plugins/module_federation/provide_shared.rs | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/crates/mako/src/plugins/module_federation.rs b/crates/mako/src/plugins/module_federation.rs index e9e4e7b03..b7d159591 100644 --- a/crates/mako/src/plugins/module_federation.rs +++ b/crates/mako/src/plugins/module_federation.rs @@ -57,10 +57,10 @@ impl Plugin for ModuleFederationPlugin { is_entry: bool, context: &Arc, ) -> Result> { - // add container entry runtime dependency if !is_entry { Ok(None) } else { + // add container entry runtime dependency match content { Content::Js(js_content) => { let entry_runtime_dep_path = self.prepare_container_entry_dep(&context.root); @@ -77,11 +77,11 @@ impl Plugin for ModuleFederationPlugin { fn runtime_plugins(&self, entry_chunk: &Chunk, context: &Arc) -> Result> { Ok(vec![ - self.get_federation_runtime_code(), - self.get_container_references_code(context), - self.get_federation_exposes_library_code(), - self.get_consume_sharing_code(entry_chunk, context), - self.get_provide_sharing_code(context), + self.init_federation_runtime_options(), + self.init_federation_runtime_remotes(context), + self.init_federation_runtime_consume(entry_chunk, context), + self.init_federation_runtime_sharing(context), + self.export_federation_container(), ]) } diff --git a/crates/mako/src/plugins/module_federation/consume_shared.rs b/crates/mako/src/plugins/module_federation/consume_shared.rs index 5002cd2d5..f826e9b8e 100644 --- a/crates/mako/src/plugins/module_federation/consume_shared.rs +++ b/crates/mako/src/plugins/module_federation/consume_shared.rs @@ -13,7 +13,7 @@ use crate::plugin::PluginResolveIdParams; use crate::resolve::{do_resolve, ConsumeSharedInfo, ResolverResource, ResolverType}; impl ModuleFederationPlugin { - pub(super) fn get_consume_sharing_code( + pub(super) fn init_federation_runtime_consume( &self, entry_chunk: &Chunk, context: &Context, diff --git a/crates/mako/src/plugins/module_federation/container.rs b/crates/mako/src/plugins/module_federation/container.rs index e7795fd25..a279255b0 100644 --- a/crates/mako/src/plugins/module_federation/container.rs +++ b/crates/mako/src/plugins/module_federation/container.rs @@ -152,7 +152,7 @@ if(!{FEDERATION_GLOBAL}.instance) {{ ) } - pub(super) fn get_federation_runtime_code(&self) -> String { + pub(super) fn init_federation_runtime_options(&self) -> String { let runtime_remotes = self.config.remotes.as_ref().map_or(Vec::new(), |remotes| { remotes .iter() @@ -229,7 +229,7 @@ if(!{FEDERATION_GLOBAL}.instance) {{ (plugins_imports, plugins_instantiations) } - pub(super) fn get_federation_exposes_library_code(&self) -> String { + pub(super) fn export_federation_container(&self) -> String { if let Some(exposes) = self.config.exposes.as_ref() { if !exposes.is_empty() { format!( diff --git a/crates/mako/src/plugins/module_federation/container_reference.rs b/crates/mako/src/plugins/module_federation/container_reference.rs index 06caa69ba..1741a8e87 100644 --- a/crates/mako/src/plugins/module_federation/container_reference.rs +++ b/crates/mako/src/plugins/module_federation/container_reference.rs @@ -12,7 +12,7 @@ use crate::module::FedereationModuleType; use crate::resolve::{RemoteInfo, ResolverResource}; impl ModuleFederationPlugin { - pub(super) fn get_container_references_code(&self, context: &Arc) -> String { + pub(super) fn init_federation_runtime_remotes(&self, context: &Arc) -> String { let module_graph = context.module_graph.read().unwrap(); let chunk_graph = context.chunk_graph.read().unwrap(); let all_chunks = chunk_graph.get_all_chunks(); diff --git a/crates/mako/src/plugins/module_federation/provide_shared.rs b/crates/mako/src/plugins/module_federation/provide_shared.rs index 2b232ad0a..b091d976c 100644 --- a/crates/mako/src/plugins/module_federation/provide_shared.rs +++ b/crates/mako/src/plugins/module_federation/provide_shared.rs @@ -9,7 +9,7 @@ use crate::generate::chunk::ChunkType; use crate::module::ModuleId; impl ModuleFederationPlugin { - pub(super) fn get_provide_sharing_code(&self, context: &Context) -> String { + pub(super) fn init_federation_runtime_sharing(&self, context: &Context) -> String { let provide_shared_map = self.provide_shared_map.read().unwrap(); let chunk_graph = context.chunk_graph.read().unwrap(); From d7aefa8b897f4ecd3f62ce567fca54ceef729bbf Mon Sep 17 00:00:00 2001 From: xusd320 Date: Thu, 23 Jan 2025 11:22:01 +0800 Subject: [PATCH 40/68] chore: rename types --- crates/mako/src/plugins/module_federation.rs | 6 +++--- .../mako/src/plugins/module_federation/consume_shared.rs | 2 +- crates/mako/src/plugins/module_federation/manifest.rs | 2 +- .../src/plugins/module_federation/provide_for_consume.rs | 2 +- .../mako/src/plugins/module_federation/provide_shared.rs | 8 ++++---- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/mako/src/plugins/module_federation.rs b/crates/mako/src/plugins/module_federation.rs index b7d159591..5569bcb0f 100644 --- a/crates/mako/src/plugins/module_federation.rs +++ b/crates/mako/src/plugins/module_federation.rs @@ -4,7 +4,7 @@ use std::sync::{Arc, RwLock}; use anyhow::Result; use constants::{FEDERATION_REMOTE_MODULE_PREFIX, FEDERATION_REMOTE_REFERENCE_PREFIX}; -use provide_shared::ProvideSharedItem; +use provide_shared::SharedDependency; use crate::ast::file::Content; use crate::build::analyze_deps::ResolvedDep; @@ -28,14 +28,14 @@ mod util; pub struct ModuleFederationPlugin { pub config: ModuleFederationConfig, - provide_shared_map: RwLock>, + shared_dependency_map: RwLock>, } impl ModuleFederationPlugin { pub fn new(config: ModuleFederationConfig) -> Self { Self { config, - provide_shared_map: RwLock::new(HashMap::new()), + shared_dependency_map: RwLock::new(HashMap::new()), } } } diff --git a/crates/mako/src/plugins/module_federation/consume_shared.rs b/crates/mako/src/plugins/module_federation/consume_shared.rs index f826e9b8e..bc82bd3e4 100644 --- a/crates/mako/src/plugins/module_federation/consume_shared.rs +++ b/crates/mako/src/plugins/module_federation/consume_shared.rs @@ -20,7 +20,7 @@ impl ModuleFederationPlugin { ) -> String { let module_graph = context.module_graph.read().unwrap(); let chunk_graph = context.chunk_graph.read().unwrap(); - let share_dependencies = self.provide_shared_map.read().unwrap(); + let share_dependencies = self.shared_dependency_map.read().unwrap(); let consume_modules_chunk_map: HashMap> = chunk_graph .installable_descendants_chunk(&entry_chunk.id) diff --git a/crates/mako/src/plugins/module_federation/manifest.rs b/crates/mako/src/plugins/module_federation/manifest.rs index de0a1bf4f..975a8b67a 100644 --- a/crates/mako/src/plugins/module_federation/manifest.rs +++ b/crates/mako/src/plugins/module_federation/manifest.rs @@ -64,7 +64,7 @@ impl ModuleFederationPlugin { }), shared: { let chunk_graph = context.chunk_graph.read().unwrap(); - let provide_shared_map = self.provide_shared_map.read().unwrap(); + let provide_shared_map = self.shared_dependency_map.read().unwrap(); provide_shared_map .iter() .map(|(_, config)| { diff --git a/crates/mako/src/plugins/module_federation/provide_for_consume.rs b/crates/mako/src/plugins/module_federation/provide_for_consume.rs index b26b15347..2bb114517 100644 --- a/crates/mako/src/plugins/module_federation/provide_for_consume.rs +++ b/crates/mako/src/plugins/module_federation/provide_for_consume.rs @@ -21,7 +21,7 @@ impl ModuleFederationPlugin { }) .collect::>(); - let provide_shared_map = self.provide_shared_map.read().unwrap(); + let provide_shared_map = self.shared_dependency_map.read().unwrap(); let provide_shared_in_chunks = provide_shared_map .iter() diff --git a/crates/mako/src/plugins/module_federation/provide_shared.rs b/crates/mako/src/plugins/module_federation/provide_shared.rs index b091d976c..8ae1b5abf 100644 --- a/crates/mako/src/plugins/module_federation/provide_shared.rs +++ b/crates/mako/src/plugins/module_federation/provide_shared.rs @@ -10,7 +10,7 @@ use crate::module::ModuleId; impl ModuleFederationPlugin { pub(super) fn init_federation_runtime_sharing(&self, context: &Context) -> String { - let provide_shared_map = self.provide_shared_map.read().unwrap(); + let provide_shared_map = self.shared_dependency_map.read().unwrap(); let chunk_graph = context.chunk_graph.read().unwrap(); if provide_shared_map.is_empty() { @@ -106,10 +106,10 @@ impl ModuleFederationPlugin { && let Some(shared_info) = shared.get(&pkg_name) && pkg_name == resolved_dep.dependency.source { - let mut provide_shared_map = self.provide_shared_map.write().unwrap(); + let mut provide_shared_map = self.shared_dependency_map.write().unwrap(); provide_shared_map .entry(resolved_dep.resolver_resource.get_resolved_path()) - .or_insert(ProvideSharedItem { + .or_insert(SharedDependency { share_key: pkg_name.clone(), version: pkg_info.version.clone().unwrap(), scope: vec![shared_info.shared_scope.clone()], @@ -128,7 +128,7 @@ impl ModuleFederationPlugin { } #[derive(Debug)] -pub(super) struct ProvideSharedItem { +pub(super) struct SharedDependency { pub(super) share_key: String, pub(super) version: String, pub(super) scope: Vec, From 7a381518b8814eb173df2c960485e73479dccf01 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Thu, 23 Jan 2025 11:25:29 +0800 Subject: [PATCH 41/68] feat: add options to disable mf manifest --- crates/mako/src/config/module_federation.rs | 2 ++ crates/mako/src/plugins/module_federation.rs | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/mako/src/config/module_federation.rs b/crates/mako/src/config/module_federation.rs index b21dc359f..2541f4999 100644 --- a/crates/mako/src/config/module_federation.rs +++ b/crates/mako/src/config/module_federation.rs @@ -16,6 +16,8 @@ pub struct ModuleFederationConfig { pub share_strategy: ShareStrategy, #[serde(default = "default_share_scope")] pub share_scope: String, + #[serde(default)] + pub manifest: bool, } pub type ExposesConfig = HashMap; diff --git a/crates/mako/src/plugins/module_federation.rs b/crates/mako/src/plugins/module_federation.rs index 5569bcb0f..6e5d41ab1 100644 --- a/crates/mako/src/plugins/module_federation.rs +++ b/crates/mako/src/plugins/module_federation.rs @@ -101,7 +101,9 @@ impl Plugin for ModuleFederationPlugin { } fn generate_end(&self, params: &PluginGenerateEndParams, context: &Arc) -> Result<()> { - self.generate_federation_manifest(context, params)?; + if self.config.manifest { + self.generate_federation_manifest(context, params)?; + } Ok(()) } From 3c88b49ec7000e76af02a5a964d13b8629cb662e Mon Sep 17 00:00:00 2001 From: xusd320 Date: Thu, 23 Jan 2025 14:47:06 +0800 Subject: [PATCH 42/68] feat: entry config should be defined as BTreeMap --- crates/mako/src/config.rs | 5 ++--- crates/mako/src/module_graph.rs | 7 +++---- crates/mako/src/plugins/module_federation/container.rs | 5 +++-- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/crates/mako/src/config.rs b/crates/mako/src/config.rs index af43c9103..beff397ae 100644 --- a/crates/mako/src/config.rs +++ b/crates/mako/src/config.rs @@ -29,7 +29,7 @@ mod tree_shaking; mod umd; mod watch; -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; use std::fmt; use std::path::{Path, PathBuf}; @@ -50,7 +50,6 @@ pub use external::{ }; pub use generic_usize::GenericUsizeDefault; pub use hmr::{deserialize_hmr, HmrConfig}; -use indexmap::IndexMap; pub use inline_css::{deserialize_inline_css, InlineCssConfig}; pub use manifest::{deserialize_manifest, ManifestConfig}; use miette::{miette, ByteOffset, Diagnostic, NamedSource, SourceOffset, SourceSpan}; @@ -131,7 +130,7 @@ pub enum Platform { #[derive(Deserialize, Serialize, Debug)] #[serde(rename_all = "camelCase")] pub struct Config { - pub entry: IndexMap, + pub entry: BTreeMap, pub output: OutputConfig, pub resolve: ResolveConfig, #[serde(deserialize_with = "deserialize_manifest", default)] diff --git a/crates/mako/src/module_graph.rs b/crates/mako/src/module_graph.rs index cf13db051..765a160ff 100644 --- a/crates/mako/src/module_graph.rs +++ b/crates/mako/src/module_graph.rs @@ -1,8 +1,7 @@ -use std::collections::{HashMap, HashSet}; +use std::collections::{BTreeSet, HashMap, HashSet}; use std::fmt; use fixedbitset::FixedBitSet; -use indexmap::IndexSet; use petgraph::graph::{DefaultIx, NodeIndex}; use petgraph::prelude::{Dfs, EdgeRef}; use petgraph::stable_graph::{StableDiGraph, WalkNeighbors}; @@ -16,7 +15,7 @@ use crate::module::{Dependencies, Dependency, Module, ModuleId}; pub struct ModuleGraph { pub id_index_map: HashMap>, pub graph: StableDiGraph, - entries: IndexSet, + entries: BTreeSet, } impl ModuleGraph { @@ -24,7 +23,7 @@ impl ModuleGraph { Self { id_index_map: HashMap::new(), graph: StableDiGraph::new(), - entries: IndexSet::new(), + entries: BTreeSet::new(), } } diff --git a/crates/mako/src/plugins/module_federation/container.rs b/crates/mako/src/plugins/module_federation/container.rs index a279255b0..178225511 100644 --- a/crates/mako/src/plugins/module_federation/container.rs +++ b/crates/mako/src/plugins/module_federation/container.rs @@ -1,3 +1,4 @@ +use std::collections::btree_map; use std::fs; use std::path::Path; @@ -18,13 +19,13 @@ impl ModuleFederationPlugin { let container_entry_name = &self.config.name; if !exposes.is_empty() { match config.entry.entry(container_entry_name.clone()) { - indexmap::map::Entry::Occupied(_) => { + btree_map::Entry::Occupied(_) => { warn!( "mf exposed name {} is conflicting with entry config.", container_entry_name ); } - indexmap::map::Entry::Vacant(vacant_entry) => { + btree_map::Entry::Vacant(vacant_entry) => { // TODO: refactor with virtual entry let container_entry_code = self.get_container_entry_code(root); let container_entry_path = root.join(format!( From 6462064a75f76e1c15492bf240c157c3cdc47c0a Mon Sep 17 00:00:00 2001 From: xusd320 Date: Thu, 23 Jan 2025 18:06:29 +0800 Subject: [PATCH 43/68] fix: mf shared consume and supports eager config --- .../mako/src/generate/chunk_pot/ast_impl.rs | 2 +- .../mako/src/generate/chunk_pot/str_impl.rs | 3 +- crates/mako/src/generate/chunk_pot/util.rs | 7 +-- crates/mako/src/plugin.rs | 15 +---- crates/mako/src/plugins/async_runtime.rs | 7 +-- crates/mako/src/plugins/central_ensure.rs | 7 +-- crates/mako/src/plugins/hmr_runtime.rs | 7 +-- crates/mako/src/plugins/module_federation.rs | 5 +- .../module_federation/consume_shared.rs | 56 ++++++++++++------- .../module_federation/provide_shared.rs | 3 +- crates/mako/src/plugins/progress.rs | 7 +-- crates/mako/src/plugins/runtime.rs | 3 +- crates/mako/src/plugins/ssu.rs | 8 +-- crates/mako/src/plugins/wasm_runtime.rs | 7 +-- 14 files changed, 53 insertions(+), 84 deletions(-) diff --git a/crates/mako/src/generate/chunk_pot/ast_impl.rs b/crates/mako/src/generate/chunk_pot/ast_impl.rs index a3f905f19..793d041ad 100644 --- a/crates/mako/src/generate/chunk_pot/ast_impl.rs +++ b/crates/mako/src/generate/chunk_pot/ast_impl.rs @@ -294,7 +294,7 @@ fn render_entry_chunk_js_without_full_hash( let mut ast = { crate::mako_profile_scope!("parse_runtime_entry"); - let runtime_content = runtime_code(chunk, context)?; + let runtime_content = runtime_code(context)?; JsAst::build( "_mako_internal/runtime_entry.js", diff --git a/crates/mako/src/generate/chunk_pot/str_impl.rs b/crates/mako/src/generate/chunk_pot/str_impl.rs index 1b7a08121..beebc5a2f 100644 --- a/crates/mako/src/generate/chunk_pot/str_impl.rs +++ b/crates/mako/src/generate/chunk_pot/str_impl.rs @@ -76,8 +76,7 @@ pub(super) fn render_entry_js_chunk( lines.push(init_install_css_chunk); lines.push(format!("var e = \"{}\";", chunk_root_module_id)); - let runtime_content = - runtime_code(chunk, context)?.replace("_%full_hash%_", &hmr_hash.to_string()); + let runtime_content = runtime_code(context)?.replace("_%full_hash%_", &hmr_hash.to_string()); let entry_prefix_code = "!(function(){\n"; diff --git a/crates/mako/src/generate/chunk_pot/util.rs b/crates/mako/src/generate/chunk_pot/util.rs index 1f504b236..9688aa60f 100644 --- a/crates/mako/src/generate/chunk_pot/util.rs +++ b/crates/mako/src/generate/chunk_pot/util.rs @@ -22,7 +22,6 @@ use twox_hash::XxHash64; use crate::ast::sourcemap::build_source_map_to_buf; use crate::compiler::Context; use crate::config::Mode; -use crate::generate::chunk::Chunk; use crate::generate::chunk_pot::ChunkPot; use crate::generate::runtime::AppRuntimeTemplate; use crate::module::{relative_to_root, Module, ModuleAst}; @@ -95,7 +94,7 @@ pub(crate) fn empty_module_fn_expr() -> FnExpr { } } -pub(crate) fn runtime_code(entry_chunk: &Chunk, context: &Arc) -> Result { +pub(crate) fn runtime_code(context: &Arc) -> Result { let umd = context.config.umd.as_ref().map(|umd| umd.name.clone()); let umd_export = context.config.umd.as_ref().map_or(vec![], |umd| { umd.export @@ -132,9 +131,7 @@ pub(crate) fn runtime_code(entry_chunk: &Chunk, context: &Arc) -> Resul let app_runtime = app_runtime.render_once()?; let app_runtime = app_runtime.replace( "// __inject_runtime_code__", - &context - .plugin_driver - .runtime_plugins_code(entry_chunk, context)?, + &context.plugin_driver.runtime_plugins_code(context)?, ); Ok(app_runtime) } diff --git a/crates/mako/src/plugin.rs b/crates/mako/src/plugin.rs index fbef805c0..7ae3aabdb 100644 --- a/crates/mako/src/plugin.rs +++ b/crates/mako/src/plugin.rs @@ -12,7 +12,6 @@ use crate::ast::file::{Content, File}; use crate::build::analyze_deps::ResolvedDep; use crate::compiler::{Args, Compiler, Context}; use crate::config::{CodeSplittingAdvancedOptions, Config}; -use crate::generate::chunk::Chunk; use crate::generate::chunk_graph::ChunkGraph; use crate::generate::generate_chunks::ChunkFile; use crate::module::{Dependency, ModuleAst, ModuleId}; @@ -163,11 +162,7 @@ pub trait Plugin: Any + Send + Sync { Ok(()) } - fn runtime_plugins( - &self, - _entry_chunk: &Chunk, - _context: &Arc, - ) -> Result> { + fn runtime_plugins(&self, _context: &Arc) -> Result> { Ok(Vec::new()) } @@ -400,14 +395,10 @@ impl PluginDriver { Ok(()) } - pub fn runtime_plugins_code( - &self, - entry_chunk: &Chunk, - context: &Arc, - ) -> Result { + pub fn runtime_plugins_code(&self, context: &Arc) -> Result { let mut plugins = Vec::new(); for plugin in &self.plugins { - plugins.extend(plugin.runtime_plugins(entry_chunk, context)?); + plugins.extend(plugin.runtime_plugins(context)?); } Ok(plugins.join("\n")) } diff --git a/crates/mako/src/plugins/async_runtime.rs b/crates/mako/src/plugins/async_runtime.rs index 294d38d80..02729e977 100644 --- a/crates/mako/src/plugins/async_runtime.rs +++ b/crates/mako/src/plugins/async_runtime.rs @@ -3,7 +3,6 @@ use std::sync::Arc; use anyhow; use crate::compiler::Context; -use crate::generate::chunk::Chunk; use crate::plugin::Plugin; pub struct AsyncRuntimePlugin {} @@ -13,11 +12,7 @@ impl Plugin for AsyncRuntimePlugin { "async_runtime" } - fn runtime_plugins( - &self, - _entry_chunk: &Chunk, - context: &Arc, - ) -> anyhow::Result> { + fn runtime_plugins(&self, context: &Arc) -> anyhow::Result> { if context .module_graph .read() diff --git a/crates/mako/src/plugins/central_ensure.rs b/crates/mako/src/plugins/central_ensure.rs index 5b5f832f2..6c2c31f5e 100644 --- a/crates/mako/src/plugins/central_ensure.rs +++ b/crates/mako/src/plugins/central_ensure.rs @@ -5,7 +5,6 @@ use std::sync::Arc; use anyhow::anyhow; use crate::compiler::Context; -use crate::generate::chunk::Chunk; use crate::module::generate_module_id; use crate::plugin::Plugin; @@ -52,11 +51,7 @@ impl Plugin for CentralChunkEnsure { fn name(&self) -> &str { "dev_ensure2" } - fn runtime_plugins( - &self, - _entry_chunk: &Chunk, - context: &Arc, - ) -> anyhow::Result> { + fn runtime_plugins(&self, context: &Arc) -> anyhow::Result> { let chunk_async_map = module_ensure_map(context)?; // TODO: compress the map to reduce duplicated chunk ids diff --git a/crates/mako/src/plugins/hmr_runtime.rs b/crates/mako/src/plugins/hmr_runtime.rs index 32c60e694..2ed9b9a20 100644 --- a/crates/mako/src/plugins/hmr_runtime.rs +++ b/crates/mako/src/plugins/hmr_runtime.rs @@ -3,7 +3,6 @@ use std::sync::Arc; use anyhow; use crate::compiler::Context; -use crate::generate::chunk::Chunk; use crate::plugin::Plugin; pub struct HMRRuntimePlugin {} @@ -13,11 +12,7 @@ impl Plugin for HMRRuntimePlugin { "hmr_runtime" } - fn runtime_plugins( - &self, - _entry_chunk: &Chunk, - context: &Arc, - ) -> anyhow::Result> { + fn runtime_plugins(&self, context: &Arc) -> anyhow::Result> { if context.args.watch { Ok(vec![include_str!("hmr_runtime/hmr_runtime.js").to_string()]) } else { diff --git a/crates/mako/src/plugins/module_federation.rs b/crates/mako/src/plugins/module_federation.rs index 6e5d41ab1..7fb941833 100644 --- a/crates/mako/src/plugins/module_federation.rs +++ b/crates/mako/src/plugins/module_federation.rs @@ -11,7 +11,6 @@ use crate::build::analyze_deps::ResolvedDep; use crate::compiler::{Args, Context}; use crate::config::module_federation::ModuleFederationConfig; use crate::config::{CodeSplittingAdvancedOptions, Config}; -use crate::generate::chunk::Chunk; use crate::generate::chunk_graph::ChunkGraph; use crate::module_graph::ModuleGraph; use crate::plugin::{Plugin, PluginGenerateEndParams, PluginResolveIdParams}; @@ -75,11 +74,11 @@ impl Plugin for ModuleFederationPlugin { } } - fn runtime_plugins(&self, entry_chunk: &Chunk, context: &Arc) -> Result> { + fn runtime_plugins(&self, context: &Arc) -> Result> { Ok(vec![ self.init_federation_runtime_options(), self.init_federation_runtime_remotes(context), - self.init_federation_runtime_consume(entry_chunk, context), + self.init_federation_runtime_consume(context), self.init_federation_runtime_sharing(context), self.export_federation_container(), ]) diff --git a/crates/mako/src/plugins/module_federation/consume_shared.rs b/crates/mako/src/plugins/module_federation/consume_shared.rs index bc82bd3e4..239ec6427 100644 --- a/crates/mako/src/plugins/module_federation/consume_shared.rs +++ b/crates/mako/src/plugins/module_federation/consume_shared.rs @@ -7,34 +7,34 @@ use super::constants::FEDERATION_SHARED_REFERENCE_PREFIX; use super::ModuleFederationPlugin; use crate::build::analyze_deps::{AnalyzeDepsResult, ResolvedDep}; use crate::compiler::Context; -use crate::generate::chunk::{Chunk, ChunkType}; +use crate::generate::chunk::ChunkType; use crate::module::{md5_hash, Dependency, ResolveType}; use crate::plugin::PluginResolveIdParams; use crate::resolve::{do_resolve, ConsumeSharedInfo, ResolverResource, ResolverType}; impl ModuleFederationPlugin { - pub(super) fn init_federation_runtime_consume( - &self, - entry_chunk: &Chunk, - context: &Context, - ) -> String { + pub(super) fn init_federation_runtime_consume(&self, context: &Context) -> String { let module_graph = context.module_graph.read().unwrap(); let chunk_graph = context.chunk_graph.read().unwrap(); let share_dependencies = self.shared_dependency_map.read().unwrap(); + let mut initial_consumes = Vec::::new(); + let consume_modules_chunk_map: HashMap> = chunk_graph - .installable_descendants_chunk(&entry_chunk.id) + .get_all_chunks() .into_iter() .filter_map(|c| { - let modules = chunk_graph - .chunk(&c) - .unwrap() + let modules = c .modules .iter() .filter_map(|m| { if let Some(module) = module_graph.get_module(m) && module.is_consume_share() { + if let ChunkType::Entry(_, _, _) = c.chunk_type { + initial_consumes.push(m.id.clone()); + } + Some(m.id.clone()) } else { None @@ -44,10 +44,11 @@ impl ModuleFederationPlugin { if modules.is_empty() { None } else { - Some((c.id, modules)) + Some((c.id.id.clone(), modules)) } }) .collect(); + let consume_shared_module_ids = consume_modules_chunk_map .iter() @@ -55,17 +56,21 @@ impl ModuleFederationPlugin { acc.extend(cur.1.iter()); acc }); + let consume_shared_modules = consume_shared_module_ids .iter() .map(|id| module_graph.get_module(&id.as_str().into()).unwrap()) .collect::>(); + let module_to_handler_mapping_code = consume_shared_modules .iter() .map(|s| { let resolved_resource = s.info.as_ref().unwrap().resolved_resource.as_ref().unwrap(); let module_full_path = match resolved_resource { - ResolverResource::Shared(info) => info.deps.resolved_deps[0].resolver_resource.get_resolved_path(), - _ => panic!("{} is not a shared module", resolved_resource.get_resolved_path()) + ResolverResource::Shared(info) => + info.deps.resolved_deps[0].resolver_resource.get_resolved_path(), + _ => + panic!("{} is not a shared module", resolved_resource.get_resolved_path()) }; let module_relative_path = diff_paths(&module_full_path, &context.root) @@ -76,22 +81,26 @@ impl ModuleFederationPlugin { let module_in_chunk = chunk_graph.get_chunk_for_module(&module_full_path.as_str().into()).unwrap(); let getter = match &module_in_chunk.chunk_type { - ChunkType::Entry(_, _, false) | ChunkType::Worker(_) => { - format!( - r#"() => (() => requireModule("{module_relative_path}"))"# + ChunkType::Entry(_, _, _) | ChunkType::Worker(_) => { + format!(r#"() => (() => requireModule("{module_relative_path}"))"# ) }, ChunkType::Async | ChunkType::Sync - | ChunkType::Entry(_, _, true) => { let dependency_chunks = chunk_graph.sync_dependencies_chunk(&module_in_chunk.id); format!( r#"() => (Promise.all([{}]).then(() => requireModule("{module_relative_path}")))"#, - [dependency_chunks, vec![module_in_chunk.id.clone()]].concat().iter().map(|e| format!(r#"requireModule.ensure("{}")"#, e.id)).collect::>().join(",") + [ + dependency_chunks, + vec![module_in_chunk.id.clone()] + ] + .concat().iter() + .map(|e| format!(r#"requireModule.ensure("{}")"#, e.id)) + .collect::>().join(",") ) }, - ChunkType::Runtime => panic!("mf shared dependency should not bundled to runtime chunk") + ChunkType::Runtime => panic!("mf shared dependency should not be bundled to runtime chunk") }; let share_dependency = share_dependencies.get(&s.id.id).unwrap(); @@ -110,6 +119,7 @@ impl ModuleFederationPlugin { .collect::>() .join(","); + let initial_consumes_code = serde_json::to_string(&initial_consumes).unwrap(); let chunk_mapping_code = serde_json::to_string(&consume_modules_chunk_map).unwrap(); format!( r#" @@ -117,7 +127,7 @@ impl ModuleFederationPlugin { !(() => {{ var installedModules = {{}}; var moduleToHandlerMapping = {{{module_to_handler_mapping_code}}}; - + var initialConsumes = {initial_consumes_code}; var chunkMapping = {chunk_mapping_code}; requireModule.chunkEnsures.consumes = (chunkId, promises) => {{ requireModule.federation.bundlerRuntime.consumes({{ @@ -189,7 +199,11 @@ impl ModuleFederationPlugin { dependency: Dependency { source: params.dep.source.clone(), resolve_as: None, - resolve_type: ResolveType::DynamicImport(Default::default()), + resolve_type: if shared_info.eager { + ResolveType::Require + } else { + ResolveType::DynamicImport(Default::default()) + }, order: params.dep.order, span: params.dep.span, }, diff --git a/crates/mako/src/plugins/module_federation/provide_shared.rs b/crates/mako/src/plugins/module_federation/provide_shared.rs index 8ae1b5abf..a6f0e59cf 100644 --- a/crates/mako/src/plugins/module_federation/provide_shared.rs +++ b/crates/mako/src/plugins/module_federation/provide_shared.rs @@ -36,14 +36,13 @@ impl ModuleFederationPlugin { .to_string(); match &module_in_chunk.chunk_type { - ChunkType::Entry(_, _, false) | ChunkType::Worker(_) => { + ChunkType::Entry(_, _, _) | ChunkType::Worker(_) => { format!( r#"() => (() => requireModule("{module_relative_path}"))"# ) }, ChunkType::Async | ChunkType::Sync - | ChunkType::Entry(_, _, true) => { let dependency_chunks = chunk_graph.sync_dependencies_chunk(&module_in_chunk.id); format!( diff --git a/crates/mako/src/plugins/progress.rs b/crates/mako/src/plugins/progress.rs index a5c8ec959..b68d3b304 100644 --- a/crates/mako/src/plugins/progress.rs +++ b/crates/mako/src/plugins/progress.rs @@ -7,7 +7,6 @@ use parking_lot::Mutex; use crate::ast::file::Content; use crate::compiler::Context; -use crate::generate::chunk::Chunk; use crate::plugin::{Plugin, PluginLoadParam}; /* @@ -279,11 +278,7 @@ impl Plugin for ProgressPlugin { Ok(()) } - fn runtime_plugins( - &self, - _entry_chunk: &Chunk, - _context: &Arc, - ) -> anyhow::Result> { + fn runtime_plugins(&self, _context: &Arc) -> anyhow::Result> { self.handler( 0.9, "runtime plugins".to_string(), diff --git a/crates/mako/src/plugins/runtime.rs b/crates/mako/src/plugins/runtime.rs index 7bc787ba3..dedd7d18a 100644 --- a/crates/mako/src/plugins/runtime.rs +++ b/crates/mako/src/plugins/runtime.rs @@ -3,7 +3,6 @@ use std::sync::Arc; use anyhow::{anyhow, Result}; use crate::compiler::Context; -use crate::generate::chunk::Chunk; use crate::generate::swc_helpers::SwcHelpers; use crate::module::ModuleId; use crate::plugin::Plugin; @@ -15,7 +14,7 @@ impl Plugin for MakoRuntime { "mako/runtime" } - fn runtime_plugins(&self, _entry_chunk: &Chunk, context: &Arc) -> Result> { + fn runtime_plugins(&self, context: &Arc) -> Result> { let plugins = vec![ self.public_path(context), self.helper_runtime(context).unwrap(), diff --git a/crates/mako/src/plugins/ssu.rs b/crates/mako/src/plugins/ssu.rs index cf0c10307..bee841d00 100644 --- a/crates/mako/src/plugins/ssu.rs +++ b/crates/mako/src/plugins/ssu.rs @@ -18,7 +18,7 @@ use crate::config::{ AllowChunks, ChunkGroup, CodeSplitting, CodeSplittingAdvancedOptions, CodeSplittingStrategy, CodeSplittingStrategyOptions, Config, }; -use crate::generate::chunk::{Chunk, ChunkType}; +use crate::generate::chunk::ChunkType; use crate::generate::chunk_pot::util::{hash_hashmap, hash_vec}; use crate::generate::generate_chunks::{ChunkFile, ChunkFileType}; use crate::generate::transform::transform_modules; @@ -554,11 +554,7 @@ module.export = Promise.all( Ok(()) } - fn runtime_plugins( - &self, - _entry_chunk: &Chunk, - _context: &Arc, - ) -> Result> { + fn runtime_plugins(&self, _context: &Arc) -> Result> { if *self.cache_valid.lock().unwrap() { let cache = self.cached_state.lock().unwrap(); diff --git a/crates/mako/src/plugins/wasm_runtime.rs b/crates/mako/src/plugins/wasm_runtime.rs index 6059db934..8087bd106 100644 --- a/crates/mako/src/plugins/wasm_runtime.rs +++ b/crates/mako/src/plugins/wasm_runtime.rs @@ -8,7 +8,6 @@ use wasmparser::{Import, Parser, Payload}; use crate::ast::file::{Content, JsContent}; use crate::compiler::Context; -use crate::generate::chunk::Chunk; use crate::plugin::{Plugin, PluginLoadParam}; pub struct WasmRuntimePlugin {} @@ -20,11 +19,7 @@ impl Plugin for WasmRuntimePlugin { "wasm_runtime" } - fn runtime_plugins( - &self, - _entry_chunk: &Chunk, - context: &Arc, - ) -> anyhow::Result> { + fn runtime_plugins(&self, context: &Arc) -> anyhow::Result> { if context .assets_info .lock() From 2ac48bc4cbaec05d1e0d6827bedf8534feb26e94 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Thu, 23 Jan 2025 18:45:50 +0800 Subject: [PATCH 44/68] fix: mf shared eager --- .../src/plugins/module_federation/consume_shared.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/crates/mako/src/plugins/module_federation/consume_shared.rs b/crates/mako/src/plugins/module_federation/consume_shared.rs index 239ec6427..9df8b4200 100644 --- a/crates/mako/src/plugins/module_federation/consume_shared.rs +++ b/crates/mako/src/plugins/module_federation/consume_shared.rs @@ -120,6 +120,17 @@ impl ModuleFederationPlugin { .join(","); let initial_consumes_code = serde_json::to_string(&initial_consumes).unwrap(); + let install_initial_comsumes_code = if initial_consumes.is_empty() { + "" + } else { + r#" + requireModule.federation.installInitialConsumes = () => (requireModule.federation.bundlerRuntime.installInitialConsumes({ + initialConsumes: initialConsumes, + installedModules: installedModules, + moduleToHandlerMapping: moduleToHandlerMapping, + webpackRequire: requireModule + }))"# + }; let chunk_mapping_code = serde_json::to_string(&consume_modules_chunk_map).unwrap(); format!( r#" @@ -128,6 +139,7 @@ impl ModuleFederationPlugin { var installedModules = {{}}; var moduleToHandlerMapping = {{{module_to_handler_mapping_code}}}; var initialConsumes = {initial_consumes_code}; + {install_initial_comsumes_code} var chunkMapping = {chunk_mapping_code}; requireModule.chunkEnsures.consumes = (chunkId, promises) => {{ requireModule.federation.bundlerRuntime.consumes({{ From 1b8b9d9fe44ca471aa1616c2af33281e6c5d1970 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Fri, 24 Jan 2025 15:30:21 +0800 Subject: [PATCH 45/68] fix: not generate chunk for mf remote module --- crates/mako/src/build.rs | 4 ++-- crates/mako/src/generate/chunk.rs | 4 ++++ crates/mako/src/generate/generate_chunks.rs | 23 +++++++++++++++++-- crates/mako/src/generate/optimize_chunk.rs | 2 +- .../module_federation/container_reference.rs | 5 +--- crates/mako/src/stats.rs | 6 ++--- crates/mako/templates/app_runtime.stpl | 3 +++ .../module-federation/host/mako.config.json | 3 ++- examples/module-federation/host/package.json | 4 +++- examples/module-federation/host/src/App.tsx | 15 ++++++++---- examples/module-federation/host/src/index.ts | 2 +- .../module-federation/widget/mako.config.json | 4 ++-- .../module-federation/widget/package.json | 4 +++- 13 files changed, 56 insertions(+), 23 deletions(-) diff --git a/crates/mako/src/build.rs b/crates/mako/src/build.rs index aa4be17b5..d061d9aab 100644 --- a/crates/mako/src/build.rs +++ b/crates/mako/src/build.rs @@ -16,7 +16,7 @@ use crate::ast::file::{Content, File, JsContent}; use crate::ast::utils::get_module_system; use crate::compiler::{Compiler, Context}; use crate::generate::chunk_pot::util::hash_hashmap; -use crate::module::{FedereationModuleType, Module, ModuleAst, ModuleId, ModuleInfo}; +use crate::module::{FedereationModuleType, Module, ModuleAst, ModuleId, ModuleInfo, ModuleSystem}; use crate::plugin::NextBuildParam; use crate::resolve::{ConsumeSharedInfo, RemoteInfo, ResolverResource}; use crate::utils::thread_pool; @@ -376,7 +376,7 @@ __mako_require__.loadScript('{}', (e) => e.type === 'load' ? resolve() : reject( deps: consume_share_info.deps.clone(), resolved_resource: Some(ResolverResource::Shared(consume_share_info.clone())), federation: Some(FedereationModuleType::ConsumeShare), - module_system: crate::module::ModuleSystem::Custom, + module_system: ModuleSystem::Custom, ..Default::default() }), side_effects: true, diff --git a/crates/mako/src/generate/chunk.rs b/crates/mako/src/generate/chunk.rs index 6bd52993d..e1817e8fb 100644 --- a/crates/mako/src/generate/chunk.rs +++ b/crates/mako/src/generate/chunk.rs @@ -137,6 +137,10 @@ impl Chunk { self.modules.contains(module_id) } + pub fn root_module(&self) -> Option<&ModuleId> { + self.modules.iter().last() + } + pub fn hash(&self, mg: &ModuleGraph) -> u64 { let mut sorted_module_ids = self.modules.iter().cloned().collect::>(); sorted_module_ids.sort_by_key(|m| m.id.clone()); diff --git a/crates/mako/src/generate/generate_chunks.rs b/crates/mako/src/generate/generate_chunks.rs index 0e9646753..90499e1fd 100644 --- a/crates/mako/src/generate/generate_chunks.rs +++ b/crates/mako/src/generate/generate_chunks.rs @@ -83,9 +83,19 @@ type ChunksHashReplacer = HashMap; impl Compiler { pub fn generate_chunk_files(&self, hmr_hash: u64) -> Result> { - crate::mako_profile_function!(); + let module_graph = self.context.module_graph.read().unwrap(); let chunk_graph = self.context.chunk_graph.read().unwrap(); - let chunks = chunk_graph.get_chunks(); + + let chunks: Vec<&Chunk> = chunk_graph + .get_chunks() + .into_iter() + .filter(|c| { + !module_graph + .get_module(c.root_module().unwrap()) + .unwrap() + .is_remote() + }) + .collect(); let (entry_chunks, normal_chunks): (Vec<&Chunk>, Vec<&Chunk>) = chunks .into_iter() @@ -173,6 +183,15 @@ impl Compiler { let descendant_chunk = chunk_graph.chunk(descendant_chunk_id).unwrap(); // TODO: maybe we can split chunks to chunk pots before generate, because normal chunks will be // split here and fn generate_normal_chunk_files twice + // + if module_graph + .get_module(descendant_chunk.root_module().unwrap()) + .unwrap() + .is_remote() + { + return (acc_js, acc_css); + } + let chunk_pot = ChunkPot::from(descendant_chunk, &module_graph, &context); diff --git a/crates/mako/src/generate/optimize_chunk.rs b/crates/mako/src/generate/optimize_chunk.rs index d3f42822c..4eb5e1701 100644 --- a/crates/mako/src/generate/optimize_chunk.rs +++ b/crates/mako/src/generate/optimize_chunk.rs @@ -127,7 +127,7 @@ impl Compiler { let async_chunk_root_modules = chunks .iter() .filter_map(|chunk| match chunk.chunk_type { - ChunkType::Async => chunk.modules.iter().last(), + ChunkType::Async => chunk.root_module(), _ => None, }) .collect::>(); diff --git a/crates/mako/src/plugins/module_federation/container_reference.rs b/crates/mako/src/plugins/module_federation/container_reference.rs index 1741a8e87..1e53d6c24 100644 --- a/crates/mako/src/plugins/module_federation/container_reference.rs +++ b/crates/mako/src/plugins/module_federation/container_reference.rs @@ -8,7 +8,6 @@ use super::{ ModuleFederationPlugin, FEDERATION_REMOTE_MODULE_PREFIX, FEDERATION_REMOTE_REFERENCE_PREFIX, }; use crate::compiler::Context; -use crate::module::FedereationModuleType; use crate::resolve::{RemoteInfo, ResolverResource}; impl ModuleFederationPlugin { @@ -23,9 +22,7 @@ impl ModuleFederationPlugin { all_chunks.iter().for_each(|c| { c.modules.iter().for_each(|m| { if let Some(m) = module_graph.get_module(m) { - if let Some(info) = m.info.as_ref() - && let Some(FedereationModuleType::Remote) = info.federation.as_ref() - { + if m.is_remote() { { chunk_mapping .entry(c.id.id.as_str()) diff --git a/crates/mako/src/stats.rs b/crates/mako/src/stats.rs index b9edca043..71cf8b2da 100644 --- a/crates/mako/src/stats.rs +++ b/crates/mako/src/stats.rs @@ -124,11 +124,9 @@ impl Compiler { ChunkType::Sync => chunk_graph .dependents_chunk(&chunk.id) .iter() - .filter_map(|chunk_id| { - chunk_graph.chunk(chunk_id).unwrap().modules.iter().last() - }) + .filter_map(|chunk_id| chunk_graph.chunk(chunk_id).unwrap().root_module()) .collect::>(), - _ => vec![chunk.modules.iter().last().unwrap()], + _ => vec![chunk.root_module().unwrap()], }; let mut origins_set = IndexMap::new(); for origin_chunk_module in origin_chunk_modules { diff --git a/crates/mako/templates/app_runtime.stpl b/crates/mako/templates/app_runtime.stpl index 487c45056..5af7b8335 100644 --- a/crates/mako/templates/app_runtime.stpl +++ b/crates/mako/templates/app_runtime.stpl @@ -135,6 +135,9 @@ function createRuntime(makoModules, entryModuleId, global) { var data = installedChunks[chunkId]; if (data === 0) return; + // skip federation remote chunk + if (chunkId.startsWith("mako/container/remote/")) return; + if (data) { // 0 1 2 // [resolve, reject, promise] diff --git a/examples/module-federation/host/mako.config.json b/examples/module-federation/host/mako.config.json index aaf0d38a6..583361685 100644 --- a/examples/module-federation/host/mako.config.json +++ b/examples/module-federation/host/mako.config.json @@ -2,12 +2,13 @@ "entry": { "app1": "./src/index.ts" }, + "minify": false, "moduleFederation": { "name": "mfHost", "remotes": { "widget": "mfWidget@http://localhost:3000/mfWidget.js" }, - "shared": { "react": {}, "react-dom": {} }, + "shared": { "react": { "eager": true }, "react-dom": { "eager": true } }, "implementation": "../../../../../packages/mako/node_modules/@module-federation/webpack-bundler-runtime" }, "experimental": { diff --git a/examples/module-federation/host/package.json b/examples/module-federation/host/package.json index 6035f9496..1f3c721bc 100644 --- a/examples/module-federation/host/package.json +++ b/examples/module-federation/host/package.json @@ -3,6 +3,8 @@ "version": "0.0.1", "dependencies": { "react": "18.2.0", - "react-dom": "18.2.0" + "react-dom": "18.2.0", + "@types/react": "18.2.0", + "@types/react-dom": "18.2.0" } } diff --git a/examples/module-federation/host/src/App.tsx b/examples/module-federation/host/src/App.tsx index b0db6db67..1cc8f71ef 100644 --- a/examples/module-federation/host/src/App.tsx +++ b/examples/module-federation/host/src/App.tsx @@ -1,6 +1,9 @@ import React from 'react'; -import Widget1 from 'widget/App1'; -import Widget2 from 'widget/App2'; +// import Widget1 from 'widget/App1'; +// import Widget2 from 'widget/App2'; + +const Widget1 = React.lazy(() => import('widget/App1')); +const Widget2 = React.lazy(() => import('widget/App2')); const App = () => { return ( @@ -15,8 +18,12 @@ const App = () => { >

Host App

- - + + + + + + ); }; diff --git a/examples/module-federation/host/src/index.ts b/examples/module-federation/host/src/index.ts index b93c7a026..e59d6a0ad 100644 --- a/examples/module-federation/host/src/index.ts +++ b/examples/module-federation/host/src/index.ts @@ -1 +1 @@ -import('./bootstrap'); +import './bootstrap'; diff --git a/examples/module-federation/widget/mako.config.json b/examples/module-federation/widget/mako.config.json index c5576b24d..deb504a5f 100644 --- a/examples/module-federation/widget/mako.config.json +++ b/examples/module-federation/widget/mako.config.json @@ -2,6 +2,7 @@ "entry": { "app2": "./src/index.ts" }, + "minify": false, "publicPath": "auto", "moduleFederation": { "name": "mfWidget", @@ -25,8 +26,7 @@ "groups": [ { "name": "vendor", - "allowChunks": "all", - "minSize": 1, + "allowChunks": "async", "test": "node_modules" } ] diff --git a/examples/module-federation/widget/package.json b/examples/module-federation/widget/package.json index 716e343bf..2c7c3154d 100644 --- a/examples/module-federation/widget/package.json +++ b/examples/module-federation/widget/package.json @@ -3,6 +3,8 @@ "version": "0.0.1", "dependencies": { "react": "18.2.0", - "react-dom": "18.2.0" + "react-dom": "18.2.0", + "@types/react": "18.2.0", + "@types/react-dom": "18.2.0" } } From 53780307e3375c42a35a50619921ebada3ba990b Mon Sep 17 00:00:00 2001 From: xusd320 Date: Fri, 24 Jan 2025 15:32:11 +0800 Subject: [PATCH 46/68] fix: typos --- crates/mako/src/plugins/module_federation/consume_shared.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/mako/src/plugins/module_federation/consume_shared.rs b/crates/mako/src/plugins/module_federation/consume_shared.rs index 9df8b4200..296a8f96b 100644 --- a/crates/mako/src/plugins/module_federation/consume_shared.rs +++ b/crates/mako/src/plugins/module_federation/consume_shared.rs @@ -120,7 +120,7 @@ impl ModuleFederationPlugin { .join(","); let initial_consumes_code = serde_json::to_string(&initial_consumes).unwrap(); - let install_initial_comsumes_code = if initial_consumes.is_empty() { + let install_initial_consumes_code = if initial_consumes.is_empty() { "" } else { r#" @@ -139,7 +139,7 @@ impl ModuleFederationPlugin { var installedModules = {{}}; var moduleToHandlerMapping = {{{module_to_handler_mapping_code}}}; var initialConsumes = {initial_consumes_code}; - {install_initial_comsumes_code} + {install_initial_consumes_code} var chunkMapping = {chunk_mapping_code}; requireModule.chunkEnsures.consumes = (chunkId, promises) => {{ requireModule.federation.bundlerRuntime.consumes({{ From c4e1ff98f67841d117ec7344bd824d0217cb32c4 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Thu, 6 Feb 2025 12:59:13 +0800 Subject: [PATCH 47/68] feat: add entry filename supports --- crates/mako/src/compiler.rs | 2 +- crates/mako/src/config.rs | 29 ++++++++++----- crates/mako/src/config/entry.rs | 37 +++++++++++++++++++ crates/mako/src/config/module_federation.rs | 1 + crates/mako/src/config/umd.rs | 9 ++--- crates/mako/src/dev/update.rs | 2 +- crates/mako/src/generate/chunk.rs | 7 +++- .../mako/src/generate/chunk_pot/ast_impl.rs | 11 +++++- .../mako/src/generate/chunk_pot/str_impl.rs | 11 +++++- crates/mako/src/generate/group_chunk.rs | 2 +- .../plugins/module_federation/container.rs | 6 ++- crates/mako/src/plugins/ssu.rs | 2 +- .../module-federation/host/mako.config.json | 2 +- .../module-federation/widget/mako.config.json | 1 + 14 files changed, 98 insertions(+), 24 deletions(-) create mode 100644 crates/mako/src/config/entry.rs diff --git a/crates/mako/src/compiler.rs b/crates/mako/src/compiler.rs index 12cb27d8f..187d9f3da 100644 --- a/crates/mako/src/compiler.rs +++ b/crates/mako/src/compiler.rs @@ -427,7 +427,7 @@ impl Compiler { .entry .values() .map(|entry| { - let mut entry = entry.to_string_lossy().to_string(); + let mut entry = entry.import.to_string_lossy().to_string(); let is_browser = matches!( self.context.config.platform, crate::config::Platform::Browser diff --git a/crates/mako/src/config.rs b/crates/mako/src/config.rs index beff397ae..8d6e6159b 100644 --- a/crates/mako/src/config.rs +++ b/crates/mako/src/config.rs @@ -3,6 +3,7 @@ mod code_splitting; mod dev_server; mod devtool; mod duplicate_package_checker; +pub mod entry; mod experimental; mod external; mod generic_usize; @@ -29,9 +30,9 @@ mod tree_shaking; mod umd; mod watch; -use std::collections::{BTreeMap, HashMap}; +use std::collections::HashMap; use std::fmt; -use std::path::{Path, PathBuf}; +use std::path::Path; pub use analyze::AnalyzeConfig; use anyhow::{anyhow, Result}; @@ -43,6 +44,7 @@ pub use devtool::{deserialize_devtool, DevtoolConfig}; pub use duplicate_package_checker::{ deserialize_check_duplicate_package, DuplicatePackageCheckerConfig, }; +use entry::{Entry, EntryItem}; use experimental::ExperimentalConfig; pub use external::{ ExternalAdvanced, ExternalAdvancedSubpath, ExternalAdvancedSubpathConverter, @@ -130,7 +132,7 @@ pub enum Platform { #[derive(Deserialize, Serialize, Debug)] #[serde(rename_all = "camelCase")] pub struct Config { - pub entry: BTreeMap, + pub entry: Entry, pub output: OutputConfig, pub resolve: ResolveConfig, #[serde(deserialize_with = "deserialize_manifest", default)] @@ -365,7 +367,13 @@ impl Config { for ext in JS_EXTENSIONS { let file_path = root.join(file_path).with_extension(ext); if file_path.exists() { - config.entry.insert("index".to_string(), file_path); + config.entry.insert( + "index".to_string(), + EntryItem { + filename: None, + import: file_path, + }, + ); break 'outer; } } @@ -378,28 +386,29 @@ impl Config { // normalize entry config.entry.iter_mut().try_for_each(|(k, v)| { #[allow(clippy::needless_borrows_for_generic_args)] - if let Ok(entry_path) = root.join(&v).canonicalize() + if let Ok(entry_path) = root.join(&v.import).canonicalize() && entry_path.is_file() { - *v = entry_path; + v.import = entry_path; } else { for ext in JS_EXTENSIONS { #[allow(clippy::needless_borrows_for_generic_args)] - if let Ok(entry_path) = root.join(&v).with_extension(ext).canonicalize() + if let Ok(entry_path) = + root.join(&v.import).with_extension(ext).canonicalize() && entry_path.is_file() { - *v = entry_path; + v.import = entry_path; return Ok(()); } if let Ok(entry_path) = root - .join(&v) + .join(&v.import) .join("index") .with_extension(ext) .canonicalize() && entry_path.is_file() { - *v = entry_path; + v.import = entry_path; return Ok(()); } } diff --git a/crates/mako/src/config/entry.rs b/crates/mako/src/config/entry.rs new file mode 100644 index 000000000..87ce2811d --- /dev/null +++ b/crates/mako/src/config/entry.rs @@ -0,0 +1,37 @@ +use std::collections::BTreeMap; +use std::path::PathBuf; + +use serde::{Deserialize, Serialize}; +use serde_json::Value; + +#[derive(Serialize, Debug)] +pub struct EntryItem { + #[serde(default)] + pub filename: Option, + pub import: PathBuf, +} + +pub type Entry = BTreeMap; + +impl<'de> Deserialize<'de> for EntryItem { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let value: serde_json::Value = serde_json::Value::deserialize(deserializer)?; + match &value { + Value::String(s) => Ok(EntryItem { + filename: None, + import: s.into(), + }), + Value::Object(_) => { + Ok(serde_json::from_value::(value).map_err(serde::de::Error::custom)?) + } + _ => Err(serde::de::Error::custom(format!( + "invalid `{}` value: {}", + stringify!(deserialize_umd).replace("deserialize_", ""), + value + ))), + } + } +} diff --git a/crates/mako/src/config/module_federation.rs b/crates/mako/src/config/module_federation.rs index 2541f4999..314c3bb0a 100644 --- a/crates/mako/src/config/module_federation.rs +++ b/crates/mako/src/config/module_federation.rs @@ -6,6 +6,7 @@ use serde::{Deserialize, Serialize}; #[serde(rename_all = "camelCase")] pub struct ModuleFederationConfig { pub name: String, + pub filename: Option, pub exposes: Option, pub shared: Option, pub remotes: Option, diff --git a/crates/mako/src/config/umd.rs b/crates/mako/src/config/umd.rs index 5c64dfa44..6ddbba0f4 100644 --- a/crates/mako/src/config/umd.rs +++ b/crates/mako/src/config/umd.rs @@ -12,13 +12,12 @@ where D: serde::Deserializer<'de>, { let value: serde_json::Value = serde_json::Value::deserialize(deserializer)?; - match value { - serde_json::Value::Object(obj) => Ok(Some( - serde_json::from_value::(serde_json::Value::Object(obj)) - .map_err(serde::de::Error::custom)?, + match &value { + serde_json::Value::Object(_) => Ok(Some( + serde_json::from_value::(value).map_err(serde::de::Error::custom)?, )), serde_json::Value::String(name) => Ok(Some(Umd { - name, + name: name.clone(), ..Default::default() })), serde_json::Value::Bool(false) => Ok(None), diff --git a/crates/mako/src/dev/update.rs b/crates/mako/src/dev/update.rs index cc041f742..0ecc1f7d2 100644 --- a/crates/mako/src/dev/update.rs +++ b/crates/mako/src/dev/update.rs @@ -283,7 +283,7 @@ impl Compiler { debug!("build by modify: {:?} start", entry); // first build let is_entry = { - let mut entries = self.context.config.entry.values(); + let mut entries = self.context.config.entry.values().map(|e| &e.import); entries.any(|e| e.eq(entry)) }; diff --git a/crates/mako/src/generate/chunk.rs b/crates/mako/src/generate/chunk.rs index e1817e8fb..5f13a52c2 100644 --- a/crates/mako/src/generate/chunk.rs +++ b/crates/mako/src/generate/chunk.rs @@ -118,7 +118,12 @@ impl Chunk { } pub fn filename(&self) -> String { - format!("{}.js", self.name()) + let name = self.name(); + if name.ends_with(".js") { + name + } else { + format!("{}.js", self.name()) + } } pub fn add_module(&mut self, module_id: ModuleId) { diff --git a/crates/mako/src/generate/chunk_pot/ast_impl.rs b/crates/mako/src/generate/chunk_pot/ast_impl.rs index 793d041ad..44116bf71 100644 --- a/crates/mako/src/generate/chunk_pot/ast_impl.rs +++ b/crates/mako/src/generate/chunk_pot/ast_impl.rs @@ -218,6 +218,11 @@ pub(crate) fn render_entry_js_chunk( .into_bytes() }; + let entry_info = match &chunk.chunk_type { + ChunkType::Entry(_, name, _) => context.config.entry.get(name).unwrap(), + _ => panic!("normal chunk {} rendered as entry chunk", chunk.id.id), + }; + Ok(ChunkFile { raw_hash: hmr_hash, content, @@ -227,7 +232,11 @@ pub(crate) fn render_entry_js_chunk( chunk_id: pot.chunk_id.clone(), file_type: ChunkFileType::JS, chunk_name: pot.chunk_name.clone(), - file_name_template: context.config.output.filename.clone(), + file_name_template: entry_info + .filename + .as_ref() + .xor(context.config.output.filename.as_ref()) + .cloned(), }) } diff --git a/crates/mako/src/generate/chunk_pot/str_impl.rs b/crates/mako/src/generate/chunk_pot/str_impl.rs index beebc5a2f..991cd40b3 100644 --- a/crates/mako/src/generate/chunk_pot/str_impl.rs +++ b/crates/mako/src/generate/chunk_pot/str_impl.rs @@ -95,6 +95,11 @@ pub(super) fn render_entry_js_chunk( let mut source_map_buf: Vec = vec![]; sourcemap::SourceMap::from(chunk_raw_sourcemap).to_writer(&mut source_map_buf)?; + let entry_info = match &chunk.chunk_type { + ChunkType::Entry(_, name, _) => context.config.entry.get(name).unwrap(), + _ => panic!("normal chunk {} rendered as entry chunk", chunk.id.id), + }; + Ok(ChunkFile { raw_hash: hmr_hash, content, @@ -103,7 +108,11 @@ pub(super) fn render_entry_js_chunk( file_name: pot.js_name.clone(), chunk_id: pot.chunk_id.clone(), file_type: ChunkFileType::JS, - file_name_template: None, + file_name_template: entry_info + .filename + .as_ref() + .xor(context.config.output.filename.as_ref()) + .cloned(), chunk_name: pot.chunk_name.clone(), }) } diff --git a/crates/mako/src/generate/group_chunk.rs b/crates/mako/src/generate/group_chunk.rs index c08a40fe3..3e84f525a 100644 --- a/crates/mako/src/generate/group_chunk.rs +++ b/crates/mako/src/generate/group_chunk.rs @@ -31,7 +31,7 @@ impl Compiler { for (key, value) in &self.context.config.entry { // hmr entry id has query '?hmr' - if parse_path(&value.to_string_lossy()).unwrap().0 + if parse_path(&value.import.to_string_lossy()).unwrap().0 == parse_path(&entry.id).unwrap().0 { entry_chunk_name = key; diff --git a/crates/mako/src/plugins/module_federation/container.rs b/crates/mako/src/plugins/module_federation/container.rs index 178225511..442f362b2 100644 --- a/crates/mako/src/plugins/module_federation/container.rs +++ b/crates/mako/src/plugins/module_federation/container.rs @@ -8,6 +8,7 @@ use tracing::warn; use super::constants::{FEDERATION_EXPOSE_CHUNK_PREFIX, FEDERATION_GLOBAL}; use super::util::parse_remote; use super::ModuleFederationPlugin; +use crate::config::entry::EntryItem; use crate::config::{AllowChunks, Config}; use crate::module::md5_hash; use crate::visitors::mako_require::MAKO_REQUIRE; @@ -38,7 +39,10 @@ impl ModuleFederationPlugin { } fs::write(&container_entry_path, container_entry_code).unwrap(); - vacant_entry.insert(container_entry_path); + vacant_entry.insert(EntryItem { + filename: self.config.filename.clone(), + import: container_entry_path, + }); } } } diff --git a/crates/mako/src/plugins/ssu.rs b/crates/mako/src/plugins/ssu.rs index bee841d00..52bd99f35 100644 --- a/crates/mako/src/plugins/ssu.rs +++ b/crates/mako/src/plugins/ssu.rs @@ -166,7 +166,7 @@ impl Plugin for SUPlus { fn modify_config(&self, config: &mut Config, _root: &Path, _args: &Args) -> Result<()> { for p in config.entry.values_mut() { - *p = PathBuf::from(format!("{SSU_ENTRY_PREFIX}{}", p.to_string_lossy())); + p.import = PathBuf::from(format!("{SSU_ENTRY_PREFIX}{}", p.import.to_string_lossy())); } config.code_splitting = Some(CodeSplitting { diff --git a/examples/module-federation/host/mako.config.json b/examples/module-federation/host/mako.config.json index 583361685..bb73b47fb 100644 --- a/examples/module-federation/host/mako.config.json +++ b/examples/module-federation/host/mako.config.json @@ -6,7 +6,7 @@ "moduleFederation": { "name": "mfHost", "remotes": { - "widget": "mfWidget@http://localhost:3000/mfWidget.js" + "widget": "mfWidget@http://localhost:3000/remoteEntry.js" }, "shared": { "react": { "eager": true }, "react-dom": { "eager": true } }, "implementation": "../../../../../packages/mako/node_modules/@module-federation/webpack-bundler-runtime" diff --git a/examples/module-federation/widget/mako.config.json b/examples/module-federation/widget/mako.config.json index deb504a5f..bf67e0f18 100644 --- a/examples/module-federation/widget/mako.config.json +++ b/examples/module-federation/widget/mako.config.json @@ -6,6 +6,7 @@ "publicPath": "auto", "moduleFederation": { "name": "mfWidget", + "filename": "remoteEntry.js", "exposes": { "./App1": "./src/App1.tsx", "./App2": "./src/App2.tsx" From 4a0eabb87268e859d78ac8a7f6de252394f72d88 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Thu, 6 Feb 2025 13:42:18 +0800 Subject: [PATCH 48/68] chore: remove meaning less changes --- crates/mako/src/generate/chunk.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/crates/mako/src/generate/chunk.rs b/crates/mako/src/generate/chunk.rs index 5f13a52c2..e1817e8fb 100644 --- a/crates/mako/src/generate/chunk.rs +++ b/crates/mako/src/generate/chunk.rs @@ -118,12 +118,7 @@ impl Chunk { } pub fn filename(&self) -> String { - let name = self.name(); - if name.ends_with(".js") { - name - } else { - format!("{}.js", self.name()) - } + format!("{}.js", self.name()) } pub fn add_module(&mut self, module_id: ModuleId) { From 755f5e0e4c9d33ef8474ee680f9c22dfbf2d2649 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Thu, 6 Feb 2025 15:08:17 +0800 Subject: [PATCH 49/68] fix: entry filename and mf config --- crates/mako/src/generate/chunk_pot/ast_impl.rs | 18 ++++++++++-------- crates/mako/src/generate/chunk_pot/str_impl.rs | 18 ++++++++++-------- packages/mako/src/index.ts | 7 +++++-- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/crates/mako/src/generate/chunk_pot/ast_impl.rs b/crates/mako/src/generate/chunk_pot/ast_impl.rs index 44116bf71..7d775cdb0 100644 --- a/crates/mako/src/generate/chunk_pot/ast_impl.rs +++ b/crates/mako/src/generate/chunk_pot/ast_impl.rs @@ -218,9 +218,10 @@ pub(crate) fn render_entry_js_chunk( .into_bytes() }; - let entry_info = match &chunk.chunk_type { - ChunkType::Entry(_, name, _) => context.config.entry.get(name).unwrap(), - _ => panic!("normal chunk {} rendered as entry chunk", chunk.id.id), + let entry_info = if let ChunkType::Entry(_, name, _) = &chunk.chunk_type { + context.config.entry.get(name) + } else { + None }; Ok(ChunkFile { @@ -232,11 +233,12 @@ pub(crate) fn render_entry_js_chunk( chunk_id: pot.chunk_id.clone(), file_type: ChunkFileType::JS, chunk_name: pot.chunk_name.clone(), - file_name_template: entry_info - .filename - .as_ref() - .xor(context.config.output.filename.as_ref()) - .cloned(), + file_name_template: entry_info.and_then(|e| { + e.filename + .as_ref() + .xor(context.config.output.filename.as_ref()) + .cloned() + }), }) } diff --git a/crates/mako/src/generate/chunk_pot/str_impl.rs b/crates/mako/src/generate/chunk_pot/str_impl.rs index 991cd40b3..430ae3218 100644 --- a/crates/mako/src/generate/chunk_pot/str_impl.rs +++ b/crates/mako/src/generate/chunk_pot/str_impl.rs @@ -95,9 +95,10 @@ pub(super) fn render_entry_js_chunk( let mut source_map_buf: Vec = vec![]; sourcemap::SourceMap::from(chunk_raw_sourcemap).to_writer(&mut source_map_buf)?; - let entry_info = match &chunk.chunk_type { - ChunkType::Entry(_, name, _) => context.config.entry.get(name).unwrap(), - _ => panic!("normal chunk {} rendered as entry chunk", chunk.id.id), + let entry_info = if let ChunkType::Entry(_, name, _) = &chunk.chunk_type { + context.config.entry.get(name) + } else { + None }; Ok(ChunkFile { @@ -108,12 +109,13 @@ pub(super) fn render_entry_js_chunk( file_name: pot.js_name.clone(), chunk_id: pot.chunk_id.clone(), file_type: ChunkFileType::JS, - file_name_template: entry_info - .filename - .as_ref() - .xor(context.config.output.filename.as_ref()) - .cloned(), chunk_name: pot.chunk_name.clone(), + file_name_template: entry_info.and_then(|e| { + e.filename + .as_ref() + .xor(context.config.output.filename.as_ref()) + .cloned() + }), }) } diff --git a/packages/mako/src/index.ts b/packages/mako/src/index.ts index ca3435043..8f3a282d1 100644 --- a/packages/mako/src/index.ts +++ b/packages/mako/src/index.ts @@ -151,9 +151,12 @@ export async function build(params: BuildParams) { }); } - if (makoConfig?.moduleFederation) { + if (makoConfig?.moduleFederation || params.config?.moduleFederation) { // @ts-ignore - params.config.moduleFederation = makoConfig.moduleFederation; + params.config.moduleFederation = { + ...(makoConfig.moduleFederation || {}), + ...(params.config.moduleFederation || {}), + }; // @ts-ignore if (!params.config.moduleFederation.implementation) { // @ts-ignore From d3105d92bcc40a0dbdd93ce9cf2e164543571a75 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Thu, 6 Feb 2025 16:59:32 +0800 Subject: [PATCH 50/68] release: @umijs/mako@0.11.4-canary.20250206.0 --- packages/mako/CHANGELOG.md | 41 +++++++++++++++++++ packages/mako/npm/darwin-arm64/package.json | 2 +- packages/mako/npm/darwin-x64/package.json | 2 +- .../mako/npm/linux-arm64-gnu/package.json | 2 +- .../mako/npm/linux-arm64-musl/package.json | 2 +- packages/mako/npm/linux-x64-gnu/package.json | 2 +- packages/mako/npm/linux-x64-musl/package.json | 2 +- .../mako/npm/win32-ia32-msvc/package.json | 2 +- packages/mako/npm/win32-x64-msvc/package.json | 2 +- packages/mako/package.json | 20 ++++----- 10 files changed, 59 insertions(+), 18 deletions(-) create mode 100644 packages/mako/CHANGELOG.md diff --git a/packages/mako/CHANGELOG.md b/packages/mako/CHANGELOG.md new file mode 100644 index 000000000..2d5f53bb0 --- /dev/null +++ b/packages/mako/CHANGELOG.md @@ -0,0 +1,41 @@ +## 0.11.4-canary.20250206.0 + +`2025-02-06` + +- Merge branch 'master' into feat/module-federation-plugin by [xusd320](https://github.com/xusd320) +- fix: ci by [xusd320](https://github.com/xusd320) in [#1768](https://github.com/umijs/mako/pull/1768) +- fix: entry filename and mf config by [xusd320](https://github.com/xusd320) +- chore: remove meaning less changes by [xusd320](https://github.com/xusd320) +- feat: add entry filename supports by [xusd320](https://github.com/xusd320) +- fix: typos by [xusd320](https://github.com/xusd320) +- fix: not generate chunk for mf remote module by [xusd320](https://github.com/xusd320) +- fix: mf shared eager by [xusd320](https://github.com/xusd320) +- fix: mf shared consume and supports eager config by [xusd320](https://github.com/xusd320) +- feat: entry config should be defined as BTreeMap by [xusd320](https://github.com/xusd320) +- feat: add options to disable mf manifest by [xusd320](https://github.com/xusd320) +- chore: rename types by [xusd320](https://github.com/xusd320) +- chore: code styles by [xusd320](https://github.com/xusd320) +- perf: improve performance by [xusd320](https://github.com/xusd320) +- chore: code styles by [xusd320](https://github.com/xusd320) +- feat(copy): support advanced copy configuration with custom target paths by [bqxbqx](https://github.com/bqxbqx) in [#1711](https://github.com/umijs/mako/pull/1711) +- chore: fix typo by [xusd320](https://github.com/xusd320) +- chore: code styles by [xusd320](https://github.com/xusd320) +- chore: update mako typings by [xusd320](https://github.com/xusd320) +- Merge remote-tracking branch 'origin' into feat/module-federation-plugin by [xusd320](https://github.com/xusd320) +- feat: add config hash for mf shared module by [xusd320](https://github.com/xusd320) +- feat: mf shared manifest by [xusd320](https://github.com/xusd320) +- feat: mf patch code splitting by [xusd320](https://github.com/xusd320) +- fix: chunk groups' order when building mpa by [xusd320](https://github.com/xusd320) in [#1763](https://github.com/umijs/mako/pull/1763) +- fix: load wasm by [御风](https://github.com/御风) in [#1705](https://github.com/umijs/mako/pull/1705) +- dep: [umijs/tools@0.1.23 by @sorrycc](https://github.com/umijs/tools@0.1.23 by @sorrycc) +- fix(mako): cli delay exit by @chencheng (云谦) in [#1762](https://github.com/umijs/mako/pull/1762) +- fix: analyze don't work in safari by @chencheng (云谦) in [#1761](https://github.com/umijs/mako/pull/1761) +- chore: add check-ecosystem-usages script by @chencheng (云谦) in [#1759](https://github.com/umijs/mako/pull/1759) +- docs: changelog for 0.11.3 by [sorrycc](https://github.com/sorrycc) +- chore: upgrade [umijs/tools and do github release and changelog generate and translation by script by @sorrycc](https://github.com/umijs/tools and do github release and changelog generate and translation by script by @sorrycc) +- ci: fix ci by @chencheng (云谦) in [#1758](https://github.com/umijs/mako/pull/1758) +- chore: update the release introduction by [sorrycc](https://github.com/sorrycc) +- feat: supports chunk group exclude by [xusd320](https://github.com/xusd320) +- release: [umijs/mako@0.11.3 by @sorrycc](https://github.com/umijs/mako@0.11.3 by @sorrycc) + + diff --git a/packages/mako/npm/darwin-arm64/package.json b/packages/mako/npm/darwin-arm64/package.json index 7537c46dc..15a05b599 100644 --- a/packages/mako/npm/darwin-arm64/package.json +++ b/packages/mako/npm/darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-darwin-arm64", - "version": "0.11.3", + "version": "0.11.4-canary.20250206.0", "os": [ "darwin" ], diff --git a/packages/mako/npm/darwin-x64/package.json b/packages/mako/npm/darwin-x64/package.json index 5ce748bda..5923406cf 100644 --- a/packages/mako/npm/darwin-x64/package.json +++ b/packages/mako/npm/darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-darwin-x64", - "version": "0.11.3", + "version": "0.11.4-canary.20250206.0", "os": [ "darwin" ], diff --git a/packages/mako/npm/linux-arm64-gnu/package.json b/packages/mako/npm/linux-arm64-gnu/package.json index cb773f60f..ae3c196b5 100644 --- a/packages/mako/npm/linux-arm64-gnu/package.json +++ b/packages/mako/npm/linux-arm64-gnu/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-linux-arm64-gnu", - "version": "0.11.3", + "version": "0.11.4-canary.20250206.0", "os": [ "linux" ], diff --git a/packages/mako/npm/linux-arm64-musl/package.json b/packages/mako/npm/linux-arm64-musl/package.json index 3dbfc315d..c3e9f1393 100644 --- a/packages/mako/npm/linux-arm64-musl/package.json +++ b/packages/mako/npm/linux-arm64-musl/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-linux-arm64-musl", - "version": "0.11.3", + "version": "0.11.4-canary.20250206.0", "os": [ "linux" ], diff --git a/packages/mako/npm/linux-x64-gnu/package.json b/packages/mako/npm/linux-x64-gnu/package.json index 8c8531039..0bfdbfc56 100644 --- a/packages/mako/npm/linux-x64-gnu/package.json +++ b/packages/mako/npm/linux-x64-gnu/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-linux-x64-gnu", - "version": "0.11.3", + "version": "0.11.4-canary.20250206.0", "os": [ "linux" ], diff --git a/packages/mako/npm/linux-x64-musl/package.json b/packages/mako/npm/linux-x64-musl/package.json index 67a34e6c9..18cf29253 100644 --- a/packages/mako/npm/linux-x64-musl/package.json +++ b/packages/mako/npm/linux-x64-musl/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-linux-x64-musl", - "version": "0.11.3", + "version": "0.11.4-canary.20250206.0", "os": [ "linux" ], diff --git a/packages/mako/npm/win32-ia32-msvc/package.json b/packages/mako/npm/win32-ia32-msvc/package.json index fa7d4ea29..8bc5b105c 100644 --- a/packages/mako/npm/win32-ia32-msvc/package.json +++ b/packages/mako/npm/win32-ia32-msvc/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-win32-ia32-msvc", - "version": "0.11.3", + "version": "0.11.4-canary.20250206.0", "os": [ "win32" ], diff --git a/packages/mako/npm/win32-x64-msvc/package.json b/packages/mako/npm/win32-x64-msvc/package.json index cf264ee03..78176e9d8 100644 --- a/packages/mako/npm/win32-x64-msvc/package.json +++ b/packages/mako/npm/win32-x64-msvc/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-win32-x64-msvc", - "version": "0.11.3", + "version": "0.11.4-canary.20250206.0", "os": [ "win32" ], diff --git a/packages/mako/package.json b/packages/mako/package.json index bf647aba2..d7c6d3465 100644 --- a/packages/mako/package.json +++ b/packages/mako/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako", - "version": "0.11.3", + "version": "0.11.4-canary.20250206.0", "main": "dist/index.js", "types": "dist/index.d.ts", "bin": { @@ -77,17 +77,17 @@ "version": "napi version" }, "optionalDependencies": { - "@umijs/mako-darwin-arm64": "0.11.3", - "@umijs/mako-linux-arm64-gnu": "0.11.3", - "@umijs/mako-linux-arm64-musl": "0.11.3", - "@umijs/mako-win32-ia32-msvc": "0.11.3", - "@umijs/mako-darwin-x64": "0.11.3", - "@umijs/mako-win32-x64-msvc": "0.11.3", - "@umijs/mako-linux-x64-gnu": "0.11.3", - "@umijs/mako-linux-x64-musl": "0.11.3" + "@umijs/mako-darwin-arm64": "0.11.4-canary.20250206.0", + "@umijs/mako-linux-arm64-gnu": "0.11.4-canary.20250206.0", + "@umijs/mako-linux-arm64-musl": "0.11.4-canary.20250206.0", + "@umijs/mako-win32-ia32-msvc": "0.11.4-canary.20250206.0", + "@umijs/mako-darwin-x64": "0.11.4-canary.20250206.0", + "@umijs/mako-win32-x64-msvc": "0.11.4-canary.20250206.0", + "@umijs/mako-linux-x64-gnu": "0.11.4-canary.20250206.0", + "@umijs/mako-linux-x64-musl": "0.11.4-canary.20250206.0" }, "publishConfig": { "access": "public" }, "repository": "git@github.com:umijs/mako.git" -} +} \ No newline at end of file From b35d7ca52321cf125a9b592cf496c8299b35bae0 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Fri, 7 Feb 2025 15:39:10 +0800 Subject: [PATCH 51/68] fix: ignore shared dep when it is been external --- .../module_federation/consume_shared.rs | 92 ++++++++++--------- 1 file changed, 47 insertions(+), 45 deletions(-) diff --git a/crates/mako/src/plugins/module_federation/consume_shared.rs b/crates/mako/src/plugins/module_federation/consume_shared.rs index 296a8f96b..41156e37e 100644 --- a/crates/mako/src/plugins/module_federation/consume_shared.rs +++ b/crates/mako/src/plugins/module_federation/consume_shared.rs @@ -175,54 +175,56 @@ impl ModuleFederationPlugin { .unwrap(); let resolver_resource = do_resolve(importer, source, resolver, Some(&context.config.externals))?; - let config_joined_str = format!( - "{}|{}|{}|{}|{}|{}|{}", - shared_info.shared_scope, - source, - shared_info - .required_version - .as_ref() - .map_or("", |v| v.as_str()), - shared_info.strict_version, - resolver_resource.get_resolved_path(), - shared_info.singleton, - shared_info.eager - ); - let hash = md5_hash(&config_joined_str, 4); - return Ok(Some(ResolverResource::Shared(ConsumeSharedInfo { - name: source.to_string(), - version: resolver_resource.get_pkg_info().unwrap().version.unwrap(), - share_scope: shared_info.shared_scope.clone(), - eager: shared_info.eager, - singletion: shared_info.singleton, - required_version: shared_info.required_version.clone(), - strict_version: shared_info.strict_version, - module_id: format!( - "{}{}/{}/{}?{}", - FEDERATION_SHARED_REFERENCE_PREFIX, + if let ResolverResource::Resolved(_) = resolver_resource { + let config_joined_str = format!( + "{}|{}|{}|{}|{}|{}|{}", shared_info.shared_scope, source, - source, - hash - ), - deps: AnalyzeDepsResult { - resolved_deps: vec![ResolvedDep { - resolver_resource, - dependency: Dependency { - source: params.dep.source.clone(), - resolve_as: None, - resolve_type: if shared_info.eager { - ResolveType::Require - } else { - ResolveType::DynamicImport(Default::default()) + shared_info + .required_version + .as_ref() + .map_or("", |v| v.as_str()), + shared_info.strict_version, + resolver_resource.get_resolved_path(), + shared_info.singleton, + shared_info.eager + ); + let hash = md5_hash(&config_joined_str, 4); + return Ok(Some(ResolverResource::Shared(ConsumeSharedInfo { + name: source.to_string(), + version: resolver_resource.get_pkg_info().unwrap().version.unwrap(), + share_scope: shared_info.shared_scope.clone(), + eager: shared_info.eager, + singletion: shared_info.singleton, + required_version: shared_info.required_version.clone(), + strict_version: shared_info.strict_version, + module_id: format!( + "{}{}/{}/{}?{}", + FEDERATION_SHARED_REFERENCE_PREFIX, + shared_info.shared_scope, + source, + source, + hash + ), + deps: AnalyzeDepsResult { + resolved_deps: vec![ResolvedDep { + resolver_resource, + dependency: Dependency { + source: params.dep.source.clone(), + resolve_as: None, + resolve_type: if shared_info.eager { + ResolveType::Require + } else { + ResolveType::DynamicImport(Default::default()) + }, + order: params.dep.order, + span: params.dep.span, }, - order: params.dep.order, - span: params.dep.span, - }, - }], - ..Default::default() - }, - }))); + }], + ..Default::default() + }, + }))); + } } Ok(None) } From 771e6412f3b1248510dd89da9abfd2bec047578f Mon Sep 17 00:00:00 2001 From: xusd320 Date: Fri, 7 Feb 2025 15:41:54 +0800 Subject: [PATCH 52/68] Revert "release: @umijs/mako@0.11.4-canary.20250206.0" This reverts commit d3105d92bcc40a0dbdd93ce9cf2e164543571a75. --- packages/mako/CHANGELOG.md | 41 ------------------- packages/mako/npm/darwin-arm64/package.json | 2 +- packages/mako/npm/darwin-x64/package.json | 2 +- .../mako/npm/linux-arm64-gnu/package.json | 2 +- .../mako/npm/linux-arm64-musl/package.json | 2 +- packages/mako/npm/linux-x64-gnu/package.json | 2 +- packages/mako/npm/linux-x64-musl/package.json | 2 +- .../mako/npm/win32-ia32-msvc/package.json | 2 +- packages/mako/npm/win32-x64-msvc/package.json | 2 +- packages/mako/package.json | 20 ++++----- 10 files changed, 18 insertions(+), 59 deletions(-) delete mode 100644 packages/mako/CHANGELOG.md diff --git a/packages/mako/CHANGELOG.md b/packages/mako/CHANGELOG.md deleted file mode 100644 index 2d5f53bb0..000000000 --- a/packages/mako/CHANGELOG.md +++ /dev/null @@ -1,41 +0,0 @@ -## 0.11.4-canary.20250206.0 - -`2025-02-06` - -- Merge branch 'master' into feat/module-federation-plugin by [xusd320](https://github.com/xusd320) -- fix: ci by [xusd320](https://github.com/xusd320) in [#1768](https://github.com/umijs/mako/pull/1768) -- fix: entry filename and mf config by [xusd320](https://github.com/xusd320) -- chore: remove meaning less changes by [xusd320](https://github.com/xusd320) -- feat: add entry filename supports by [xusd320](https://github.com/xusd320) -- fix: typos by [xusd320](https://github.com/xusd320) -- fix: not generate chunk for mf remote module by [xusd320](https://github.com/xusd320) -- fix: mf shared eager by [xusd320](https://github.com/xusd320) -- fix: mf shared consume and supports eager config by [xusd320](https://github.com/xusd320) -- feat: entry config should be defined as BTreeMap by [xusd320](https://github.com/xusd320) -- feat: add options to disable mf manifest by [xusd320](https://github.com/xusd320) -- chore: rename types by [xusd320](https://github.com/xusd320) -- chore: code styles by [xusd320](https://github.com/xusd320) -- perf: improve performance by [xusd320](https://github.com/xusd320) -- chore: code styles by [xusd320](https://github.com/xusd320) -- feat(copy): support advanced copy configuration with custom target paths by [bqxbqx](https://github.com/bqxbqx) in [#1711](https://github.com/umijs/mako/pull/1711) -- chore: fix typo by [xusd320](https://github.com/xusd320) -- chore: code styles by [xusd320](https://github.com/xusd320) -- chore: update mako typings by [xusd320](https://github.com/xusd320) -- Merge remote-tracking branch 'origin' into feat/module-federation-plugin by [xusd320](https://github.com/xusd320) -- feat: add config hash for mf shared module by [xusd320](https://github.com/xusd320) -- feat: mf shared manifest by [xusd320](https://github.com/xusd320) -- feat: mf patch code splitting by [xusd320](https://github.com/xusd320) -- fix: chunk groups' order when building mpa by [xusd320](https://github.com/xusd320) in [#1763](https://github.com/umijs/mako/pull/1763) -- fix: load wasm by [御风](https://github.com/御风) in [#1705](https://github.com/umijs/mako/pull/1705) -- dep: [umijs/tools@0.1.23 by @sorrycc](https://github.com/umijs/tools@0.1.23 by @sorrycc) -- fix(mako): cli delay exit by @chencheng (云谦) in [#1762](https://github.com/umijs/mako/pull/1762) -- fix: analyze don't work in safari by @chencheng (云谦) in [#1761](https://github.com/umijs/mako/pull/1761) -- chore: add check-ecosystem-usages script by @chencheng (云谦) in [#1759](https://github.com/umijs/mako/pull/1759) -- docs: changelog for 0.11.3 by [sorrycc](https://github.com/sorrycc) -- chore: upgrade [umijs/tools and do github release and changelog generate and translation by script by @sorrycc](https://github.com/umijs/tools and do github release and changelog generate and translation by script by @sorrycc) -- ci: fix ci by @chencheng (云谦) in [#1758](https://github.com/umijs/mako/pull/1758) -- chore: update the release introduction by [sorrycc](https://github.com/sorrycc) -- feat: supports chunk group exclude by [xusd320](https://github.com/xusd320) -- release: [umijs/mako@0.11.3 by @sorrycc](https://github.com/umijs/mako@0.11.3 by @sorrycc) - - diff --git a/packages/mako/npm/darwin-arm64/package.json b/packages/mako/npm/darwin-arm64/package.json index 15a05b599..7537c46dc 100644 --- a/packages/mako/npm/darwin-arm64/package.json +++ b/packages/mako/npm/darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-darwin-arm64", - "version": "0.11.4-canary.20250206.0", + "version": "0.11.3", "os": [ "darwin" ], diff --git a/packages/mako/npm/darwin-x64/package.json b/packages/mako/npm/darwin-x64/package.json index 5923406cf..5ce748bda 100644 --- a/packages/mako/npm/darwin-x64/package.json +++ b/packages/mako/npm/darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-darwin-x64", - "version": "0.11.4-canary.20250206.0", + "version": "0.11.3", "os": [ "darwin" ], diff --git a/packages/mako/npm/linux-arm64-gnu/package.json b/packages/mako/npm/linux-arm64-gnu/package.json index ae3c196b5..cb773f60f 100644 --- a/packages/mako/npm/linux-arm64-gnu/package.json +++ b/packages/mako/npm/linux-arm64-gnu/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-linux-arm64-gnu", - "version": "0.11.4-canary.20250206.0", + "version": "0.11.3", "os": [ "linux" ], diff --git a/packages/mako/npm/linux-arm64-musl/package.json b/packages/mako/npm/linux-arm64-musl/package.json index c3e9f1393..3dbfc315d 100644 --- a/packages/mako/npm/linux-arm64-musl/package.json +++ b/packages/mako/npm/linux-arm64-musl/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-linux-arm64-musl", - "version": "0.11.4-canary.20250206.0", + "version": "0.11.3", "os": [ "linux" ], diff --git a/packages/mako/npm/linux-x64-gnu/package.json b/packages/mako/npm/linux-x64-gnu/package.json index 0bfdbfc56..8c8531039 100644 --- a/packages/mako/npm/linux-x64-gnu/package.json +++ b/packages/mako/npm/linux-x64-gnu/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-linux-x64-gnu", - "version": "0.11.4-canary.20250206.0", + "version": "0.11.3", "os": [ "linux" ], diff --git a/packages/mako/npm/linux-x64-musl/package.json b/packages/mako/npm/linux-x64-musl/package.json index 18cf29253..67a34e6c9 100644 --- a/packages/mako/npm/linux-x64-musl/package.json +++ b/packages/mako/npm/linux-x64-musl/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-linux-x64-musl", - "version": "0.11.4-canary.20250206.0", + "version": "0.11.3", "os": [ "linux" ], diff --git a/packages/mako/npm/win32-ia32-msvc/package.json b/packages/mako/npm/win32-ia32-msvc/package.json index 8bc5b105c..fa7d4ea29 100644 --- a/packages/mako/npm/win32-ia32-msvc/package.json +++ b/packages/mako/npm/win32-ia32-msvc/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-win32-ia32-msvc", - "version": "0.11.4-canary.20250206.0", + "version": "0.11.3", "os": [ "win32" ], diff --git a/packages/mako/npm/win32-x64-msvc/package.json b/packages/mako/npm/win32-x64-msvc/package.json index 78176e9d8..cf264ee03 100644 --- a/packages/mako/npm/win32-x64-msvc/package.json +++ b/packages/mako/npm/win32-x64-msvc/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-win32-x64-msvc", - "version": "0.11.4-canary.20250206.0", + "version": "0.11.3", "os": [ "win32" ], diff --git a/packages/mako/package.json b/packages/mako/package.json index d7c6d3465..bf647aba2 100644 --- a/packages/mako/package.json +++ b/packages/mako/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako", - "version": "0.11.4-canary.20250206.0", + "version": "0.11.3", "main": "dist/index.js", "types": "dist/index.d.ts", "bin": { @@ -77,17 +77,17 @@ "version": "napi version" }, "optionalDependencies": { - "@umijs/mako-darwin-arm64": "0.11.4-canary.20250206.0", - "@umijs/mako-linux-arm64-gnu": "0.11.4-canary.20250206.0", - "@umijs/mako-linux-arm64-musl": "0.11.4-canary.20250206.0", - "@umijs/mako-win32-ia32-msvc": "0.11.4-canary.20250206.0", - "@umijs/mako-darwin-x64": "0.11.4-canary.20250206.0", - "@umijs/mako-win32-x64-msvc": "0.11.4-canary.20250206.0", - "@umijs/mako-linux-x64-gnu": "0.11.4-canary.20250206.0", - "@umijs/mako-linux-x64-musl": "0.11.4-canary.20250206.0" + "@umijs/mako-darwin-arm64": "0.11.3", + "@umijs/mako-linux-arm64-gnu": "0.11.3", + "@umijs/mako-linux-arm64-musl": "0.11.3", + "@umijs/mako-win32-ia32-msvc": "0.11.3", + "@umijs/mako-darwin-x64": "0.11.3", + "@umijs/mako-win32-x64-msvc": "0.11.3", + "@umijs/mako-linux-x64-gnu": "0.11.3", + "@umijs/mako-linux-x64-musl": "0.11.3" }, "publishConfig": { "access": "public" }, "repository": "git@github.com:umijs/mako.git" -} \ No newline at end of file +} From 6179982297e6341a5004d15e70daa402e3b20f4d Mon Sep 17 00:00:00 2001 From: xusd320 Date: Fri, 7 Feb 2025 16:34:09 +0800 Subject: [PATCH 53/68] release: @umijs/mako@0.11.4-canary.20250207.0 --- packages/mako/CHANGELOG.md | 9 +++++++++ packages/mako/npm/darwin-arm64/package.json | 2 +- packages/mako/npm/darwin-x64/package.json | 2 +- .../mako/npm/linux-arm64-gnu/package.json | 2 +- .../mako/npm/linux-arm64-musl/package.json | 2 +- packages/mako/npm/linux-x64-gnu/package.json | 2 +- packages/mako/npm/linux-x64-musl/package.json | 2 +- .../mako/npm/win32-ia32-msvc/package.json | 2 +- packages/mako/npm/win32-x64-msvc/package.json | 2 +- packages/mako/package.json | 20 +++++++++---------- 10 files changed, 27 insertions(+), 18 deletions(-) create mode 100644 packages/mako/CHANGELOG.md diff --git a/packages/mako/CHANGELOG.md b/packages/mako/CHANGELOG.md new file mode 100644 index 000000000..9d39b576b --- /dev/null +++ b/packages/mako/CHANGELOG.md @@ -0,0 +1,9 @@ +## 0.11.4-canary.20250207.0 + +`2025-02-07` + +- Revert "release: [umijs/mako@0.11.4-canary.20250206.0" by @xusd320](https://github.com/umijs/mako@0.11.4-canary.20250206.0" by @xusd320) +- fix: ignore shared dep when it is been external by [xusd320](https://github.com/xusd320) +- release: [umijs/mako@0.11.4-canary.20250206.0 by @xusd320](https://github.com/umijs/mako@0.11.4-canary.20250206.0 by @xusd320) + + diff --git a/packages/mako/npm/darwin-arm64/package.json b/packages/mako/npm/darwin-arm64/package.json index 7537c46dc..5659c6a21 100644 --- a/packages/mako/npm/darwin-arm64/package.json +++ b/packages/mako/npm/darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-darwin-arm64", - "version": "0.11.3", + "version": "0.11.4-canary.20250207.0", "os": [ "darwin" ], diff --git a/packages/mako/npm/darwin-x64/package.json b/packages/mako/npm/darwin-x64/package.json index 5ce748bda..1d15db6f3 100644 --- a/packages/mako/npm/darwin-x64/package.json +++ b/packages/mako/npm/darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-darwin-x64", - "version": "0.11.3", + "version": "0.11.4-canary.20250207.0", "os": [ "darwin" ], diff --git a/packages/mako/npm/linux-arm64-gnu/package.json b/packages/mako/npm/linux-arm64-gnu/package.json index cb773f60f..14bca1c6e 100644 --- a/packages/mako/npm/linux-arm64-gnu/package.json +++ b/packages/mako/npm/linux-arm64-gnu/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-linux-arm64-gnu", - "version": "0.11.3", + "version": "0.11.4-canary.20250207.0", "os": [ "linux" ], diff --git a/packages/mako/npm/linux-arm64-musl/package.json b/packages/mako/npm/linux-arm64-musl/package.json index 3dbfc315d..66e035e33 100644 --- a/packages/mako/npm/linux-arm64-musl/package.json +++ b/packages/mako/npm/linux-arm64-musl/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-linux-arm64-musl", - "version": "0.11.3", + "version": "0.11.4-canary.20250207.0", "os": [ "linux" ], diff --git a/packages/mako/npm/linux-x64-gnu/package.json b/packages/mako/npm/linux-x64-gnu/package.json index 8c8531039..e0738fb59 100644 --- a/packages/mako/npm/linux-x64-gnu/package.json +++ b/packages/mako/npm/linux-x64-gnu/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-linux-x64-gnu", - "version": "0.11.3", + "version": "0.11.4-canary.20250207.0", "os": [ "linux" ], diff --git a/packages/mako/npm/linux-x64-musl/package.json b/packages/mako/npm/linux-x64-musl/package.json index 67a34e6c9..97c1af529 100644 --- a/packages/mako/npm/linux-x64-musl/package.json +++ b/packages/mako/npm/linux-x64-musl/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-linux-x64-musl", - "version": "0.11.3", + "version": "0.11.4-canary.20250207.0", "os": [ "linux" ], diff --git a/packages/mako/npm/win32-ia32-msvc/package.json b/packages/mako/npm/win32-ia32-msvc/package.json index fa7d4ea29..3f23e204d 100644 --- a/packages/mako/npm/win32-ia32-msvc/package.json +++ b/packages/mako/npm/win32-ia32-msvc/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-win32-ia32-msvc", - "version": "0.11.3", + "version": "0.11.4-canary.20250207.0", "os": [ "win32" ], diff --git a/packages/mako/npm/win32-x64-msvc/package.json b/packages/mako/npm/win32-x64-msvc/package.json index cf264ee03..f606b1a89 100644 --- a/packages/mako/npm/win32-x64-msvc/package.json +++ b/packages/mako/npm/win32-x64-msvc/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-win32-x64-msvc", - "version": "0.11.3", + "version": "0.11.4-canary.20250207.0", "os": [ "win32" ], diff --git a/packages/mako/package.json b/packages/mako/package.json index bf647aba2..9796b44a6 100644 --- a/packages/mako/package.json +++ b/packages/mako/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako", - "version": "0.11.3", + "version": "0.11.4-canary.20250207.0", "main": "dist/index.js", "types": "dist/index.d.ts", "bin": { @@ -77,17 +77,17 @@ "version": "napi version" }, "optionalDependencies": { - "@umijs/mako-darwin-arm64": "0.11.3", - "@umijs/mako-linux-arm64-gnu": "0.11.3", - "@umijs/mako-linux-arm64-musl": "0.11.3", - "@umijs/mako-win32-ia32-msvc": "0.11.3", - "@umijs/mako-darwin-x64": "0.11.3", - "@umijs/mako-win32-x64-msvc": "0.11.3", - "@umijs/mako-linux-x64-gnu": "0.11.3", - "@umijs/mako-linux-x64-musl": "0.11.3" + "@umijs/mako-darwin-arm64": "0.11.4-canary.20250207.0", + "@umijs/mako-linux-arm64-gnu": "0.11.4-canary.20250207.0", + "@umijs/mako-linux-arm64-musl": "0.11.4-canary.20250207.0", + "@umijs/mako-win32-ia32-msvc": "0.11.4-canary.20250207.0", + "@umijs/mako-darwin-x64": "0.11.4-canary.20250207.0", + "@umijs/mako-win32-x64-msvc": "0.11.4-canary.20250207.0", + "@umijs/mako-linux-x64-gnu": "0.11.4-canary.20250207.0", + "@umijs/mako-linux-x64-musl": "0.11.4-canary.20250207.0" }, "publishConfig": { "access": "public" }, "repository": "git@github.com:umijs/mako.git" -} +} \ No newline at end of file From f9e1174215c3881bc23ce84b56de754919159153 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Fri, 7 Feb 2025 16:56:07 +0800 Subject: [PATCH 54/68] fix: skip serialize mf manifest remoteEntry if none --- crates/mako/src/plugins/module_federation/manifest.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/mako/src/plugins/module_federation/manifest.rs b/crates/mako/src/plugins/module_federation/manifest.rs index 975a8b67a..ef42b0933 100644 --- a/crates/mako/src/plugins/module_federation/manifest.rs +++ b/crates/mako/src/plugins/module_federation/manifest.rs @@ -265,6 +265,7 @@ pub struct ManifestMetaTypes { #[derive(Serialize, Default)] #[serde(rename_all = "camelCase")] pub struct ManifestMetaData { + #[serde(skip_serializing_if = "Option::is_none")] pub remote_entry: Option, pub global_name: String, pub public_path: String, From b121dbf5dbba2c2bae6f1f977d8b972040ae74d6 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Fri, 7 Feb 2025 18:21:47 +0800 Subject: [PATCH 55/68] fix: mf manifest remoteEntry address --- .../src/plugins/module_federation/manifest.rs | 55 +++++++++++-------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/crates/mako/src/plugins/module_federation/manifest.rs b/crates/mako/src/plugins/module_federation/manifest.rs index ef42b0933..a548b796b 100644 --- a/crates/mako/src/plugins/module_federation/manifest.rs +++ b/crates/mako/src/plugins/module_federation/manifest.rs @@ -114,27 +114,34 @@ impl ModuleFederationPlugin { }) .collect() }, - meta_data: ManifestMetaData { - name: self.config.name.clone(), - build_info: ManifestMetaBuildInfo { - build_name: app_info.0.unwrap_or("default".to_string()), - build_version: app_info.1.unwrap_or("".to_string()), - }, - global_name: self.config.name.clone(), - public_path: "auto".to_string(), - r#type: "global".to_string(), - remote_entry: self.config.exposes.as_ref().and_then(|exposes| { - if exposes.is_empty() { - None - } else { - Some(ManifestMetaRemoteEntry { - name: format!("{}.js", self.config.name), - path: "".to_string(), - r#type: "global".to_string(), - }) - } - }), - ..Default::default() + meta_data: { + let chunk_graph = context.chunk_graph.read().unwrap(); + let mf_containter_entry_root_module: Option = context + .config + .entry + .get(&self.config.name) + .map(|e| e.import.to_string_lossy().to_string().into()); + let mf_containter_entry_chunk = mf_containter_entry_root_module + .map(|m| chunk_graph.get_chunk_for_module(&m).unwrap()); + + ManifestMetaData { + name: self.config.name.clone(), + build_info: ManifestMetaBuildInfo { + build_name: app_info.0.unwrap_or("default".to_string()), + build_version: app_info.1.unwrap_or("".to_string()), + }, + global_name: self.config.name.clone(), + // FIXME: hardcode now + public_path: "auto".to_string(), + // FIXME: hardcode now + r#type: "global".to_string(), + remote_entry: mf_containter_entry_chunk.map(|c| ManifestMetaRemoteEntry { + name: extract_assets(&[c.id.clone()], ¶ms.stats).0[0].clone(), + path: "".to_string(), + r#type: "global".to_string(), + }), + ..Default::default() + } }, }; fs::write( @@ -163,9 +170,9 @@ fn extract_chunk_assets( acc }); - let (sync_js_files, sync_css_files) = extract_assets(all_sync_chunks, ¶ms.stats); + let (sync_js_files, sync_css_files) = extract_assets(&all_sync_chunks, ¶ms.stats); - let (async_js_files, async_css_files) = extract_assets(all_async_chunks, ¶ms.stats); + let (async_js_files, async_css_files) = extract_assets(&all_async_chunks, ¶ms.stats); let async_js_files = async_js_files .into_iter() @@ -190,7 +197,7 @@ fn extract_chunk_assets( } fn extract_assets( - all_exposes_sync_chunks: Vec, + all_exposes_sync_chunks: &[ModuleId], stats: &StatsJsonMap, ) -> (Vec, Vec) { all_exposes_sync_chunks.iter().fold( From 8e2364a220e5d601f0d97a7cc91f4a1f1b7faa1b Mon Sep 17 00:00:00 2001 From: xusd320 Date: Fri, 7 Feb 2025 18:28:26 +0800 Subject: [PATCH 56/68] Revert "release: @umijs/mako@0.11.4-canary.20250207.0" This reverts commit 6179982297e6341a5004d15e70daa402e3b20f4d. --- packages/mako/CHANGELOG.md | 9 --------- packages/mako/npm/darwin-arm64/package.json | 2 +- packages/mako/npm/darwin-x64/package.json | 2 +- .../mako/npm/linux-arm64-gnu/package.json | 2 +- .../mako/npm/linux-arm64-musl/package.json | 2 +- packages/mako/npm/linux-x64-gnu/package.json | 2 +- packages/mako/npm/linux-x64-musl/package.json | 2 +- .../mako/npm/win32-ia32-msvc/package.json | 2 +- packages/mako/npm/win32-x64-msvc/package.json | 2 +- packages/mako/package.json | 20 +++++++++---------- 10 files changed, 18 insertions(+), 27 deletions(-) delete mode 100644 packages/mako/CHANGELOG.md diff --git a/packages/mako/CHANGELOG.md b/packages/mako/CHANGELOG.md deleted file mode 100644 index 9d39b576b..000000000 --- a/packages/mako/CHANGELOG.md +++ /dev/null @@ -1,9 +0,0 @@ -## 0.11.4-canary.20250207.0 - -`2025-02-07` - -- Revert "release: [umijs/mako@0.11.4-canary.20250206.0" by @xusd320](https://github.com/umijs/mako@0.11.4-canary.20250206.0" by @xusd320) -- fix: ignore shared dep when it is been external by [xusd320](https://github.com/xusd320) -- release: [umijs/mako@0.11.4-canary.20250206.0 by @xusd320](https://github.com/umijs/mako@0.11.4-canary.20250206.0 by @xusd320) - - diff --git a/packages/mako/npm/darwin-arm64/package.json b/packages/mako/npm/darwin-arm64/package.json index 5659c6a21..7537c46dc 100644 --- a/packages/mako/npm/darwin-arm64/package.json +++ b/packages/mako/npm/darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-darwin-arm64", - "version": "0.11.4-canary.20250207.0", + "version": "0.11.3", "os": [ "darwin" ], diff --git a/packages/mako/npm/darwin-x64/package.json b/packages/mako/npm/darwin-x64/package.json index 1d15db6f3..5ce748bda 100644 --- a/packages/mako/npm/darwin-x64/package.json +++ b/packages/mako/npm/darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-darwin-x64", - "version": "0.11.4-canary.20250207.0", + "version": "0.11.3", "os": [ "darwin" ], diff --git a/packages/mako/npm/linux-arm64-gnu/package.json b/packages/mako/npm/linux-arm64-gnu/package.json index 14bca1c6e..cb773f60f 100644 --- a/packages/mako/npm/linux-arm64-gnu/package.json +++ b/packages/mako/npm/linux-arm64-gnu/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-linux-arm64-gnu", - "version": "0.11.4-canary.20250207.0", + "version": "0.11.3", "os": [ "linux" ], diff --git a/packages/mako/npm/linux-arm64-musl/package.json b/packages/mako/npm/linux-arm64-musl/package.json index 66e035e33..3dbfc315d 100644 --- a/packages/mako/npm/linux-arm64-musl/package.json +++ b/packages/mako/npm/linux-arm64-musl/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-linux-arm64-musl", - "version": "0.11.4-canary.20250207.0", + "version": "0.11.3", "os": [ "linux" ], diff --git a/packages/mako/npm/linux-x64-gnu/package.json b/packages/mako/npm/linux-x64-gnu/package.json index e0738fb59..8c8531039 100644 --- a/packages/mako/npm/linux-x64-gnu/package.json +++ b/packages/mako/npm/linux-x64-gnu/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-linux-x64-gnu", - "version": "0.11.4-canary.20250207.0", + "version": "0.11.3", "os": [ "linux" ], diff --git a/packages/mako/npm/linux-x64-musl/package.json b/packages/mako/npm/linux-x64-musl/package.json index 97c1af529..67a34e6c9 100644 --- a/packages/mako/npm/linux-x64-musl/package.json +++ b/packages/mako/npm/linux-x64-musl/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-linux-x64-musl", - "version": "0.11.4-canary.20250207.0", + "version": "0.11.3", "os": [ "linux" ], diff --git a/packages/mako/npm/win32-ia32-msvc/package.json b/packages/mako/npm/win32-ia32-msvc/package.json index 3f23e204d..fa7d4ea29 100644 --- a/packages/mako/npm/win32-ia32-msvc/package.json +++ b/packages/mako/npm/win32-ia32-msvc/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-win32-ia32-msvc", - "version": "0.11.4-canary.20250207.0", + "version": "0.11.3", "os": [ "win32" ], diff --git a/packages/mako/npm/win32-x64-msvc/package.json b/packages/mako/npm/win32-x64-msvc/package.json index f606b1a89..cf264ee03 100644 --- a/packages/mako/npm/win32-x64-msvc/package.json +++ b/packages/mako/npm/win32-x64-msvc/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako-win32-x64-msvc", - "version": "0.11.4-canary.20250207.0", + "version": "0.11.3", "os": [ "win32" ], diff --git a/packages/mako/package.json b/packages/mako/package.json index 9796b44a6..bf647aba2 100644 --- a/packages/mako/package.json +++ b/packages/mako/package.json @@ -1,6 +1,6 @@ { "name": "@umijs/mako", - "version": "0.11.4-canary.20250207.0", + "version": "0.11.3", "main": "dist/index.js", "types": "dist/index.d.ts", "bin": { @@ -77,17 +77,17 @@ "version": "napi version" }, "optionalDependencies": { - "@umijs/mako-darwin-arm64": "0.11.4-canary.20250207.0", - "@umijs/mako-linux-arm64-gnu": "0.11.4-canary.20250207.0", - "@umijs/mako-linux-arm64-musl": "0.11.4-canary.20250207.0", - "@umijs/mako-win32-ia32-msvc": "0.11.4-canary.20250207.0", - "@umijs/mako-darwin-x64": "0.11.4-canary.20250207.0", - "@umijs/mako-win32-x64-msvc": "0.11.4-canary.20250207.0", - "@umijs/mako-linux-x64-gnu": "0.11.4-canary.20250207.0", - "@umijs/mako-linux-x64-musl": "0.11.4-canary.20250207.0" + "@umijs/mako-darwin-arm64": "0.11.3", + "@umijs/mako-linux-arm64-gnu": "0.11.3", + "@umijs/mako-linux-arm64-musl": "0.11.3", + "@umijs/mako-win32-ia32-msvc": "0.11.3", + "@umijs/mako-darwin-x64": "0.11.3", + "@umijs/mako-win32-x64-msvc": "0.11.3", + "@umijs/mako-linux-x64-gnu": "0.11.3", + "@umijs/mako-linux-x64-musl": "0.11.3" }, "publishConfig": { "access": "public" }, "repository": "git@github.com:umijs/mako.git" -} \ No newline at end of file +} From 9dca2971d7e308cdb61e24035eb98e0b391c865b Mon Sep 17 00:00:00 2001 From: xusd320 Date: Fri, 7 Feb 2025 22:17:01 +0800 Subject: [PATCH 57/68] fix: typo --- crates/mako/src/plugins/module_federation/manifest.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/mako/src/plugins/module_federation/manifest.rs b/crates/mako/src/plugins/module_federation/manifest.rs index a548b796b..529875b9a 100644 --- a/crates/mako/src/plugins/module_federation/manifest.rs +++ b/crates/mako/src/plugins/module_federation/manifest.rs @@ -116,12 +116,12 @@ impl ModuleFederationPlugin { }, meta_data: { let chunk_graph = context.chunk_graph.read().unwrap(); - let mf_containter_entry_root_module: Option = context + let mf_container_entry_root_module: Option = context .config .entry .get(&self.config.name) .map(|e| e.import.to_string_lossy().to_string().into()); - let mf_containter_entry_chunk = mf_containter_entry_root_module + let mf_containter_entry_chunk = mf_container_entry_root_module .map(|m| chunk_graph.get_chunk_for_module(&m).unwrap()); ManifestMetaData { From b6c6995a03f2346efb187563d0bc12a4837681a1 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Sat, 8 Feb 2025 10:04:08 +0800 Subject: [PATCH 58/68] fix: mako mf manifest publicPath --- crates/mako/src/plugins/module_federation/manifest.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/mako/src/plugins/module_federation/manifest.rs b/crates/mako/src/plugins/module_federation/manifest.rs index 529875b9a..cb138ad7e 100644 --- a/crates/mako/src/plugins/module_federation/manifest.rs +++ b/crates/mako/src/plugins/module_federation/manifest.rs @@ -131,8 +131,7 @@ impl ModuleFederationPlugin { build_version: app_info.1.unwrap_or("".to_string()), }, global_name: self.config.name.clone(), - // FIXME: hardcode now - public_path: "auto".to_string(), + public_path: context.config.public_path.clone(), // FIXME: hardcode now r#type: "global".to_string(), remote_entry: mf_containter_entry_chunk.map(|c| ManifestMetaRemoteEntry { From 23dacc28d8534d9d0c0c0f86ac83adddc86aaa01 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Sat, 8 Feb 2025 10:59:13 +0800 Subject: [PATCH 59/68] fix: mf manifest panic --- crates/mako/src/plugins/module_federation/manifest.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/crates/mako/src/plugins/module_federation/manifest.rs b/crates/mako/src/plugins/module_federation/manifest.rs index cb138ad7e..c18aa1047 100644 --- a/crates/mako/src/plugins/module_federation/manifest.rs +++ b/crates/mako/src/plugins/module_federation/manifest.rs @@ -67,23 +67,22 @@ impl ModuleFederationPlugin { let provide_shared_map = self.shared_dependency_map.read().unwrap(); provide_shared_map .iter() - .map(|(_, config)| { + .filter_map(|(_, config)| { let module_id: ModuleId = config.file_path.clone().into(); let chunk_id = chunk_graph .get_chunk_for_module(&module_id) - .as_ref() - .unwrap() + .as_ref()? .id .clone(); let assets = extract_chunk_assets(vec![chunk_id], &chunk_graph, params); - ManifestShared { + Some(ManifestShared { id: format!("{}:{}", self.config.name, config.share_key), name: config.share_key.clone(), require_version: config.shared_config.required_version.clone(), version: config.version.clone(), singleton: config.shared_config.singleton, assets, - } + }) }) .collect() }, From 2a9df446034236483d69d8a01944f0c34d52f019 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Sat, 8 Feb 2025 11:08:31 +0800 Subject: [PATCH 60/68] fix: mf typings --- crates/binding/src/lib.rs | 1 + packages/mako/binding.d.ts | 1 + packages/mako/src/index.ts | 18 ++++++++++++++---- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/crates/binding/src/lib.rs b/crates/binding/src/lib.rs index 9749a6c0b..a55f4dd00 100644 --- a/crates/binding/src/lib.rs +++ b/crates/binding/src/lib.rs @@ -169,6 +169,7 @@ pub struct BuildParams { runtimePlugins?: string[]; shareScope?: string; shareStrategy?: "version-first" | "loaded-first"; + implementation: string; }; experimental?: { webpackSyntaxValidate?: string[]; diff --git a/packages/mako/binding.d.ts b/packages/mako/binding.d.ts index 656de6ce4..755640c86 100644 --- a/packages/mako/binding.d.ts +++ b/packages/mako/binding.d.ts @@ -275,6 +275,7 @@ export interface BuildParams { runtimePlugins?: string[]; shareScope?: string; shareStrategy?: 'version-first' | 'loaded-first'; + implementation: string; }; experimental?: { webpackSyntaxValidate?: string[]; diff --git a/packages/mako/src/index.ts b/packages/mako/src/index.ts index 8f3a282d1..feb410a62 100644 --- a/packages/mako/src/index.ts +++ b/packages/mako/src/index.ts @@ -153,17 +153,27 @@ export async function build(params: BuildParams) { if (makoConfig?.moduleFederation || params.config?.moduleFederation) { // @ts-ignore - params.config.moduleFederation = { + const moduleFederation = { ...(makoConfig.moduleFederation || {}), ...(params.config.moduleFederation || {}), }; - // @ts-ignore - if (!params.config.moduleFederation.implementation) { + if (!moduleFederation.implementation) { // @ts-ignore - params.config.moduleFederation.implementation = require.resolve( + moduleFederation.implementation = require.resolve( '@module-federation/webpack-bundler-runtime', ); } + + if (moduleFederation?.shared) { + if (Array.isArray(moduleFederation.shared)) { + moduleFederation.shared = moduleFederation.shared.reduce( + (acc, cur) => ({ ...acc, [cur]: {} }), + {}, + ); + } + } + // @ts-ignore + params.config.moduleFederation = moduleFederation; } // support dump mako config From aba1029b7f4a9dbf2d5ead89d7da3ef936211d3f Mon Sep 17 00:00:00 2001 From: xusd320 Date: Sat, 8 Feb 2025 11:40:22 +0800 Subject: [PATCH 61/68] test: add e2e test for mf --- .../module-federation.consumer/.gitignore | 2 + .../module-federation.consumer/expect.js | 22 ++++++++ .../mako.config.json | 15 ++++++ .../module-federation.consumer/package.json | 10 ++++ .../public/index.html | 7 +++ .../module-federation.consumer/src/App.tsx | 26 ++++++++++ .../src/bootstrap.tsx | 5 ++ .../module-federation.consumer/src/index.ts | 1 + .../module-federation.producer/.gitignore | 2 + .../module-federation.producer/expect.js | 30 +++++++++++ .../mako.config.json | 16 ++++++ .../module-federation.producer/package.json | 10 ++++ .../public/index.html | 7 +++ .../module-federation.producer/src/App.tsx | 18 +++++++ .../src/bootstrap.tsx | 6 +++ .../module-federation.producer/src/index.ts | 1 + pnpm-lock.yaml | 50 +++++++++++++++++-- pnpm-workspace.yaml | 2 +- 18 files changed, 224 insertions(+), 6 deletions(-) create mode 100644 e2e/fixtures/module-federation.consumer/.gitignore create mode 100644 e2e/fixtures/module-federation.consumer/expect.js create mode 100644 e2e/fixtures/module-federation.consumer/mako.config.json create mode 100644 e2e/fixtures/module-federation.consumer/package.json create mode 100644 e2e/fixtures/module-federation.consumer/public/index.html create mode 100644 e2e/fixtures/module-federation.consumer/src/App.tsx create mode 100644 e2e/fixtures/module-federation.consumer/src/bootstrap.tsx create mode 100644 e2e/fixtures/module-federation.consumer/src/index.ts create mode 100644 e2e/fixtures/module-federation.producer/.gitignore create mode 100644 e2e/fixtures/module-federation.producer/expect.js create mode 100644 e2e/fixtures/module-federation.producer/mako.config.json create mode 100644 e2e/fixtures/module-federation.producer/package.json create mode 100644 e2e/fixtures/module-federation.producer/public/index.html create mode 100644 e2e/fixtures/module-federation.producer/src/App.tsx create mode 100644 e2e/fixtures/module-federation.producer/src/bootstrap.tsx create mode 100644 e2e/fixtures/module-federation.producer/src/index.ts diff --git a/e2e/fixtures/module-federation.consumer/.gitignore b/e2e/fixtures/module-federation.consumer/.gitignore new file mode 100644 index 000000000..de4d1f007 --- /dev/null +++ b/e2e/fixtures/module-federation.consumer/.gitignore @@ -0,0 +1,2 @@ +dist +node_modules diff --git a/e2e/fixtures/module-federation.consumer/expect.js b/e2e/fixtures/module-federation.consumer/expect.js new file mode 100644 index 000000000..3cf2fe3b1 --- /dev/null +++ b/e2e/fixtures/module-federation.consumer/expect.js @@ -0,0 +1,22 @@ +const assert = require("assert"); +const { parseBuildResult } = require("../../../scripts/test-utils"); +const { files } = parseBuildResult(__dirname); + +const manifest = JSON.parse(files["mf-manifest.json"]); + +assert( + manifest.remotes[0].alias === 'producer' + && manifest.remotes[0].federationContainerName === 'producer' + && manifest.remotes[0].moduleName === 'App', + "should include mf remotes info" +) + +assert( + manifest.shared.map(s => s.name).sort().join(",") === "react,react-dom", + "should include mf shared dependencies" +) + +assert( + manifest.shared.every(s => s.assets.js.sync.length !== 0), + "should include mf shared assets" +) diff --git a/e2e/fixtures/module-federation.consumer/mako.config.json b/e2e/fixtures/module-federation.consumer/mako.config.json new file mode 100644 index 000000000..dcfe4ae67 --- /dev/null +++ b/e2e/fixtures/module-federation.consumer/mako.config.json @@ -0,0 +1,15 @@ +{ + "entry": { + "app1": "./src/index.ts" + }, + "minify": false, + "moduleFederation": { + "name": "consumer", + "remotes": { + "producer": "producer@http://localhost:3000/remoteEntry.js" + }, + "shared": { "react": { "eager": true }, "react-dom": { "eager": true } }, + "manifest": true, + "implementation": "../../../../../packages/mako/node_modules/@module-federation/webpack-bundler-runtime" + } +} diff --git a/e2e/fixtures/module-federation.consumer/package.json b/e2e/fixtures/module-federation.consumer/package.json new file mode 100644 index 000000000..723a9fb2d --- /dev/null +++ b/e2e/fixtures/module-federation.consumer/package.json @@ -0,0 +1,10 @@ +{ + "name": "mf-consumer", + "version": "0.0.1", + "dependencies": { + "react": "18.2.0", + "react-dom": "18.2.0", + "@types/react": "18.2.0", + "@types/react-dom": "18.2.0" + } +} diff --git a/e2e/fixtures/module-federation.consumer/public/index.html b/e2e/fixtures/module-federation.consumer/public/index.html new file mode 100644 index 000000000..7e0bd8d29 --- /dev/null +++ b/e2e/fixtures/module-federation.consumer/public/index.html @@ -0,0 +1,7 @@ + + + +
+ + + diff --git a/e2e/fixtures/module-federation.consumer/src/App.tsx b/e2e/fixtures/module-federation.consumer/src/App.tsx new file mode 100644 index 000000000..0d9833d2e --- /dev/null +++ b/e2e/fixtures/module-federation.consumer/src/App.tsx @@ -0,0 +1,26 @@ +import React from 'react'; + +// @ts-ignore +const RemoteComp = React.lazy(() => import('producer/App')); + +const App = () => { + return ( +
+
+

Consumer App

+
+ + + +
+ ); +}; + +export default App; diff --git a/e2e/fixtures/module-federation.consumer/src/bootstrap.tsx b/e2e/fixtures/module-federation.consumer/src/bootstrap.tsx new file mode 100644 index 000000000..b597a4423 --- /dev/null +++ b/e2e/fixtures/module-federation.consumer/src/bootstrap.tsx @@ -0,0 +1,5 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App'; + +ReactDOM.render(, document.getElementById('root')); diff --git a/e2e/fixtures/module-federation.consumer/src/index.ts b/e2e/fixtures/module-federation.consumer/src/index.ts new file mode 100644 index 000000000..e59d6a0ad --- /dev/null +++ b/e2e/fixtures/module-federation.consumer/src/index.ts @@ -0,0 +1 @@ +import './bootstrap'; diff --git a/e2e/fixtures/module-federation.producer/.gitignore b/e2e/fixtures/module-federation.producer/.gitignore new file mode 100644 index 000000000..de4d1f007 --- /dev/null +++ b/e2e/fixtures/module-federation.producer/.gitignore @@ -0,0 +1,2 @@ +dist +node_modules diff --git a/e2e/fixtures/module-federation.producer/expect.js b/e2e/fixtures/module-federation.producer/expect.js new file mode 100644 index 000000000..ab5ff0183 --- /dev/null +++ b/e2e/fixtures/module-federation.producer/expect.js @@ -0,0 +1,30 @@ +const assert = require("assert"); +const { parseBuildResult } = require("../../../scripts/test-utils"); +const { files } = parseBuildResult(__dirname); + +const manifest = JSON.parse(files["mf-manifest.json"]); + +assert( + manifest.metaData.remoteEntry.name === 'remoteEntry.js', + "should generate mf contanier entry" +) + +assert( + manifest.exposes[0].name === 'App', + "should include mf exposes" +) + +assert( + manifest.exposes[0].assets.js.sync.length !== 0, + "should include mf exposes assets" +) + +assert( + manifest.shared.map(s => s.name).sort().join(",") === "react,react-dom", + "should include mf shared dependencies" +) + +assert( + manifest.shared.every(s => s.assets.js.sync.length !== 0), + "should include mf shared assets" +) diff --git a/e2e/fixtures/module-federation.producer/mako.config.json b/e2e/fixtures/module-federation.producer/mako.config.json new file mode 100644 index 000000000..e966ee81d --- /dev/null +++ b/e2e/fixtures/module-federation.producer/mako.config.json @@ -0,0 +1,16 @@ +{ + "entry": { + "app2": "./src/index.ts" + }, + "publicPath": "auto", + "moduleFederation": { + "name": "producer", + "filename": "remoteEntry.js", + "exposes": { + "./App": "./src/App.tsx" + }, + "shared": { "react": {}, "react-dom": {} }, + "manifest": true, + "implementation": "../../../../../packages/mako/node_modules/@module-federation/webpack-bundler-runtime" + } +} diff --git a/e2e/fixtures/module-federation.producer/package.json b/e2e/fixtures/module-federation.producer/package.json new file mode 100644 index 000000000..c803f552e --- /dev/null +++ b/e2e/fixtures/module-federation.producer/package.json @@ -0,0 +1,10 @@ +{ + "name": "mf-producer", + "version": "0.0.1", + "dependencies": { + "react": "18.2.0", + "react-dom": "18.2.0", + "@types/react": "18.2.0", + "@types/react-dom": "18.2.0" + } +} diff --git a/e2e/fixtures/module-federation.producer/public/index.html b/e2e/fixtures/module-federation.producer/public/index.html new file mode 100644 index 000000000..5de48ef2f --- /dev/null +++ b/e2e/fixtures/module-federation.producer/public/index.html @@ -0,0 +1,7 @@ + + + +
+ + + diff --git a/e2e/fixtures/module-federation.producer/src/App.tsx b/e2e/fixtures/module-federation.producer/src/App.tsx new file mode 100644 index 000000000..2a1875c7f --- /dev/null +++ b/e2e/fixtures/module-federation.producer/src/App.tsx @@ -0,0 +1,18 @@ +import React from 'react'; + +const App = () => { + return ( +
+

Widget App2

+
+ ); +}; + +export default App; diff --git a/e2e/fixtures/module-federation.producer/src/bootstrap.tsx b/e2e/fixtures/module-federation.producer/src/bootstrap.tsx new file mode 100644 index 000000000..ae31e4134 --- /dev/null +++ b/e2e/fixtures/module-federation.producer/src/bootstrap.tsx @@ -0,0 +1,6 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +import App from './App'; + +ReactDOM.render(, document.getElementById('root')); diff --git a/e2e/fixtures/module-federation.producer/src/index.ts b/e2e/fixtures/module-federation.producer/src/index.ts new file mode 100644 index 000000000..b93c7a026 --- /dev/null +++ b/e2e/fixtures/module-federation.producer/src/index.ts @@ -0,0 +1 @@ +import('./bootstrap'); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 073c28112..503c5d6c9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -191,6 +191,36 @@ importers: specifier: 18.2.0 version: 18.2.0(react@18.2.0) + e2e/fixtures/module-federation.consumer: + dependencies: + '@types/react': + specifier: 18.2.0 + version: 18.2.0 + '@types/react-dom': + specifier: 18.2.0 + version: 18.2.0 + react: + specifier: 18.2.0 + version: 18.2.0 + react-dom: + specifier: 18.2.0 + version: 18.2.0(react@18.2.0) + + e2e/fixtures/module-federation.producer: + dependencies: + '@types/react': + specifier: 18.2.0 + version: 18.2.0 + '@types/react-dom': + specifier: 18.2.0 + version: 18.2.0 + react: + specifier: 18.2.0 + version: 18.2.0 + react-dom: + specifier: 18.2.0 + version: 18.2.0(react@18.2.0) + examples/config-externals: {} examples/dead-simple: {} @@ -655,7 +685,7 @@ packages: '@emotion/hash': 0.8.0 '@emotion/unitless': 0.7.5 classnames: 2.3.2 - csstype: 3.1.2 + csstype: 3.1.3 rc-util: 5.37.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -5889,7 +5919,6 @@ packages: /@types/prop-types@15.7.5: resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==} - dev: true /@types/ps-tree@1.1.2: resolution: {integrity: sha512-ZREFYlpUmPQJ0esjxoG1fMvB2HNaD3z+mjqdSosZvd3RalncI9NEur73P8ZJz4YQdL64CmV1w0RuqoRUlhQRBw==} @@ -5903,6 +5932,12 @@ packages: resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} dev: true + /@types/react-dom@18.2.0: + resolution: {integrity: sha512-8yQrvS6sMpSwIovhPOwfyNf2Wz6v/B62LFSVYQ85+Rq3tLsBIG7rP5geMxaijTUxSkrO6RzN/IRuIAADYQsleA==} + dependencies: + '@types/react': 18.2.7 + dev: false + /@types/react-dom@18.2.4: resolution: {integrity: sha512-G2mHoTMTL4yoydITgOGwWdWMVd8sNgyEP85xVmMKAPUBwQWm9wBPQUmvbeF4V3WBY1P7mmL4BkjQ0SqUpf1snw==} dependencies: @@ -5933,20 +5968,26 @@ packages: '@types/react': 18.2.7 dev: true + /@types/react@18.2.0: + resolution: {integrity: sha512-0FLj93y5USLHdnhIhABk83rm8XEGA7kH3cr+YUlvxoUGp1xNt/DINUMvqPxLyOQMzLmZe8i4RTHbvb8MC7NmrA==} + dependencies: + '@types/prop-types': 15.7.5 + '@types/scheduler': 0.16.3 + csstype: 3.1.3 + dev: false + /@types/react@18.2.7: resolution: {integrity: sha512-ojrXpSH2XFCmHm7Jy3q44nXDyN54+EYKP2lBhJ2bqfyPj6cIUW/FZW/Csdia34NQgq7KYcAlHi5184m4X88+yw==} dependencies: '@types/prop-types': 15.7.5 '@types/scheduler': 0.16.3 csstype: 3.1.3 - dev: true /@types/resolve@1.20.6: resolution: {integrity: sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ==} /@types/scheduler@0.16.3: resolution: {integrity: sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==} - dev: true /@types/semver@7.5.8: resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} @@ -8999,7 +9040,6 @@ packages: /csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} - dev: true /current-script-polyfill@1.0.0: resolution: {integrity: sha512-qv8s+G47V6Hq+g2kRE5th+ASzzrL7b6l+tap1DHKK25ZQJv3yIFhH96XaQ7NGL+zRW3t/RDbweJf/dJDe5Z5KA==} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 58b2f7b75..b5d16bf03 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -3,7 +3,7 @@ packages: - "client" - "crates/binding" - "packages/*" - - "crates/mako/test/compile/auto-code-splitting" + - "e2e/fixtures/module-federation.*" - "e2e/fixtures.umi/react-16" - "e2e/fixtures.umi/config.less.plugins" - "e2e/fixtures.umi/stable-hash" From a59da24907da849c6656d7d8865962deab02ef8d Mon Sep 17 00:00:00 2001 From: xusd320 Date: Sat, 8 Feb 2025 11:41:48 +0800 Subject: [PATCH 62/68] fix: typo --- crates/mako/src/plugins/module_federation/manifest.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/mako/src/plugins/module_federation/manifest.rs b/crates/mako/src/plugins/module_federation/manifest.rs index c18aa1047..7c23ff9ef 100644 --- a/crates/mako/src/plugins/module_federation/manifest.rs +++ b/crates/mako/src/plugins/module_federation/manifest.rs @@ -120,7 +120,7 @@ impl ModuleFederationPlugin { .entry .get(&self.config.name) .map(|e| e.import.to_string_lossy().to_string().into()); - let mf_containter_entry_chunk = mf_container_entry_root_module + let mf_container_entry_chunk = mf_container_entry_root_module .map(|m| chunk_graph.get_chunk_for_module(&m).unwrap()); ManifestMetaData { @@ -133,7 +133,7 @@ impl ModuleFederationPlugin { public_path: context.config.public_path.clone(), // FIXME: hardcode now r#type: "global".to_string(), - remote_entry: mf_containter_entry_chunk.map(|c| ManifestMetaRemoteEntry { + remote_entry: mf_container_entry_chunk.map(|c| ManifestMetaRemoteEntry { name: extract_assets(&[c.id.clone()], ¶ms.stats).0[0].clone(), path: "".to_string(), r#type: "global".to_string(), From ebc21d67084871b390098a120e1273dc6a48deb6 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Mon, 10 Feb 2025 11:16:33 +0800 Subject: [PATCH 63/68] chore: update README --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 73dd97edc..0fcdc32db 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@
- + Mako logo # Mako 🦈 @@ -10,7 +10,7 @@ [![](https://badgen.net/npm/license/umi)](https://www.npmjs.com/package/@umijs/mako) [![codecov](https://codecov.io/gh/umijs/mako/graph/badge.svg?token=ptCnNedFGf)](https://codecov.io/gh/umijs/mako) -Mako `['mɑːkoʊ]` is an **extremely fast**, **production-grade** web bundler based on **Rust**. +Mako `['mɑːkoʊ]` is an **extremely fast**, **production-grade** web bundler based on **Rust**. ✨ See more at [makojs.dev](https://makojs.dev).
@@ -56,6 +56,7 @@ This project is inspired by: - [oxc-resolver](https://github.com/oxc-project/oxc-resolver) by [@Boshen](https://github.com/Boshen) which powered the resolver of Mako. - [Oxc](https://github.com/oxc-project/oxc/) by [@Boshen](https://github.com/Boshen) from which we learned a lot about how to develop efficiently in Rust. - [biome](https://github.com/biomejs/biome) by [@ematipico](https://github.com/ematipico) from which we learned a lot about how to develop efficiently in Rust. +- [module-federation](https://github.com/module-federation/core) by [@ScriptedAlchemy](https://github.com/ScriptedAlchemy),which inspired a lot and powered the module federation feature of Mako. ## LICENSE From 08fdf40bd4ad81b08f2d783138c38b8cfb2400df Mon Sep 17 00:00:00 2001 From: xusd320 Date: Mon, 10 Feb 2025 22:54:51 +0800 Subject: [PATCH 64/68] fix: update mf bingding typings --- crates/binding/src/lib.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/crates/binding/src/lib.rs b/crates/binding/src/lib.rs index a55f4dd00..0ce12f513 100644 --- a/crates/binding/src/lib.rs +++ b/crates/binding/src/lib.rs @@ -158,11 +158,15 @@ pub struct BuildParams { }; moduleFederation?: { name: string; - // filename?: string; + filename?: string; exposes?: Record; shared: Record; remotes?: Record; From d4baf7f5316941aa19fbf3886d546852f4983c0d Mon Sep 17 00:00:00 2001 From: xusd320 Date: Tue, 11 Feb 2025 10:15:08 +0800 Subject: [PATCH 65/68] fix: typings --- crates/binding/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/binding/src/lib.rs b/crates/binding/src/lib.rs index 0ce12f513..bd1a7c7da 100644 --- a/crates/binding/src/lib.rs +++ b/crates/binding/src/lib.rs @@ -166,7 +166,7 @@ pub struct BuildParams { strictVersion?: bool; requiredVersion?: string; eager?: bool; - shareScope?: string; */ + shareScope?: string; } >; remotes?: Record; From 29b5585136849c0f209dc7432751b091d1e8218c Mon Sep 17 00:00:00 2001 From: xusd320 Date: Tue, 11 Feb 2025 10:30:52 +0800 Subject: [PATCH 66/68] fix: should not generate mf remotes runtime when remotes is empty --- crates/mako/src/lib.rs | 1 + crates/mako/src/main.rs | 1 + .../mako/src/plugins/module_federation/container_reference.rs | 4 ++++ 3 files changed, 6 insertions(+) diff --git a/crates/mako/src/lib.rs b/crates/mako/src/lib.rs index 3bebd29c7..4cf918a36 100644 --- a/crates/mako/src/lib.rs +++ b/crates/mako/src/lib.rs @@ -1,6 +1,7 @@ #![feature(box_patterns)] #![feature(hasher_prefixfree_extras)] #![feature(let_chains)] +#![feature(is_none_or)] pub mod ast; mod build; diff --git a/crates/mako/src/main.rs b/crates/mako/src/main.rs index cfc740591..ae366423d 100644 --- a/crates/mako/src/main.rs +++ b/crates/mako/src/main.rs @@ -1,5 +1,6 @@ #![feature(box_patterns)] #![feature(let_chains)] +#![feature(is_none_or)] extern crate swc_malloc; diff --git a/crates/mako/src/plugins/module_federation/container_reference.rs b/crates/mako/src/plugins/module_federation/container_reference.rs index 1e53d6c24..841da7cd8 100644 --- a/crates/mako/src/plugins/module_federation/container_reference.rs +++ b/crates/mako/src/plugins/module_federation/container_reference.rs @@ -12,6 +12,10 @@ use crate::resolve::{RemoteInfo, ResolverResource}; impl ModuleFederationPlugin { pub(super) fn init_federation_runtime_remotes(&self, context: &Arc) -> String { + if self.config.remotes.as_ref().is_none_or(|r| r.is_empty()) { + return "".to_string(); + } + let module_graph = context.module_graph.read().unwrap(); let chunk_graph = context.chunk_graph.read().unwrap(); let all_chunks = chunk_graph.get_all_chunks(); From d9c29fac5be588874f26d59b474f0391cbec9f74 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Tue, 18 Feb 2025 15:42:53 +0800 Subject: [PATCH 67/68] chore: remote wrong comment --- crates/mako/src/module.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/mako/src/module.rs b/crates/mako/src/module.rs index 662943ea6..a2a85b976 100644 --- a/crates/mako/src/module.rs +++ b/crates/mako/src/module.rs @@ -403,7 +403,6 @@ pub enum FedereationModuleType { pub struct Module { pub id: ModuleId, pub is_entry: bool, - // only module federation remote module pub info: Option, pub side_effects: bool, } From e7c1f18ceb5ff81b3103499c77a3c06f673d1ed9 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Thu, 20 Feb 2025 11:01:22 +0800 Subject: [PATCH 68/68] feat: add chunk matcher for mf --- crates/mako/src/generate/chunk_pot/util.rs | 10 ++++++++++ crates/mako/src/generate/runtime.rs | 1 + crates/mako/templates/app_runtime.stpl | 6 ++++-- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/crates/mako/src/generate/chunk_pot/util.rs b/crates/mako/src/generate/chunk_pot/util.rs index 9688aa60f..4d027c9a8 100644 --- a/crates/mako/src/generate/chunk_pot/util.rs +++ b/crates/mako/src/generate/chunk_pot/util.rs @@ -105,6 +105,15 @@ pub(crate) fn runtime_code(context: &Arc) -> Result { let chunk_graph = context.chunk_graph.read().unwrap(); let has_dynamic_chunks = chunk_graph.get_all_chunks().len() > 1; let has_hmr = context.args.watch; + let chunk_matcher = context.config.module_federation.as_ref().and_then(|mf| { + mf.remotes.as_ref().and_then(|remotes| { + if remotes.is_empty() { + None + } else { + Some(r#"/^mako\/container\/remote\//"#.to_string()) + } + }) + }); let app_runtime = AppRuntimeTemplate { has_dynamic_chunks, has_hmr, @@ -127,6 +136,7 @@ pub(crate) fn runtime_code(context: &Arc) -> Result { .as_ref() .map_or(false, |o| o.concatenate_modules.unwrap_or(false)), global_module_registry: context.config.output.global_module_registry, + chunk_matcher, }; let app_runtime = app_runtime.render_once()?; let app_runtime = app_runtime.replace( diff --git a/crates/mako/src/generate/runtime.rs b/crates/mako/src/generate/runtime.rs index 81edd7ca3..84879c2f7 100644 --- a/crates/mako/src/generate/runtime.rs +++ b/crates/mako/src/generate/runtime.rs @@ -14,4 +14,5 @@ pub struct AppRuntimeTemplate { pub concatenate_enabled: bool, pub cross_origin_loading: Option, pub global_module_registry: bool, + pub chunk_matcher: Option, } diff --git a/crates/mako/templates/app_runtime.stpl b/crates/mako/templates/app_runtime.stpl index 5af7b8335..69734d85c 100644 --- a/crates/mako/templates/app_runtime.stpl +++ b/crates/mako/templates/app_runtime.stpl @@ -71,7 +71,7 @@ function createRuntime(makoModules, entryModuleId, global) { // required modules requireModule.m = makoModules; - // required modules + // modules registry requireModule.c = modulesRegistry; <% if concatenate_enabled { %> @@ -135,8 +135,10 @@ function createRuntime(makoModules, entryModuleId, global) { var data = installedChunks[chunkId]; if (data === 0) return; + <% if chunk_matcher.is_some() { %> // skip federation remote chunk - if (chunkId.startsWith("mako/container/remote/")) return; + if (<%= chunk_matcher.unwrap() %>.test(chunkId)) return + <% } %> if (data) { // 0 1 2