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) module_graph: ResolvedVc<ModuleGraph>,
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 ) -> Result<Vc<EcmascriptChunkItemContent>> {
47 let analyze = self.module.analyze();
48 let analyze_ref = analyze.await?;
49 let async_module_options = analyze_ref.async_module.module_options(async_module_info);
50
51 let content = self.module.module_content(
52 *self.module_graph,
53 *self.chunking_context,
54 async_module_info,
55 );
56
57 Ok(EcmascriptChunkItemContent::new(
58 content,
59 *self.chunking_context,
60 *self.module.await?.full_module.await?.options,
61 async_module_options,
62 ))
63 }
64}
65
66#[turbo_tasks::value_impl]
67impl ChunkItem for EcmascriptModulePartChunkItem {
68 #[turbo_tasks::function]
69 fn asset_ident(&self) -> Vc<AssetIdent> {
70 self.module.ident()
71 }
72
73 #[turbo_tasks::function]
74 fn chunking_context(&self) -> Vc<Box<dyn ChunkingContext>> {
75 *ResolvedVc::upcast(self.chunking_context)
76 }
77
78 #[turbo_tasks::function]
79 async fn ty(&self) -> Result<Vc<Box<dyn ChunkType>>> {
80 Ok(Vc::upcast(
81 Vc::<EcmascriptChunkType>::default().resolve().await?,
82 ))
83 }
84
85 #[turbo_tasks::function]
86 fn module(&self) -> Vc<Box<dyn Module>> {
87 *ResolvedVc::upcast(self.module)
88 }
89}
90
91#[turbo_tasks::value(shared)]
92pub(super) struct SideEffectsModuleChunkItem {
93 pub module: ResolvedVc<SideEffectsModule>,
94 pub module_graph: ResolvedVc<ModuleGraph>,
95 pub chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
96}
97
98#[turbo_tasks::value_impl]
99impl ChunkItem for SideEffectsModuleChunkItem {
100 #[turbo_tasks::function]
101 fn asset_ident(&self) -> Vc<AssetIdent> {
102 self.module.ident()
103 }
104
105 #[turbo_tasks::function]
106 fn ty(&self) -> Vc<Box<dyn ChunkType>> {
107 Vc::upcast(EcmascriptChunkType::value_default())
108 }
109
110 #[turbo_tasks::function]
111 fn module(&self) -> Vc<Box<dyn Module>> {
112 *ResolvedVc::upcast(self.module)
113 }
114
115 #[turbo_tasks::function]
116 fn chunking_context(&self) -> Vc<Box<dyn ChunkingContext>> {
117 *self.chunking_context
118 }
119}
120
121#[turbo_tasks::value_impl]
122impl EcmascriptChunkItem for SideEffectsModuleChunkItem {
123 #[turbo_tasks::function]
124 async fn content(&self) -> Result<Vc<EcmascriptChunkItemContent>> {
125 let mut code = RopeBuilder::default();
126 let mut has_top_level_await = false;
127
128 let module = self.module.await?;
129
130 for &side_effect in self.module.await?.side_effects.iter() {
131 let need_await = 'need_await: {
132 let async_module = *side_effect.get_async_module().await?;
133 if let Some(async_module) = async_module {
134 if async_module.await?.has_top_level_await {
135 break 'need_await true;
136 }
137 }
138 false
139 };
140
141 if !has_top_level_await && need_await {
142 has_top_level_await = true;
143 }
144
145 code.push_bytes(
146 format!(
147 "{}{TURBOPACK_IMPORT}({});\n",
148 if need_await { "await " } else { "" },
149 StringifyModuleId(&*side_effect.chunk_item_id(*self.chunking_context).await?)
150 )
151 .as_bytes(),
152 );
153 }
154
155 code.push_bytes(
156 format!(
157 "{TURBOPACK_EXPORT_NAMESPACE}({TURBOPACK_IMPORT}({}));\n",
158 StringifyModuleId(
159 &*module
160 .resolved_as
161 .chunk_item_id(*self.chunking_context)
162 .await?
163 )
164 )
165 .as_bytes(),
166 );
167
168 let code = code.build();
169
170 Ok(EcmascriptChunkItemContent {
171 inner_code: code,
172 source_map: None,
173 rewrite_source_path: None,
174 options: EcmascriptChunkItemOptions {
175 strict: true,
176 exports: true,
177 async_module: if has_top_level_await {
178 Some(AsyncModuleOptions {
179 has_top_level_await: true,
180 })
181 } else {
182 None
183 },
184 ..Default::default()
185 },
186 placeholder_for_future_extensions: (),
187 }
188 .cell())
189 }
190}