turbopack_ecmascript/tree_shake/
chunk_item.rs1use anyhow::Result;
2use turbo_tasks::{ResolvedVc, ValueDefault, Vc};
3use turbo_tasks_fs::rope::RopeBuilder;
4use turbopack_core::{
5 chunk::{AsyncModuleInfo, ChunkItem, ChunkType, ChunkingContext, ModuleChunkItemIdExt},
6 ident::AssetIdent,
7 module::Module,
8 module_graph::ModuleGraph,
9};
10
11use super::asset::EcmascriptModulePartAsset;
12use crate::{
13 EcmascriptAnalyzable,
14 chunk::{
15 EcmascriptChunkItem, EcmascriptChunkItemContent, EcmascriptChunkItemOptions,
16 EcmascriptChunkPlaceable, EcmascriptChunkType,
17 },
18 references::async_module::AsyncModuleOptions,
19 runtime_functions::{TURBOPACK_EXPORT_NAMESPACE, TURBOPACK_IMPORT},
20 tree_shake::side_effect_module::SideEffectsModule,
21 utils::StringifyModuleId,
22};
23
24#[turbo_tasks::value(shared)]
29pub struct EcmascriptModulePartChunkItem {
30 pub(super) module: ResolvedVc<EcmascriptModulePartAsset>,
31 pub(super) chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
32}
33
34#[turbo_tasks::value_impl]
35impl EcmascriptChunkItem for EcmascriptModulePartChunkItem {
36 #[turbo_tasks::function]
37 fn content(self: Vc<Self>) -> Vc<EcmascriptChunkItemContent> {
38 panic!("content() should never be called");
39 }
40
41 #[turbo_tasks::function]
42 async fn content_with_async_module_info(
43 &self,
44 async_module_info: Option<Vc<AsyncModuleInfo>>,
45 ) -> Result<Vc<EcmascriptChunkItemContent>> {
46 let analyze = self.module.analyze();
47 let analyze_ref = analyze.await?;
48 let async_module_options = analyze_ref.async_module.module_options(async_module_info);
49
50 let content = self
51 .module
52 .module_content(*self.chunking_context, async_module_info);
53
54 Ok(EcmascriptChunkItemContent::new(
55 content,
56 *self.chunking_context,
57 *self.module.await?.full_module.await?.options,
58 async_module_options,
59 ))
60 }
61}
62
63#[turbo_tasks::value_impl]
64impl ChunkItem for EcmascriptModulePartChunkItem {
65 #[turbo_tasks::function]
66 fn asset_ident(&self) -> Vc<AssetIdent> {
67 self.module.ident()
68 }
69
70 #[turbo_tasks::function]
71 fn chunking_context(&self) -> Vc<Box<dyn ChunkingContext>> {
72 *ResolvedVc::upcast(self.chunking_context)
73 }
74
75 #[turbo_tasks::function]
76 async fn ty(&self) -> Result<Vc<Box<dyn ChunkType>>> {
77 Ok(Vc::upcast(
78 Vc::<EcmascriptChunkType>::default().resolve().await?,
79 ))
80 }
81
82 #[turbo_tasks::function]
83 fn module(&self) -> Vc<Box<dyn Module>> {
84 *ResolvedVc::upcast(self.module)
85 }
86}
87
88#[turbo_tasks::value(shared)]
89pub(super) struct SideEffectsModuleChunkItem {
90 pub module: ResolvedVc<SideEffectsModule>,
91 pub module_graph: ResolvedVc<ModuleGraph>,
92 pub chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
93}
94
95#[turbo_tasks::value_impl]
96impl ChunkItem for SideEffectsModuleChunkItem {
97 #[turbo_tasks::function]
98 fn asset_ident(&self) -> Vc<AssetIdent> {
99 self.module.ident()
100 }
101
102 #[turbo_tasks::function]
103 fn ty(&self) -> Vc<Box<dyn ChunkType>> {
104 Vc::upcast(EcmascriptChunkType::value_default())
105 }
106
107 #[turbo_tasks::function]
108 fn module(&self) -> Vc<Box<dyn Module>> {
109 *ResolvedVc::upcast(self.module)
110 }
111
112 #[turbo_tasks::function]
113 fn chunking_context(&self) -> Vc<Box<dyn ChunkingContext>> {
114 *self.chunking_context
115 }
116}
117
118#[turbo_tasks::value_impl]
119impl EcmascriptChunkItem for SideEffectsModuleChunkItem {
120 #[turbo_tasks::function]
121 async fn content(&self) -> Result<Vc<EcmascriptChunkItemContent>> {
122 let mut code = RopeBuilder::default();
123 let mut has_top_level_await = false;
124
125 let module = self.module.await?;
126
127 for &side_effect in self.module.await?.side_effects.iter() {
128 let need_await = 'need_await: {
129 let async_module = *side_effect.get_async_module().await?;
130 if let Some(async_module) = async_module
131 && async_module.await?.has_top_level_await
132 {
133 break 'need_await true;
134 }
135 false
136 };
137
138 if !has_top_level_await && need_await {
139 has_top_level_await = true;
140 }
141
142 code.push_bytes(
143 format!(
144 "{}{TURBOPACK_IMPORT}({});\n",
145 if need_await { "await " } else { "" },
146 StringifyModuleId(&*side_effect.chunk_item_id(*self.chunking_context).await?)
147 )
148 .as_bytes(),
149 );
150 }
151
152 code.push_bytes(
153 format!(
154 "{TURBOPACK_EXPORT_NAMESPACE}({TURBOPACK_IMPORT}({}));\n",
155 StringifyModuleId(
156 &*module
157 .resolved_as
158 .chunk_item_id(*self.chunking_context)
159 .await?
160 )
161 )
162 .as_bytes(),
163 );
164
165 let code = code.build();
166
167 Ok(EcmascriptChunkItemContent {
168 inner_code: code,
169 source_map: None,
170 rewrite_source_path: None,
171 options: EcmascriptChunkItemOptions {
172 strict: true,
173 exports: true,
174 async_module: if has_top_level_await {
175 Some(AsyncModuleOptions {
176 has_top_level_await: true,
177 })
178 } else {
179 None
180 },
181 ..Default::default()
182 },
183 additional_ids: Default::default(),
184 placeholder_for_future_extensions: (),
185 }
186 .cell())
187 }
188}