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 ChunkingTypeOption, 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}
40
41#[turbo_tasks::value(shared)]
42pub struct HmrEntryModule {
43 pub ident: ResolvedVc<AssetIdent>,
44 pub module: ResolvedVc<Box<dyn ChunkableModule>>,
45}
46
47#[turbo_tasks::value_impl]
48impl HmrEntryModule {
49 #[turbo_tasks::function]
50 pub fn new(
51 ident: ResolvedVc<AssetIdent>,
52 module: ResolvedVc<Box<dyn ChunkableModule>>,
53 ) -> Vc<Self> {
54 Self { ident, module }.cell()
55 }
56}
57
58#[turbo_tasks::value_impl]
59impl Module for HmrEntryModule {
60 #[turbo_tasks::function]
61 fn ident(&self) -> Vc<AssetIdent> {
62 hmr_entry_point_base_ident().with_asset(rcstr!("ENTRY"), *self.ident)
63 }
64
65 #[turbo_tasks::function]
66 fn source(&self) -> Vc<OptionSource> {
67 Vc::cell(None)
68 }
69
70 #[turbo_tasks::function]
71 async fn references(&self) -> Result<Vc<ModuleReferences>> {
72 Ok(Vc::cell(vec![ResolvedVc::upcast(
73 HmrEntryModuleReference::new(Vc::upcast(*self.module))
74 .to_resolved()
75 .await?,
76 )]))
77 }
78 #[turbo_tasks::function]
79 fn side_effects(self: Vc<Self>) -> Vc<ModuleSideEffects> {
80 ModuleSideEffects::SideEffectful.cell()
81 }
82}
83
84#[turbo_tasks::value_impl]
85impl ChunkableModule for HmrEntryModule {
86 #[turbo_tasks::function]
87 fn as_chunk_item(
88 self: ResolvedVc<Self>,
89 module_graph: ResolvedVc<ModuleGraph>,
90 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
91 ) -> Vc<Box<dyn ChunkItem>> {
92 ecmascript_chunk_item(ResolvedVc::upcast(self), module_graph, chunking_context)
93 }
94}
95
96#[turbo_tasks::value_impl]
97impl Asset for HmrEntryModule {
98 #[turbo_tasks::function]
99 fn content(self: Vc<Self>) -> Vc<AssetContent> {
100 todo!("HmrEntryModule doesn't implement content()")
101 }
102}
103
104#[turbo_tasks::value_impl]
105impl EcmascriptChunkPlaceable for HmrEntryModule {
106 #[turbo_tasks::function]
107 fn get_exports(self: Vc<Self>) -> Vc<EcmascriptExports> {
108 EcmascriptExports::None.cell()
109 }
110
111 #[turbo_tasks::function]
112 async fn chunk_item_content(
113 self: Vc<Self>,
114 chunking_context: Vc<Box<dyn ChunkingContext>>,
115 module_graph: Vc<ModuleGraph>,
116 _async_module_info: Option<Vc<AsyncModuleInfo>>,
117 _estimated: bool,
118 ) -> Result<Vc<EcmascriptChunkItemContent>> {
119 let this = self.await?;
120 let module = this.module;
121 let chunk_item = module.as_chunk_item(module_graph, chunking_context);
122 let id = chunking_context
123 .chunk_item_id_strategy()
124 .await?
125 .get_id(chunk_item)
126 .await?;
127
128 let mut code = RopeBuilder::default();
129 writeln!(code, "{TURBOPACK_REQUIRE}({});", StringifyJs(&id))?;
130 Ok(EcmascriptChunkItemContent {
131 inner_code: code.build(),
132 options: EcmascriptChunkItemOptions {
133 strict: true,
134 ..Default::default()
135 },
136 ..Default::default()
137 }
138 .cell())
139 }
140}
141
142#[turbo_tasks::value_impl]
143impl EvaluatableAsset for HmrEntryModule {}
144
145#[turbo_tasks::value]
146#[derive(ValueToString)]
147#[value_to_string("entry")]
148pub struct HmrEntryModuleReference {
149 pub module: ResolvedVc<Box<dyn Module>>,
150}
151
152#[turbo_tasks::value_impl]
153impl HmrEntryModuleReference {
154 #[turbo_tasks::function]
155 pub fn new(module: ResolvedVc<Box<dyn Module>>) -> Vc<Self> {
156 HmrEntryModuleReference { module }.cell()
157 }
158}
159
160#[turbo_tasks::value_impl]
161impl ModuleReference for HmrEntryModuleReference {
162 #[turbo_tasks::function]
163 fn resolve_reference(&self) -> Vc<ModuleResolveResult> {
164 *ModuleResolveResult::module(self.module)
165 }
166
167 #[turbo_tasks::function]
168 fn chunking_type(&self) -> Vc<ChunkingTypeOption> {
169 Vc::cell(Some(ChunkingType::Parallel {
170 inherit_async: false,
171 hoisted: false,
172 }))
173 }
174}