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 reference::ModuleReferences,
15};
16use turbopack_ecmascript::{
17 chunk::{
18 EcmascriptChunkItem, EcmascriptChunkItemContent, EcmascriptChunkPlaceable,
19 EcmascriptChunkType, EcmascriptExports,
20 },
21 references::esm::{EsmExport, EsmExports},
22 runtime_functions::{TURBOPACK_EXPORT_NAMESPACE, TURBOPACK_IMPORT},
23 utils::StringifyJs,
24};
25
26use super::server_utility_reference::NextServerUtilityModuleReference;
27
28#[turbo_tasks::value(shared)]
29pub struct NextServerUtilityModule {
30 pub module: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>,
31}
32
33#[turbo_tasks::value_impl]
34impl NextServerUtilityModule {
35 #[turbo_tasks::function]
36 pub fn new(module: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>) -> Vc<Self> {
37 NextServerUtilityModule { module }.cell()
38 }
39
40 #[turbo_tasks::function]
41 pub fn server_path(&self) -> Vc<FileSystemPath> {
42 self.module.ident().path()
43 }
44}
45
46#[turbo_tasks::value_impl]
47impl Module for NextServerUtilityModule {
48 #[turbo_tasks::function]
49 fn ident(&self) -> Vc<AssetIdent> {
50 self.module
51 .ident()
52 .with_modifier(rcstr!("Next.js server utility"))
53 }
54
55 #[turbo_tasks::function]
56 async fn references(&self) -> Result<Vc<ModuleReferences>> {
57 Ok(Vc::cell(vec![ResolvedVc::upcast(
58 NextServerUtilityModuleReference::new(Vc::upcast(*self.module))
59 .to_resolved()
60 .await?,
61 )]))
62 }
63}
64
65#[turbo_tasks::value_impl]
66impl Asset for NextServerUtilityModule {
67 #[turbo_tasks::function]
68 fn content(&self) -> Result<Vc<AssetContent>> {
69 bail!("Next.js server utility module has no content")
70 }
71}
72
73#[turbo_tasks::value_impl]
74impl ChunkableModule for NextServerUtilityModule {
75 #[turbo_tasks::function]
76 fn as_chunk_item(
77 self: ResolvedVc<Self>,
78 module_graph: ResolvedVc<ModuleGraph>,
79 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
80 ) -> Vc<Box<dyn turbopack_core::chunk::ChunkItem>> {
81 Vc::upcast(
82 NextServerComponentChunkItem {
83 module_graph,
84 chunking_context,
85 inner: self,
86 }
87 .cell(),
88 )
89 }
90}
91
92#[turbo_tasks::value_impl]
93impl EcmascriptChunkPlaceable for NextServerUtilityModule {
94 #[turbo_tasks::function]
95 async fn get_exports(&self) -> Result<Vc<EcmascriptExports>> {
96 let module_reference = ResolvedVc::upcast(
97 NextServerUtilityModuleReference::new(Vc::upcast(*self.module))
98 .to_resolved()
99 .await?,
100 );
101
102 let mut exports = BTreeMap::new();
103 exports.insert(
104 "default".into(),
105 EsmExport::ImportedBinding(module_reference, "default".into(), false),
106 );
107
108 Ok(EcmascriptExports::EsmExports(
109 EsmExports {
110 exports,
111 star_exports: vec![module_reference],
112 }
113 .resolved_cell(),
114 )
115 .cell())
116 }
117}
118
119#[turbo_tasks::value]
120struct NextServerComponentChunkItem {
121 module_graph: ResolvedVc<ModuleGraph>,
122 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
123 inner: ResolvedVc<NextServerUtilityModule>,
124}
125
126#[turbo_tasks::value_impl]
127impl EcmascriptChunkItem for NextServerComponentChunkItem {
128 #[turbo_tasks::function]
129 async fn content(&self) -> Result<Vc<EcmascriptChunkItemContent>> {
130 let inner = self.inner.await?;
131
132 let module_id = inner
133 .module
134 .chunk_item_id(Vc::upcast(*self.chunking_context))
135 .await?;
136 Ok(EcmascriptChunkItemContent {
137 inner_code: formatdoc!(
138 "{TURBOPACK_EXPORT_NAMESPACE}({TURBOPACK_IMPORT}({}));",
139 StringifyJs(&module_id),
140 )
141 .into(),
142 ..Default::default()
143 }
144 .cell())
145 }
146}
147
148#[turbo_tasks::value_impl]
149impl ChunkItem for NextServerComponentChunkItem {
150 #[turbo_tasks::function]
151 fn asset_ident(&self) -> Vc<AssetIdent> {
152 self.inner.ident()
153 }
154
155 #[turbo_tasks::function]
156 fn chunking_context(&self) -> Vc<Box<dyn ChunkingContext>> {
157 *self.chunking_context
158 }
159
160 #[turbo_tasks::function]
161 fn ty(&self) -> Vc<Box<dyn ChunkType>> {
162 Vc::upcast(Vc::<EcmascriptChunkType>::default())
163 }
164
165 #[turbo_tasks::function]
166 fn module(&self) -> Vc<Box<dyn Module>> {
167 Vc::upcast(*self.inner)
168 }
169}