From 533c38f0956a08560e13904f4c542f716e1b3d5a Mon Sep 17 00:00:00 2001 From: ahabhgk Date: Wed, 22 Nov 2023 14:17:17 +0800 Subject: [PATCH] wip --- .../src/dependency/dependency_type.rs | 3 + crates/rspack_core/src/lib.rs | 6 + .../container/container_entry_dependency.rs | 6 - .../mf/container/container_entry_module.rs | 7 +- .../container/container_reference_plugin.rs | 103 +++++++++- crates/rspack_core/src/mf/container/mod.rs | 5 + .../src/mf/container/remote_module.rs | 192 ++++++++++++++++++ .../src/mf/container/remote_runtime_module.rs | 35 ++++ .../remote_to_external_dependency.rs | 46 +++++ 9 files changed, 391 insertions(+), 12 deletions(-) create mode 100644 crates/rspack_core/src/mf/container/remote_module.rs create mode 100644 crates/rspack_core/src/mf/container/remote_runtime_module.rs create mode 100644 crates/rspack_core/src/mf/container/remote_to_external_dependency.rs diff --git a/crates/rspack_core/src/dependency/dependency_type.rs b/crates/rspack_core/src/dependency/dependency_type.rs index 21115f520e3f..90b9c5ba2842 100644 --- a/crates/rspack_core/src/dependency/dependency_type.rs +++ b/crates/rspack_core/src/dependency/dependency_type.rs @@ -66,6 +66,8 @@ pub enum DependencyType { ContainerExposed, /// container entry, ContainerEntry, + /// remote to external, + RemoteToExternal, Custom(Box), // TODO it will increase large layout size } @@ -107,6 +109,7 @@ impl DependencyType { DependencyType::ImportMetaContext => Cow::Borrowed("import.meta context"), DependencyType::ContainerExposed => Cow::Borrowed("container exposed"), DependencyType::ContainerEntry => Cow::Borrowed("container entry"), + DependencyType::RemoteToExternal => Cow::Borrowed("remote to external"), } } } diff --git a/crates/rspack_core/src/lib.rs b/crates/rspack_core/src/lib.rs index 964c7d17c521..69cf5df5d94b 100644 --- a/crates/rspack_core/src/lib.rs +++ b/crates/rspack_core/src/lib.rs @@ -95,6 +95,8 @@ pub enum SourceType { Css, Wasm, Asset, + Remote, + ShareInit, #[default] Unknown, } @@ -106,6 +108,8 @@ impl std::fmt::Display for SourceType { SourceType::Css => write!(f, "css"), SourceType::Wasm => write!(f, "wasm"), SourceType::Asset => write!(f, "asset"), + SourceType::Remote => write!(f, "remote"), + SourceType::ShareInit => write!(f, "share-init"), SourceType::Unknown => write!(f, "unknown"), } } @@ -132,6 +136,7 @@ pub enum ModuleType { AssetSource, Asset, Runtime, + Remote, } impl ModuleType { @@ -216,6 +221,7 @@ impl ModuleType { ModuleType::AssetResource => "asset/resource", ModuleType::AssetInline => "asset/inline", ModuleType::Runtime => "runtime", + ModuleType::Remote => "remote-module", } } } diff --git a/crates/rspack_core/src/mf/container/container_entry_dependency.rs b/crates/rspack_core/src/mf/container/container_entry_dependency.rs index c05e7796d6f7..8d22efbf1ad1 100644 --- a/crates/rspack_core/src/mf/container/container_entry_dependency.rs +++ b/crates/rspack_core/src/mf/container/container_entry_dependency.rs @@ -52,12 +52,6 @@ impl ModuleDependency for ContainerEntryDependency { fn request(&self) -> &str { &self.resource_identifier } - - fn user_request(&self) -> &str { - &self.resource_identifier - } - - fn set_request(&mut self, _request: String) {} } impl AsContextDependency for ContainerEntryDependency {} diff --git a/crates/rspack_core/src/mf/container/container_entry_module.rs b/crates/rspack_core/src/mf/container/container_entry_module.rs index 969e1cd27d28..c76b46840f84 100644 --- a/crates/rspack_core/src/mf/container/container_entry_module.rs +++ b/crates/rspack_core/src/mf/container/container_entry_module.rs @@ -20,13 +20,14 @@ pub struct ContainerEntryModule { blocks: Vec, dependencies: Vec, identifier: ModuleIdentifier, - name: String, + lib_ident: String, exposes: Vec<(String, ExposeOptions)>, share_scope: String, } impl ContainerEntryModule { pub fn new(name: String, exposes: Vec<(String, ExposeOptions)>, share_scope: String) -> Self { + let lib_ident = format!("webpack/container/entry/{}", &name); Self { blocks: Vec::new(), dependencies: Vec::new(), @@ -35,7 +36,7 @@ impl ContainerEntryModule { share_scope, serde_json::to_string(&exposes).expect("should able to json to_string") )), - name, + lib_ident, exposes, share_scope, } @@ -89,7 +90,7 @@ impl Module for ContainerEntryModule { } fn lib_ident(&self, _options: LibIdentOptions) -> Option> { - Some(format!("webpack/container/entry/{}", self.name).into()) + Some(self.lib_ident.as_str().into()) } async fn build( diff --git a/crates/rspack_core/src/mf/container/container_reference_plugin.rs b/crates/rspack_core/src/mf/container/container_reference_plugin.rs index 135151655c09..943a3c663284 100644 --- a/crates/rspack_core/src/mf/container/container_reference_plugin.rs +++ b/crates/rspack_core/src/mf/container/container_reference_plugin.rs @@ -1,6 +1,103 @@ -use crate::Plugin; +use async_trait::async_trait; + +use super::{remote_module::RemoteModule, RemoteRuntimeModule}; +use crate::{ + AdditionalChunkRuntimeRequirementsArgs, ExternalType, FactorizeArgs, ModuleExt, + ModuleFactoryResult, NormalModuleFactoryContext, Plugin, + PluginAdditionalChunkRuntimeRequirementsOutput, PluginContext, PluginFactorizeHookOutput, + RuntimeGlobals, +}; + +#[derive(Debug)] +pub struct ContainerReferencePluginOptions { + pub remote_type: ExternalType, + pub remotes: Vec<(String, RemoteOptions)>, + pub share_scope: Option, +} #[derive(Debug)] -pub struct ContainerReferencePlugin; +pub struct RemoteOptions { + pub external: Vec, + pub share_scope: String, +} + +#[derive(Debug)] +pub struct ContainerReferencePlugin { + options: ContainerReferencePluginOptions, +} + +#[async_trait] +impl Plugin for ContainerReferencePlugin { + async fn factorize( + &self, + _ctx: PluginContext, + args: FactorizeArgs<'_>, + _job_ctx: &mut NormalModuleFactoryContext, + ) -> PluginFactorizeHookOutput { + let request = args.dependency.request(); + if !request.contains("!") { + for (key, config) in &self.options.remotes { + let key_len = key.len(); + let internal_request = &request[key_len..]; + if request.starts_with(key) + && (request.len() == key_len || internal_request.starts_with('/')) + { + let remote = RemoteModule::new( + request.to_owned(), + config + .external + .iter() + .enumerate() + .map(|(i, e)| { + if e.starts_with("internal ") { + e[9..].to_string() + } else { + format!( + "webpack/container/reference/{}", + (i > 0) + .then(|| format!("/fallback-{}", i)) + .unwrap_or_default() + ) + } + }) + .collect(), + format!(".{}", internal_request), + config.share_scope.clone(), + ) + .boxed(); + return Ok(Some(ModuleFactoryResult::new(remote))); + } + } + } + Ok(None) + } -impl Plugin for ContainerReferencePlugin {} + fn runtime_requirements_in_tree( + &self, + _ctx: PluginContext, + args: &mut AdditionalChunkRuntimeRequirementsArgs, + ) -> PluginAdditionalChunkRuntimeRequirementsOutput { + if args + .runtime_requirements + .contains(RuntimeGlobals::ENSURE_CHUNK_HANDLERS) + { + args.runtime_requirements.insert(RuntimeGlobals::MODULE); + args + .runtime_requirements + .insert(RuntimeGlobals::MODULE_FACTORIES_ADD_ONLY); + args + .runtime_requirements + .insert(RuntimeGlobals::HAS_OWN_PROPERTY); + args + .runtime_requirements + .insert(RuntimeGlobals::INITIALIZE_SHARING); + args + .runtime_requirements + .insert(RuntimeGlobals::SHARE_SCOPE_MAP); + args + .compilation + .add_runtime_module(args.chunk, Box::new(RemoteRuntimeModule::default())); + } + Ok(()) + } +} diff --git a/crates/rspack_core/src/mf/container/mod.rs b/crates/rspack_core/src/mf/container/mod.rs index e65440c13e47..6274f82aaed1 100644 --- a/crates/rspack_core/src/mf/container/mod.rs +++ b/crates/rspack_core/src/mf/container/mod.rs @@ -4,6 +4,11 @@ mod container_entry_module_factory; mod container_exposed_dependency; mod container_plugin; mod container_reference_plugin; +mod remote_module; +mod remote_runtime_module; +mod remote_to_external_dependency; pub use container_entry_module_factory::ContainerEntryModuleFactory; pub use container_plugin::{ContainerPlugin, ContainerPluginOptions, ExposeOptions}; +pub use remote_runtime_module::RemoteRuntimeModule; +pub use remote_to_external_dependency::RemoteToExternalDependency; diff --git a/crates/rspack_core/src/mf/container/remote_module.rs b/crates/rspack_core/src/mf/container/remote_module.rs new file mode 100644 index 000000000000..444c701214e5 --- /dev/null +++ b/crates/rspack_core/src/mf/container/remote_module.rs @@ -0,0 +1,192 @@ +use std::borrow::Cow; +use std::hash::Hash; + +use async_trait::async_trait; +use rspack_error::{IntoTWithDiagnosticArray, Result, TWithDiagnosticArray}; +use rspack_hash::RspackHash; +use rspack_identifier::{Identifiable, Identifier}; +use rspack_sources::{RawSource, Source, SourceExt}; + +use super::RemoteToExternalDependency; +use crate::{ + AsyncDependenciesBlockIdentifier, BoxDependency, BuildContext, BuildInfo, BuildResult, + CodeGenerationResult, Compilation, Context, DependenciesBlock, DependencyId, LibIdentOptions, + Module, ModuleIdentifier, ModuleType, RuntimeSpec, SourceType, +}; + +#[derive(Debug)] +pub struct RemoteModule { + blocks: Vec, + dependencies: Vec, + identifier: ModuleIdentifier, + readable_identifier: String, + lib_ident: String, + request: String, + external_requests: Vec, + share_scope: String, +} + +impl RemoteModule { + pub fn new( + request: String, + external_requests: Vec, + internal_request: String, + share_scope: String, + ) -> Self { + let readable_identifier = format!("remote {}", &request); + let lib_ident = format!("webpack/container/remote/{}", &request); + Self { + blocks: Default::default(), + dependencies: Default::default(), + identifier: ModuleIdentifier::from(format!( + "remote ({}) {} {}", + share_scope, + external_requests.join(" "), + internal_request + )), + readable_identifier, + lib_ident, + request, + external_requests, + share_scope, + } + } +} + +impl Identifiable for RemoteModule { + fn identifier(&self) -> Identifier { + self.identifier + } +} + +impl DependenciesBlock for RemoteModule { + fn add_block_id(&mut self, block: AsyncDependenciesBlockIdentifier) { + self.blocks.push(block) + } + + fn get_blocks(&self) -> &[AsyncDependenciesBlockIdentifier] { + &self.blocks + } + + fn add_dependency_id(&mut self, dependency: DependencyId) { + self.dependencies.push(dependency) + } + + fn get_dependencies(&self) -> &[DependencyId] { + &self.dependencies + } +} + +#[async_trait] +impl Module for RemoteModule { + fn size(&self, _source_type: &SourceType) -> f64 { + 6.0 + } + + fn module_type(&self) -> &ModuleType { + &ModuleType::Remote + } + + fn source_types(&self) -> &[SourceType] { + &[SourceType::Remote, SourceType::ShareInit] + } + + fn original_source(&self) -> Option<&dyn Source> { + None + } + + fn readable_identifier(&self, _context: &Context) -> Cow { + self.readable_identifier.as_str().into() + } + + fn lib_ident(&self, _options: LibIdentOptions) -> Option> { + Some(self.lib_ident.as_str().into()) + } + + fn name_for_condition(&self) -> Option> { + Some(self.request.as_str().into()) + } + + async fn build( + &mut self, + build_context: BuildContext<'_>, + ) -> Result> { + let mut hasher = RspackHash::from(&build_context.compiler_options.output); + self.update_hash(&mut hasher); + + let build_info = BuildInfo { + strict: true, + hash: Some(hasher.digest(&build_context.compiler_options.output.hash_digest)), + ..Default::default() + }; + + let mut dependencies = Vec::new(); + if self.external_requests.len() == 1 { + let dep = RemoteToExternalDependency::new(self.external_requests[0].clone()); + dependencies.push(Box::new(dep) as BoxDependency); + } + + Ok( + BuildResult { + build_info, + build_meta: Default::default(), + dependencies, + blocks: Vec::new(), + analyze_result: Default::default(), + } + .with_empty_diagnostic(), + ) + } + + #[allow(clippy::unwrap_in_result)] + fn code_generation( + &self, + compilation: &Compilation, + _runtime: Option<&RuntimeSpec>, + ) -> Result { + let mut codegen = CodeGenerationResult::default(); + let module = compilation.module_graph.get_module(&self.dependencies[0]); + let id = module.and_then(|m| { + compilation + .chunk_graph + .get_module_id(m.identifier()) + .as_deref() + }); + codegen.add(SourceType::Remote, RawSource::from("").boxed()); + codegen.data.insert(CodeGenerationDataShareInit { + share_scope: self.share_scope.clone(), + init_stage: 20, + init: id + .map(|id| { + format!( + "initExternal({})", + serde_json::to_string(id).expect("module_id should able to json to_string") + ) + }) + .unwrap_or_default(), + }); + Ok(codegen) + } +} + +impl Hash for RemoteModule { + fn hash(&self, state: &mut H) { + "__rspack_internal__RemoteModule".hash(state); + self.identifier().hash(state); + } +} + +impl PartialEq for RemoteModule { + fn eq(&self, other: &Self) -> bool { + self.identifier() == other.identifier() + } +} + +impl Eq for RemoteModule {} + +#[derive(Clone, Debug)] +pub struct CodeGenerationDataShareInit { + pub share_scope: String, + pub init_stage: u32, + pub init: String, +} diff --git a/crates/rspack_core/src/mf/container/remote_runtime_module.rs b/crates/rspack_core/src/mf/container/remote_runtime_module.rs new file mode 100644 index 000000000000..ce254b3c8348 --- /dev/null +++ b/crates/rspack_core/src/mf/container/remote_runtime_module.rs @@ -0,0 +1,35 @@ +use rspack_identifier::Identifier; +use rspack_sources::BoxSource; + +use crate::{impl_runtime_module, ChunkUkey, Compilation, RuntimeModule}; + +#[derive(Debug, Eq)] +pub struct RemoteRuntimeModule { + id: Identifier, + chunk: Option, +} + +impl Default for RemoteRuntimeModule { + fn default() -> Self { + Self { + id: Identifier::from("webpack/runtime/remotes_loading"), + chunk: None, + } + } +} + +impl RuntimeModule for RemoteRuntimeModule { + fn name(&self) -> Identifier { + self.id + } + + fn generate(&self, compilation: &Compilation) -> BoxSource { + todo!() + } + + fn attach(&mut self, chunk: ChunkUkey) { + self.chunk = Some(chunk); + } +} + +impl_runtime_module!(RemoteRuntimeModule); diff --git a/crates/rspack_core/src/mf/container/remote_to_external_dependency.rs b/crates/rspack_core/src/mf/container/remote_to_external_dependency.rs new file mode 100644 index 000000000000..9fbb3a2e2562 --- /dev/null +++ b/crates/rspack_core/src/mf/container/remote_to_external_dependency.rs @@ -0,0 +1,46 @@ +use crate::{ + AsContextDependency, AsDependencyTemplate, Dependency, DependencyCategory, DependencyId, + DependencyType, ModuleDependency, +}; + +#[derive(Debug, Clone)] +pub struct RemoteToExternalDependency { + id: DependencyId, + request: String, +} + +impl RemoteToExternalDependency { + pub fn new(request: String) -> Self { + Self { + id: DependencyId::new(), + request, + } + } +} + +impl Dependency for RemoteToExternalDependency { + fn dependency_debug_name(&self) -> &'static str { + "RemoteToExternalDependency" + } + + fn id(&self) -> &DependencyId { + &self.id + } + + fn dependency_type(&self) -> &DependencyType { + &DependencyType::RemoteToExternal + } + + fn category(&self) -> &DependencyCategory { + &DependencyCategory::Esm + } +} + +impl ModuleDependency for RemoteToExternalDependency { + fn request(&self) -> &str { + &self.request + } +} + +impl AsContextDependency for RemoteToExternalDependency {} +impl AsDependencyTemplate for RemoteToExternalDependency {}