use rspack_cacheable::{cacheable, cacheable_dyn};
use rspack_core::{
DependencyCodeGeneration, DependencyTemplate, DependencyTemplateType, InitFragmentKey,
InitFragmentStage, ModuleGraph, NormalInitFragment, PrefetchExportsInfoMode, RuntimeGlobals,
TemplateContext, TemplateReplaceSource, UsageState,
};
use swc_core::atoms::Atom;
#[cacheable]
#[derive(Debug, Clone)]
pub struct ESMCompatibilityDependency;
#[cacheable_dyn]
impl DependencyCodeGeneration for ESMCompatibilityDependency {
fn dependency_template(&self) -> Option<DependencyTemplateType> {
Some(ESMCompatibilityDependencyTemplate::template_type())
}
}
#[cacheable]
#[derive(Debug, Default)]
pub struct ESMCompatibilityDependencyTemplate;
impl ESMCompatibilityDependencyTemplate {
pub fn template_type() -> DependencyTemplateType {
DependencyTemplateType::Custom("ESMCompatibilityDependency")
}
}
impl DependencyTemplate for ESMCompatibilityDependencyTemplate {
fn render(
&self,
_dep: &dyn DependencyCodeGeneration,
_source: &mut TemplateReplaceSource,
code_generatable_context: &mut TemplateContext,
) {
let TemplateContext {
init_fragments,
compilation,
module,
runtime,
concatenation_scope,
runtime_template,
..
} = code_generatable_context;
if concatenation_scope.is_some() {
return;
}
let module_graph = compilation.get_module_graph();
let module = module_graph
.module_by_identifier(&module.identifier())
.expect("should have mgm");
let name = Atom::from("__esModule");
let exports_info = compilation
.exports_info_artifact
.get_prefetched_exports_info(&module.identifier(), PrefetchExportsInfoMode::Default);
let used = exports_info
.get_read_only_export_info(&name)
.get_used(*runtime);
if !matches!(used, UsageState::Unused) {
init_fragments.push(Box::new(NormalInitFragment::new(
format!(
"{}({});\n",
runtime_template.render_runtime_globals(&RuntimeGlobals::MAKE_NAMESPACE_OBJECT),
runtime_template.render_exports_argument(module.get_exports_argument()),
),
InitFragmentStage::StageESMExports,
0,
InitFragmentKey::ESMCompatibility,
None,
)));
}
if ModuleGraph::is_async(&compilation.async_modules_artifact, &module.identifier()) {
init_fragments.push(Box::new(NormalInitFragment::new(
format!(
"{}({}, async function (__rspack_load_async_deps, __rspack_async_done) {{ try {{\n",
runtime_template.render_runtime_globals(&RuntimeGlobals::ASYNC_MODULE),
runtime_template.render_module_argument(
module_graph
.module_by_identifier(&module.identifier())
.expect("should have mgm")
.get_module_argument()
),
),
InitFragmentStage::StageAsyncBoundary,
0,
InitFragmentKey::unique(),
Some(format!(
"\n__rspack_async_done();\n}} catch(e) {{ __rspack_async_done(e); }} }}{});",
if module.build_meta().has_top_level_await {
", 1"
} else {
""
}
)),
)));
}
}
}