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