Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Module Federation, part 3, ProvideSharedPlugin #4778

Merged
merged 3 commits into from
Nov 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -107,6 +107,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
Loading