Skip to content

Commit

Permalink
feat: Module Federation, part 3, ProvideSharedPlugin (#4778)
Browse files Browse the repository at this point in the history
* ok

* fix

* fix
  • Loading branch information
ahabhgk authored and JSerFeng committed Nov 30, 2023
1 parent a2cc4c5 commit 4759d91
Show file tree
Hide file tree
Showing 58 changed files with 1,137 additions and 101 deletions.
9 changes: 9 additions & 0 deletions crates/node_binding/binding.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ export const enum BuiltinPluginName {
ContainerPlugin = 'ContainerPlugin',
ContainerReferencePlugin = 'ContainerReferencePlugin',
ModuleFederationRuntimePlugin = 'ModuleFederationRuntimePlugin',
ProvideSharedPlugin = 'ProvideSharedPlugin',
HttpExternalsRspackPlugin = 'HttpExternalsRspackPlugin',
CopyRspackPlugin = 'CopyRspackPlugin',
HtmlRspackPlugin = 'HtmlRspackPlugin',
Expand Down Expand Up @@ -1009,6 +1010,14 @@ export interface RawProgressPluginOptions {
profile: boolean
}

export interface RawProvideOptions {
key: string
shareKey: string
shareScope: string
version?: string | false | undefined
eager: boolean
}

export interface RawReactOptions {
runtime?: "automatic" | "classic"
importSource?: string
Expand Down
12 changes: 11 additions & 1 deletion crates/rspack_binding_options/src/options/raw_builtins/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use rspack_core::{
mf::{
container_plugin::ContainerPlugin, container_reference_plugin::ContainerReferencePlugin,
module_federation_runtime_plugin::ModuleFederationRuntimePlugin,
provide_shared_plugin::ProvideSharedPlugin,
},
BoxPlugin, Define, DefinePlugin, PluginExt, Provide, ProvidePlugin,
};
Expand All @@ -42,7 +43,7 @@ use rspack_plugin_swc_js_minimizer::SwcJsMinimizerRspackPlugin;
use rspack_plugin_wasm::enable_wasm_loading_plugin;
use rspack_plugin_web_worker_template::web_worker_template_plugin;

use self::raw_mf::RawContainerReferencePluginOptions;
use self::raw_mf::{RawContainerReferencePluginOptions, RawProvideOptions};
pub use self::{
raw_banner::RawBannerPluginOptions, raw_copy::RawCopyRspackPluginOptions,
raw_html::RawHtmlRspackPluginOptions, raw_limit_chunk_count::RawLimitChunkCountPluginOptions,
Expand Down Expand Up @@ -81,6 +82,7 @@ pub enum BuiltinPluginName {
ContainerPlugin,
ContainerReferencePlugin,
ModuleFederationRuntimePlugin,
ProvideSharedPlugin,

// rspack specific plugins
HttpExternalsRspackPlugin,
Expand Down Expand Up @@ -214,6 +216,14 @@ impl RawOptionsApply for BuiltinPlugin {
BuiltinPluginName::ModuleFederationRuntimePlugin => {
plugins.push(ModuleFederationRuntimePlugin::default().boxed())
}
BuiltinPluginName::ProvideSharedPlugin => {
let mut provides: Vec<_> = downcast_into::<Vec<RawProvideOptions>>(self.options)?
.into_iter()
.map(Into::into)
.collect();
provides.sort_unstable_by_key(|(k, _)| k.to_string());
plugins.push(ProvideSharedPlugin::new(provides).boxed())
}

// rspack specific plugins
BuiltinPluginName::HttpExternalsRspackPlugin => {
Expand Down
40 changes: 40 additions & 0 deletions crates/rspack_binding_options/src/options/raw_builtins/raw_mf.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use napi::Either;
use napi_derive::napi;
use rspack_core::mf::{
container_plugin::{ContainerPluginOptions, ExposeOptions},
container_reference_plugin::{ContainerReferencePluginOptions, RemoteOptions},
provide_shared_plugin::{ProvideOptions, ProvideVersion},
};

use crate::RawLibraryOptions;
Expand Down Expand Up @@ -87,3 +89,41 @@ impl From<RawRemoteOptions> for (String, RemoteOptions) {
)
}
}

#[derive(Debug)]
#[napi(object)]
pub struct RawProvideOptions {
pub key: String,
pub share_key: String,
pub share_scope: String,
#[napi(ts_type = "string | false | undefined")]
pub version: Option<RawProvideVersion>,
pub eager: bool,
}

impl From<RawProvideOptions> for (String, ProvideOptions) {
fn from(value: RawProvideOptions) -> Self {
(
value.key,
ProvideOptions {
share_key: value.share_key,
share_scope: value.share_scope,
version: value.version.map(|v| RawProvideVersionWrapper(v).into()),
eager: value.eager,
},
)
}
}

pub type RawProvideVersion = Either<String, bool>;

struct RawProvideVersionWrapper(RawProvideVersion);

impl From<RawProvideVersionWrapper> for ProvideVersion {
fn from(value: RawProvideVersionWrapper) -> Self {
match value.0 {
Either::A(s) => ProvideVersion::Version(s),
Either::B(_) => ProvideVersion::False,
}
}
}
28 changes: 28 additions & 0 deletions crates/rspack_core/src/build_chunk_graph/code_splitter.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use anyhow::anyhow;
use itertools::Itertools;
use rspack_error::{internal_error, Result};
use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};

Expand Down Expand Up @@ -145,6 +146,33 @@ impl<'me> CodeSplitter<'me> {
entrypoint.ukey,
);
}

let global_included_modules = compilation
.global_entry
.include_dependencies
.iter()
.filter_map(|dep| {
compilation
.module_graph
.module_identifier_by_dependency_id(dep)
})
.copied()
.sorted_unstable();
let included_modules = entry_data
.include_dependencies
.iter()
.filter_map(|dep| {
compilation
.module_graph
.module_identifier_by_dependency_id(dep)
})
.copied()
.sorted_unstable();
let included_modules = global_included_modules.chain(included_modules);
input_entrypoints_and_modules
.entry(entrypoint.ukey)
.or_default()
.extend(included_modules);
}

let mut runtime_chunks = HashSet::default();
Expand Down
25 changes: 25 additions & 0 deletions crates/rspack_core/src/compiler/compilation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ impl Compilation {
} else {
let data = EntryData {
dependencies: vec![entry_id],
include_dependencies: vec![],
options,
};
self.entries.insert(name, data);
Expand All @@ -191,6 +192,30 @@ impl Compilation {
}
}

pub async fn add_include(&mut self, entry: BoxDependency, options: EntryOptions) -> Result<()> {
let entry_id = *entry.id();
self.module_graph.add_dependency(entry);
if let Some(name) = options.name.clone() {
if let Some(data) = self.entries.get_mut(&name) {
data.include_dependencies.push(entry_id);
} else {
let data = EntryData {
dependencies: vec![],
include_dependencies: vec![entry_id],
options,
};
self.entries.insert(name, data);
}
} else {
self.global_entry.include_dependencies.push(entry_id);
}
self
.update_module_graph(vec![MakeParam::ForceBuildDeps(HashSet::from_iter([(
entry_id, None,
)]))])
.await
}

pub fn update_asset(
&mut self,
filename: &str,
Expand Down
11 changes: 11 additions & 0 deletions crates/rspack_core/src/compiler/queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,17 @@ impl WorkerTask for FactorizeTask {
.await?
.split_into_parts()
}
DependencyType::ProvideSharedModule => {
let factory = crate::mf::provide_shared_module_factory::ProvideSharedModuleFactory;
factory
.create(ModuleFactoryCreateData {
resolve_options: self.resolve_options,
context,
dependency,
})
.await?
.split_into_parts()
}
_ => {
assert!(dependency.as_context_dependency().is_none());
let factory = NormalModuleFactory::new(
Expand Down
6 changes: 6 additions & 0 deletions crates/rspack_core/src/dependency/dependency_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ pub enum DependencyType {
ContainerEntry,
/// remote to external,
RemoteToExternal,
/// provide shared module
ProvideSharedModule,
/// provide module for shared
ProvideModuleForShared,
Custom(Box<str>), // TODO it will increase large layout size
}

Expand Down Expand Up @@ -110,6 +114,8 @@ impl DependencyType {
DependencyType::ContainerExposed => Cow::Borrowed("container exposed"),
DependencyType::ContainerEntry => Cow::Borrowed("container entry"),
DependencyType::RemoteToExternal => Cow::Borrowed("remote to external"),
DependencyType::ProvideSharedModule => Cow::Borrowed("provide shared module"),
DependencyType::ProvideModuleForShared => Cow::Borrowed("provide module for shared"),
}
}
}
Expand Down
46 changes: 43 additions & 3 deletions crates/rspack_core/src/dependency/runtime_template.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use swc_core::ecma::atoms::JsWord;

use crate::{
get_import_var, property_access, AsyncDependenciesBlockIdentifier, Compilation, DependencyId,
ExportsType, FakeNamespaceObjectMode, InitFragmentExt, InitFragmentKey, InitFragmentStage,
ModuleGraph, ModuleIdentifier, NormalInitFragment, RuntimeGlobals, TemplateContext,
get_import_var, property_access, AsyncDependenciesBlockIdentifier, Compilation,
DependenciesBlock, DependencyId, ExportsType, FakeNamespaceObjectMode, InitFragmentExt,
InitFragmentKey, InitFragmentStage, ModuleGraph, ModuleIdentifier, NormalInitFragment,
RuntimeGlobals, TemplateContext,
};

pub fn export_from_import(
Expand Down Expand Up @@ -364,3 +365,42 @@ pub fn returning_function(return_value: &str, args: &str) -> String {
pub fn basic_function(args: &str, body: &str) -> String {
format!("function({args}) {{\n{body}\n}}")
}

pub fn sync_module_factory(
dep: &DependencyId,
request: &str,
compilation: &Compilation,
runtime_requirements: &mut RuntimeGlobals,
) -> String {
let factory = returning_function(
&module_raw(compilation, runtime_requirements, dep, request, false),
"",
);
returning_function(&factory, "")
}

pub fn async_module_factory(
block_id: &AsyncDependenciesBlockIdentifier,
request: &str,
compilation: &Compilation,
runtime_requirements: &mut RuntimeGlobals,
) -> String {
let block = compilation
.module_graph
.block_by_id(block_id)
.expect("should have block");
let dep = block.get_dependencies()[0];
let ensure_chunk = block_promise(Some(block_id), runtime_requirements, compilation);
let factory = returning_function(
&module_raw(compilation, runtime_requirements, &dep, request, false),
"",
);
returning_function(
&if ensure_chunk.starts_with("Promise.resolve(") {
factory
} else {
format!("{ensure_chunk}.then({})", returning_function(&factory, ""))
},
"",
)
}
2 changes: 2 additions & 0 deletions crates/rspack_core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ pub enum ModuleType {
Asset,
Runtime,
Remote,
Provide,
}

impl ModuleType {
Expand Down Expand Up @@ -223,6 +224,7 @@ impl ModuleType {
ModuleType::AssetInline => "asset/inline",
ModuleType::Runtime => "runtime",
ModuleType::Remote => "remote-module",
ModuleType::Provide => "provide-module",
}
}
}
Expand Down
7 changes: 5 additions & 2 deletions crates/rspack_core/src/mf/container/remote_module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use rspack_sources::{RawSource, Source, SourceExt};

use super::remote_to_external_dependency::RemoteToExternalDependency;
use crate::{
mf::share_runtime_module::{CodeGenerationDataShareInit, DataInit, ShareInitData},
mf::share_runtime_module::{CodeGenerationDataShareInit, ShareInitData},
AsyncDependenciesBlockIdentifier, BoxDependency, BuildContext, BuildInfo, BuildResult,
CodeGenerationResult, Compilation, Context, DependenciesBlock, DependencyId, LibIdentOptions,
Module, ModuleIdentifier, ModuleType, RuntimeSpec, SourceType,
Expand Down Expand Up @@ -160,7 +160,10 @@ impl Module for RemoteModule {
items: vec![ShareInitData {
share_scope: self.share_scope.clone(),
init_stage: 20,
init: DataInit::ExternalModuleId(id.map(|id| id.to_string())),
init: format!(
"initExternal({});",
serde_json::to_string(&id).expect("module_id should able to json to_string")
),
}],
});
Ok(codegen)
Expand Down
5 changes: 5 additions & 0 deletions crates/rspack_core/src/mf/sharing/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
pub mod provide_for_shared_dependency;
pub mod provide_shared_dependency;
pub mod provide_shared_module;
pub mod provide_shared_module_factory;
pub mod provide_shared_plugin;
pub mod share_runtime_module;
46 changes: 46 additions & 0 deletions crates/rspack_core/src/mf/sharing/provide_for_shared_dependency.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use crate::{
AsContextDependency, AsDependencyTemplate, Dependency, DependencyCategory, DependencyId,
DependencyType, ModuleDependency,
};

#[derive(Debug, Clone)]
pub struct ProvideForSharedDependency {
id: DependencyId,
request: String,
}

impl ProvideForSharedDependency {
pub fn new(request: String) -> Self {
Self {
id: DependencyId::new(),
request,
}
}
}

impl Dependency for ProvideForSharedDependency {
fn dependency_debug_name(&self) -> &'static str {
"ProvideForSharedDependency"
}

fn id(&self) -> &DependencyId {
&self.id
}

fn dependency_type(&self) -> &DependencyType {
&DependencyType::ProvideModuleForShared
}

fn category(&self) -> &DependencyCategory {
&DependencyCategory::Esm
}
}

impl ModuleDependency for ProvideForSharedDependency {
fn request(&self) -> &str {
&self.request
}
}

impl AsContextDependency for ProvideForSharedDependency {}
impl AsDependencyTemplate for ProvideForSharedDependency {}
Loading

0 comments on commit 4759d91

Please sign in to comment.