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