1use std::io::Write;
2
3use anyhow::Result;
4use turbo_rcstr::{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 ChunkItem, ChunkType, ChunkableModule, ChunkableModuleReference, ChunkingContext,
11 EvaluatableAsset,
12 },
13 ident::AssetIdent,
14 module::{Module, ModuleSideEffects},
15 module_graph::ModuleGraph,
16 output::OutputAssetsReference,
17 reference::{ModuleReference, ModuleReferences},
18 resolve::ModuleResolveResult,
19 source::OptionSource,
20};
21use turbopack_ecmascript::{
22 chunk::{
23 EcmascriptChunkItem, EcmascriptChunkItemContent, EcmascriptChunkItemOptions,
24 EcmascriptChunkPlaceable, EcmascriptChunkType, EcmascriptExports,
25 },
26 runtime_functions::TURBOPACK_REQUIRE,
27 utils::StringifyJs,
28};
29
30#[turbo_tasks::function]
33async fn hmr_entry_point_base_ident() -> Result<Vc<AssetIdent>> {
34 Ok(AssetIdent::from_path(
35 VirtualFileSystem::new_with_name(rcstr!("hmr-entry"))
36 .root()
37 .await?
38 .join("hmr-entry.js")?,
39 ))
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 fn ident(&self) -> Vc<AssetIdent> {
63 hmr_entry_point_base_ident().with_asset(rcstr!("ENTRY"), *self.ident)
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![ResolvedVc::upcast(
74 HmrEntryModuleReference::new(Vc::upcast(*self.module))
75 .to_resolved()
76 .await?,
77 )]))
78 }
79 #[turbo_tasks::function]
80 fn side_effects(self: Vc<Self>) -> Vc<ModuleSideEffects> {
81 ModuleSideEffects::SideEffectful.cell()
82 }
83}
84
85#[turbo_tasks::value_impl]
86impl ChunkableModule for HmrEntryModule {
87 #[turbo_tasks::function]
88 fn as_chunk_item(
89 self: ResolvedVc<Self>,
90 module_graph: ResolvedVc<ModuleGraph>,
91 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
92 ) -> Vc<Box<dyn ChunkItem>> {
93 Vc::upcast(
94 HmrEntryChunkItem {
95 module: self,
96 module_graph,
97 chunking_context,
98 }
99 .cell(),
100 )
101 }
102}
103
104#[turbo_tasks::value_impl]
105impl Asset for HmrEntryModule {
106 #[turbo_tasks::function]
107 fn content(self: Vc<Self>) -> Vc<AssetContent> {
108 todo!("HmrEntryModule doesn't implement content()")
109 }
110}
111
112#[turbo_tasks::value_impl]
113impl EcmascriptChunkPlaceable for HmrEntryModule {
114 #[turbo_tasks::function]
115 fn get_exports(self: Vc<Self>) -> Vc<EcmascriptExports> {
116 EcmascriptExports::None.cell()
117 }
118}
119
120#[turbo_tasks::value_impl]
121impl EvaluatableAsset for HmrEntryModule {}
122
123#[turbo_tasks::value]
124pub struct HmrEntryModuleReference {
125 pub module: ResolvedVc<Box<dyn Module>>,
126}
127
128#[turbo_tasks::value_impl]
129impl HmrEntryModuleReference {
130 #[turbo_tasks::function]
131 pub fn new(module: ResolvedVc<Box<dyn Module>>) -> Vc<Self> {
132 HmrEntryModuleReference { module }.cell()
133 }
134}
135
136#[turbo_tasks::value_impl]
137impl ValueToString for HmrEntryModuleReference {
138 #[turbo_tasks::function]
139 fn to_string(&self) -> Vc<RcStr> {
140 Vc::cell(rcstr!("entry"))
141 }
142}
143
144#[turbo_tasks::value_impl]
145impl ModuleReference for HmrEntryModuleReference {
146 #[turbo_tasks::function]
147 fn resolve_reference(&self) -> Vc<ModuleResolveResult> {
148 *ModuleResolveResult::module(self.module)
149 }
150}
151
152#[turbo_tasks::value_impl]
153impl ChunkableModuleReference for HmrEntryModuleReference {}
154
155#[turbo_tasks::value]
157struct HmrEntryChunkItem {
158 module: ResolvedVc<HmrEntryModule>,
159 module_graph: ResolvedVc<ModuleGraph>,
160 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
161}
162
163#[turbo_tasks::value_impl]
164impl OutputAssetsReference for HmrEntryChunkItem {}
165
166#[turbo_tasks::value_impl]
167impl ChunkItem for HmrEntryChunkItem {
168 #[turbo_tasks::function]
169 fn chunking_context(&self) -> Vc<Box<dyn ChunkingContext>> {
170 *self.chunking_context
171 }
172
173 #[turbo_tasks::function]
174 fn asset_ident(&self) -> Vc<AssetIdent> {
175 self.module.ident()
176 }
177
178 #[turbo_tasks::function]
179 fn ty(&self) -> Vc<Box<dyn ChunkType>> {
180 Vc::upcast(Vc::<EcmascriptChunkType>::default())
181 }
182
183 #[turbo_tasks::function]
184 fn module(&self) -> Vc<Box<dyn Module>> {
185 Vc::upcast(*self.module)
186 }
187}
188
189#[turbo_tasks::value_impl]
190impl EcmascriptChunkItem for HmrEntryChunkItem {
191 #[turbo_tasks::function]
192 async fn content(&self) -> Result<Vc<EcmascriptChunkItemContent>> {
193 let this = self.module.await?;
194 let module = this.module;
195 let chunk_item = module.as_chunk_item(*self.module_graph, *self.chunking_context);
196 let id = self.chunking_context.chunk_item_id(chunk_item).await?;
197
198 let mut code = RopeBuilder::default();
199 writeln!(code, "{TURBOPACK_REQUIRE}({});", StringifyJs(&id))?;
200 Ok(EcmascriptChunkItemContent {
201 inner_code: code.build(),
202 options: EcmascriptChunkItemOptions {
203 strict: true,
204 ..Default::default()
205 },
206 ..Default::default()
207 }
208 .cell())
209 }
210}