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