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,
10 reference::{ModuleReference, ModuleReferences},
11 reference_type::{CommonJsReferenceSubType, ReferenceType},
12 resolve::{
13 ModuleResolveResult, ModuleResolveResultItem,
14 origin::{ResolveOrigin, ResolveOriginExt},
15 parse::Request,
16 resolve,
17 },
18 source::Source,
19};
20use turbopack_resolve::ecmascript::apply_cjs_specific_options;
21
22use self::{parse::WebpackRuntime, references::module_references};
23use crate::EcmascriptInputTransforms;
24
25pub mod parse;
26pub(crate) mod references;
27
28#[turbo_tasks::value]
29pub struct WebpackModuleAsset {
30 pub source: ResolvedVc<Box<dyn Source>>,
31 pub runtime: ResolvedVc<WebpackRuntime>,
32 pub transforms: ResolvedVc<EcmascriptInputTransforms>,
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 ) -> Vc<Self> {
43 Self::cell(WebpackModuleAsset {
44 source,
45 runtime,
46 transforms,
47 })
48 }
49}
50
51#[turbo_tasks::value_impl]
52impl Module for WebpackModuleAsset {
53 #[turbo_tasks::function]
54 fn ident(&self) -> Vc<AssetIdent> {
55 self.source.ident().with_modifier(rcstr!("webpack"))
56 }
57
58 #[turbo_tasks::function]
59 fn references(&self) -> Vc<ModuleReferences> {
60 module_references(*self.source, *self.runtime, *self.transforms)
61 }
62}
63
64#[turbo_tasks::value_impl]
65impl Asset for WebpackModuleAsset {
66 #[turbo_tasks::function]
67 fn content(&self) -> Vc<AssetContent> {
68 self.source.content()
69 }
70}
71
72#[turbo_tasks::value(shared)]
73pub struct WebpackChunkAssetReference {
74 #[turbo_tasks(trace_ignore)]
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(),
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(),
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 ty = ReferenceType::CommonJs(CommonJsReferenceSubType::Undefined);
163 let options = self.origin.resolve_options(ty.clone()).await?;
164
165 let options = apply_cjs_specific_options(options);
166
167 let resolved = resolve(
168 self.origin.origin_path().await?.parent(),
169 ReferenceType::CommonJs(CommonJsReferenceSubType::Undefined),
170 *self.request,
171 options,
172 );
173
174 Ok(resolved
175 .await?
176 .map_module(|source| async move {
177 Ok(ModuleResolveResultItem::Module(ResolvedVc::upcast(
178 WebpackModuleAsset::new(*source, *self.runtime, *self.transforms)
179 .to_resolved()
180 .await?,
181 )))
182 })
183 .await?
184 .cell())
185 }
186}
187
188#[turbo_tasks::value_impl]
189impl ValueToString for WebpackRuntimeAssetReference {
190 #[turbo_tasks::function]
191 async fn to_string(&self) -> Result<Vc<RcStr>> {
192 Ok(Vc::cell(
193 format!("webpack {}", self.request.to_string().await?,).into(),
194 ))
195 }
196}