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