next_core/next_server_utility/
server_utility_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},
12 source::OptionSource,
13};
14use turbopack_ecmascript::{
15 chunk::{
16 EcmascriptChunkItemContent, EcmascriptChunkPlaceable, EcmascriptExports,
17 ecmascript_chunk_item,
18 },
19 references::esm::EsmExports,
20 runtime_functions::{TURBOPACK_EXPORT_NAMESPACE, TURBOPACK_IMPORT},
21 utils::StringifyJs,
22};
23
24use super::server_utility_reference::NextServerUtilityModuleReference;
25
26#[turbo_tasks::value(shared)]
27pub struct NextServerUtilityModule {
28 pub module: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>,
29}
30
31#[turbo_tasks::value_impl]
32impl NextServerUtilityModule {
33 #[turbo_tasks::function]
34 pub fn new(module: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>) -> Vc<Self> {
35 NextServerUtilityModule { module }.cell()
36 }
37
38 #[turbo_tasks::function]
39 pub fn server_path(&self) -> Vc<FileSystemPath> {
40 self.module.ident().path()
41 }
42}
43
44impl NextServerUtilityModule {
45 async fn module_reference(&self) -> Result<ResolvedVc<Box<dyn ModuleReference>>> {
46 Ok(ResolvedVc::upcast(
47 NextServerUtilityModuleReference::new(Vc::upcast(*self.module))
48 .to_resolved()
49 .await?,
50 ))
51 }
52}
53
54#[turbo_tasks::value_impl]
55impl Module for NextServerUtilityModule {
56 #[turbo_tasks::function]
57 fn ident(&self) -> Vc<AssetIdent> {
58 self.module
59 .ident()
60 .with_modifier(rcstr!("Next.js server utility"))
61 }
62
63 #[turbo_tasks::function]
64 fn source(&self) -> Vc<OptionSource> {
65 Vc::cell(None)
66 }
67
68 #[turbo_tasks::function]
69 async fn references(&self) -> Result<Vc<ModuleReferences>> {
70 Ok(Vc::cell(vec![self.module_reference().await?]))
71 }
72
73 #[turbo_tasks::function]
74 fn side_effects(self: Vc<Self>) -> Vc<ModuleSideEffects> {
75 ModuleSideEffects::ModuleEvaluationIsSideEffectFree.cell()
77 }
78}
79
80#[turbo_tasks::value_impl]
81impl ChunkableModule for NextServerUtilityModule {
82 #[turbo_tasks::function]
83 fn as_chunk_item(
84 self: ResolvedVc<Self>,
85 module_graph: ResolvedVc<ModuleGraph>,
86 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
87 ) -> Vc<Box<dyn turbopack_core::chunk::ChunkItem>> {
88 ecmascript_chunk_item(ResolvedVc::upcast(self), module_graph, chunking_context)
89 }
90}
91
92#[turbo_tasks::value_impl]
93impl EcmascriptChunkPlaceable for NextServerUtilityModule {
94 #[turbo_tasks::function]
95 fn get_exports(&self) -> Vc<EcmascriptExports> {
96 let module_reference: Vc<Box<dyn ModuleReference>> = Vc::upcast(
97 NextServerUtilityModuleReference::new(Vc::upcast(*self.module)),
98 );
99 EsmExports::reexport_including_default(module_reference)
100 }
101
102 #[turbo_tasks::function]
103 async fn chunk_item_content(
104 &self,
105 chunking_context: Vc<Box<dyn ChunkingContext>>,
106 _module_graph: Vc<ModuleGraph>,
107 _async_module_info: Option<Vc<AsyncModuleInfo>>,
108 _estimated: bool,
109 ) -> Result<Vc<EcmascriptChunkItemContent>> {
110 let module_id = self.module.chunk_item_id(chunking_context).await?;
111 Ok(EcmascriptChunkItemContent {
112 inner_code: formatdoc!(
113 r#"
114 {TURBOPACK_EXPORT_NAMESPACE}({TURBOPACK_IMPORT}({}));
115 "#,
116 StringifyJs(&module_id),
117 )
118 .into(),
119 ..Default::default()
120 }
121 .cell())
122 }
123}