1use std::collections::BTreeSet;
2
3use anyhow::Result;
4use bincode::{Decode, Encode};
5use turbo_rcstr::{RcStr, rcstr};
6use turbo_tasks::{ResolvedVc, Vc, trace::TraceRawVcs};
7use turbo_tasks_fs::FileSystemPath;
8use turbopack::module_options::{
9 CssOptionsContext, EcmascriptOptionsContext, JsxTransformOptions, TypescriptTransformOptions,
10 module_options_context::ModuleOptionsContext, side_effect_free_packages_glob,
11};
12use turbopack_browser::{
13 BrowserChunkingContext, CurrentChunkMethod, react_refresh::assert_can_resolve_react_refresh,
14};
15use turbopack_core::{
16 chunk::{
17 AssetSuffix, ChunkLoadRetry, ChunkingConfig, ChunkingContext, ContentHashing, CrossOrigin,
18 MangleType, MinifyType, SourceMapSourceType, SourceMapsType, UnusedReferences, UrlBehavior,
19 chunk_id_strategy::ModuleIdStrategy,
20 },
21 compile_time_info::{CompileTimeDefines, CompileTimeInfo, FreeVarReference, FreeVarReferences},
22 environment::{BrowserEnvironment, Environment, ExecutionEnvironment},
23 free_var_references,
24 issue::IssueSeverity,
25 module_graph::{
26 binding_usage_info::OptionBindingUsageInfo, style_groups::StyleGroupsAlgorithm,
27 },
28 resolve::{parse::Request, pattern::Pattern},
29};
30use turbopack_css::chunk::CssChunkType;
31use turbopack_ecmascript::{
32 AnalyzeMode, TypeofWindow,
33 chunk::EcmascriptChunkType,
34 references::esm::UrlRewriteBehavior,
35 transform::{PresetEnvConfig, ReactCompilerTarget},
36};
37use turbopack_node::{
38 execution_context::ExecutionContext,
39 transforms::postcss::{PostCssConfigLocation, PostCssTransformOptions},
40};
41use turbopack_resolve::resolve_options_context::{ResolveOptionsContext, TsConfigHandling};
42
43use crate::{
44 mode::NextMode,
45 next_build::get_postcss_package_mapping,
46 next_client::{
47 runtime_entry::{RuntimeEntries, RuntimeEntry},
48 transforms::get_next_client_transforms_rules,
49 },
50 next_config::NextConfig,
51 next_font::local::NextFontLocalResolvePlugin,
52 next_import_map::{
53 get_next_client_fallback_import_map, get_next_client_import_map,
54 get_next_client_resolved_map,
55 },
56 next_shared::{
57 resolve::NextSharedRuntimeResolvePlugin,
58 webpack_rules::{
59 WebpackLoaderBuiltinCondition, babel::detect_react_compiler_target,
60 webpack_loader_options,
61 },
62 },
63 transform_options::{
64 get_decorators_transform_options, get_jsx_transform_options,
65 get_typescript_transform_options,
66 },
67 util::{
68 OptionEnvMap, defines, foreign_code_context_condition,
69 free_var_references_with_vercel_system_env_warnings, internal_assets_conditions,
70 module_styles_rule_condition, worker_forwarded_globals,
71 },
72};
73
74#[turbo_tasks::function]
75async fn next_client_defines(define_env: Vc<OptionEnvMap>) -> Result<Vc<CompileTimeDefines>> {
76 Ok(defines(&*define_env.await?).cell())
77}
78
79#[turbo_tasks::function]
80async fn next_client_free_vars(
81 define_env: Vc<OptionEnvMap>,
82 report_system_env_inlining: Vc<IssueSeverity>,
83) -> Result<Vc<FreeVarReferences>> {
84 Ok(free_var_references!(
85 ..free_var_references_with_vercel_system_env_warnings(
86 defines(&*define_env.await?),
87 *report_system_env_inlining.await?
88 ),
89 Buffer = FreeVarReference::EcmaScriptModule {
90 request: rcstr!("node:buffer"),
91 lookup_path: None,
92 export: Some(rcstr!("Buffer")),
93 },
94 process = FreeVarReference::EcmaScriptModule {
95 request: rcstr!("node:process"),
96 lookup_path: None,
97 export: Some(rcstr!("default")),
98 }
99 )
100 .cell())
101}
102
103#[turbo_tasks::function]
104pub async fn get_client_compile_time_info(
105 browserslist_query: RcStr,
106 define_env: Vc<OptionEnvMap>,
107 report_system_env_inlining: Vc<IssueSeverity>,
108 hot_module_replacement_enabled: bool,
109) -> Result<Vc<CompileTimeInfo>> {
110 CompileTimeInfo::builder(
111 Environment::new(ExecutionEnvironment::Browser(
112 BrowserEnvironment {
113 dom: true,
114 web_worker: false,
115 service_worker: false,
116 browserslist_query: browserslist_query.to_owned(),
117 }
118 .resolved_cell(),
119 ))
120 .to_resolved()
121 .await?,
122 )
123 .defines(next_client_defines(define_env).to_resolved().await?)
124 .free_var_references(
125 next_client_free_vars(define_env, report_system_env_inlining)
126 .to_resolved()
127 .await?,
128 )
129 .hot_module_replacement_enabled(hot_module_replacement_enabled)
130 .cell()
131 .await
132}
133
134#[turbo_tasks::value(shared, task_input)]
135#[derive(Debug, Clone, Hash)]
136pub enum ClientContextType {
137 Pages { pages_dir: FileSystemPath },
138 App { app_dir: FileSystemPath },
139 Fallback,
140 Other,
141}
142
143#[turbo_tasks::function]
144pub async fn get_client_resolve_options_context(
145 project_path: FileSystemPath,
146 ty: ClientContextType,
147 mode: Vc<NextMode>,
148 next_config: Vc<NextConfig>,
149 execution_context: Vc<ExecutionContext>,
150) -> Result<Vc<ResolveOptionsContext>> {
151 let next_client_import_map = get_next_client_import_map(
152 project_path.clone(),
153 ty.clone(),
154 next_config,
155 mode,
156 execution_context,
157 )
158 .to_resolved()
159 .await?;
160 let next_client_fallback_import_map = get_next_client_fallback_import_map(ty.clone())
161 .to_resolved()
162 .await?;
163 let expose_testing_api = mode.await?.is_development()
164 || *next_config
165 .enable_expose_testing_api_in_production_build()
166 .await?;
167 let next_client_resolved_map = get_next_client_resolved_map(
168 project_path.clone(),
169 project_path.clone(),
170 *mode.await?,
171 expose_testing_api,
172 )
173 .await?
174 .to_resolved()
175 .await?;
176 let mut custom_conditions: Vec<_> = mode.await?.custom_resolve_conditions().collect();
177
178 if *next_config.enable_cache_components().await? {
179 custom_conditions.push(rcstr!("next-js"));
180 };
181
182 let resolve_options_context = ResolveOptionsContext {
183 enable_node_modules: Some(project_path.root().owned().await?),
184 custom_conditions,
185 import_map: Some(next_client_import_map),
186 fallback_import_map: Some(next_client_fallback_import_map),
187 resolved_map: Some(next_client_resolved_map),
188 browser: true,
189 module: true,
190 before_resolve_plugins: vec![ResolvedVc::upcast(
191 NextFontLocalResolvePlugin::new(project_path.clone())
192 .to_resolved()
193 .await?,
194 )],
195 after_resolve_plugins: vec![ResolvedVc::upcast(
196 NextSharedRuntimeResolvePlugin::new(project_path.clone())
197 .to_resolved()
198 .await?,
199 )],
200 ..Default::default()
201 };
202
203 let tsconfig_path = next_config.typescript_tsconfig_path().await?;
204 let tsconfig_path = project_path.join(
205 tsconfig_path
206 .as_ref()
207 .unwrap_or(&rcstr!("tsconfig.json")),
210 )?;
211
212 Ok(ResolveOptionsContext {
213 enable_typescript: true,
214 enable_react: true,
215 enable_mjs_extension: true,
216 custom_extensions: next_config.resolve_extension().owned().await?,
217 tsconfig_path: TsConfigHandling::Fixed(tsconfig_path),
218 rules: vec![(
219 foreign_code_context_condition(next_config, project_path).await?,
220 resolve_options_context.clone().resolved_cell(),
221 )],
222 ..resolve_options_context
223 }
224 .cell())
225}
226
227#[turbo_tasks::function]
228pub async fn get_client_module_options_context(
229 project_path: FileSystemPath,
230 execution_context: ResolvedVc<ExecutionContext>,
231 env: ResolvedVc<Environment>,
232 ty: ClientContextType,
233 mode: Vc<NextMode>,
234 next_config: Vc<NextConfig>,
235 encryption_key: ResolvedVc<RcStr>,
236) -> Result<Vc<ModuleOptionsContext>> {
237 let next_mode = mode.await?;
238 let resolve_options_context = get_client_resolve_options_context(
239 project_path.clone(),
240 ty.clone(),
241 mode,
242 next_config,
243 *execution_context,
244 );
245
246 let tsconfig_path = next_config
247 .typescript_tsconfig_path()
248 .await?
249 .as_ref()
250 .map(|p| project_path.join(p))
251 .transpose()?;
252
253 let tsconfig = get_typescript_transform_options(project_path.clone(), tsconfig_path.clone())
254 .to_resolved()
255 .await?;
256 let decorators_options =
257 get_decorators_transform_options(project_path.clone(), tsconfig_path.clone());
258 let enable_mdx_rs = *next_config.mdx_rs().await?;
259 let jsx_runtime_options = get_jsx_transform_options(
260 project_path.clone(),
261 mode,
262 Some(resolve_options_context),
263 false,
264 next_config,
265 tsconfig_path,
266 )
267 .to_resolved()
268 .await?;
269
270 let mut loader_conditions = BTreeSet::new();
271 loader_conditions.insert(WebpackLoaderBuiltinCondition::Browser);
272 loader_conditions.extend(mode.await?.webpack_loader_conditions());
273
274 let mut foreign_conditions = loader_conditions.clone();
278 foreign_conditions.insert(WebpackLoaderBuiltinCondition::Foreign);
279 let foreign_enable_webpack_loaders =
280 *webpack_loader_options(project_path.clone(), next_config, foreign_conditions).await?;
281
282 let enable_webpack_loaders =
284 *webpack_loader_options(project_path.clone(), next_config, loader_conditions).await?;
285
286 let module_fragments_enabled_for_user_code = *next_config
287 .module_fragments_enabled_for_user_code(next_mode.is_development())
288 .await?;
289 let module_fragments_enabled_for_foreign_code = *next_config
290 .module_fragments_enabled_for_foreign_code(next_mode.is_development())
291 .await?;
292 let target_browsers = env.runtime_versions();
293
294 let next_client_rules = get_next_client_transforms_rules(
295 next_config,
296 &project_path,
297 ty.clone(),
298 mode,
299 false,
300 encryption_key,
301 target_browsers,
302 )
303 .await?;
304 let foreign_next_client_rules = get_next_client_transforms_rules(
305 next_config,
306 &project_path,
307 ty.clone(),
308 mode,
309 true,
310 encryption_key,
311 target_browsers,
312 )
313 .await?;
314
315 let local_postcss_config = *next_config
316 .experimental_turbopack_local_postcss_config()
317 .await?;
318 let postcss_config_location = if local_postcss_config == Some(true) {
319 PostCssConfigLocation::LocalPathOrProjectPath
320 } else {
321 PostCssConfigLocation::ProjectPathOrLocalPath
322 };
323 let postcss_transform_options = PostCssTransformOptions {
324 postcss_package: Some(
325 get_postcss_package_mapping(project_path.clone())
326 .to_resolved()
327 .await?,
328 ),
329 config_location: postcss_config_location,
330 ..Default::default()
331 };
332 let postcss_foreign_transform_options = PostCssTransformOptions {
333 config_location: PostCssConfigLocation::ProjectPath,
336 ..postcss_transform_options.clone()
337 };
338 let enable_postcss_transform = Some(postcss_transform_options.resolved_cell());
339 let enable_foreign_postcss_transform = Some(postcss_foreign_transform_options.resolved_cell());
340
341 let source_maps = *next_config.client_source_maps(mode).await?;
342
343 let preset_env_config = (*next_config.experimental_swc_env_options().await?)
344 .as_ref()
345 .map(|opts| {
346 PresetEnvConfig {
347 mode: opts.mode.clone(),
348 core_js: opts.core_js.clone(),
349 skip: opts.skip.clone(),
350 include: opts.include.clone(),
351 exclude: opts.exclude.clone(),
352 shipped_proposals: opts.shipped_proposals,
353 force_all_transforms: opts.force_all_transforms,
354 debug: opts.debug,
355 loose: opts.loose,
356 }
357 .resolved_cell()
358 });
359
360 let enable_rust_react_compiler = *next_config.rust_react_compiler().await?;
361 let rust_react_compiler_target = if enable_rust_react_compiler.is_some() {
362 match detect_react_compiler_target(&project_path).await? {
363 Some(ReactCompilerTarget::React18) => ReactCompilerTarget::React18,
364 _ => ReactCompilerTarget::React19,
365 }
366 } else {
367 ReactCompilerTarget::React19
368 };
369
370 let module_options_context = ModuleOptionsContext {
371 ecmascript: EcmascriptOptionsContext {
372 esm_url_rewrite_behavior: Some(UrlRewriteBehavior::Relative),
373 enable_typeof_window_inlining: Some(TypeofWindow::Object),
374 enable_import_as_bytes: *next_config.turbopack_import_type_bytes().await?,
375 source_maps,
376 infer_module_side_effects: *next_config.turbopack_infer_module_side_effects().await?,
377 cjs_tree_shaking: *next_config.turbopack_cjs_tree_shaking().await?,
378 preset_env_config,
379 ..Default::default()
380 },
381 css: CssOptionsContext {
382 source_maps,
383 module_css_condition: Some(module_styles_rule_condition()),
384 lightningcss_features: *next_config.lightningcss_feature_flags().await?,
385 ..Default::default()
386 },
387 static_url_tag: Some(rcstr!("client")),
388 environment: Some(env),
389 execution_context: Some(execution_context),
390 follow_reexports: true,
391 module_fragments_enabled: module_fragments_enabled_for_user_code,
392 enable_postcss_transform,
393 side_effect_free_packages: Some(
394 side_effect_free_packages_glob(next_config.optimize_package_imports())
395 .to_resolved()
396 .await?,
397 ),
398 keep_last_successful_parse: next_mode.is_development(),
399 analyze_mode: AnalyzeMode::CodeGeneration,
400 ..Default::default()
401 };
402
403 let foreign_codes_options_context = ModuleOptionsContext {
405 ecmascript: EcmascriptOptionsContext {
406 enable_typeof_window_inlining: None,
407 ignore_dynamic_requests: true,
409 preset_env_config: None,
412 ..module_options_context.ecmascript
413 },
414 enable_webpack_loaders: foreign_enable_webpack_loaders,
415 enable_postcss_transform: enable_foreign_postcss_transform,
416 module_rules: foreign_next_client_rules,
417 follow_reexports: true,
418 module_fragments_enabled: module_fragments_enabled_for_foreign_code,
419 ..module_options_context.clone()
421 };
422
423 let internal_context = ModuleOptionsContext {
424 ecmascript: EcmascriptOptionsContext {
425 enable_typescript_transform: Some(
426 TypescriptTransformOptions::default().resolved_cell(),
427 ),
428 enable_jsx: Some(JsxTransformOptions::default().resolved_cell()),
429 preset_env_config: None,
431 ..module_options_context.ecmascript.clone()
432 },
433 enable_postcss_transform: None,
434 ..module_options_context.clone()
435 };
436
437 let module_options_context = ModuleOptionsContext {
438 ecmascript: EcmascriptOptionsContext {
442 enable_jsx: Some(jsx_runtime_options),
443 enable_typescript_transform: Some(tsconfig),
444 enable_decorators: Some(decorators_options.to_resolved().await?),
445 enable_rust_react_compiler,
446 rust_react_compiler_target,
447 ..module_options_context.ecmascript.clone()
448 },
449 enable_webpack_loaders,
450 enable_mdx_rs,
451 rules: vec![
452 (
453 foreign_code_context_condition(next_config, project_path).await?,
454 foreign_codes_options_context.resolved_cell(),
455 ),
456 (
457 internal_assets_conditions().await?,
458 internal_context.resolved_cell(),
459 ),
460 ],
461 module_rules: next_client_rules,
462 ..module_options_context
463 }
464 .cell();
465
466 Ok(module_options_context)
467}
468
469#[turbo_tasks::task_input(contains_unresolved_vcs)]
470#[derive(Clone, Debug, PartialEq, Eq, Hash, TraceRawVcs, Encode, Decode)]
471pub struct ClientChunkingContextOptions {
472 pub mode: Vc<NextMode>,
473 pub root_path: FileSystemPath,
474 pub client_root: FileSystemPath,
475 pub client_root_to_root_path: RcStr,
476 pub client_static_folder_name: RcStr,
477 pub asset_prefix: Vc<RcStr>,
478 pub service_worker_scope_base_path: Vc<Option<RcStr>>,
479 pub environment: Vc<Environment>,
480 pub module_id_strategy: Vc<ModuleIdStrategy>,
481 pub export_usage: Vc<OptionBindingUsageInfo>,
482 pub unused_references: Vc<UnusedReferences>,
483 pub minify: Vc<bool>,
484 pub source_maps: Vc<SourceMapsType>,
485 pub no_mangling: Vc<bool>,
486 pub scope_hoisting: Vc<bool>,
487 pub nested_async_chunking: Vc<bool>,
488 pub shared_runtime: Vc<bool>,
489 pub debug_ids: Vc<bool>,
490 pub worker_asset_prefix: Vc<Option<RcStr>>,
491 pub should_use_absolute_url_references: Vc<bool>,
492 pub css_url_suffix: Vc<Option<RcStr>>,
493 pub hash_salt: ResolvedVc<RcStr>,
494 pub cross_origin: Vc<CrossOrigin>,
495 pub chunk_loading_global: Vc<Option<RcStr>>,
496 pub style_groups_algorithm: StyleGroupsAlgorithm,
497 pub chunking_first_page_load_priority: Option<u32>,
498 pub chunking_priority_boost_percent: Option<u32>,
499 pub chunking_request_cost: Option<u64>,
500 pub generate_component_chunks: Vc<bool>,
501}
502
503const NEXT_CHUNK_LOAD_RETRY: ChunkLoadRetry = ChunkLoadRetry {
506 max_retry_attempts: 1,
507 base_delay_ms: 200,
508 max_jitter_ms: 400,
509};
510
511#[turbo_tasks::function]
512pub async fn get_client_chunking_context(
513 options: ClientChunkingContextOptions,
514) -> Result<Vc<Box<dyn ChunkingContext>>> {
515 let ClientChunkingContextOptions {
516 mode,
517 root_path,
518 client_root,
519 client_root_to_root_path,
520 client_static_folder_name,
521 asset_prefix,
522 service_worker_scope_base_path,
523 environment,
524 module_id_strategy,
525 export_usage,
526 unused_references,
527 minify,
528 source_maps,
529 no_mangling,
530 scope_hoisting,
531 nested_async_chunking,
532 shared_runtime,
533 debug_ids,
534 worker_asset_prefix,
535 should_use_absolute_url_references,
536 css_url_suffix,
537 hash_salt,
538 cross_origin,
539 chunk_loading_global,
540 style_groups_algorithm,
541 chunking_first_page_load_priority,
542 chunking_priority_boost_percent,
543 chunking_request_cost,
544 generate_component_chunks,
545 } = options;
546
547 let next_mode = mode.await?;
548 let asset_prefix = asset_prefix.owned().await?;
549 let service_worker_scope_base_path = service_worker_scope_base_path.owned().await?;
550 let cross_origin_loading = *cross_origin.await?;
551 let mut builder = BrowserChunkingContext::builder(
552 root_path,
553 client_root.clone(),
554 client_root_to_root_path,
555 client_root.clone(),
556 client_root
557 .join(&client_static_folder_name)?
558 .join("chunks")?,
559 client_root
560 .join(&client_static_folder_name)?
561 .join("media")?,
562 environment.to_resolved().await?,
563 next_mode.runtime_type(),
564 )
565 .chunk_base_path(Some(asset_prefix.clone()))
566 .service_worker_scope_base_path(service_worker_scope_base_path)
567 .asset_suffix(AssetSuffix::Inferred.resolved_cell())
568 .minify_type(if *minify.await? {
569 MinifyType::Minify {
570 mangle: (!*no_mangling.await?).then_some(MangleType::OptimalSize),
571 }
572 } else {
573 MinifyType::NoMinify
574 })
575 .source_maps(*source_maps.await?)
576 .asset_base_path(Some(asset_prefix))
577 .current_chunk_method(CurrentChunkMethod::DocumentCurrentScript)
578 .cross_origin(cross_origin_loading)
579 .chunk_load_retry(NEXT_CHUNK_LOAD_RETRY)
580 .export_usage(*export_usage.await?)
581 .unused_references(unused_references.to_resolved().await?)
582 .module_id_strategy(module_id_strategy.to_resolved().await?)
583 .debug_ids(*debug_ids.await?)
584 .worker_asset_prefix(worker_asset_prefix.owned().await?)
585 .should_use_absolute_url_references(*should_use_absolute_url_references.await?)
586 .nested_async_availability(*nested_async_chunking.await?)
587 .worker_forwarded_globals(worker_forwarded_globals())
588 .hash_salt(hash_salt)
589 .default_url_behavior(UrlBehavior {
590 suffix: AssetSuffix::Inferred,
591 static_suffix: css_url_suffix.to_resolved().await?,
592 });
593
594 if let Some(g) = &*chunk_loading_global.await? {
595 builder = builder.chunk_loading_global(g.clone());
596 }
597
598 if next_mode.is_development() {
599 builder = builder
600 .hot_module_replacement()
601 .source_map_source_type(SourceMapSourceType::AbsoluteFileUri)
602 .dynamic_chunk_content_loading(true);
603 } else {
604 builder = builder
605 .chunking_config(
606 Vc::<EcmascriptChunkType>::default().to_resolved().await?,
607 ChunkingConfig {
608 min_chunk_size: 50_000,
609 max_chunk_count_per_group: 40,
610 max_merge_chunk_size: 200_000,
611 first_page_load_priority: chunking_first_page_load_priority,
612 priority_boost_percent: chunking_priority_boost_percent,
613 request_cost: chunking_request_cost,
614 generate_component_chunks: *generate_component_chunks.await?,
617 min_component_chunk_size: 20_000,
618 ..Default::default()
619 },
620 )
621 .chunking_config(
622 Vc::<CssChunkType>::default().to_resolved().await?,
623 ChunkingConfig {
624 max_merge_chunk_size: 100_000,
625 style_groups_algorithm: style_groups_algorithm.clone(),
626 ..Default::default()
627 },
628 )
629 .chunk_content_hashing(ContentHashing::Direct { length: 13 })
630 .module_merging(*scope_hoisting.await?)
631 .shared_runtime(*shared_runtime.await?);
632 }
633
634 Ok(Vc::upcast(builder.build()))
635}
636
637#[turbo_tasks::task_input(contains_unresolved_vcs)]
638#[derive(Clone, Debug, PartialEq, Eq, Hash, TraceRawVcs, Encode, Decode)]
639pub struct ServiceWorkerChunkingContextOptions {
640 pub mode: Vc<NextMode>,
641 pub root_path: FileSystemPath,
642 pub output_root: FileSystemPath,
643 pub output_root_to_root_path: RcStr,
644 pub environment: Vc<Environment>,
645 pub minify: Vc<bool>,
646 pub source_maps: Vc<SourceMapsType>,
647 pub no_mangling: Vc<bool>,
648 pub hash_salt: ResolvedVc<RcStr>,
649}
650
651#[turbo_tasks::function]
652pub async fn get_service_worker_chunking_context(
653 options: ServiceWorkerChunkingContextOptions,
654) -> Result<Vc<Box<dyn ChunkingContext>>> {
655 let ServiceWorkerChunkingContextOptions {
656 mode,
657 root_path,
658 output_root,
659 output_root_to_root_path,
660 environment,
661 minify,
662 source_maps,
663 no_mangling,
664 hash_salt,
665 } = options;
666
667 let next_mode = mode.await?;
668 let builder = BrowserChunkingContext::builder(
669 root_path,
670 output_root.clone(),
671 output_root_to_root_path,
672 output_root.clone(),
673 output_root.join("chunks")?,
674 output_root.join("media")?,
675 environment.to_resolved().await?,
676 next_mode.runtime_type(),
677 )
678 .current_chunk_method(CurrentChunkMethod::StringLiteral)
679 .asset_suffix(AssetSuffix::None.resolved_cell())
680 .minify_type(if *minify.await? {
681 MinifyType::Minify {
682 mangle: (!*no_mangling.await?).then_some(MangleType::OptimalSize),
683 }
684 } else {
685 MinifyType::NoMinify
686 })
687 .source_maps(*source_maps.await?)
688 .hash_salt(hash_salt)
689 .single_chunk()
690 .await?;
691
692 Ok(Vc::upcast(builder.build()))
693}
694
695#[turbo_tasks::function]
696pub async fn get_client_runtime_entries(
697 project_root: FileSystemPath,
698 ty: ClientContextType,
699 mode: Vc<NextMode>,
700 next_config: Vc<NextConfig>,
701 execution_context: Vc<ExecutionContext>,
702) -> Result<Vc<RuntimeEntries>> {
703 let mut runtime_entries = vec![];
704 let resolve_options_context = get_client_resolve_options_context(
705 project_root.clone(),
706 ty.clone(),
707 mode,
708 next_config,
709 execution_context,
710 );
711
712 if mode.await?.is_development() {
713 let enable_react_refresh =
714 assert_can_resolve_react_refresh(project_root.clone(), resolve_options_context)
715 .await?
716 .as_request();
717
718 if let Some(request) = enable_react_refresh {
722 runtime_entries.push(
723 RuntimeEntry::Request(request.to_resolved().await?, project_root.join("_")?)
724 .resolved_cell(),
725 )
726 };
727 }
728
729 if matches!(ty, ClientContextType::App { .. },) {
730 runtime_entries.push(
731 RuntimeEntry::Request(
732 Request::parse(Pattern::Constant(rcstr!(
733 "next/dist/client/app-next-turbopack.js"
734 )))
735 .to_resolved()
736 .await?,
737 project_root.join("_")?,
738 )
739 .resolved_cell(),
740 );
741 }
742
743 Ok(Vc::cell(runtime_entries))
744}