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 fn server_path(&self) -> Vc<FileSystemPath> {
59 self.module.ident().path()
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 fn ident(&self) -> Vc<AssetIdent> {
77 self.module
78 .ident()
79 .with_modifier(rcstr!("Next.js Server Component"))
80 }
81
82 #[turbo_tasks::function]
83 fn source(&self) -> Vc<OptionSource> {
84 Vc::cell(None)
85 }
86
87 #[turbo_tasks::function]
88 async fn references(&self) -> Result<Vc<ModuleReferences>> {
89 Ok(Vc::cell(vec![self.module_reference().to_resolved().await?]))
90 }
91
92 #[turbo_tasks::function]
93 fn side_effects(self: Vc<Self>) -> Vc<ModuleSideEffects> {
94 ModuleSideEffects::ModuleEvaluationIsSideEffectFree.cell()
96 }
97}
98
99#[turbo_tasks::value_impl]
100impl ChunkableModule for NextServerComponentModule {
101 #[turbo_tasks::function]
102 fn as_chunk_item(
103 self: ResolvedVc<Self>,
104 module_graph: ResolvedVc<ModuleGraph>,
105 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
106 ) -> Vc<Box<dyn turbopack_core::chunk::ChunkItem>> {
107 ecmascript_chunk_item(ResolvedVc::upcast(self), module_graph, chunking_context)
108 }
109}
110
111#[turbo_tasks::value_impl]
112impl EcmascriptChunkPlaceable for NextServerComponentModule {
113 #[turbo_tasks::function]
114 fn get_exports(&self) -> Vc<EcmascriptExports> {
115 let module_reference = self.module_reference();
116 EsmExports::reexport_including_default(module_reference)
117 }
118
119 #[turbo_tasks::function]
120 async fn chunk_item_content(
121 &self,
122 chunking_context: Vc<Box<dyn ChunkingContext>>,
123 _module_graph: Vc<ModuleGraph>,
124 _async_module_info: Option<Vc<AsyncModuleInfo>>,
125 _estimated: bool,
126 ) -> Result<Vc<EcmascriptChunkItemContent>> {
127 let module_id = self.module.chunk_item_id(chunking_context).await?;
128 Ok(EcmascriptChunkItemContent {
129 inner_code: formatdoc!(
130 r#"
131 {TURBOPACK_EXPORT_NAMESPACE}({TURBOPACK_IMPORT}({}));
132 "#,
133 StringifyJs(&module_id),
134 )
135 .into(),
136 ..Default::default()
137 }
138 .cell())
139 }
140}