next_core/next_dynamic/
dynamic_module.rs1use anyhow::Result;
2use indoc::formatdoc;
3use turbo_rcstr::{RcStr, rcstr};
4use turbo_tasks::{ResolvedVc, Vc};
5use turbopack_core::{
6 chunk::{AsyncModuleInfo, ChunkableModule, ChunkingContext, ModuleChunkItemIdExt},
7 ident::AssetIdent,
8 module::{Module, ModuleSideEffects},
9 module_graph::ModuleGraph,
10 reference::{ModuleReference, ModuleReferences, SingleChunkableModuleReference},
11 resolve::ExportUsage,
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
24#[turbo_tasks::value(shared)]
27pub struct NextDynamicEntryModule {
28 module: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>,
29}
30
31#[turbo_tasks::value_impl]
32impl NextDynamicEntryModule {
33 #[turbo_tasks::function]
34 pub fn new(module: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>) -> Vc<Self> {
35 NextDynamicEntryModule { module }.cell()
36 }
37}
38
39fn dynamic_ref_description() -> RcStr {
40 rcstr!("next/dynamic reference")
41}
42
43impl NextDynamicEntryModule {
44 async fn module_reference(&self) -> Result<ResolvedVc<Box<dyn ModuleReference>>> {
45 Ok(ResolvedVc::upcast(
46 SingleChunkableModuleReference::new(
47 Vc::upcast(*self.module),
48 dynamic_ref_description(),
49 ExportUsage::all(),
50 )
51 .to_resolved()
52 .await?,
53 ))
54 }
55}
56
57#[turbo_tasks::value_impl]
58impl Module for NextDynamicEntryModule {
59 #[turbo_tasks::function]
60 fn ident(&self) -> Vc<AssetIdent> {
61 self.module
62 .ident()
63 .with_modifier(rcstr!("next/dynamic entry"))
64 }
65
66 #[turbo_tasks::function]
67 fn source(&self) -> Vc<OptionSource> {
68 Vc::cell(None)
69 }
70
71 #[turbo_tasks::function]
72 async fn references(&self) -> Result<Vc<ModuleReferences>> {
73 Ok(Vc::cell(vec![self.module_reference().await?]))
74 }
75 #[turbo_tasks::function]
76 fn side_effects(self: Vc<Self>) -> Vc<ModuleSideEffects> {
77 ModuleSideEffects::ModuleEvaluationIsSideEffectFree.cell()
79 }
80}
81
82#[turbo_tasks::value_impl]
83impl ChunkableModule for NextDynamicEntryModule {
84 #[turbo_tasks::function]
85 fn as_chunk_item(
86 self: ResolvedVc<Self>,
87 module_graph: ResolvedVc<ModuleGraph>,
88 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
89 ) -> Vc<Box<dyn turbopack_core::chunk::ChunkItem>> {
90 ecmascript_chunk_item(ResolvedVc::upcast(self), module_graph, chunking_context)
91 }
92}
93
94#[turbo_tasks::value_impl]
95impl EcmascriptChunkPlaceable for NextDynamicEntryModule {
96 #[turbo_tasks::function]
97 fn get_exports(&self) -> Vc<EcmascriptExports> {
98 let module_reference: Vc<Box<dyn ModuleReference>> =
99 Vc::upcast(SingleChunkableModuleReference::new(
100 Vc::upcast(*self.module),
101 dynamic_ref_description(),
102 ExportUsage::all(),
103 ));
104 EsmExports::reexport_including_default(module_reference)
105 }
106
107 #[turbo_tasks::function]
108 async fn chunk_item_content(
109 &self,
110 chunking_context: Vc<Box<dyn ChunkingContext>>,
111 _module_graph: Vc<ModuleGraph>,
112 _async_module_info: Option<Vc<AsyncModuleInfo>>,
113 _estimated: bool,
114 ) -> Result<Vc<EcmascriptChunkItemContent>> {
115 let module_id = self.module.chunk_item_id(chunking_context).await?;
116 Ok(EcmascriptChunkItemContent {
117 inner_code: formatdoc!(
118 r#"
119 {TURBOPACK_EXPORT_NAMESPACE}({TURBOPACK_IMPORT}({}));
120 "#,
121 StringifyJs(&module_id),
122 )
123 .into(),
124 ..Default::default()
125 }
126 .cell())
127 }
128}