Skip to content
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
8 changes: 6 additions & 2 deletions crates/rspack_core/src/runtime_globals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,8 +288,9 @@ define_runtime_globals! {
// defer import support
const ASYNC_MODULE_EXPORT_SYMBOL;
const MAKE_DEFERRED_NAMESPACE_OBJECT;
const MAKE_DEFERRED_NAMESPACE_OBJECT_SYMBOL;
const MAKE_OPTIMIZED_DEFERRED_NAMESPACE_OBJECT;
const DEFERRED_MODULES_ASYNC_TRANSITIVE_DEPENDENCIES;
const DEFERRED_MODULES_ASYNC_TRANSITIVE_DEPENDENCIES_SYMBOL;

// rspack only
const ASYNC_STARTUP;
Expand Down Expand Up @@ -358,8 +359,11 @@ pub fn runtime_globals_to_string(
RuntimeGlobals::STARTUP => format!("{scope_name}.x"),
RuntimeGlobals::MAKE_NAMESPACE_OBJECT => format!("{scope_name}.r"),
RuntimeGlobals::MAKE_DEFERRED_NAMESPACE_OBJECT => format!("{scope_name}.z"),
RuntimeGlobals::MAKE_DEFERRED_NAMESPACE_OBJECT_SYMBOL => format!("{scope_name}.zS"),
RuntimeGlobals::MAKE_OPTIMIZED_DEFERRED_NAMESPACE_OBJECT => format!("{scope_name}.zO"),
RuntimeGlobals::DEFERRED_MODULES_ASYNC_TRANSITIVE_DEPENDENCIES => format!("{scope_name}.zT"),
RuntimeGlobals::DEFERRED_MODULES_ASYNC_TRANSITIVE_DEPENDENCIES_SYMBOL => {
format!("{scope_name}.zS")
}
RuntimeGlobals::EXPORTS => {
runtime_variable_to_string(&RuntimeVariable::Exports, compiler_options)
}
Expand Down
77 changes: 70 additions & 7 deletions crates/rspack_core/src/runtime_template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1228,18 +1228,16 @@ impl ModuleCodegenRuntimeTemplate {
request: &str,
message: &str,
weak: bool,
phase: ImportPhase,
) -> String {
if compilation
.get_module_graph()
.module_identifier_by_dependency_id(dep_id)
.is_none()
{
let mg = compilation.get_module_graph();
let Some(target_module) = mg.get_module_by_dependency_id(dep_id) else {
return self.missing_module_promise(request);
};

let promise = self.block_promise(block, compilation, message);
let exports_type = get_exports_type(
compilation.get_module_graph(),
mg,
&compilation.module_graph_cache_artifact,
dep_id,
&module_id,
Expand All @@ -1257,8 +1255,73 @@ impl ModuleCodegenRuntimeTemplate {
} else {
None
};
let mut fake_type = FakeNamespaceObjectMode::PROMISE_LIKE;

let mut appending;

if phase.is_defer() && !target_module.build_meta().has_top_level_await {
let mode = render_make_deferred_namespace_mode_from_exports_type(exports_type);
let async_deps = get_outgoing_async_modules(compilation, target_module.as_ref());
if !async_deps.is_empty() {
if let Some(header) = header {
let rendered_async_deps_fn = self.render_runtime_globals(
&RuntimeGlobals::DEFERRED_MODULES_ASYNC_TRANSITIVE_DEPENDENCIES,
);
appending = format!(
".then({})",
self.basic_function(
"",
&format!(
"{header}\nreturn {}({})",
&rendered_async_deps_fn,
json_stringify(&async_deps)
)
)
);
} else {
let rendered_async_deps_fn = self.render_runtime_globals(
&RuntimeGlobals::DEFERRED_MODULES_ASYNC_TRANSITIVE_DEPENDENCIES,
);
appending = format!(
".then({})",
self.returning_function(
&format!(
"{}({})",
&rendered_async_deps_fn,
json_stringify(&async_deps)
),
""
)
);
}
appending.push_str(&format!(
".then({}.bind({}, {module_id_expr}, {mode}))",
self.render_runtime_globals(&RuntimeGlobals::MAKE_DEFERRED_NAMESPACE_OBJECT),
self.render_runtime_globals(&RuntimeGlobals::REQUIRE)
));
} else if let Some(header) = header {
let rendered_async_deps_fn =
self.render_runtime_globals(&RuntimeGlobals::MAKE_DEFERRED_NAMESPACE_OBJECT);
appending = format!(
".then({})",
self.basic_function(
"",
&format!(
"{header}\nreturn {}({module_id_expr}, {mode});",
&rendered_async_deps_fn
)
)
);
} else {
appending = format!(
".then({}.bind({}, {module_id_expr}, {mode}))",
self.render_runtime_globals(&RuntimeGlobals::MAKE_DEFERRED_NAMESPACE_OBJECT),
self.render_runtime_globals(&RuntimeGlobals::REQUIRE)
);
}
return format!("{promise}{appending}");
}

let mut fake_type = FakeNamespaceObjectMode::PROMISE_LIKE;
match exports_type {
ExportsType::Namespace => {
if let Some(header) = header {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use rspack_cacheable::{
use rspack_core::{
AsContextDependency, Dependency, DependencyCategory, DependencyCodeGeneration, DependencyId,
DependencyRange, DependencyTemplate, DependencyTemplateType, DependencyType, ExportsType,
ExtendedReferencedExport, FactorizeInfo, ImportAttributes, ModuleDependency, ModuleGraph,
ModuleGraphCacheArtifact, ReferencedExport, ResourceIdentifier, TemplateContext,
ExtendedReferencedExport, FactorizeInfo, ImportAttributes, ImportPhase, ModuleDependency,
ModuleGraph, ModuleGraphCacheArtifact, ReferencedExport, ResourceIdentifier, TemplateContext,
TemplateReplaceSource, create_exports_object_referenced,
};
use swc_core::ecma::atoms::Atom;
Expand Down Expand Up @@ -68,6 +68,7 @@ pub struct ImportDependency {
#[cacheable(with=AsOption<AsVec<AsVec<AsPreset>>>)]
referenced_exports: Option<Vec<Vec<Atom>>>,
attributes: Option<ImportAttributes>,
phase: ImportPhase,
pub comments: Vec<(bool, String)>,
resource_identifier: ResourceIdentifier,
factorize_info: FactorizeInfo,
Expand All @@ -80,6 +81,7 @@ impl ImportDependency {
range: DependencyRange,
referenced_exports: Option<Vec<Vec<Atom>>>,
attributes: Option<ImportAttributes>,
phase: ImportPhase,
optional: bool,
comments: Vec<(bool, String)>,
) -> Self {
Expand All @@ -91,6 +93,7 @@ impl ImportDependency {
id: DependencyId::new(),
referenced_exports,
attributes,
phase,
resource_identifier,
factorize_info: Default::default(),
optional,
Expand Down Expand Up @@ -125,6 +128,10 @@ impl Dependency for ImportDependency {
self.attributes.as_ref()
}

fn get_phase(&self) -> ImportPhase {
self.phase
}

fn range(&self) -> Option<DependencyRange> {
Some(self.range)
}
Expand Down Expand Up @@ -217,6 +224,7 @@ impl DependencyTemplate for ImportDependencyTemplate {
dep.request(),
dep.dependency_type().as_str(),
false,
dep.get_phase(),
)
.as_str(),
None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use rspack_cacheable::{
use rspack_core::{
AsContextDependency, Dependency, DependencyCategory, DependencyCodeGeneration, DependencyId,
DependencyRange, DependencyTemplate, DependencyTemplateType, DependencyType, FactorizeInfo,
ImportAttributes, ModuleDependency, ModuleGraphCacheArtifact, ResourceIdentifier,
ImportAttributes, ImportPhase, ModuleDependency, ModuleGraphCacheArtifact, ResourceIdentifier,
TemplateContext, TemplateReplaceSource,
};
use swc_core::ecma::atoms::Atom;
Expand All @@ -25,6 +25,7 @@ pub struct ImportEagerDependency {
#[cacheable(with=AsOption<AsVec<AsVec<AsPreset>>>)]
referenced_exports: Option<Vec<Vec<Atom>>>,
attributes: Option<ImportAttributes>,
phase: ImportPhase,
resource_identifier: ResourceIdentifier,
factorize_info: FactorizeInfo,
}
Expand All @@ -35,6 +36,7 @@ impl ImportEagerDependency {
range: DependencyRange,
referenced_exports: Option<Vec<Vec<Atom>>>,
attributes: Option<ImportAttributes>,
phase: ImportPhase,
) -> Self {
let resource_identifier =
create_resource_identifier_for_esm_dependency(request.as_str(), attributes.as_ref());
Expand All @@ -44,6 +46,7 @@ impl ImportEagerDependency {
id: DependencyId::new(),
referenced_exports,
attributes,
phase,
resource_identifier,
factorize_info: Default::default(),
}
Expand Down Expand Up @@ -76,6 +79,10 @@ impl Dependency for ImportEagerDependency {
self.attributes.as_ref()
}

fn get_phase(&self) -> ImportPhase {
self.phase
}

fn range(&self) -> Option<DependencyRange> {
Some(self.range)
}
Expand Down Expand Up @@ -164,6 +171,7 @@ impl DependencyTemplate for ImportEagerDependencyTemplate {
&dep.request,
dep.dependency_type().as_str(),
false,
dep.get_phase(),
)
.as_str(),
None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::borrow::Cow;
use rspack_core::{
AsyncDependenciesBlock, ChunkGroupOptions, ContextDependency, ContextNameSpaceObject,
ContextOptions, DependencyCategory, DependencyRange, DependencyType, DynamicImportFetchPriority,
DynamicImportMode, GroupOptions, ImportAttributes,
DynamicImportMode, GroupOptions, ImportAttributes, ImportPhase,
};
use rspack_error::{Error, Severity};
use rspack_util::{SpanExt, swc::get_swc_comments};
Expand Down Expand Up @@ -321,6 +321,16 @@ impl JavascriptParserPlugin for ImportParserPlugin {
parser.add_warning(error.into());
}

let phase: ImportPhase = node
.callee
.as_import()
.expect("should be import")
.phase
.into();
if phase.is_defer() && !parser.compiler_options.experiments.defer_import {
parser.add_error(rspack_error::error!("deferImport is still an experimental feature. To continue using it, please enable 'experiments.deferImport'.").into());
}

let attributes = get_attributes_from_call_expr(node);
let param = parser.evaluate_expression(dyn_imported.expr.as_ref());

Expand All @@ -331,6 +341,7 @@ impl JavascriptParserPlugin for ImportParserPlugin {
import_call_span.into(),
exports,
attributes,
phase,
);
let dep_idx = parser.next_dependency_idx();
parser.add_dependency(Box::new(dep));
Expand All @@ -345,6 +356,7 @@ impl JavascriptParserPlugin for ImportParserPlugin {
import_call_span.into(),
exports,
attributes,
phase,
parser.in_try,
get_swc_comments(
parser.comments,
Expand Down Expand Up @@ -378,6 +390,10 @@ impl JavascriptParserPlugin for ImportParserPlugin {
return None;
}

if phase.is_defer() {
parser.add_error(rspack_error::error!("import.defer() is not yet supported for ContextModule (the import path is a dynamic expression).").into());
}

let ContextModuleScanResult {
context,
reg,
Expand Down
7 changes: 4 additions & 3 deletions crates/rspack_plugin_lazy_compilation/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use rspack_collections::Identifiable;
use rspack_core::{
AsyncDependenciesBlock, AsyncDependenciesBlockIdentifier, BoxDependency, BuildContext, BuildInfo,
BuildMeta, BuildResult, ChunkGraph, CodeGenerationResult, Compilation, Context,
DependenciesBlock, DependencyId, DependencyRange, FactoryMeta, LibIdentOptions, Module,
ModuleArgument, ModuleCodeGenerationContext, ModuleFactoryCreateData, ModuleGraph,
DependenciesBlock, DependencyId, DependencyRange, FactoryMeta, ImportPhase, LibIdentOptions,
Module, ModuleArgument, ModuleCodeGenerationContext, ModuleFactoryCreateData, ModuleGraph,
ModuleIdentifier, ModuleLayer, ModuleType, RuntimeGlobals, RuntimeSpec, SourceType,
ValueCacheVersions, impl_module_meta_info, module_update_hash,
rspack_sources::{BoxSource, RawStringSource},
Expand Down Expand Up @@ -262,7 +262,8 @@ impl Module for LazyCompilationProxyModule {
Some(block_id),
&self.resource,
"import()",
false
false,
ImportPhase::Evaluation,
),
json_stringify(
ChunkGraph::get_module_id(&compilation.module_ids_artifact, *module)
Expand Down
5 changes: 4 additions & 1 deletion crates/rspack_plugin_rstest/src/parser_plugin.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use camino::Utf8PathBuf;
use rspack_core::{
AsyncDependenciesBlock, ConstDependency, DependencyRange, ImportAttributes, RuntimeGlobals,
AsyncDependenciesBlock, ConstDependency, DependencyRange, ImportAttributes, ImportPhase,
RuntimeGlobals,
};
use rspack_plugin_javascript::{
JavascriptParserPlugin,
Expand Down Expand Up @@ -143,6 +144,7 @@ impl RstestParserPlugin {
call_expr.span.into(),
None,
Some(attrs),
ImportPhase::Evaluation,
parser.in_try,
get_swc_comments(
parser.comments,
Expand Down Expand Up @@ -467,6 +469,7 @@ impl RstestParserPlugin {
call_expr.span.into(),
None,
Some(attrs),
ImportPhase::Evaluation,
parser.in_try,
get_swc_comments(
parser.comments,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,33 @@ var rspackQueues = hasSymbol ? Symbol("rspack queues") : "__rspack_queues";
var rspackExports = <%- ASYNC_MODULE_EXPORT_SYMBOL %> = hasSymbol ? Symbol("rspack exports") : "<%- EXPORTS %>";
var rspackError = hasSymbol ? Symbol("rspack error") : "__rspack_error";
var rspackDone = hasSymbol ? Symbol("rspack done") : "__rspack_done";
var rspackDefer = <%- MAKE_DEFERRED_NAMESPACE_OBJECT_SYMBOL %> = hasSymbol ? Symbol("rspack defer") : "__rspack_defer";
var rspackDefer = <%- DEFERRED_MODULES_ASYNC_TRANSITIVE_DEPENDENCIES_SYMBOL %> = hasSymbol ? Symbol("rspack defer") : "__rspack_defer";
<%- DEFERRED_MODULES_ASYNC_TRANSITIVE_DEPENDENCIES %> = <%- basicFunction("asyncDeps") %> {
var hasUnresolvedAsyncSubgraph = asyncDeps.some((id) => {
var cache = <%- _module_cache %>[id];
return !cache || cache[rspackDone] === false;
});
if (hasUnresolvedAsyncSubgraph) {
return ({ then(onFulfilled, onRejected) { return Promise.all(asyncDeps.map(<%- REQUIRE %>)).then(onFulfilled, onRejected) } });
}
}
var resolveQueue = <%- basicFunction("queue") %> {
if (queue && queue.d < 1) {
queue.d = 1;
queue.forEach(<%- expressionFunction("fn.r--", "fn") %>);
if (queue && queue.d < 1) {
queue.d = 1;
queue.forEach(<%- expressionFunction("fn.r--", "fn") %>);
queue.forEach(<%- expressionFunction("fn.r-- ? fn.r++ : fn()", "fn") %>);
}
}
var wrapDeps = <%- basicFunction("deps") %> {
return deps.map(<%- basicFunction("dep") %> {
if (dep !== null && typeof dep === "object") {
if(!dep[rspackQueues] && dep[rspackDefer]) {
var asyncDeps = dep[rspackDefer];
var hasUnresolvedAsyncSubgraph = asyncDeps.some(<%- basicFunction("id") %> {
var cache = <%- _module_cache %>[id];
return !cache || cache[rspackDone] === false;
});
if (hasUnresolvedAsyncSubgraph) {
var asyncDeps = <%- DEFERRED_MODULES_ASYNC_TRANSITIVE_DEPENDENCIES %>(dep[rspackDefer]);
if (asyncDeps) {
var d = dep;
dep = {
then(callback) {
Promise.all(asyncDeps.map(<%- REQUIRE %>)).then(<%- returningFunction("callback(d)", "") %>)
then(onFulfilled, onRejected) {
asyncDeps.then(<%- returningFunction("onFulfilled(d)", "") %>, onRejected);
}
};
} else return dep;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
}
};
<% if (_has_async) { %>
if(isAsync) obj[<%- MAKE_DEFERRED_NAMESPACE_OBJECT_SYMBOL %>] = asyncDeps;
if(isAsync) obj[<%- DEFERRED_MODULES_ASYNC_TRANSITIVE_DEPENDENCIES_SYMBOL %>] = asyncDeps;
<% } %>
return obj;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export {};

__configCases__defer_import_async_in_graph_dynamic_import.push("START async-mod-dep.js");
__configCases__defer_import_async_in_graph_dynamic_import.push("END async-mod-dep.js");
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import "./async-mod-dep.js";

__configCases__defer_import_async_in_graph_dynamic_import.push("START async-mod.js");

await 0;
export let x = 2;

__configCases__defer_import_async_in_graph_dynamic_import.push("END async-mod.js");
Loading
Loading