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