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