next_core/next_dynamic/
dynamic_module.rs1use std::collections::BTreeMap;
2
3use anyhow::{Result, bail};
4use indoc::formatdoc;
5use turbo_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};
15use turbopack_ecmascript::{
16 chunk::{
17 EcmascriptChunkItem, EcmascriptChunkItemContent, EcmascriptChunkPlaceable,
18 EcmascriptChunkType, EcmascriptExports,
19 },
20 references::esm::{EsmExport, EsmExports},
21 runtime_functions::{TURBOPACK_EXPORT_NAMESPACE, TURBOPACK_IMPORT},
22 utils::StringifyJs,
23};
24
25#[turbo_tasks::function]
26fn modifier() -> Vc<RcStr> {
27 Vc::cell("next/dynamic entry".into())
28}
29
30#[turbo_tasks::value(shared)]
33pub struct NextDynamicEntryModule {
34 module: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>,
35}
36
37#[turbo_tasks::value_impl]
38impl NextDynamicEntryModule {
39 #[turbo_tasks::function]
40 pub fn new(module: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>) -> Vc<Self> {
41 NextDynamicEntryModule { module }.cell()
42 }
43}
44
45#[turbo_tasks::function]
46fn dynamic_ref_description() -> Vc<RcStr> {
47 Vc::cell("next/dynamic reference".into())
48}
49
50#[turbo_tasks::value_impl]
51impl Module for NextDynamicEntryModule {
52 #[turbo_tasks::function]
53 fn ident(&self) -> Vc<AssetIdent> {
54 self.module.ident().with_modifier(modifier())
55 }
56
57 #[turbo_tasks::function]
58 async fn references(&self) -> Result<Vc<ModuleReferences>> {
59 Ok(Vc::cell(vec![ResolvedVc::upcast(
60 SingleChunkableModuleReference::new(
61 Vc::upcast(*self.module),
62 dynamic_ref_description(),
63 )
64 .to_resolved()
65 .await?,
66 )]))
67 }
68}
69
70#[turbo_tasks::value_impl]
71impl Asset for NextDynamicEntryModule {
72 #[turbo_tasks::function]
73 fn content(&self) -> Result<Vc<AssetContent>> {
74 bail!("Next.js Server Component module has no content")
75 }
76}
77
78#[turbo_tasks::value_impl]
79impl ChunkableModule for NextDynamicEntryModule {
80 #[turbo_tasks::function]
81 fn as_chunk_item(
82 self: ResolvedVc<Self>,
83 module_graph: ResolvedVc<ModuleGraph>,
84 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
85 ) -> Vc<Box<dyn turbopack_core::chunk::ChunkItem>> {
86 Vc::upcast(
87 NextDynamicEntryChunkItem {
88 chunking_context,
89 module_graph,
90 inner: self,
91 }
92 .cell(),
93 )
94 }
95}
96
97#[turbo_tasks::value_impl]
98impl EcmascriptChunkPlaceable for NextDynamicEntryModule {
99 #[turbo_tasks::function]
100 async fn get_exports(&self) -> Result<Vc<EcmascriptExports>> {
101 let module_reference = ResolvedVc::upcast(
102 SingleChunkableModuleReference::new(
103 Vc::upcast(*self.module),
104 dynamic_ref_description(),
105 )
106 .to_resolved()
107 .await?,
108 );
109
110 let mut exports = BTreeMap::new();
111 exports.insert(
112 "default".into(),
113 EsmExport::ImportedBinding(module_reference, "default".into(), 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}