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::{RuntimeType, asset_context::get_runtime_asset_context, embed_js::embed_static_code};
15
16#[turbo_tasks::function]
18pub async fn get_browser_runtime_code(
19 environment: ResolvedVc<Environment>,
20 chunk_base_path: Vc<Option<RcStr>>,
21 chunk_suffix_path: Vc<Option<RcStr>>,
22 runtime_type: RuntimeType,
23 output_root_to_root_path: RcStr,
24 generate_source_map: bool,
25) -> Result<Vc<Code>> {
26 let asset_context = get_runtime_asset_context(*environment).resolve().await?;
27
28 let shared_runtime_utils_code = embed_static_code(
29 asset_context,
30 rcstr!("shared/runtime-utils.ts"),
31 generate_source_map,
32 );
33
34 let mut runtime_base_code = vec!["browser/runtime/base/runtime-base.ts"];
35 match runtime_type {
36 RuntimeType::Production => runtime_base_code.push("browser/runtime/base/build-base.ts"),
37 RuntimeType::Development => {
38 runtime_base_code.push("browser/runtime/base/dev-base.ts");
39 }
40 #[cfg(feature = "test")]
41 RuntimeType::Dummy => {
42 panic!("This configuration is not supported in the browser runtime")
43 }
44 }
45
46 let chunk_loading = &*asset_context
47 .compile_time_info()
48 .environment()
49 .chunk_loading()
50 .await?;
51
52 let mut runtime_backend_code = vec![];
53 match (chunk_loading, runtime_type) {
54 (ChunkLoading::Edge, RuntimeType::Development) => {
55 runtime_backend_code.push("browser/runtime/edge/runtime-backend-edge.ts");
56 runtime_backend_code.push("browser/runtime/edge/dev-backend-edge.ts");
57 }
58 (ChunkLoading::Edge, RuntimeType::Production) => {
59 runtime_backend_code.push("browser/runtime/edge/runtime-backend-edge.ts");
60 }
61 (ChunkLoading::NodeJs, _) => {
63 panic!("Node.js runtime is not supported in the browser runtime!")
64 }
65 (ChunkLoading::Dom, RuntimeType::Development) => {
66 runtime_backend_code.push("browser/runtime/dom/runtime-backend-dom.ts");
67 runtime_backend_code.push("browser/runtime/dom/dev-backend-dom.ts");
68 }
69 (ChunkLoading::Dom, RuntimeType::Production) => {
70 runtime_backend_code.push("browser/runtime/dom/runtime-backend-dom.ts");
71 }
72
73 #[cfg(feature = "test")]
74 (_, RuntimeType::Dummy) => {
75 panic!("This configuration is not supported in the browser runtime")
76 }
77 };
78
79 let mut code: CodeBuilder = CodeBuilder::default();
80 let relative_root_path = output_root_to_root_path;
81 let chunk_base_path = chunk_base_path.await?;
82 let chunk_base_path = chunk_base_path.as_ref().map_or_else(|| "", |f| f.as_str());
83 let chunk_suffix_path = chunk_suffix_path.await?;
84 let chunk_suffix_path = chunk_suffix_path
85 .as_ref()
86 .map_or_else(|| "", |f| f.as_str());
87
88 writedoc!(
89 code,
90 r#"
91 (() => {{
92 if (!Array.isArray(globalThis.TURBOPACK)) {{
93 return;
94 }}
95
96 const CHUNK_BASE_PATH = {};
97 const CHUNK_SUFFIX_PATH = {};
98 const RELATIVE_ROOT_PATH = {};
99 const RUNTIME_PUBLIC_PATH = {};
100 "#,
101 StringifyJs(chunk_base_path),
102 StringifyJs(chunk_suffix_path),
103 StringifyJs(relative_root_path.as_str()),
104 StringifyJs(chunk_base_path),
105 )?;
106
107 code.push_code(&*shared_runtime_utils_code.await?);
108 for runtime_code in runtime_base_code {
109 code.push_code(
110 &*embed_static_code(asset_context, runtime_code.into(), generate_source_map).await?,
111 );
112 }
113
114 if *environment.supports_commonjs_externals().await? {
115 code.push_code(
116 &*embed_static_code(
117 asset_context,
118 rcstr!("shared-node/base-externals-utils.ts"),
119 generate_source_map,
120 )
121 .await?,
122 );
123 }
124 if *environment.node_externals().await? {
125 code.push_code(
126 &*embed_static_code(
127 asset_context,
128 rcstr!("shared-node/node-externals-utils.ts"),
129 generate_source_map,
130 )
131 .await?,
132 );
133 }
134 if *environment.supports_wasm().await? {
135 code.push_code(
136 &*embed_static_code(
137 asset_context,
138 rcstr!("shared-node/node-wasm-utils.ts"),
139 generate_source_map,
140 )
141 .await?,
142 );
143 }
144
145 for backend_code in runtime_backend_code {
146 code.push_code(
147 &*embed_static_code(asset_context, backend_code.into(), generate_source_map).await?,
148 );
149 }
150
151 writedoc!(
154 code,
155 r#"
156 const chunksToRegister = globalThis.TURBOPACK;
157 globalThis.TURBOPACK = {{ push: registerChunk }};
158 chunksToRegister.forEach(registerChunk);
159 "#
160 )?;
161 if matches!(runtime_type, RuntimeType::Development) {
162 writedoc!(
163 code,
164 r#"
165 const chunkListsToRegister = globalThis.TURBOPACK_CHUNK_LISTS || [];
166 globalThis.TURBOPACK_CHUNK_LISTS = {{ push: registerChunkList }};
167 chunkListsToRegister.forEach(registerChunkList);
168 "#
169 )?;
170 }
171 writedoc!(
172 code,
173 r#"
174 }})();
175 "#
176 )?;
177
178 Ok(Code::cell(code.build()))
179}