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