1use std::{borrow::Cow, collections::BTreeMap, ops::ControlFlow};
2
3use anyhow::{Result, bail};
4use rustc_hash::FxHashSet;
5use serde::{Deserialize, Serialize};
6use swc_core::{
7 common::{DUMMY_SP, SyntaxContext},
8 ecma::ast::{
9 AssignTarget, Expr, ExprStmt, Ident, KeyValueProp, ObjectLit, Prop, PropName, PropOrSpread,
10 SimpleAssignTarget, Stmt, Str,
11 },
12 quote, quote_expr,
13};
14use turbo_rcstr::{RcStr, rcstr};
15use turbo_tasks::{
16 FxIndexMap, NonLocalValue, ResolvedVc, TryFlatJoinIterExt, ValueToString, Vc,
17 trace::TraceRawVcs,
18};
19use turbo_tasks_fs::glob::Glob;
20use turbopack_core::{
21 chunk::{ChunkingContext, ModuleChunkItemIdExt},
22 ident::AssetIdent,
23 issue::{IssueExt, IssueSeverity, StyledString, analyze::AnalyzeIssue},
24 module::Module,
25 module_graph::export_usage::ModuleExportUsageInfo,
26 reference::ModuleReference,
27 resolve::ModulePart,
28};
29
30use super::base::ReferencedAsset;
31use crate::{
32 EcmascriptModuleAsset, ScopeHoistingContext,
33 analyzer::graph::EvalContext,
34 chunk::{EcmascriptChunkPlaceable, EcmascriptExports},
35 code_gen::{CodeGeneration, CodeGenerationHoistedStmt},
36 magic_identifier,
37 runtime_functions::{TURBOPACK_DYNAMIC, TURBOPACK_ESM},
38 tree_shake::asset::EcmascriptModulePartAsset,
39 utils::module_id_to_lit,
40};
41
42#[derive(Clone, Hash, Debug, PartialEq, Eq, Serialize, Deserialize, TraceRawVcs, NonLocalValue)]
43pub enum EsmExport {
44 LocalBinding(RcStr, bool),
48 ImportedBinding(ResolvedVc<Box<dyn ModuleReference>>, RcStr, bool),
52 ImportedNamespace(ResolvedVc<Box<dyn ModuleReference>>),
54 Error,
56}
57
58#[turbo_tasks::function]
59pub async fn is_export_missing(
60 module: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>,
61 export_name: RcStr,
62) -> Result<Vc<bool>> {
63 if export_name == "__turbopack_module_id__" {
64 return Ok(Vc::cell(false));
65 }
66
67 let exports = module.get_exports().await?;
68 let exports = match &*exports {
69 EcmascriptExports::None => return Ok(Vc::cell(true)),
70 EcmascriptExports::Unknown => return Ok(Vc::cell(false)),
71 EcmascriptExports::Value => return Ok(Vc::cell(false)),
72 EcmascriptExports::CommonJs => return Ok(Vc::cell(false)),
73 EcmascriptExports::EmptyCommonJs => return Ok(Vc::cell(export_name != "default")),
74 EcmascriptExports::DynamicNamespace => return Ok(Vc::cell(false)),
75 EcmascriptExports::EsmExports(exports) => *exports,
76 };
77
78 let exports = exports.await?;
79 if exports.exports.contains_key(&export_name) {
80 return Ok(Vc::cell(false));
81 }
82 if export_name == "default" {
83 return Ok(Vc::cell(true));
84 }
85
86 if exports.star_exports.is_empty() {
87 return Ok(Vc::cell(true));
88 }
89
90 let all_export_names = get_all_export_names(*module).await?;
91 if all_export_names.esm_exports.contains_key(&export_name) {
92 return Ok(Vc::cell(false));
93 }
94
95 for &dynamic_module in &all_export_names.dynamic_exporting_modules {
96 let exports = dynamic_module.get_exports().await?;
97 match &*exports {
98 EcmascriptExports::Value
99 | EcmascriptExports::CommonJs
100 | EcmascriptExports::DynamicNamespace
101 | EcmascriptExports::Unknown => {
102 return Ok(Vc::cell(false));
103 }
104 EcmascriptExports::None
105 | EcmascriptExports::EmptyCommonJs
106 | EcmascriptExports::EsmExports(_) => {}
107 }
108 }
109
110 Ok(Vc::cell(true))
111}
112
113#[turbo_tasks::function]
114pub async fn all_known_export_names(
115 module: Vc<Box<dyn EcmascriptChunkPlaceable>>,
116) -> Result<Vc<Vec<RcStr>>> {
117 let export_names = get_all_export_names(module).await?;
118 Ok(Vc::cell(export_names.esm_exports.keys().cloned().collect()))
119}
120
121#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, TraceRawVcs, NonLocalValue)]
122pub enum FoundExportType {
123 Found,
124 Dynamic,
125 NotFound,
126 SideEffects,
127 Unknown,
128}
129
130#[turbo_tasks::value]
131pub struct FollowExportsResult {
132 pub module: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>,
133 pub export_name: Option<RcStr>,
134 pub ty: FoundExportType,
135}
136
137#[turbo_tasks::function]
138pub async fn follow_reexports(
139 module: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>,
140 export_name: RcStr,
141 side_effect_free_packages: Vc<Glob>,
142 ignore_side_effect_of_entry: bool,
143) -> Result<Vc<FollowExportsResult>> {
144 if !ignore_side_effect_of_entry
145 && !*module
146 .is_marked_as_side_effect_free(side_effect_free_packages)
147 .await?
148 {
149 return Ok(FollowExportsResult::cell(FollowExportsResult {
150 module,
151 export_name: Some(export_name),
152 ty: FoundExportType::SideEffects,
153 }));
154 }
155 let mut module = module;
156 let mut export_name = export_name;
157 loop {
158 let exports = module.get_exports().await?;
159 let EcmascriptExports::EsmExports(exports) = &*exports else {
160 return Ok(FollowExportsResult::cell(FollowExportsResult {
161 module,
162 export_name: Some(export_name),
163 ty: FoundExportType::Dynamic,
164 }));
165 };
166
167 let exports_ref = exports.await?;
169 if let Some(export) = exports_ref.exports.get(&export_name) {
170 match handle_declared_export(module, export_name, export, side_effect_free_packages)
171 .await?
172 {
173 ControlFlow::Continue((m, n)) => {
174 module = m.to_resolved().await?;
175 export_name = n;
176 continue;
177 }
178 ControlFlow::Break(result) => {
179 return Ok(result.cell());
180 }
181 }
182 }
183
184 if !exports_ref.star_exports.is_empty() && &*export_name != "default" {
186 let result = find_export_from_reexports(*module, export_name.clone()).await?;
187 if let Some(m) = result.esm_export {
188 module = m;
189 continue;
190 }
191 return match &result.dynamic_exporting_modules[..] {
192 [] => Ok(FollowExportsResult {
193 module,
194 export_name: Some(export_name),
195 ty: FoundExportType::NotFound,
196 }
197 .cell()),
198 [module] => Ok(FollowExportsResult {
199 module: *module,
200 export_name: Some(export_name),
201 ty: FoundExportType::Dynamic,
202 }
203 .cell()),
204 _ => Ok(FollowExportsResult {
205 module,
206 export_name: Some(export_name),
207 ty: FoundExportType::Dynamic,
208 }
209 .cell()),
210 };
211 }
212
213 return Ok(FollowExportsResult::cell(FollowExportsResult {
214 module,
215 export_name: Some(export_name),
216 ty: FoundExportType::NotFound,
217 }));
218 }
219}
220
221async fn handle_declared_export(
222 module: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>,
223 export_name: RcStr,
224 export: &EsmExport,
225 side_effect_free_packages: Vc<Glob>,
226) -> Result<ControlFlow<FollowExportsResult, (Vc<Box<dyn EcmascriptChunkPlaceable>>, RcStr)>> {
227 match export {
228 EsmExport::ImportedBinding(reference, name, _) => {
229 if let ReferencedAsset::Some(module) =
230 *ReferencedAsset::from_resolve_result(reference.resolve_reference()).await?
231 {
232 if !*module
233 .is_marked_as_side_effect_free(side_effect_free_packages)
234 .await?
235 {
236 return Ok(ControlFlow::Break(FollowExportsResult {
237 module,
238 export_name: Some(name.clone()),
239 ty: FoundExportType::SideEffects,
240 }));
241 }
242 return Ok(ControlFlow::Continue((*module, name.clone())));
243 }
244 }
245 EsmExport::ImportedNamespace(reference) => {
246 if let ReferencedAsset::Some(module) =
247 *ReferencedAsset::from_resolve_result(reference.resolve_reference()).await?
248 {
249 return Ok(ControlFlow::Break(FollowExportsResult {
250 module,
251 export_name: None,
252 ty: FoundExportType::Found,
253 }));
254 }
255 }
256 EsmExport::LocalBinding(..) => {
257 return Ok(ControlFlow::Break(FollowExportsResult {
258 module,
259 export_name: Some(export_name),
260 ty: FoundExportType::Found,
261 }));
262 }
263 EsmExport::Error => {
264 return Ok(ControlFlow::Break(FollowExportsResult {
265 module,
266 export_name: Some(export_name),
267 ty: FoundExportType::Unknown,
268 }));
269 }
270 }
271 Ok(ControlFlow::Break(FollowExportsResult {
272 module,
273 export_name: Some(export_name),
274 ty: FoundExportType::Unknown,
275 }))
276}
277
278#[turbo_tasks::value]
279struct FindExportFromReexportsResult {
280 esm_export: Option<ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>>,
281 dynamic_exporting_modules: Vec<ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>>,
282}
283
284#[turbo_tasks::function]
285async fn find_export_from_reexports(
286 module: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>,
287 export_name: RcStr,
288) -> Result<Vc<FindExportFromReexportsResult>> {
289 if let Some(module) =
290 Vc::try_resolve_downcast_type::<EcmascriptModulePartAsset>(*module).await?
291 && matches!(module.await?.part, ModulePart::Exports)
292 {
293 let module_part = EcmascriptModulePartAsset::select_part(
294 *module.await?.full_module,
295 ModulePart::export(export_name.clone()),
296 );
297
298 if (Vc::try_resolve_downcast_type::<EcmascriptModuleAsset>(module_part).await?).is_none() {
301 return Ok(find_export_from_reexports(
302 Vc::upcast(module_part),
303 export_name,
304 ));
305 }
306 }
307
308 let all_export_names = get_all_export_names(*module).await?;
309 let esm_export = all_export_names.esm_exports.get(&export_name).copied();
310 Ok(FindExportFromReexportsResult {
311 esm_export,
312 dynamic_exporting_modules: all_export_names.dynamic_exporting_modules.clone(),
313 }
314 .cell())
315}
316
317#[turbo_tasks::value]
318struct AllExportNamesResult {
319 esm_exports: FxIndexMap<RcStr, ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>>,
320 dynamic_exporting_modules: Vec<ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>>,
321}
322
323#[turbo_tasks::function]
324async fn get_all_export_names(
325 module: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>,
326) -> Result<Vc<AllExportNamesResult>> {
327 let exports = module.get_exports().await?;
328 let EcmascriptExports::EsmExports(exports) = &*exports else {
329 return Ok(AllExportNamesResult {
330 esm_exports: FxIndexMap::default(),
331 dynamic_exporting_modules: vec![module],
332 }
333 .cell());
334 };
335
336 let exports = exports.await?;
337 let mut esm_exports = FxIndexMap::default();
338 let mut dynamic_exporting_modules = Vec::new();
339 esm_exports.extend(exports.exports.keys().cloned().map(|n| (n, module)));
340 let star_export_names = exports
341 .star_exports
342 .iter()
343 .map(|esm_ref| async {
344 Ok(
345 if let ReferencedAsset::Some(m) =
346 *ReferencedAsset::from_resolve_result(esm_ref.resolve_reference()).await?
347 {
348 Some(expand_star_exports(*m))
349 } else {
350 None
351 },
352 )
353 })
354 .try_flat_join()
355 .await?;
356 for star_export_names in star_export_names {
357 let star_export_names = star_export_names.await?;
358 esm_exports.extend(
359 star_export_names
360 .esm_exports
361 .iter()
362 .map(|(k, &v)| (k.clone(), v)),
363 );
364 dynamic_exporting_modules
365 .extend(star_export_names.dynamic_exporting_modules.iter().copied());
366 }
367
368 Ok(AllExportNamesResult {
369 esm_exports,
370 dynamic_exporting_modules,
371 }
372 .cell())
373}
374
375#[turbo_tasks::value]
376pub struct ExpandStarResult {
377 pub esm_exports: FxIndexMap<RcStr, ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>>,
378 pub dynamic_exporting_modules: Vec<ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>>,
379}
380
381#[turbo_tasks::function]
382pub async fn expand_star_exports(
383 root_module: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>,
384) -> Result<Vc<ExpandStarResult>> {
385 let mut esm_exports = FxIndexMap::default();
386 let mut dynamic_exporting_modules = Vec::new();
387 let mut checked_modules = FxHashSet::default();
388 checked_modules.insert(root_module);
389 let mut queue = vec![(root_module, root_module.get_exports())];
390 while let Some((asset, exports)) = queue.pop() {
391 match &*exports.await? {
392 EcmascriptExports::EsmExports(exports) => {
393 let exports = exports.await?;
394 for key in exports.exports.keys() {
395 if key == "default" {
396 continue;
397 }
398 esm_exports.entry(key.clone()).or_insert_with(|| asset);
399 }
400 for esm_ref in exports.star_exports.iter() {
401 if let ReferencedAsset::Some(asset) =
402 &*ReferencedAsset::from_resolve_result(esm_ref.resolve_reference()).await?
403 && checked_modules.insert(*asset)
404 {
405 queue.push((*asset, asset.get_exports()));
406 }
407 }
408 }
409 EcmascriptExports::None | EcmascriptExports::EmptyCommonJs => {
410 emit_star_exports_issue(
411 asset.ident(),
412 format!(
413 "export * used with module {} which has no exports\nTypescript only: Did \
414 you want to export only types with `export type * from \"...\"`?\nNote: \
415 Using `export type` is more efficient than `export *` as it won't emit \
416 any runtime code.",
417 asset.ident().to_string().await?
418 )
419 .into(),
420 )
421 .await?
422 }
423 EcmascriptExports::Value => {
424 emit_star_exports_issue(
425 asset.ident(),
426 format!(
427 "export * used with module {} which only has a default export (default \
428 export is not exported with export *)\nDid you want to use `export {{ \
429 default }} from \"...\";` instead?",
430 asset.ident().to_string().await?
431 )
432 .into(),
433 )
434 .await?
435 }
436 EcmascriptExports::CommonJs => {
437 dynamic_exporting_modules.push(asset);
438 emit_star_exports_issue(
439 asset.ident(),
440 format!(
441 "export * used with module {} which is a CommonJS module with exports \
442 only available at runtime\nList all export names manually (`export {{ a, \
443 b, c }} from \"...\") or rewrite the module to ESM, to avoid the \
444 additional runtime code.`",
445 asset.ident().to_string().await?
446 )
447 .into(),
448 )
449 .await?;
450 }
451 EcmascriptExports::DynamicNamespace => {
452 dynamic_exporting_modules.push(asset);
453 }
454 EcmascriptExports::Unknown => {
455 dynamic_exporting_modules.push(asset);
457 }
458 }
459 }
460
461 Ok(ExpandStarResult {
462 esm_exports,
463 dynamic_exporting_modules,
464 }
465 .cell())
466}
467
468async fn emit_star_exports_issue(source_ident: Vc<AssetIdent>, message: RcStr) -> Result<()> {
469 AnalyzeIssue::new(
470 IssueSeverity::Warning,
471 source_ident,
472 Vc::cell(rcstr!("unexpected export *")),
473 StyledString::Text(message).cell(),
474 None,
475 None,
476 )
477 .to_resolved()
478 .await?
479 .emit();
480 Ok(())
481}
482
483#[turbo_tasks::value(shared)]
484#[derive(Hash, Debug)]
485pub struct EsmExports {
486 pub exports: BTreeMap<RcStr, EsmExport>,
487 pub star_exports: Vec<ResolvedVc<Box<dyn ModuleReference>>>,
488}
489
490#[turbo_tasks::value(shared)]
495#[derive(Hash, Debug)]
496pub struct ExpandedExports {
497 pub exports: BTreeMap<RcStr, EsmExport>,
498 pub dynamic_exports: Vec<ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>>,
500}
501
502#[turbo_tasks::value_impl]
503impl EsmExports {
504 #[turbo_tasks::function]
505 pub async fn expand_exports(
506 &self,
507 export_usage_info: Vc<ModuleExportUsageInfo>,
508 ) -> Result<Vc<ExpandedExports>> {
509 let mut exports: BTreeMap<RcStr, EsmExport> = self.exports.clone();
510 let mut dynamic_exports = vec![];
511 let export_usage_info = export_usage_info.await?;
512
513 if !matches!(*export_usage_info, ModuleExportUsageInfo::All) {
514 exports.retain(|export, _| export_usage_info.is_export_used(export));
515 }
516
517 for &esm_ref in self.star_exports.iter() {
518 let ReferencedAsset::Some(asset) =
521 &*ReferencedAsset::from_resolve_result(esm_ref.resolve_reference()).await?
522 else {
523 continue;
524 };
525
526 let export_info = expand_star_exports(**asset).await?;
527
528 for export in export_info.esm_exports.keys() {
529 if export == "default" {
530 continue;
531 }
532 if !export_usage_info.is_export_used(export) {
533 continue;
534 }
535
536 if !exports.contains_key(export) {
537 exports.insert(
538 export.clone(),
539 EsmExport::ImportedBinding(
540 ResolvedVc::upcast(esm_ref),
541 export.clone(),
542 false,
543 ),
544 );
545 }
546 }
547
548 if !export_info.dynamic_exporting_modules.is_empty() {
549 dynamic_exports.push(*asset);
550 }
551 }
552
553 Ok(ExpandedExports {
554 exports,
555 dynamic_exports,
556 }
557 .cell())
558 }
559}
560
561impl EsmExports {
562 pub async fn code_generation(
563 self: Vc<Self>,
564 chunking_context: Vc<Box<dyn ChunkingContext>>,
565 scope_hoisting_context: ScopeHoistingContext<'_>,
566 eval_context: &EvalContext,
567 module: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>,
568 ) -> Result<CodeGeneration> {
569 let export_usage_info = chunking_context.module_export_usage(*ResolvedVc::upcast(module));
570 let expanded = self.expand_exports(export_usage_info).await?;
571
572 if scope_hoisting_context.skip_module_exports() && expanded.dynamic_exports.is_empty() {
573 return Ok(CodeGeneration::empty());
579 }
580
581 let mut dynamic_exports = Vec::<Box<Expr>>::new();
582 {
583 let id = if let Some(module) = scope_hoisting_context.module()
584 && !expanded.dynamic_exports.is_empty()
585 {
586 Some(module.chunk_item_id(Vc::upcast(chunking_context)).await?)
587 } else {
588 None
589 };
590
591 for dynamic_export_asset in &expanded.dynamic_exports {
592 let ident = ReferencedAsset::get_ident_from_placeable(
593 dynamic_export_asset,
594 chunking_context,
595 )
596 .await?;
597
598 if let Some(id) = &id {
599 dynamic_exports.push(quote_expr!(
600 "$turbopack_dynamic($arg, $id)",
601 turbopack_dynamic: Expr = TURBOPACK_DYNAMIC.into(),
602 arg: Expr = Ident::new(ident.into(), DUMMY_SP, Default::default()).into(),
603 id: Expr = module_id_to_lit(id)
604 ));
605 } else {
606 dynamic_exports.push(quote_expr!(
607 "$turbopack_dynamic($arg)",
608 turbopack_dynamic: Expr = TURBOPACK_DYNAMIC.into(),
609 arg: Expr = Ident::new(ident.into(), DUMMY_SP, Default::default()).into()
610 ));
611 }
612 }
613 }
614
615 let mut getters = Vec::new();
616 for (exported, local) in &expanded.exports {
617 let expr = match local {
618 EsmExport::Error => Some(quote!(
619 "(() => { throw new Error(\"Failed binding. See build errors!\"); })" as Expr,
620 )),
621 EsmExport::LocalBinding(name, mutable) => {
622 let binding =
626 if let Some((local, ctxt)) = eval_context.imports.exports.get(exported) {
627 Some((Cow::Borrowed(local.as_str()), *ctxt))
628 } else {
629 bail!(
630 "Expected export to be in eval context {:?} {:?}",
631 exported,
632 eval_context.imports,
633 )
634 };
635 let (local, ctxt) = binding.unwrap_or_else(|| {
636 (
638 if name == "default" {
639 Cow::Owned(magic_identifier::mangle("default export"))
640 } else {
641 Cow::Borrowed(name.as_str())
642 },
643 SyntaxContext::empty(),
644 )
645 });
646
647 if *mutable {
648 Some(quote!(
649 "([() => $local, ($new) => $local = $new])" as Expr,
650 local = Ident::new(local.into(), DUMMY_SP, ctxt),
651 new = Ident::new(format!("new_{name}").into(), DUMMY_SP, ctxt),
652 ))
653 } else {
654 Some(quote!(
655 "(() => $local)" as Expr,
656 local = Ident::new((name as &str).into(), DUMMY_SP, ctxt)
657 ))
658 }
659 }
660 EsmExport::ImportedBinding(esm_ref, name, mutable) => {
661 let referenced_asset =
662 ReferencedAsset::from_resolve_result(esm_ref.resolve_reference()).await?;
663 referenced_asset
664 .get_ident(chunking_context, Some(name.clone()), scope_hoisting_context)
665 .await?
666 .map(|ident| {
667 let expr = ident.as_expr_individual(DUMMY_SP);
668 if *mutable {
669 quote!(
670 "([() => $expr, ($new) => $lhs = $new])" as Expr,
671 expr: Expr = expr.clone().map_either(Expr::from, Expr::from).into_inner(),
672 lhs: AssignTarget = AssignTarget::Simple(
673 expr.map_either(|i| SimpleAssignTarget::Ident(i.into()), SimpleAssignTarget::Member).into_inner()),
674 new = Ident::new(
675 format!("new_{name}").into(),
676 DUMMY_SP,
677 Default::default()
678 ),
679 )
680 } else {
681 quote!(
682 "(() => $expr)" as Expr,
683 expr: Expr = expr.map_either(Expr::from, Expr::from).into_inner()
684 )
685 }
686 })
687 }
688 EsmExport::ImportedNamespace(esm_ref) => {
689 let referenced_asset =
690 ReferencedAsset::from_resolve_result(esm_ref.resolve_reference()).await?;
691 referenced_asset
692 .get_ident(chunking_context, None, scope_hoisting_context)
693 .await?
694 .map(|ident| {
695 quote!(
696 "(() => $imported)" as Expr,
697 imported: Expr = ident.as_expr(DUMMY_SP, false)
698 )
699 })
700 }
701 };
702 if let Some(expr) = expr {
703 getters.push(PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
704 key: PropName::Str(Str {
705 span: DUMMY_SP,
706 value: exported.as_str().into(),
707 raw: None,
708 }),
709 value: Box::new(expr),
710 }))));
711 }
712 }
713 let getters = Expr::Object(ObjectLit {
714 span: DUMMY_SP,
715 props: getters,
716 });
717 let dynamic_stmt = if !dynamic_exports.is_empty() {
718 Some(Stmt::Expr(ExprStmt {
719 span: DUMMY_SP,
720 expr: Expr::from_exprs(dynamic_exports),
721 }))
722 } else {
723 None
724 };
725
726 let early_hoisted_stmts = vec![CodeGenerationHoistedStmt::new(
727 rcstr!("__turbopack_esm__"),
728 if let Some(module) = scope_hoisting_context.module() {
729 let id = module.chunk_item_id(Vc::upcast(chunking_context)).await?;
730 quote!("$turbopack_esm($getters, $id);" as Stmt,
731 turbopack_esm: Expr = TURBOPACK_ESM.into(),
732 getters: Expr = getters,
733 id: Expr = module_id_to_lit(&id)
734 )
735 } else {
736 quote!("$turbopack_esm($getters);" as Stmt,
737 turbopack_esm: Expr = TURBOPACK_ESM.into(),
738 getters: Expr = getters
739 )
740 },
741 )];
742
743 Ok(CodeGeneration::new(
744 vec![],
745 [dynamic_stmt
746 .map(|stmt| CodeGenerationHoistedStmt::new(rcstr!("__turbopack_dynamic__"), stmt))]
747 .into_iter()
748 .flatten()
749 .collect(),
750 early_hoisted_stmts,
751 ))
752 }
753}