turbopack_ecmascript/webpack/
mod.rs1use anyhow::Result;
2use swc_core::ecma::ast::Lit;
3use turbo_rcstr::{RcStr, rcstr};
4use turbo_tasks::{ResolvedVc, ValueToString, Vc};
5use turbopack_core::{
6 chunk::{ChunkingType, TracedMode},
7 compile_time_info::CompileTimeInfo,
8 file_source::FileSource,
9 ident::AssetIdent,
10 module::{Module, ModuleSideEffects},
11 reference::{ModuleReference, ModuleReferences},
12 reference_type::{CommonJsReferenceSubType, ReferenceType},
13 resolve::{
14 ModuleResolveResult, ModuleResolveResultItem, origin::ResolveOrigin, parse::Request,
15 resolve,
16 },
17 source::Source,
18};
19use turbopack_resolve::ecmascript::apply_cjs_specific_options;
20
21use self::{parse::WebpackRuntime, references::module_references};
22use crate::EcmascriptInputTransforms;
23
24pub mod parse;
25pub(crate) mod references;
26
27#[turbo_tasks::value]
28pub struct WebpackModuleAsset {
29 pub source: ResolvedVc<Box<dyn Source>>,
30 pub runtime: ResolvedVc<WebpackRuntime>,
31 pub transforms: ResolvedVc<EcmascriptInputTransforms>,
32 pub compile_time_info: ResolvedVc<CompileTimeInfo>,
33}
34
35#[turbo_tasks::value_impl]
36impl WebpackModuleAsset {
37 #[turbo_tasks::function]
38 pub fn new(
39 source: ResolvedVc<Box<dyn Source>>,
40 runtime: ResolvedVc<WebpackRuntime>,
41 transforms: ResolvedVc<EcmascriptInputTransforms>,
42 compile_time_info: ResolvedVc<CompileTimeInfo>,
43 ) -> Vc<Self> {
44 Self::cell(WebpackModuleAsset {
45 source,
46 runtime,
47 transforms,
48 compile_time_info,
49 })
50 }
51}
52
53#[turbo_tasks::value_impl]
54impl Module for WebpackModuleAsset {
55 #[turbo_tasks::function]
56 async fn ident(&self) -> Result<Vc<AssetIdent>> {
57 Ok(self
58 .source
59 .ident()
60 .owned()
61 .await?
62 .with_modifier(rcstr!("webpack"))
63 .into_vc())
64 }
65
66 #[turbo_tasks::function]
67 fn source(&self) -> Vc<turbopack_core::source::OptionSource> {
68 Vc::cell(Some(self.source))
69 }
70
71 #[turbo_tasks::function]
72 fn references(&self) -> Vc<ModuleReferences> {
73 module_references(
74 *self.source,
75 *self.runtime,
76 *self.transforms,
77 *self.compile_time_info,
78 )
79 }
80
81 #[turbo_tasks::function]
82 fn side_effects(self: Vc<Self>) -> Vc<ModuleSideEffects> {
83 ModuleSideEffects::SideEffectful.cell()
84 }
85}
86
87#[turbo_tasks::value(shared)]
88#[derive(ValueToString)]
89#[value_to_string("webpack chunk {}", self.chunk_id())]
90pub struct WebpackChunkAssetReference {
91 #[turbo_tasks(trace_ignore)]
92 #[bincode(with_serde)]
93 pub chunk_id: Lit,
94 pub runtime: ResolvedVc<WebpackRuntime>,
95 pub transforms: ResolvedVc<EcmascriptInputTransforms>,
96 pub compile_time_info: ResolvedVc<CompileTimeInfo>,
97}
98
99impl WebpackChunkAssetReference {
100 fn chunk_id(&self) -> RcStr {
101 match &self.chunk_id {
102 Lit::Str(s) => RcStr::from(s.value.to_string_lossy().to_string()),
103 Lit::Num(n) => RcStr::from(n.to_string()),
104 _ => panic!("Unexpected literal type"),
105 }
106 }
107}
108
109#[turbo_tasks::value_impl]
110impl ModuleReference for WebpackChunkAssetReference {
111 #[turbo_tasks::function]
112 async fn resolve_reference(&self) -> Result<Vc<ModuleResolveResult>> {
113 let runtime = self.runtime.await?;
114 Ok(match &*runtime {
115 WebpackRuntime::Webpack5 { context_path } => {
116 let chunk_id = match &self.chunk_id {
119 Lit::Str(str) => str.value.to_string_lossy().into_owned(),
120 Lit::Num(num) => format!("{num}"),
121 _ => todo!(),
122 };
123 let filename = format!("./chunks/{chunk_id}.js");
124 let source = Vc::upcast(FileSource::new(context_path.join(&filename)?));
125
126 *ModuleResolveResult::module(ResolvedVc::upcast(
127 WebpackModuleAsset::new(
128 source,
129 *self.runtime,
130 *self.transforms,
131 *self.compile_time_info,
132 )
133 .to_resolved()
134 .await?,
135 ))
136 }
137 WebpackRuntime::None => *ModuleResolveResult::unresolvable(),
138 })
139 }
140
141 fn chunking_type(&self) -> Option<ChunkingType> {
142 Some(ChunkingType::Traced {
143 mode: TracedMode::Transitive,
144 })
145 }
146}
147
148#[turbo_tasks::value(shared)]
149#[derive(ValueToString)]
150#[value_to_string("webpack entry")]
151pub struct WebpackEntryAssetReference {
152 pub source: ResolvedVc<Box<dyn Source>>,
153 pub runtime: ResolvedVc<WebpackRuntime>,
154 pub transforms: ResolvedVc<EcmascriptInputTransforms>,
155 pub compile_time_info: ResolvedVc<CompileTimeInfo>,
156}
157
158#[turbo_tasks::value_impl]
159impl ModuleReference for WebpackEntryAssetReference {
160 #[turbo_tasks::function]
161 async fn resolve_reference(&self) -> Result<Vc<ModuleResolveResult>> {
162 Ok(*ModuleResolveResult::module(ResolvedVc::upcast(
163 WebpackModuleAsset::new(
164 *self.source,
165 *self.runtime,
166 *self.transforms,
167 *self.compile_time_info,
168 )
169 .to_resolved()
170 .await?,
171 )))
172 }
173
174 fn chunking_type(&self) -> Option<ChunkingType> {
175 Some(ChunkingType::Traced {
176 mode: TracedMode::Transitive,
177 })
178 }
179}
180
181#[turbo_tasks::value(shared)]
182#[derive(ValueToString)]
183#[value_to_string("webpack {request}")]
184pub struct WebpackRuntimeAssetReference {
185 pub origin: ResolvedVc<Box<dyn ResolveOrigin>>,
186 pub request: ResolvedVc<Request>,
187 pub runtime: ResolvedVc<WebpackRuntime>,
188 pub transforms: ResolvedVc<EcmascriptInputTransforms>,
189 pub compile_time_info: ResolvedVc<CompileTimeInfo>,
190}
191
192#[turbo_tasks::value_impl]
193impl ModuleReference for WebpackRuntimeAssetReference {
194 #[turbo_tasks::function]
195 async fn resolve_reference(&self) -> Result<Vc<ModuleResolveResult>> {
196 let origin = self.origin.into_trait_ref().await?;
197 let options = origin.resolve_options();
198
199 let options = apply_cjs_specific_options(options);
200
201 let resolved = resolve(
202 origin.origin_path().parent(),
203 ReferenceType::CommonJs(CommonJsReferenceSubType::Undefined),
204 *self.request,
205 options,
206 );
207
208 Ok(resolved
209 .await?
210 .map_module(|source| async move {
211 Ok(ModuleResolveResultItem::Module(ResolvedVc::upcast(
212 WebpackModuleAsset::new(
213 *source,
214 *self.runtime,
215 *self.transforms,
216 *self.compile_time_info,
217 )
218 .to_resolved()
219 .await?,
220 )))
221 })
222 .await?
223 .cell())
224 }
225
226 fn chunking_type(&self) -> Option<ChunkingType> {
227 Some(ChunkingType::Traced {
228 mode: TracedMode::Transitive,
229 })
230 }
231}