next_core/next_dynamic/
dynamic_module.rs1use std::collections::BTreeMap;
2
3use anyhow::{Result, bail};
4use indoc::formatdoc;
5use turbo_rcstr::{RcStr, rcstr};
6use turbo_tasks::{ResolvedVc, Vc};
7use turbopack_core::{
8 asset::{Asset, AssetContent},
9 chunk::{ChunkItem, ChunkType, ChunkableModule, ChunkingContext, ModuleChunkItemIdExt},
10 ident::AssetIdent,
11 module::Module,
12 module_graph::ModuleGraph,
13 reference::{ModuleReferences, SingleChunkableModuleReference},
14 resolve::ExportUsage,
15};
16use turbopack_ecmascript::{
17 chunk::{
18 EcmascriptChunkItem, EcmascriptChunkItemContent, EcmascriptChunkPlaceable,
19 EcmascriptChunkType, EcmascriptExports,
20 },
21 references::esm::{EsmExport, EsmExports},
22 runtime_functions::{TURBOPACK_EXPORT_NAMESPACE, TURBOPACK_IMPORT},
23 utils::StringifyJs,
24};
25
26#[turbo_tasks::value(shared)]
29pub struct NextDynamicEntryModule {
30 module: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>,
31}
32
33#[turbo_tasks::value_impl]
34impl NextDynamicEntryModule {
35 #[turbo_tasks::function]
36 pub fn new(module: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>) -> Vc<Self> {
37 NextDynamicEntryModule { module }.cell()
38 }
39}
40
41fn dynamic_ref_description() -> RcStr {
42 rcstr!("next/dynamic reference")
43}
44
45#[turbo_tasks::value_impl]
46impl Module for NextDynamicEntryModule {
47 #[turbo_tasks::function]
48 fn ident(&self) -> Vc<AssetIdent> {
49 self.module
50 .ident()
51 .with_modifier(rcstr!("next/dynamic entry"))
52 }
53
54 #[turbo_tasks::function]
55 async fn references(&self) -> Result<Vc<ModuleReferences>> {
56 Ok(Vc::cell(vec![ResolvedVc::upcast(
57 SingleChunkableModuleReference::new(
58 Vc::upcast(*self.module),
59 dynamic_ref_description(),
60 ExportUsage::all(),
61 )
62 .to_resolved()
63 .await?,
64 )]))
65 }
66}
67
68#[turbo_tasks::value_impl]
69impl Asset for NextDynamicEntryModule {
70 #[turbo_tasks::function]
71 fn content(&self) -> Result<Vc<AssetContent>> {
72 bail!("Next.js Server Component module has no content")
73 }
74}
75
76#[turbo_tasks::value_impl]
77impl ChunkableModule for NextDynamicEntryModule {
78 #[turbo_tasks::function]
79 fn as_chunk_item(
80 self: ResolvedVc<Self>,
81 module_graph: ResolvedVc<ModuleGraph>,
82 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
83 ) -> Vc<Box<dyn turbopack_core::chunk::ChunkItem>> {
84 Vc::upcast(
85 NextDynamicEntryChunkItem {
86 chunking_context,
87 module_graph,
88 inner: self,
89 }
90 .cell(),
91 )
92 }
93}
94
95#[turbo_tasks::value_impl]
96impl EcmascriptChunkPlaceable for NextDynamicEntryModule {
97 #[turbo_tasks::function]
98 async fn get_exports(&self) -> Result<Vc<EcmascriptExports>> {
99 let module_reference = ResolvedVc::upcast(
100 SingleChunkableModuleReference::new(
101 Vc::upcast(*self.module),
102 dynamic_ref_description(),
103 ExportUsage::all(),
104 )
105 .to_resolved()
106 .await?,
107 );
108
109 let mut exports = BTreeMap::new();
110 let default = rcstr!("default");
111 exports.insert(
112 default.clone(),
113 EsmExport::ImportedBinding(module_reference, default, false),
114 );
115
116 Ok(EcmascriptExports::EsmExports(
117 EsmExports {
118 exports,
119 star_exports: vec![module_reference],
120 }
121 .resolved_cell(),
122 )
123 .cell())
124 }
125}
126
127#[turbo_tasks::value]
128struct NextDynamicEntryChunkItem {
129 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
130 module_graph: ResolvedVc<ModuleGraph>,
131 inner: ResolvedVc<NextDynamicEntryModule>,
132}
133
134#[turbo_tasks::value_impl]
135impl EcmascriptChunkItem for NextDynamicEntryChunkItem {
136 #[turbo_tasks::function]
137 async fn content(&self) -> Result<Vc<EcmascriptChunkItemContent>> {
138 let inner = self.inner.await?;
139
140 let module_id = inner
141 .module
142 .chunk_item_id(Vc::upcast(*self.chunking_context))
143 .await?;
144 Ok(EcmascriptChunkItemContent {
145 inner_code: formatdoc!(
146 r#"
147 {TURBOPACK_EXPORT_NAMESPACE}({TURBOPACK_IMPORT}({}));
148 "#,
149 StringifyJs(&module_id),
150 )
151 .into(),
152 ..Default::default()
153 }
154 .cell())
155 }
156}
157
158#[turbo_tasks::value_impl]
159impl ChunkItem for NextDynamicEntryChunkItem {
160 #[turbo_tasks::function]
161 fn asset_ident(&self) -> Vc<AssetIdent> {
162 self.inner.ident()
163 }
164
165 #[turbo_tasks::function]
166 fn chunking_context(&self) -> Vc<Box<dyn ChunkingContext>> {
167 *self.chunking_context
168 }
169
170 #[turbo_tasks::function]
171 fn ty(&self) -> Vc<Box<dyn ChunkType>> {
172 Vc::upcast(Vc::<EcmascriptChunkType>::default())
173 }
174
175 #[turbo_tasks::function]
176 fn module(&self) -> Vc<Box<dyn Module>> {
177 Vc::upcast(*self.inner)
178 }
179}