turbopack_browser/ecmascript/evaluate/
runtime.rs1use anyhow::Result;
2use turbo_rcstr::rcstr;
3use turbo_tasks::{ResolvedVc, ValueToString, Vc};
4use turbo_tasks_fs::{File, FileContent, FileSystem, FileSystemPath};
5use turbopack_core::{
6 asset::{Asset, AssetContent},
7 chunk::{ChunkingContext, MinifyType},
8 code_builder::{Code, CodeBuilder},
9 ident::AssetIdent,
10 output::{OutputAsset, OutputAssetsReference, OutputAssetsWithReferenced},
11 source_map::{GenerateSourceMap, SourceMapAsset},
12};
13use turbopack_ecmascript::minify::minify;
14use turbopack_ecmascript_runtime::RuntimeType;
15
16use crate::BrowserChunkingContext;
17
18#[turbo_tasks::value(shared)]
25#[derive(ValueToString)]
26#[value_to_string("Ecmascript Browser Runtime Chunk")]
27pub struct EcmascriptBrowserRuntimeChunk {
28 chunking_context: ResolvedVc<BrowserChunkingContext>,
29 include_async_module_runtime: bool,
30}
31
32#[turbo_tasks::value_impl]
33impl EcmascriptBrowserRuntimeChunk {
34 #[turbo_tasks::function]
35 pub fn new(
36 chunking_context: ResolvedVc<BrowserChunkingContext>,
37 include_async_module_runtime: bool,
38 ) -> Vc<Self> {
39 EcmascriptBrowserRuntimeChunk {
40 chunking_context,
41 include_async_module_runtime,
42 }
43 .cell()
44 }
45
46 #[turbo_tasks::function]
47 pub(crate) async fn code(self: Vc<Self>) -> Result<Vc<Code>> {
48 let this = self.await?;
49 let chunking_context = this.chunking_context;
50 let environment = chunking_context.environment();
51
52 let output_root_to_root_path = chunking_context.output_root_to_root_path().owned().await?;
53 let source_maps = *chunking_context
54 .reference_chunk_source_maps(Vc::upcast(self))
55 .await?;
56 let asset_context = turbopack::get_runtime_asset_context(environment);
57 let runtime_type = *chunking_context.runtime_type().await?;
58
59 let mut code = CodeBuilder::new(source_maps, *chunking_context.debug_ids_enabled().await?);
60
61 match runtime_type {
62 RuntimeType::Production | RuntimeType::Development => {
63 let runtime_code = turbopack_ecmascript_runtime::get_browser_runtime_code(
64 asset_context,
65 chunking_context.chunk_base_path(),
66 chunking_context.asset_suffix(),
67 runtime_type,
68 output_root_to_root_path,
69 source_maps,
70 chunking_context.chunk_loading_global(),
71 chunking_context.cross_origin(),
72 chunking_context.chunk_load_retry(),
73 this.include_async_module_runtime,
74 chunking_context.chunk_loading(),
75 *chunking_context.generate_component_chunks().await?,
76 );
77 code.push_code(&*runtime_code.await?);
78 }
79 #[cfg(feature = "test")]
80 RuntimeType::Dummy => {
81 let runtime_code = turbopack_ecmascript_runtime::get_dummy_runtime_code();
82 code.push_code(&runtime_code);
83 }
84 }
85
86 let mut code = code.build();
87
88 if let MinifyType::Minify { mangle } = *chunking_context.minify_type().await? {
89 code = minify(code, source_maps, mangle)?;
90 }
91
92 Ok(code.cell())
93 }
94
95 #[turbo_tasks::function]
96 async fn ident_for_path(self: Vc<Self>) -> Result<Vc<AssetIdent>> {
97 Ok(AssetIdent::from_path(
98 turbopack_ecmascript_runtime::embed_fs()
99 .root()
100 .await?
101 .join("runtime.js")?,
102 )
103 .into_vc())
104 }
105
106 #[turbo_tasks::function]
107 async fn source_map(self: Vc<Self>) -> Result<Vc<SourceMapAsset>> {
108 let this = self.await?;
109 Ok(SourceMapAsset::new(
110 Vc::upcast(*this.chunking_context),
111 self.ident_for_path(),
112 Vc::upcast(self),
113 ))
114 }
115}
116
117#[turbo_tasks::value_impl]
118impl OutputAssetsReference for EcmascriptBrowserRuntimeChunk {
119 #[turbo_tasks::function]
120 async fn references(self: Vc<Self>) -> Result<Vc<OutputAssetsWithReferenced>> {
121 let this = self.await?;
122 let mut references = vec![];
123
124 if *this
125 .chunking_context
126 .reference_chunk_source_maps(Vc::upcast(self))
127 .await?
128 {
129 references.push(ResolvedVc::upcast(self.source_map().to_resolved().await?))
130 }
131
132 Ok(OutputAssetsWithReferenced::from_assets(Vc::cell(
133 references,
134 )))
135 }
136}
137
138#[turbo_tasks::value_impl]
139impl OutputAsset for EcmascriptBrowserRuntimeChunk {
140 #[turbo_tasks::function]
141 async fn path(self: Vc<Self>) -> Result<Vc<FileSystemPath>> {
142 let this = self.await?;
143 let ident = self.ident_for_path();
144 Ok(this.chunking_context.chunk_path(
145 Some(Vc::upcast(self)),
146 ident,
147 Some(rcstr!("turbopack")),
148 rcstr!(".js"),
149 ))
150 }
151}
152
153#[turbo_tasks::value_impl]
154impl Asset for EcmascriptBrowserRuntimeChunk {
155 #[turbo_tasks::function]
156 async fn content(self: Vc<Self>) -> Result<Vc<AssetContent>> {
157 Ok(AssetContent::file(
158 FileContent::Content(File::from(
159 self.code()
160 .to_rope_with_magic_comments(|| self.source_map())
161 .await?,
162 ))
163 .cell(),
164 ))
165 }
166}
167
168#[turbo_tasks::value_impl]
169impl GenerateSourceMap for EcmascriptBrowserRuntimeChunk {
170 #[turbo_tasks::function]
171 fn generate_source_map(self: Vc<Self>) -> Vc<FileContent> {
172 self.code().generate_source_map()
173 }
174}