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