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, FxIndexSet, 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(get_all_export_names(*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 star_exports: Vec<RcStr>,
378 pub has_dynamic_exports: bool,
379}
380
381#[turbo_tasks::function]
382pub async fn expand_star_exports(
383 root_module: Vc<Box<dyn EcmascriptChunkPlaceable>>,
384) -> Result<Vc<ExpandStarResult>> {
385 let mut set = FxIndexSet::default();
386 let mut has_dynamic_exports = false;
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 set.extend(exports.exports.keys().filter(|n| *n != "default").cloned());
395 for esm_ref in exports.star_exports.iter() {
396 if let ReferencedAsset::Some(asset) =
397 &*ReferencedAsset::from_resolve_result(esm_ref.resolve_reference()).await?
398 && checked_modules.insert(**asset)
399 {
400 queue.push((**asset, asset.get_exports()));
401 }
402 }
403 }
404 EcmascriptExports::None | EcmascriptExports::EmptyCommonJs => {
405 emit_star_exports_issue(
406 asset.ident(),
407 format!(
408 "export * used with module {} which has no exports\nTypescript only: Did \
409 you want to export only types with `export type * from \"...\"`?\nNote: \
410 Using `export type` is more efficient than `export *` as it won't emit \
411 any runtime code.",
412 asset.ident().to_string().await?
413 )
414 .into(),
415 )
416 .await?
417 }
418 EcmascriptExports::Value => {
419 emit_star_exports_issue(
420 asset.ident(),
421 format!(
422 "export * used with module {} which only has a default export (default \
423 export is not exported with export *)\nDid you want to use `export {{ \
424 default }} from \"...\";` instead?",
425 asset.ident().to_string().await?
426 )
427 .into(),
428 )
429 .await?
430 }
431 EcmascriptExports::CommonJs => {
432 has_dynamic_exports = true;
433 emit_star_exports_issue(
434 asset.ident(),
435 format!(
436 "export * used with module {} which is a CommonJS module with exports \
437 only available at runtime\nList all export names manually (`export {{ a, \
438 b, c }} from \"...\") or rewrite the module to ESM, to avoid the \
439 additional runtime code.`",
440 asset.ident().to_string().await?
441 )
442 .into(),
443 )
444 .await?;
445 }
446 EcmascriptExports::DynamicNamespace => {
447 has_dynamic_exports = true;
448 }
449 EcmascriptExports::Unknown => {
450 has_dynamic_exports = true;
452 }
453 }
454 }
455
456 Ok(ExpandStarResult {
457 star_exports: set.into_iter().collect(),
458 has_dynamic_exports,
459 }
460 .cell())
461}
462
463async fn emit_star_exports_issue(source_ident: Vc<AssetIdent>, message: RcStr) -> Result<()> {
464 AnalyzeIssue::new(
465 IssueSeverity::Warning,
466 source_ident,
467 Vc::cell(rcstr!("unexpected export *")),
468 StyledString::Text(message).cell(),
469 None,
470 None,
471 )
472 .to_resolved()
473 .await?
474 .emit();
475 Ok(())
476}
477
478#[turbo_tasks::value(shared)]
479#[derive(Hash, Debug)]
480pub struct EsmExports {
481 pub exports: BTreeMap<RcStr, EsmExport>,
482 pub star_exports: Vec<ResolvedVc<Box<dyn ModuleReference>>>,
483}
484
485#[turbo_tasks::value(shared)]
490#[derive(Hash, Debug)]
491pub struct ExpandedExports {
492 pub exports: BTreeMap<RcStr, EsmExport>,
493 pub dynamic_exports: Vec<ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>>,
495}
496
497#[turbo_tasks::value_impl]
498impl EsmExports {
499 #[turbo_tasks::function]
500 pub async fn expand_exports(
501 &self,
502 export_usage_info: Vc<ModuleExportUsageInfo>,
503 ) -> Result<Vc<ExpandedExports>> {
504 let mut exports: BTreeMap<RcStr, EsmExport> = self.exports.clone();
505 let mut dynamic_exports = vec![];
506 let export_usage_info = export_usage_info.await?;
507
508 if !matches!(*export_usage_info, ModuleExportUsageInfo::All) {
509 exports.retain(|export, _| export_usage_info.is_export_used(export));
510 }
511
512 for &esm_ref in self.star_exports.iter() {
513 let ReferencedAsset::Some(asset) =
516 &*ReferencedAsset::from_resolve_result(esm_ref.resolve_reference()).await?
517 else {
518 continue;
519 };
520
521 let export_info = expand_star_exports(**asset).await?;
522
523 for export in &export_info.star_exports {
524 if !export_usage_info.is_export_used(export) {
525 continue;
526 }
527
528 if !exports.contains_key(export) {
529 exports.insert(
530 export.clone(),
531 EsmExport::ImportedBinding(
532 ResolvedVc::upcast(esm_ref),
533 export.clone(),
534 false,
535 ),
536 );
537 }
538 }
539
540 if export_info.has_dynamic_exports {
541 dynamic_exports.push(*asset);
542 }
543 }
544
545 Ok(ExpandedExports {
546 exports,
547 dynamic_exports,
548 }
549 .cell())
550 }
551}
552
553impl EsmExports {
554 pub async fn code_generation(
555 self: Vc<Self>,
556 chunking_context: Vc<Box<dyn ChunkingContext>>,
557 scope_hoisting_context: ScopeHoistingContext<'_>,
558 eval_context: &EvalContext,
559 module: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>,
560 ) -> Result<CodeGeneration> {
561 let export_usage_info = chunking_context.module_export_usage(*ResolvedVc::upcast(module));
562 let expanded = self.expand_exports(export_usage_info).await?;
563
564 if scope_hoisting_context.skip_module_exports() && expanded.dynamic_exports.is_empty() {
565 return Ok(CodeGeneration::empty());
571 }
572
573 let mut dynamic_exports = Vec::<Box<Expr>>::new();
574 {
575 let id = if let Some(module) = scope_hoisting_context.module()
576 && !expanded.dynamic_exports.is_empty()
577 {
578 Some(module.chunk_item_id(Vc::upcast(chunking_context)).await?)
579 } else {
580 None
581 };
582
583 for dynamic_export_asset in &expanded.dynamic_exports {
584 let ident = ReferencedAsset::get_ident_from_placeable(
585 dynamic_export_asset,
586 chunking_context,
587 )
588 .await?;
589
590 if let Some(id) = &id {
591 dynamic_exports.push(quote_expr!(
592 "$turbopack_dynamic($arg, $id)",
593 turbopack_dynamic: Expr = TURBOPACK_DYNAMIC.into(),
594 arg: Expr = Ident::new(ident.into(), DUMMY_SP, Default::default()).into(),
595 id: Expr = module_id_to_lit(id)
596 ));
597 } else {
598 dynamic_exports.push(quote_expr!(
599 "$turbopack_dynamic($arg)",
600 turbopack_dynamic: Expr = TURBOPACK_DYNAMIC.into(),
601 arg: Expr = Ident::new(ident.into(), DUMMY_SP, Default::default()).into()
602 ));
603 }
604 }
605 }
606
607 let mut getters = Vec::new();
608 for (exported, local) in &expanded.exports {
609 let expr = match local {
610 EsmExport::Error => Some(quote!(
611 "(() => { throw new Error(\"Failed binding. See build errors!\"); })" as Expr,
612 )),
613 EsmExport::LocalBinding(name, mutable) => {
614 let binding =
618 if let Some((local, ctxt)) = eval_context.imports.exports.get(exported) {
619 Some((Cow::Borrowed(local.as_str()), *ctxt))
620 } else {
621 bail!(
622 "Expected export to be in eval context {:?} {:?}",
623 exported,
624 eval_context.imports,
625 )
626 };
627 let (local, ctxt) = binding.unwrap_or_else(|| {
628 (
630 if name == "default" {
631 Cow::Owned(magic_identifier::mangle("default export"))
632 } else {
633 Cow::Borrowed(name.as_str())
634 },
635 SyntaxContext::empty(),
636 )
637 });
638
639 if *mutable {
640 Some(quote!(
641 "([() => $local, ($new) => $local = $new])" as Expr,
642 local = Ident::new(local.into(), DUMMY_SP, ctxt),
643 new = Ident::new(format!("new_{name}").into(), DUMMY_SP, ctxt),
644 ))
645 } else {
646 Some(quote!(
647 "(() => $local)" as Expr,
648 local = Ident::new((name as &str).into(), DUMMY_SP, ctxt)
649 ))
650 }
651 }
652 EsmExport::ImportedBinding(esm_ref, name, mutable) => {
653 let referenced_asset =
654 ReferencedAsset::from_resolve_result(esm_ref.resolve_reference()).await?;
655 referenced_asset
656 .get_ident(chunking_context, Some(name.clone()), scope_hoisting_context)
657 .await?
658 .map(|ident| {
659 let expr = ident.as_expr_individual(DUMMY_SP);
660 if *mutable {
661 quote!(
662 "([() => $expr, ($new) => $lhs = $new])" as Expr,
663 expr: Expr = expr.clone().map_either(Expr::from, Expr::from).into_inner(),
664 lhs: AssignTarget = AssignTarget::Simple(
665 expr.map_either(|i| SimpleAssignTarget::Ident(i.into()), SimpleAssignTarget::Member).into_inner()),
666 new = Ident::new(
667 format!("new_{name}").into(),
668 DUMMY_SP,
669 Default::default()
670 ),
671 )
672 } else {
673 quote!(
674 "(() => $expr)" as Expr,
675 expr: Expr = expr.map_either(Expr::from, Expr::from).into_inner()
676 )
677 }
678 })
679 }
680 EsmExport::ImportedNamespace(esm_ref) => {
681 let referenced_asset =
682 ReferencedAsset::from_resolve_result(esm_ref.resolve_reference()).await?;
683 referenced_asset
684 .get_ident(chunking_context, None, scope_hoisting_context)
685 .await?
686 .map(|ident| {
687 quote!(
688 "(() => $imported)" as Expr,
689 imported: Expr = ident.as_expr(DUMMY_SP, false)
690 )
691 })
692 }
693 };
694 if let Some(expr) = expr {
695 getters.push(PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
696 key: PropName::Str(Str {
697 span: DUMMY_SP,
698 value: exported.as_str().into(),
699 raw: None,
700 }),
701 value: Box::new(expr),
702 }))));
703 }
704 }
705 let getters = Expr::Object(ObjectLit {
706 span: DUMMY_SP,
707 props: getters,
708 });
709 let dynamic_stmt = if !dynamic_exports.is_empty() {
710 Some(Stmt::Expr(ExprStmt {
711 span: DUMMY_SP,
712 expr: Expr::from_exprs(dynamic_exports),
713 }))
714 } else {
715 None
716 };
717
718 let early_hoisted_stmts = vec![CodeGenerationHoistedStmt::new(
719 rcstr!("__turbopack_esm__"),
720 if let Some(module) = scope_hoisting_context.module() {
721 let id = module.chunk_item_id(Vc::upcast(chunking_context)).await?;
722 quote!("$turbopack_esm($getters, $id);" as Stmt,
723 turbopack_esm: Expr = TURBOPACK_ESM.into(),
724 getters: Expr = getters,
725 id: Expr = module_id_to_lit(&id)
726 )
727 } else {
728 quote!("$turbopack_esm($getters);" as Stmt,
729 turbopack_esm: Expr = TURBOPACK_ESM.into(),
730 getters: Expr = getters
731 )
732 },
733 )];
734
735 Ok(CodeGeneration::new(
736 vec![],
737 [dynamic_stmt
738 .map(|stmt| CodeGenerationHoistedStmt::new(rcstr!("__turbopack_dynamic__"), stmt))]
739 .into_iter()
740 .flatten()
741 .collect(),
742 early_hoisted_stmts,
743 ))
744 }
745}