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