1use std::io::Write;
2
3use anyhow::Result;
4use turbo_rcstr::rcstr;
5use turbo_tasks::{ResolvedVc, ValueToString, Vc};
6use turbo_tasks_fs::{FileSystem, VirtualFileSystem, rope::RopeBuilder};
7use turbopack_core::{
8 asset::{Asset, AssetContent},
9 chunk::{
10 AsyncModuleInfo, ChunkItem, ChunkableModule, ChunkingContext, ChunkingType,
11 EvaluatableAsset,
12 },
13 ident::AssetIdent,
14 module::{Module, ModuleSideEffects},
15 module_graph::ModuleGraph,
16 reference::{ModuleReference, ModuleReferences},
17 resolve::ModuleResolveResult,
18 source::OptionSource,
19};
20use turbopack_ecmascript::{
21 chunk::{
22 EcmascriptChunkItemContent, EcmascriptChunkItemOptions, EcmascriptChunkPlaceable,
23 EcmascriptExports, ecmascript_chunk_item,
24 },
25 runtime_functions::TURBOPACK_REQUIRE,
26 utils::StringifyJs,
27};
28
29#[turbo_tasks::function]
32async fn hmr_entry_point_base_ident() -> Result<Vc<AssetIdent>> {
33 Ok(AssetIdent::from_path(
34 VirtualFileSystem::new_with_name(rcstr!("hmr-entry"))
35 .root()
36 .await?
37 .join("hmr-entry.js")?,
38 )
39 .into_vc())
40}
41
42#[turbo_tasks::value(shared)]
43pub struct HmrEntryModule {
44 pub ident: ResolvedVc<AssetIdent>,
45 pub module: ResolvedVc<Box<dyn ChunkableModule>>,
46}
47
48#[turbo_tasks::value_impl]
49impl HmrEntryModule {
50 #[turbo_tasks::function]
51 pub fn new(
52 ident: ResolvedVc<AssetIdent>,
53 module: ResolvedVc<Box<dyn ChunkableModule>>,
54 ) -> Vc<Self> {
55 Self { ident, module }.cell()
56 }
57}
58
59#[turbo_tasks::value_impl]
60impl Module for HmrEntryModule {
61 #[turbo_tasks::function]
62 async fn ident(&self) -> Result<Vc<AssetIdent>> {
63 Ok(hmr_entry_point_base_ident()
64 .owned()
65 .await?
66 .with_asset(rcstr!("ENTRY"), self.ident)
67 .into_vc())
68 }
69
70 #[turbo_tasks::function]
71 fn source(&self) -> Vc<OptionSource> {
72 Vc::cell(None)
73 }
74
75 #[turbo_tasks::function]
76 async fn references(&self) -> Result<Vc<ModuleReferences>> {
77 Ok(Vc::cell(vec![ResolvedVc::upcast(
78 HmrEntryModuleReference::new(Vc::upcast(*self.module))
79 .to_resolved()
80 .await?,
81 )]))
82 }
83 #[turbo_tasks::function]
84 fn side_effects(self: Vc<Self>) -> Vc<ModuleSideEffects> {
85 ModuleSideEffects::SideEffectful.cell()
86 }
87}
88
89#[turbo_tasks::value_impl]
90impl ChunkableModule for HmrEntryModule {
91 #[turbo_tasks::function]
92 fn as_chunk_item(
93 self: ResolvedVc<Self>,
94 module_graph: ResolvedVc<ModuleGraph>,
95 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
96 ) -> Vc<Box<dyn ChunkItem>> {
97 ecmascript_chunk_item(ResolvedVc::upcast(self), module_graph, chunking_context)
98 }
99}
100
101#[turbo_tasks::value_impl]
102impl Asset for HmrEntryModule {
103 #[turbo_tasks::function]
104 fn content(self: Vc<Self>) -> Vc<AssetContent> {
105 todo!("HmrEntryModule doesn't implement content()")
106 }
107}
108
109#[turbo_tasks::value_impl]
110impl EcmascriptChunkPlaceable for HmrEntryModule {
111 #[turbo_tasks::function]
112 fn get_exports(self: Vc<Self>) -> Vc<EcmascriptExports> {
113 EcmascriptExports::None.cell()
114 }
115
116 #[turbo_tasks::function]
117 async fn chunk_item_content(
118 self: Vc<Self>,
119 chunking_context: Vc<Box<dyn ChunkingContext>>,
120 module_graph: Vc<ModuleGraph>,
121 _async_module_info: Option<Vc<AsyncModuleInfo>>,
122 _estimated: bool,
123 ) -> Result<Vc<EcmascriptChunkItemContent>> {
124 let this = self.await?;
125 let module = this.module;
126 let chunk_item = module.as_chunk_item(module_graph, chunking_context);
127 let id = chunking_context
128 .chunk_item_id_strategy()
129 .await?
130 .get_id(chunk_item)
131 .await?;
132
133 let mut code = RopeBuilder::default();
134 writeln!(code, "{TURBOPACK_REQUIRE}({});", StringifyJs(&id))?;
135 Ok(EcmascriptChunkItemContent {
136 inner_code: code.build(),
137 options: EcmascriptChunkItemOptions {
138 strict: true,
139 ..Default::default()
140 },
141 ..Default::default()
142 }
143 .cell())
144 }
145}
146
147#[turbo_tasks::value_impl]
148impl EvaluatableAsset for HmrEntryModule {}
149
150#[turbo_tasks::value]
151#[derive(ValueToString)]
152#[value_to_string("entry")]
153pub struct HmrEntryModuleReference {
154 pub module: ResolvedVc<Box<dyn Module>>,
155}
156
157#[turbo_tasks::value_impl]
158impl HmrEntryModuleReference {
159 #[turbo_tasks::function]
160 pub fn new(module: ResolvedVc<Box<dyn Module>>) -> Vc<Self> {
161 HmrEntryModuleReference { module }.cell()
162 }
163}
164
165#[turbo_tasks::value_impl]
166impl ModuleReference for HmrEntryModuleReference {
167 #[turbo_tasks::function]
168 fn resolve_reference(&self) -> Vc<ModuleResolveResult> {
169 *ModuleResolveResult::module(self.module)
170 }
171
172 fn chunking_type(&self) -> Option<ChunkingType> {
173 Some(ChunkingType::Parallel {
174 inherit_async: false,
175 hoisted: false,
176 })
177 }
178}