Skip to main content

turbopack_ecmascript/webpack/
mod.rs

1use 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                // TODO determine filename from chunk_request_expr
119                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}