next_core/next_server_utility/
server_utility_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_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 async fn references(&self) -> Result<Vc<ModuleReferences>> {
58 Ok(Vc::cell(vec![ResolvedVc::upcast(
59 NextServerUtilityModuleReference::new(Vc::upcast(*self.module))
60 .to_resolved()
61 .await?,
62 )]))
63 }
64}
65
66#[turbo_tasks::value_impl]
67impl Asset for NextServerUtilityModule {
68 #[turbo_tasks::function]
69 fn content(&self) -> Result<Vc<AssetContent>> {
70 bail!("Next.js server utility module has no content")
71 }
72}
73
74#[turbo_tasks::value_impl]
75impl ChunkableModule for NextServerUtilityModule {
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 NextServerUtilityModule {
95 #[turbo_tasks::function]
96 async fn get_exports(&self) -> Result<Vc<EcmascriptExports>> {
97 let module_reference = ResolvedVc::upcast(
98 NextServerUtilityModuleReference::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<NextServerUtilityModule>,
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 "{TURBOPACK_EXPORT_NAMESPACE}({TURBOPACK_IMPORT}({}));",
141 StringifyJs(&module_id),
142 )
143 .into(),
144 ..Default::default()
145 }
146 .cell())
147 }
148}
149
150#[turbo_tasks::value_impl]
151impl ChunkItem for NextServerComponentChunkItem {
152 #[turbo_tasks::function]
153 fn asset_ident(&self) -> Vc<AssetIdent> {
154 self.inner.ident()
155 }
156
157 #[turbo_tasks::function]
158 fn chunking_context(&self) -> Vc<Box<dyn ChunkingContext>> {
159 *self.chunking_context
160 }
161
162 #[turbo_tasks::function]
163 fn ty(&self) -> Vc<Box<dyn ChunkType>> {
164 Vc::upcast(Vc::<EcmascriptChunkType>::default())
165 }
166
167 #[turbo_tasks::function]
168 fn module(&self) -> Vc<Box<dyn Module>> {
169 Vc::upcast(*self.inner)
170 }
171}