turbopack_ecmascript_runtime/
browser_runtime.rs1use std::io::Write;
2
3use anyhow::Result;
4use indoc::writedoc;
5use turbo_rcstr::{RcStr, rcstr};
6use turbo_tasks::{ResolvedVc, Vc};
7use turbopack_core::{
8 code_builder::{Code, CodeBuilder},
9 context::AssetContext,
10 environment::{ChunkLoading, Environment},
11};
12use turbopack_ecmascript::utils::StringifyJs;
13
14use crate::{
15 ChunkSuffix, RuntimeType, asset_context::get_runtime_asset_context, embed_js::embed_static_code,
16};
17
18#[turbo_tasks::function]
20pub async fn get_browser_runtime_code(
21 environment: ResolvedVc<Environment>,
22 chunk_base_path: Vc<Option<RcStr>>,
23 chunk_suffix: Vc<ChunkSuffix>,
24 runtime_type: RuntimeType,
25 output_root_to_root_path: RcStr,
26 generate_source_map: bool,
27) -> Result<Vc<Code>> {
28 let asset_context = get_runtime_asset_context(*environment).resolve().await?;
29
30 let shared_runtime_utils_code = embed_static_code(
31 asset_context,
32 rcstr!("shared/runtime-utils.ts"),
33 generate_source_map,
34 );
35
36 let mut runtime_base_code = vec!["browser/runtime/base/runtime-base.ts"];
37 match runtime_type {
38 RuntimeType::Production => runtime_base_code.push("browser/runtime/base/build-base.ts"),
39 RuntimeType::Development => {
40 runtime_base_code.push("browser/runtime/base/dev-base.ts");
41 }
42 #[cfg(feature = "test")]
43 RuntimeType::Dummy => {
44 panic!("This configuration is not supported in the browser runtime")
45 }
46 }
47
48 let chunk_loading = &*asset_context
49 .compile_time_info()
50 .environment()
51 .chunk_loading()
52 .await?;
53
54 let mut runtime_backend_code = vec![];
55 match (chunk_loading, runtime_type) {
56 (ChunkLoading::Edge, RuntimeType::Development) => {
57 runtime_backend_code.push("browser/runtime/edge/runtime-backend-edge.ts");
58 runtime_backend_code.push("browser/runtime/edge/dev-backend-edge.ts");
59 }
60 (ChunkLoading::Edge, RuntimeType::Production) => {
61 runtime_backend_code.push("browser/runtime/edge/runtime-backend-edge.ts");
62 }
63 (ChunkLoading::NodeJs, _) => {
65 panic!("Node.js runtime is not supported in the browser runtime!")
66 }
67 (ChunkLoading::Dom, RuntimeType::Development) => {
68 runtime_backend_code.push("browser/runtime/dom/runtime-backend-dom.ts");
69 runtime_backend_code.push("browser/runtime/dom/dev-backend-dom.ts");
70 }
71 (ChunkLoading::Dom, RuntimeType::Production) => {
72 runtime_backend_code.push("browser/runtime/dom/runtime-backend-dom.ts");
73 }
74
75 #[cfg(feature = "test")]
76 (_, RuntimeType::Dummy) => {
77 panic!("This configuration is not supported in the browser runtime")
78 }
79 };
80
81 let mut code: CodeBuilder = CodeBuilder::default();
82 let relative_root_path = output_root_to_root_path;
83 let chunk_base_path = chunk_base_path.await?;
84 let chunk_base_path = chunk_base_path.as_ref().map_or_else(|| "", |f| f.as_str());
85 let chunk_suffix = chunk_suffix.await?;
86
87 writedoc!(
88 code,
89 r#"
90 (() => {{
91 if (!Array.isArray(globalThis.TURBOPACK)) {{
92 return;
93 }}
94
95 const CHUNK_BASE_PATH = {};
96 const RELATIVE_ROOT_PATH = {};
97 const RUNTIME_PUBLIC_PATH = {};
98 "#,
99 StringifyJs(chunk_base_path),
100 StringifyJs(relative_root_path.as_str()),
101 StringifyJs(chunk_base_path),
102 )?;
103
104 match &*chunk_suffix {
105 ChunkSuffix::None => {
106 writedoc!(
107 code,
108 r#"
109 const CHUNK_SUFFIX = "";
110 "#
111 )?;
112 }
113 ChunkSuffix::Constant(suffix) => {
114 writedoc!(
115 code,
116 r#"
117 const CHUNK_SUFFIX = {};
118 "#,
119 StringifyJs(suffix.as_str())
120 )?;
121 }
122 ChunkSuffix::FromScriptSrc => {
123 writedoc!(
124 code,
125 r#"
126 const CHUNK_SUFFIX = (self.TURBOPACK_CHUNK_SUFFIX ?? document?.currentScript?.getAttribute?.('src')?.replace(/^(.*(?=\?)|^.*$)/, "")) || "";
127 "#
128 )?;
129 }
130 }
131
132 code.push_code(&*shared_runtime_utils_code.await?);
133 for runtime_code in runtime_base_code {
134 code.push_code(
135 &*embed_static_code(asset_context, runtime_code.into(), generate_source_map).await?,
136 );
137 }
138
139 if *environment.supports_commonjs_externals().await? {
140 code.push_code(
141 &*embed_static_code(
142 asset_context,
143 rcstr!("shared-node/base-externals-utils.ts"),
144 generate_source_map,
145 )
146 .await?,
147 );
148 }
149 if *environment.node_externals().await? {
150 code.push_code(
151 &*embed_static_code(
152 asset_context,
153 rcstr!("shared-node/node-externals-utils.ts"),
154 generate_source_map,
155 )
156 .await?,
157 );
158 }
159 if *environment.supports_wasm().await? {
160 code.push_code(
161 &*embed_static_code(
162 asset_context,
163 rcstr!("shared-node/node-wasm-utils.ts"),
164 generate_source_map,
165 )
166 .await?,
167 );
168 }
169
170 for backend_code in runtime_backend_code {
171 code.push_code(
172 &*embed_static_code(asset_context, backend_code.into(), generate_source_map).await?,
173 );
174 }
175
176 writedoc!(
179 code,
180 r#"
181 const chunksToRegister = globalThis.TURBOPACK;
182 globalThis.TURBOPACK = {{ push: registerChunk }};
183 chunksToRegister.forEach(registerChunk);
184 "#
185 )?;
186 if matches!(runtime_type, RuntimeType::Development) {
187 writedoc!(
188 code,
189 r#"
190 const chunkListsToRegister = globalThis.TURBOPACK_CHUNK_LISTS || [];
191 globalThis.TURBOPACK_CHUNK_LISTS = {{ push: registerChunkList }};
192 chunkListsToRegister.forEach(registerChunkList);
193 "#
194 )?;
195 }
196 writedoc!(
197 code,
198 r#"
199 }})();
200 "#
201 )?;
202
203 Ok(Code::cell(code.build()))
204}