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: Option<RcStr>,
21 chunk_suffix_path: 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).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");
72 }
73
74 #[cfg(feature = "test")]
75 (_, RuntimeType::Dummy) => {
76 panic!("This configuration is not supported in the browser runtime")
77 }
78 };
79
80 let mut code: CodeBuilder = CodeBuilder::default();
81 let relative_root_path = output_root_to_root_path;
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
84 .as_ref()
85 .map_or_else(|| "", |f| f.as_str());
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 CHUNK_SUFFIX_PATH = {};
97 const RELATIVE_ROOT_PATH = {};
98 const RUNTIME_PUBLIC_PATH = {};
99 "#,
100 StringifyJs(chunk_base_path),
101 StringifyJs(chunk_suffix_path),
102 StringifyJs(relative_root_path.as_str()),
103 StringifyJs(chunk_base_path),
104 )?;
105
106 code.push_code(&*shared_runtime_utils_code.await?);
107 for runtime_code in runtime_base_code {
108 code.push_code(
109 &*embed_static_code(asset_context, runtime_code.into(), generate_source_map).await?,
110 );
111 }
112
113 if *environment.supports_commonjs_externals().await? {
114 code.push_code(
115 &*embed_static_code(
116 asset_context,
117 rcstr!("shared-node/base-externals-utils.ts"),
118 generate_source_map,
119 )
120 .await?,
121 );
122 }
123 if *environment.node_externals().await? {
124 code.push_code(
125 &*embed_static_code(
126 asset_context,
127 rcstr!("shared-node/node-externals-utils.ts"),
128 generate_source_map,
129 )
130 .await?,
131 );
132 }
133 if *environment.supports_wasm().await? {
134 code.push_code(
135 &*embed_static_code(
136 asset_context,
137 rcstr!("shared-node/node-wasm-utils.ts"),
138 generate_source_map,
139 )
140 .await?,
141 );
142 }
143
144 for backend_code in runtime_backend_code {
145 code.push_code(
146 &*embed_static_code(asset_context, backend_code.into(), generate_source_map).await?,
147 );
148 }
149
150 writedoc!(
153 code,
154 r#"
155 const chunksToRegister = globalThis.TURBOPACK;
156 globalThis.TURBOPACK = {{ push: registerChunk }};
157 chunksToRegister.forEach(registerChunk);
158 "#
159 )?;
160 if matches!(runtime_type, RuntimeType::Development) {
161 writedoc!(
162 code,
163 r#"
164 const chunkListsToRegister = globalThis.TURBOPACK_CHUNK_LISTS || [];
165 chunkListsToRegister.forEach(registerChunkList);
166 globalThis.TURBOPACK_CHUNK_LISTS = {{ push: registerChunkList }};
167 "#
168 )?;
169 }
170 writedoc!(
171 code,
172 r#"
173 }})();
174 "#
175 )?;
176
177 Ok(Code::cell(code.build()))
178}