next_core/next_dynamic/
dynamic_transition.rs

1use anyhow::{Result, bail};
2use turbo_tasks::{ResolvedVc, Vc};
3use turbopack::{ModuleAssetContext, transition::Transition};
4use turbopack_core::{
5    context::{AssetContext, ProcessResult},
6    reference_type::ReferenceType,
7    source::Source,
8};
9use turbopack_ecmascript::chunk::EcmascriptChunkPlaceable;
10
11use super::NextDynamicEntryModule;
12
13/// This transition is used to create the marker asset for a next/dynamic
14/// import. Optionally, it can also apply another transition (i.e. to the client context).
15///
16/// This will get picked up during module processing and will be used to
17/// create the dynamic entry, and the dynamic manifest entry.
18#[turbo_tasks::value]
19pub struct NextDynamicTransition {
20    client_transition: Option<ResolvedVc<Box<dyn Transition>>>,
21}
22
23#[turbo_tasks::value_impl]
24impl NextDynamicTransition {
25    /// Create a transition that only add a marker `NextDynamicEntryModule`.
26    #[turbo_tasks::function]
27    pub fn new_marker() -> Vc<Self> {
28        NextDynamicTransition {
29            client_transition: None,
30        }
31        .cell()
32    }
33
34    /// Create a transition that applies `client_transition` and adds a marker
35    /// `NextDynamicEntryModule`.
36    #[turbo_tasks::function]
37    pub fn new_client(client_transition: ResolvedVc<Box<dyn Transition>>) -> Vc<Self> {
38        NextDynamicTransition {
39            client_transition: Some(client_transition),
40        }
41        .cell()
42    }
43}
44
45#[turbo_tasks::value_impl]
46impl Transition for NextDynamicTransition {
47    #[turbo_tasks::function]
48    async fn process(
49        self: Vc<Self>,
50        source: Vc<Box<dyn Source>>,
51        module_asset_context: Vc<ModuleAssetContext>,
52        _reference_type: ReferenceType,
53    ) -> Result<Vc<ProcessResult>> {
54        let module_asset_context = self.process_context(module_asset_context);
55        let module = match self.await?.client_transition {
56            Some(client_transition) => {
57                client_transition.process(source, module_asset_context, ReferenceType::Undefined)
58            }
59            None => module_asset_context.process(source, ReferenceType::Undefined),
60        };
61
62        Ok(match &*module.try_into_module().await? {
63            Some(client_module) => {
64                let Some(client_module) =
65                    ResolvedVc::try_sidecast::<Box<dyn EcmascriptChunkPlaceable>>(*client_module)
66                else {
67                    bail!("not an ecmascript client_module");
68                };
69
70                ProcessResult::Module(ResolvedVc::upcast(
71                    NextDynamicEntryModule::new(*client_module)
72                        .to_resolved()
73                        .await?,
74                ))
75            }
76            None => ProcessResult::Ignore,
77        }
78        .cell())
79    }
80}