next_core/next_server_utility/
server_utility_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::{ChunkItem, ChunkType, ChunkableModule, ChunkingContext, ModuleChunkItemIdExt},
10 ident::AssetIdent,
11 module::{Module, ModuleSideEffects},
12 module_graph::ModuleGraph,
13 output::OutputAssetsReference,
14 reference::ModuleReferences,
15 source::OptionSource,
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_utility_reference::NextServerUtilityModuleReference;
28
29#[turbo_tasks::value(shared)]
30pub struct NextServerUtilityModule {
31 pub module: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>,
32}
33
34#[turbo_tasks::value_impl]
35impl NextServerUtilityModule {
36 #[turbo_tasks::function]
37 pub fn new(module: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>) -> Vc<Self> {
38 NextServerUtilityModule { 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 NextServerUtilityModule {
49 #[turbo_tasks::function]
50 fn ident(&self) -> Vc<AssetIdent> {
51 self.module
52 .ident()
53 .with_modifier(rcstr!("Next.js server utility"))
54 }
55
56 #[turbo_tasks::function]
57 fn source(&self) -> Vc<OptionSource> {
58 Vc::cell(None)
59 }
60
61 #[turbo_tasks::function]
62 async fn references(&self) -> Result<Vc<ModuleReferences>> {
63 Ok(Vc::cell(vec![ResolvedVc::upcast(
64 NextServerUtilityModuleReference::new(Vc::upcast(*self.module))
65 .to_resolved()
66 .await?,
67 )]))
68 }
69
70 #[turbo_tasks::function]
71 fn side_effects(self: Vc<Self>) -> Vc<ModuleSideEffects> {
72 ModuleSideEffects::ModuleEvaluationIsSideEffectFree.cell()
74 }
75}
76
77#[turbo_tasks::value_impl]
78impl ChunkableModule for NextServerUtilityModule {
79 #[turbo_tasks::function]
80 fn as_chunk_item(
81 self: ResolvedVc<Self>,
82 module_graph: ResolvedVc<ModuleGraph>,
83 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
84 ) -> Vc<Box<dyn turbopack_core::chunk::ChunkItem>> {
85 Vc::upcast(
86 NextServerComponentChunkItem {
87 module_graph,
88 chunking_context,
89 inner: self,
90 }
91 .cell(),
92 )
93 }
94}
95
96#[turbo_tasks::value_impl]
97impl EcmascriptChunkPlaceable for NextServerUtilityModule {
98 #[turbo_tasks::function]
99 async fn get_exports(&self) -> Result<Vc<EcmascriptExports>> {
100 let module_reference = ResolvedVc::upcast(
101 NextServerUtilityModuleReference::new(Vc::upcast(*self.module))
102 .to_resolved()
103 .await?,
104 );
105
106 let mut exports = BTreeMap::new();
107 let default = rcstr!("default");
108 exports.insert(
109 default.clone(),
110 EsmExport::ImportedBinding(module_reference, default, false),
111 );
112
113 Ok(EcmascriptExports::EsmExports(
114 EsmExports {
115 exports,
116 star_exports: vec![module_reference],
117 }
118 .resolved_cell(),
119 )
120 .cell())
121 }
122}
123
124#[turbo_tasks::value]
125struct NextServerComponentChunkItem {
126 module_graph: ResolvedVc<ModuleGraph>,
127 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
128 inner: ResolvedVc<NextServerUtilityModule>,
129}
130
131#[turbo_tasks::value_impl]
132impl OutputAssetsReference for NextServerComponentChunkItem {}
133
134#[turbo_tasks::value_impl]
135impl EcmascriptChunkItem for NextServerComponentChunkItem {
136 #[turbo_tasks::function]
137 async fn content(&self) -> Result<Vc<EcmascriptChunkItemContent>> {
138 let inner = self.inner.await?;
139
140 let module_id = inner.module.chunk_item_id(*self.chunking_context).await?;
141 Ok(EcmascriptChunkItemContent {
142 inner_code: formatdoc!(
143 "{TURBOPACK_EXPORT_NAMESPACE}({TURBOPACK_IMPORT}({}));",
144 StringifyJs(&module_id),
145 )
146 .into(),
147 ..Default::default()
148 }
149 .cell())
150 }
151}
152
153#[turbo_tasks::value_impl]
154impl ChunkItem for NextServerComponentChunkItem {
155 #[turbo_tasks::function]
156 fn asset_ident(&self) -> Vc<AssetIdent> {
157 self.inner.ident()
158 }
159
160 #[turbo_tasks::function]
161 fn chunking_context(&self) -> Vc<Box<dyn ChunkingContext>> {
162 *self.chunking_context
163 }
164
165 #[turbo_tasks::function]
166 fn ty(&self) -> Vc<Box<dyn ChunkType>> {
167 Vc::upcast(Vc::<EcmascriptChunkType>::default())
168 }
169
170 #[turbo_tasks::function]
171 fn module(&self) -> Vc<Box<dyn Module>> {
172 Vc::upcast(*self.inner)
173 }
174}