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