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)]
72#[derive(ValueToString)]
73#[value_to_string("webpack chunk {}", self.chunk_id())]
74pub struct WebpackChunkAssetReference {
75 #[turbo_tasks(trace_ignore)]
76 #[bincode(with_serde)]
77 pub chunk_id: Lit,
78 pub runtime: ResolvedVc<WebpackRuntime>,
79 pub transforms: ResolvedVc<EcmascriptInputTransforms>,
80}
81
82impl WebpackChunkAssetReference {
83 fn chunk_id(&self) -> RcStr {
84 match &self.chunk_id {
85 Lit::Str(s) => RcStr::from(s.value.to_string_lossy().to_string()),
86 Lit::Num(n) => RcStr::from(n.to_string()),
87 _ => panic!("Unexpected literal type"),
88 }
89 }
90}
91
92#[turbo_tasks::value_impl]
93impl ModuleReference for WebpackChunkAssetReference {
94 #[turbo_tasks::function]
95 async fn resolve_reference(&self) -> Result<Vc<ModuleResolveResult>> {
96 let runtime = self.runtime.await?;
97 Ok(match &*runtime {
98 WebpackRuntime::Webpack5 {
99 chunk_request_expr: _,
100 context_path,
101 } => {
102 let chunk_id = match &self.chunk_id {
104 Lit::Str(str) => str.value.to_string_lossy().into_owned(),
105 Lit::Num(num) => format!("{num}"),
106 _ => todo!(),
107 };
108 let filename = format!("./chunks/{chunk_id}.js");
109 let source = Vc::upcast(FileSource::new(context_path.join(&filename)?));
110
111 *ModuleResolveResult::module(ResolvedVc::upcast(
112 WebpackModuleAsset::new(source, *self.runtime, *self.transforms)
113 .to_resolved()
114 .await?,
115 ))
116 }
117 WebpackRuntime::None => *ModuleResolveResult::unresolvable(),
118 })
119 }
120}
121
122#[turbo_tasks::value(shared)]
123#[derive(ValueToString)]
124#[value_to_string("webpack entry")]
125pub struct WebpackEntryAssetReference {
126 pub source: ResolvedVc<Box<dyn Source>>,
127 pub runtime: ResolvedVc<WebpackRuntime>,
128 pub transforms: ResolvedVc<EcmascriptInputTransforms>,
129}
130
131#[turbo_tasks::value_impl]
132impl ModuleReference for WebpackEntryAssetReference {
133 #[turbo_tasks::function]
134 async fn resolve_reference(&self) -> Result<Vc<ModuleResolveResult>> {
135 Ok(*ModuleResolveResult::module(ResolvedVc::upcast(
136 WebpackModuleAsset::new(*self.source, *self.runtime, *self.transforms)
137 .to_resolved()
138 .await?,
139 )))
140 }
141}
142
143#[turbo_tasks::value(shared)]
144#[derive(ValueToString)]
145#[value_to_string("webpack {request}")]
146pub struct WebpackRuntimeAssetReference {
147 pub origin: ResolvedVc<Box<dyn ResolveOrigin>>,
148 pub request: ResolvedVc<Request>,
149 pub runtime: ResolvedVc<WebpackRuntime>,
150 pub transforms: ResolvedVc<EcmascriptInputTransforms>,
151}
152
153#[turbo_tasks::value_impl]
154impl ModuleReference for WebpackRuntimeAssetReference {
155 #[turbo_tasks::function]
156 async fn resolve_reference(&self) -> Result<Vc<ModuleResolveResult>> {
157 let options = self.origin.resolve_options();
158
159 let options = apply_cjs_specific_options(options);
160
161 let resolved = resolve(
162 self.origin.origin_path().await?.parent(),
163 ReferenceType::CommonJs(CommonJsReferenceSubType::Undefined),
164 *self.request,
165 options,
166 );
167
168 Ok(resolved
169 .await?
170 .map_module(|source| async move {
171 Ok(ModuleResolveResultItem::Module(ResolvedVc::upcast(
172 WebpackModuleAsset::new(*source, *self.runtime, *self.transforms)
173 .to_resolved()
174 .await?,
175 )))
176 })
177 .await?
178 .cell())
179 }
180}