Skip to content

Commit

Permalink
feat: port "module-import" external type (#7479)
Browse files Browse the repository at this point in the history
  • Loading branch information
fi3ework authored Aug 7, 2024
1 parent e6c8b93 commit 7b9117f
Show file tree
Hide file tree
Showing 12 changed files with 358 additions and 86 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

150 changes: 103 additions & 47 deletions crates/rspack_core/src/external_module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,29 @@ pub struct ExternalModule {
factory_meta: Option<FactoryMeta>,
build_info: Option<BuildInfo>,
build_meta: Option<BuildMeta>,
dependency_meta: DependencyMeta,
}

#[derive(Debug)]
pub enum ExternalTypeEnum {
Import,
Module,
}

pub type MetaExternalType = Option<ExternalTypeEnum>;

#[derive(Debug)]
pub struct DependencyMeta {
pub external_type: MetaExternalType,
}

impl ExternalModule {
pub fn new(request: ExternalRequest, external_type: ExternalType, user_request: String) -> Self {
pub fn new(
request: ExternalRequest,
external_type: ExternalType,
user_request: String,
dependency_meta: DependencyMeta,
) -> Self {
Self {
dependencies: Vec::new(),
blocks: Vec::new(),
Expand All @@ -147,6 +166,7 @@ impl ExternalModule {
build_info: None,
build_meta: None,
source_map_kind: SourceMapKind::empty(),
dependency_meta,
}
}

Expand All @@ -170,6 +190,7 @@ impl ExternalModule {
) -> Result<(BoxSource, ChunkInitFragments, RuntimeGlobals)> {
let mut chunk_init_fragments: ChunkInitFragments = Default::default();
let mut runtime_requirements: RuntimeGlobals = Default::default();

let source = match self.external_type.as_str() {
"this" if let Some(request) = request => format!(
"{} = (function() {{ return {}; }}());",
Expand Down Expand Up @@ -234,52 +255,62 @@ impl ExternalModule {
to_identifier(id)
)
}
"import" if let Some(request) = request => format!(
"{} = {};",
get_namespace_object_export(concatenation_scope),
get_source_for_import(request, compilation)
),
"module" | "import" | "module-import" if let Some(request) = request => {
match self.get_module_import_type(external_type) {
"import" => {
format!(
"{} = {};",
get_namespace_object_export(concatenation_scope),
get_source_for_import(request, compilation)
)
}
"module" => {
if compilation.options.output.module {
let id = to_identifier(&request.primary);
chunk_init_fragments.push(
NormalInitFragment::new(
format!(
"import * as __WEBPACK_EXTERNAL_MODULE_{}__ from {};\n",
id.clone(),
json_stringify(request.primary())
),
InitFragmentStage::StageHarmonyImports,
0,
InitFragmentKey::ExternalModule(request.primary().into()),
None,
)
.boxed(),
);
runtime_requirements.insert(RuntimeGlobals::DEFINE_PROPERTY_GETTERS);
format!(
r#"
var x = y => {{ var x = {{}}; {}(x, y); return x; }}
var y = x => () => x
{} = __WEBPACK_EXTERNAL_MODULE_{}__;
"#,
RuntimeGlobals::DEFINE_PROPERTY_GETTERS,
get_namespace_object_export(concatenation_scope),
id.clone()
)
} else {
format!(
"{} = {};",
get_namespace_object_export(concatenation_scope),
get_source_for_import(request, compilation)
)
}
}
r#type => panic!(
"Unhandled external type: {} in \"module-import\" type",
r#type
),
}
}
"var" | "promise" | "const" | "let" | "assign" if let Some(request) = request => format!(
"{} = {};",
get_namespace_object_export(concatenation_scope),
get_source_for_default_case(false, request)
),
"module" if let Some(request) = request => {
if compilation.options.output.module {
let id = to_identifier(&request.primary);
chunk_init_fragments.push(
NormalInitFragment::new(
format!(
"import * as __WEBPACK_EXTERNAL_MODULE_{}__ from {};\n",
id.clone(),
json_stringify(request.primary())
),
InitFragmentStage::StageHarmonyImports,
0,
InitFragmentKey::ExternalModule(request.primary().into()),
None,
)
.boxed(),
);
runtime_requirements.insert(RuntimeGlobals::DEFINE_PROPERTY_GETTERS);
format!(
r#"
var x = y => {{ var x = {{}}; {}(x, y); return x; }}
var y = x => () => x
{} = __WEBPACK_EXTERNAL_MODULE_{}__;
"#,
RuntimeGlobals::DEFINE_PROPERTY_GETTERS,
get_namespace_object_export(concatenation_scope),
id.clone()
)
} else {
format!(
"{} = {};",
get_namespace_object_export(concatenation_scope),
get_source_for_import(request, compilation)
)
}
}
"script" if let Some(request) = request => {
let url_and_global = extract_url_and_global(request.primary())?;
runtime_requirements.insert(RuntimeGlobals::LOAD_SCRIPT);
Expand Down Expand Up @@ -316,6 +347,24 @@ if(typeof {global} !== "undefined") return resolve();
runtime_requirements,
))
}

fn get_module_import_type<'a>(&self, external_type: &'a ExternalType) -> &'a str {
match external_type.as_str() {
"module-import" => {
let external_type = self
.dependency_meta
.external_type
.as_ref()
.expect("should get \"module\" or \"import\" external type from dependency");

match external_type {
ExternalTypeEnum::Import => "import",
ExternalTypeEnum::Module => "module",
}
}
import_or_module => import_or_module,
}
}
}

impl Identifiable for ExternalModule {
Expand Down Expand Up @@ -412,6 +461,7 @@ impl Module for ExternalModule {
) -> Result<BuildResult> {
let mut hasher = RspackHash::from(&build_context.compiler_options.output);
self.update_hash(&mut hasher);
let (_, external_type) = self.get_request_and_external_type();

let build_info = BuildInfo {
hash: Some(hasher.digest(&build_context.compiler_options.output.hash_digest)),
Expand All @@ -431,12 +481,18 @@ impl Module for ExternalModule {
match self.external_type.as_str() {
"this" => build_result.build_info.strict = false,
"system" => build_result.build_meta.exports_type = BuildMetaExportsType::Namespace,
"module" => build_result.build_meta.exports_type = BuildMetaExportsType::Namespace,
"script" | "promise" => build_result.build_meta.has_top_level_await = true,
"import" => {
build_result.build_meta.has_top_level_await = true;
build_result.build_meta.exports_type = BuildMetaExportsType::Namespace;
}
"module" | "import" | "module-import" => match self.get_module_import_type(external_type) {
"module" => build_result.build_meta.exports_type = BuildMetaExportsType::Namespace,
"import" => {
build_result.build_meta.has_top_level_await = true;
build_result.build_meta.exports_type = BuildMetaExportsType::Namespace;
}
r#type => panic!(
"Unhandled external type: {} in \"module-import\" type",
r#type
),
},
_ => build_result.build_meta.exports_type = BuildMetaExportsType::Dynamic,
}
build_result
Expand Down
13 changes: 7 additions & 6 deletions crates/rspack_plugin_externals/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ version = "0.1.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
regex = { workspace = true }
rspack_core = { path = "../rspack_core" }
rspack_error = { path = "../rspack_error" }
rspack_hook = { path = "../rspack_hook" }
rspack_regex = { path = "../rspack_regex" }
tracing = { workspace = true }
regex = { workspace = true }
rspack_core = { path = "../rspack_core" }
rspack_error = { path = "../rspack_error" }
rspack_hook = { path = "../rspack_hook" }
rspack_plugin_javascript = { path = "../rspack_plugin_javascript" }
rspack_regex = { path = "../rspack_regex" }
tracing = { workspace = true }

[package.metadata.cargo-shear]
ignored = ["tracing"]
30 changes: 26 additions & 4 deletions crates/rspack_plugin_externals/src/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ use std::sync::LazyLock;

use regex::Regex;
use rspack_core::{
ApplyContext, BoxModule, CompilerOptions, ContextInfo, ExternalItem, ExternalItemFnCtx,
ExternalItemValue, ExternalModule, ExternalRequest, ExternalRequestValue, ExternalType,
ModuleDependency, ModuleExt, ModuleFactoryCreateData, NormalModuleFactoryFactorize, Plugin,
PluginContext,
ApplyContext, BoxModule, CompilerOptions, ContextInfo, DependencyMeta, ExternalItem,
ExternalItemFnCtx, ExternalItemValue, ExternalModule, ExternalRequest, ExternalRequestValue,
ExternalType, ExternalTypeEnum, ModuleDependency, ModuleExt, ModuleFactoryCreateData,
NormalModuleFactoryFactorize, Plugin, PluginContext,
};
use rspack_error::Result;
use rspack_hook::{plugin, plugin_hook};
use rspack_plugin_javascript::dependency::{HarmonyImportSideEffectDependency, ImportDependency};

static UNSPECIFIED_EXTERNAL_TYPE_REGEXP: LazyLock<Regex> =
LazyLock::new(|| Regex::new(r"^[a-z0-9-]+ ").expect("Invalid regex"));
Expand Down Expand Up @@ -101,10 +102,31 @@ impl ExternalsPlugin {
None
}

let dependency_meta: DependencyMeta = DependencyMeta {
external_type: {
if dependency
.as_any()
.downcast_ref::<ImportDependency>()
.is_some()
{
Some(ExternalTypeEnum::Import)
} else if dependency
.as_any()
.downcast_ref::<HarmonyImportSideEffectDependency>()
.is_some()
{
Some(ExternalTypeEnum::Module)
} else {
None
}
},
};

Some(ExternalModule::new(
external_module_config,
r#type.unwrap_or(external_module_type),
dependency.request().to_owned(),
dependency_meta,
))
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ module.exports = {
+ "outputModule": true,
@@ ... @@
- "externalsType": "var",
+ "externalsType": "module",
+ "externalsType": "module-import",
@@ ... @@
- "dynamicImport": undefined,
- "dynamicImportInWorker": undefined,
Expand Down
Loading

2 comments on commit 7b9117f

@rspack-bot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Ran ecosystem CI: Open

suite result
modernjs ❌ failure
_selftest ✅ success
nx ❌ failure
rspress ✅ success
rsbuild ❌ failure
examples ✅ success

@rspack-bot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Benchmark detail: Open

Name Base (2024-08-07 0b5ee31) Current Change
10000_development-mode + exec 2.32 s ± 22 ms 2.35 s ± 27 ms +1.13 %
10000_development-mode_hmr + exec 706 ms ± 7.7 ms 707 ms ± 12 ms +0.15 %
10000_production-mode + exec 2.85 s ± 23 ms 2.87 s ± 34 ms +0.76 %
arco-pro_development-mode + exec 1.88 s ± 60 ms 1.89 s ± 100 ms +0.39 %
arco-pro_development-mode_hmr + exec 434 ms ± 2.1 ms 435 ms ± 2.5 ms +0.17 %
arco-pro_production-mode + exec 3.62 s ± 262 ms 3.53 s ± 254 ms -2.63 %
arco-pro_production-mode_generate-package-json-webpack-plugin + exec 3.55 s ± 192 ms 3.53 s ± 151 ms -0.73 %
threejs_development-mode_10x + exec 1.71 s ± 13 ms 1.71 s ± 12 ms +0.10 %
threejs_development-mode_10x_hmr + exec 826 ms ± 8.9 ms 827 ms ± 4.9 ms +0.09 %
threejs_production-mode_10x + exec 5.51 s ± 33 ms 5.52 s ± 38 ms +0.08 %

Please sign in to comment.