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