1use std::collections::BTreeSet;
2
3use anyhow::{Result, bail};
4use bincode::{Decode, Encode};
5use turbo_rcstr::{RcStr, rcstr};
6use turbo_tasks::{ResolvedVc, Vc, trace::TraceRawVcs};
7use turbo_tasks_fs::FileSystemPath;
8use turbopack::{
9 module_options::{
10 CssOptionsContext, EcmascriptOptionsContext, ExternalsTracingOptions, JsxTransformOptions,
11 ModuleOptionsContext, ModuleRule, TypescriptTransformOptions,
12 side_effect_free_packages_glob,
13 },
14 transition::Transition,
15};
16use turbopack_core::{
17 chunk::{
18 AssetSuffix, ChunkingConfig, MangleType, MinifyType, SourceMapSourceType, SourceMapsType,
19 UnusedReferences, UrlBehavior, chunk_id_strategy::ModuleIdStrategy,
20 },
21 compile_time_defines,
22 compile_time_info::{CompileTimeDefines, CompileTimeInfo, FreeVarReferences},
23 environment::{Environment, ExecutionEnvironment, NodeJsEnvironment, NodeJsVersion},
24 issue::IssueSeverity,
25 module_graph::{
26 binding_usage_info::OptionBindingUsageInfo, style_groups::StyleGroupsAlgorithm,
27 },
28 target::CompileTarget,
29};
30use turbopack_css::chunk::CssChunkType;
31use turbopack_ecmascript::{
32 AnalyzeMode, CustomTransformer, TransformPlugin, TypeofWindow, chunk::EcmascriptChunkType,
33 references::esm::UrlRewriteBehavior,
34};
35use turbopack_ecmascript_plugins::transform::directives::{
36 client::ClientDirectiveTransformer, client_disallowed::ClientDisallowedDirectiveTransformer,
37};
38use turbopack_node::{
39 execution_context::ExecutionContext,
40 transforms::postcss::{PostCssConfigLocation, PostCssTransformOptions},
41};
42use turbopack_nodejs::NodeJsChunkingContext;
43use turbopack_resolve::resolve_options_context::{ResolveOptionsContext, TsConfigHandling};
44
45use crate::{
46 app_structure::CollectedRootParams,
47 mode::NextMode,
48 next_build::get_postcss_package_mapping,
49 next_config::NextConfig,
50 next_import_map::{get_next_edge_and_server_fallback_import_map, get_next_server_import_map},
51 next_server::{
52 resolve::{ExternalCjsModulesResolvePlugin, ExternalPredicate},
53 transforms::{get_next_server_internal_transforms_rules, get_next_server_transforms_rules},
54 },
55 next_shared::{
56 resolve::{NextExternalResolvePlugin, NextNodeSharedRuntimeResolvePlugin},
57 transforms::{
58 EcmascriptTransformStage, emotion::get_emotion_transform_rule, get_ecma_transform_rule,
59 next_react_server_components::get_next_react_server_components_transform_rule,
60 react_remove_properties::get_react_remove_properties_transform_rule,
61 relay::get_relay_transform_rule, remove_console::get_remove_console_transform_rule,
62 styled_components::get_styled_components_transform_rule,
63 styled_jsx::get_styled_jsx_transform_rule,
64 swc_ecma_transform_plugins::get_swc_ecma_transform_plugin_rule,
65 },
66 webpack_rules::{WebpackLoaderBuiltinCondition, webpack_loader_options},
67 },
68 transform_options::{
69 get_decorators_transform_options, get_jsx_transform_options,
70 get_typescript_transform_options,
71 },
72 util::{
73 NextRuntime, OptionEnvMap, defines, foreign_code_context_condition,
74 free_var_references_with_vercel_system_env_warnings, get_transpiled_packages,
75 internal_assets_conditions, load_next_js_jsonc_file, module_styles_rule_condition,
76 worker_forwarded_globals,
77 },
78};
79
80#[turbo_tasks::value(shared, task_input)]
81#[derive(Debug, Clone, Hash)]
82pub enum ServerContextType {
83 Pages {
84 pages_dir: FileSystemPath,
85 },
86 PagesApi {
87 pages_dir: FileSystemPath,
88 },
89 AppSSR {
90 app_dir: FileSystemPath,
91 },
92 AppRSC {
93 app_dir: FileSystemPath,
94 ecmascript_client_reference_transition_name: Option<RcStr>,
95 client_transition: Option<ResolvedVc<Box<dyn Transition>>>,
96 },
97 AppRoute {
98 app_dir: FileSystemPath,
99 ecmascript_client_reference_transition_name: Option<RcStr>,
100 },
101 Middleware {
102 app_dir: Option<FileSystemPath>,
103 ecmascript_client_reference_transition_name: Option<RcStr>,
104 },
105 Instrumentation {
106 app_dir: Option<FileSystemPath>,
107 ecmascript_client_reference_transition_name: Option<RcStr>,
108 },
109}
110
111impl ServerContextType {
112 pub fn should_use_react_server_condition(&self) -> bool {
113 matches!(
114 self,
115 ServerContextType::AppRSC { .. }
116 | ServerContextType::AppRoute { .. }
117 | ServerContextType::Middleware { .. }
118 | ServerContextType::Instrumentation { .. }
119 )
120 }
121}
122
123#[turbo_tasks::function]
124pub async fn get_server_resolve_options_context(
125 project_path: FileSystemPath,
126 ty: ServerContextType,
127 mode: Vc<NextMode>,
128 next_config: Vc<NextConfig>,
129 execution_context: Vc<ExecutionContext>,
130 collected_root_params: Option<Vc<CollectedRootParams>>,
131) -> Result<Vc<ResolveOptionsContext>> {
132 let next_server_import_map = get_next_server_import_map(
133 project_path.clone(),
134 ty.clone(),
135 next_config,
136 mode,
137 execution_context,
138 collected_root_params,
139 )
140 .to_resolved()
141 .await?;
142 let next_server_fallback_import_map =
143 get_next_edge_and_server_fallback_import_map(project_path.clone(), NextRuntime::NodeJs)
144 .to_resolved()
145 .await?;
146
147 let foreign_code_context_condition =
148 foreign_code_context_condition(next_config, project_path.clone()).await?;
149 let root_dir = project_path.root().owned().await?;
150
151 let mut external_packages: Vec<RcStr> = load_next_js_jsonc_file(
153 project_path.clone(),
154 rcstr!("dist/lib/server-external-packages.jsonc"),
155 )
156 .await?;
157
158 let mut transpiled_packages = get_transpiled_packages(next_config, project_path.clone())
159 .owned()
160 .await?;
161
162 transpiled_packages.extend(
163 (*next_config.optimize_package_imports().await?)
164 .iter()
165 .cloned(),
166 );
167
168 let server_external_packages = &*next_config.server_external_packages().await?;
169
170 let conflicting_packages = transpiled_packages
171 .iter()
172 .filter(|package| server_external_packages.contains(package))
173 .collect::<Vec<_>>();
174
175 if !conflicting_packages.is_empty() {
176 bail!(
177 "The packages specified in the 'transpilePackages' conflict with the \
178 'serverExternalPackages': {:?}",
179 conflicting_packages
180 );
181 }
182
183 external_packages.extend(server_external_packages.iter().cloned());
185
186 external_packages.retain(|item| !transpiled_packages.contains(item));
187
188 let server_external_packages_plugin = ExternalCjsModulesResolvePlugin::new(
189 project_path.root().owned().await?,
190 ExternalPredicate::Only(ResolvedVc::cell(external_packages)).cell(),
191 *next_config.import_externals().await?,
192 )
193 .to_resolved()
194 .await?;
195
196 let mut custom_conditions: Vec<_> = mode.await?.custom_resolve_conditions().collect();
197 custom_conditions.extend(NextRuntime::NodeJs.custom_resolve_conditions());
198
199 if ty.should_use_react_server_condition() {
200 custom_conditions.push(rcstr!("react-server"));
201 };
202
203 if *next_config.enable_cache_components().await?
204 && !matches!(ty, ServerContextType::Middleware { .. } | ServerContextType::Instrumentation { .. })
206 {
207 custom_conditions.push(rcstr!("next-js"));
208 };
209
210 let external_cjs_modules_plugin = if *next_config.bundle_pages_router_dependencies().await? {
211 server_external_packages_plugin
212 } else {
213 ExternalCjsModulesResolvePlugin::new(
214 project_path.root().owned().await?,
215 ExternalPredicate::AllExcept(ResolvedVc::cell(transpiled_packages)).cell(),
216 *next_config.import_externals().await?,
217 )
218 .to_resolved()
219 .await?
220 };
221
222 let next_external_plugin = NextExternalResolvePlugin::new(project_path.clone())
223 .to_resolved()
224 .await?;
225 let next_node_shared_runtime_plugin =
226 NextNodeSharedRuntimeResolvePlugin::new(project_path.clone(), ty.clone())
227 .to_resolved()
228 .await?;
229
230 let after_resolve_plugins = match ty {
231 ServerContextType::Pages { .. } | ServerContextType::PagesApi { .. } => {
232 vec![
233 ResolvedVc::upcast(next_node_shared_runtime_plugin),
234 ResolvedVc::upcast(external_cjs_modules_plugin),
235 ResolvedVc::upcast(next_external_plugin),
236 ]
237 }
238 ServerContextType::AppSSR { .. }
239 | ServerContextType::AppRSC { .. }
240 | ServerContextType::AppRoute { .. } => {
241 vec![
242 ResolvedVc::upcast(next_node_shared_runtime_plugin),
243 ResolvedVc::upcast(server_external_packages_plugin),
244 ResolvedVc::upcast(next_external_plugin),
245 ]
246 }
247 ServerContextType::Middleware { .. } | ServerContextType::Instrumentation { .. } => {
248 vec![
249 ResolvedVc::upcast(next_node_shared_runtime_plugin),
250 ResolvedVc::upcast(server_external_packages_plugin),
251 ResolvedVc::upcast(next_external_plugin),
252 ]
253 }
254 };
255
256 let resolve_options_context = ResolveOptionsContext {
257 enable_node_modules: Some(root_dir.clone()),
258 enable_node_externals: true,
259 enable_node_native_modules: true,
260 module: true,
261 custom_conditions,
262 import_map: Some(next_server_import_map),
263 fallback_import_map: Some(next_server_fallback_import_map),
264 server_relative_root: Some(project_path.clone()),
267 after_resolve_plugins,
268 ..Default::default()
269 };
270
271 let tsconfig_path = next_config.typescript_tsconfig_path().await?;
272 let tsconfig_path = project_path.join(
273 tsconfig_path
274 .as_ref()
275 .unwrap_or(&rcstr!("tsconfig.json")),
278 )?;
279
280 Ok(ResolveOptionsContext {
281 enable_typescript: true,
282 enable_react: true,
283 enable_mjs_extension: true,
284 custom_extensions: next_config.resolve_extension().owned().await?,
285 tsconfig_path: TsConfigHandling::Fixed(tsconfig_path),
286 rules: vec![(
287 foreign_code_context_condition,
288 resolve_options_context.clone().resolved_cell(),
289 )],
290 ..resolve_options_context
291 }
292 .cell())
293}
294
295#[turbo_tasks::function]
296async fn next_server_defines(define_env: Vc<OptionEnvMap>) -> Result<Vc<CompileTimeDefines>> {
297 Ok(defines(&*define_env.await?).cell())
298}
299
300#[turbo_tasks::function]
301async fn next_server_free_vars(
302 define_env: Vc<OptionEnvMap>,
303 report_system_env_inlining: Vc<IssueSeverity>,
304) -> Result<Vc<FreeVarReferences>> {
305 Ok(free_var_references_with_vercel_system_env_warnings(
306 defines(&*define_env.await?),
307 *report_system_env_inlining.await?,
308 )
309 .cell())
310}
311
312#[turbo_tasks::function]
313pub async fn get_server_compile_time_info(
314 cwd: Vc<FileSystemPath>,
315 define_env: Vc<OptionEnvMap>,
316 node_version: ResolvedVc<NodeJsVersion>,
317 report_system_env_inlining: Vc<IssueSeverity>,
318 hot_module_replacement_enabled: bool,
319 import_meta_env_base_url: RcStr,
320) -> Result<Vc<CompileTimeInfo>> {
321 CompileTimeInfo::builder(
322 Environment::new(ExecutionEnvironment::NodeJsLambda(
323 NodeJsEnvironment {
324 compile_target: CompileTarget::current().to_resolved().await?,
325 node_version,
326 cwd: ResolvedVc::cell(Some(cwd.owned().await?)),
327 }
328 .resolved_cell(),
329 ))
330 .to_resolved()
331 .await?,
332 )
333 .defines(next_server_defines(define_env).to_resolved().await?)
334 .free_var_references(
335 next_server_free_vars(define_env, report_system_env_inlining)
336 .to_resolved()
337 .await?,
338 )
339 .hot_module_replacement_enabled(hot_module_replacement_enabled)
340 .import_meta_env_base_url(import_meta_env_base_url)
341 .cell()
342 .await
343}
344
345#[turbo_tasks::function]
346pub async fn get_tracing_compile_time_info() -> Result<Vc<CompileTimeInfo>> {
347 CompileTimeInfo::builder(
348 Environment::new(ExecutionEnvironment::NodeJsLambda(
349 NodeJsEnvironment::default().resolved_cell(),
350 ))
351 .to_resolved()
352 .await?,
353 )
354 .defines(
378 compile_time_defines!(
379 process.env.TURBOPACK = "1",
380 )
382 .resolved_cell(),
383 )
384 .cell()
385 .await
386}
387
388#[turbo_tasks::function]
389pub async fn get_server_module_options_context(
390 project_path: FileSystemPath,
391 execution_context: ResolvedVc<ExecutionContext>,
392 ty: ServerContextType,
393 mode: Vc<NextMode>,
394 next_config: Vc<NextConfig>,
395 next_runtime: NextRuntime,
396 encryption_key: ResolvedVc<RcStr>,
397 environment: ResolvedVc<Environment>,
398 client_environment: ResolvedVc<Environment>,
399 enable_tracing: bool,
400) -> Result<Vc<ModuleOptionsContext>> {
401 let next_mode = mode.await?;
402 let mut next_server_rules = get_next_server_transforms_rules(
403 next_config,
404 ty.clone(),
405 mode,
406 false,
407 next_runtime,
408 encryption_key,
409 )
410 .await?;
411 let mut foreign_next_server_rules = get_next_server_transforms_rules(
412 next_config,
413 ty.clone(),
414 mode,
415 true,
416 next_runtime,
417 encryption_key,
418 )
419 .await?;
420 let mut internal_custom_rules = get_next_server_internal_transforms_rules(
421 ty.clone(),
422 next_config.mdx_rs().await?.is_some(),
423 )
424 .await?;
425
426 let foreign_code_context_condition =
427 foreign_code_context_condition(next_config, project_path.clone()).await?;
428 let local_postcss_config = *next_config
429 .experimental_turbopack_local_postcss_config()
430 .await?;
431 let postcss_config_location = if local_postcss_config == Some(true) {
432 PostCssConfigLocation::LocalPathOrProjectPath
433 } else {
434 PostCssConfigLocation::ProjectPathOrLocalPath
435 };
436 let postcss_transform_options = PostCssTransformOptions {
437 postcss_package: Some(
438 get_postcss_package_mapping(project_path.clone())
439 .to_resolved()
440 .await?,
441 ),
442 config_location: postcss_config_location,
443 ..Default::default()
444 };
445 let postcss_foreign_transform_options = PostCssTransformOptions {
446 config_location: PostCssConfigLocation::ProjectPath,
450 ..postcss_transform_options.clone()
451 };
452 let enable_postcss_transform = Some(postcss_transform_options.resolved_cell());
453 let enable_foreign_postcss_transform = Some(postcss_foreign_transform_options.resolved_cell());
454
455 let mut loader_conditions = BTreeSet::new();
456 loader_conditions.extend(mode.await?.webpack_loader_conditions());
457 loader_conditions.extend(next_runtime.webpack_loader_conditions());
458
459 let mut foreign_conditions = loader_conditions.clone();
463 foreign_conditions.insert(WebpackLoaderBuiltinCondition::Foreign);
464 let foreign_enable_webpack_loaders =
465 *webpack_loader_options(project_path.clone(), next_config, foreign_conditions).await?;
466
467 let enable_webpack_loaders =
469 *webpack_loader_options(project_path.clone(), next_config, loader_conditions).await?;
470
471 let module_fragments_enabled_for_user_code = *next_config
472 .module_fragments_enabled_for_user_code(next_mode.is_development())
473 .await?;
474 let module_fragments_enabled_for_foreign_code = *next_config
475 .module_fragments_enabled_for_foreign_code(next_mode.is_development())
476 .await?;
477
478 let tsconfig_path = next_config
479 .typescript_tsconfig_path()
480 .await?
481 .as_ref()
482 .map(|p| project_path.join(p))
483 .transpose()?;
484
485 let tsconfig = get_typescript_transform_options(project_path.clone(), tsconfig_path.clone())
487 .to_resolved()
488 .await?;
489 let decorators_options =
490 get_decorators_transform_options(project_path.clone(), tsconfig_path.clone());
491 let enable_mdx_rs = *next_config.mdx_rs().await?;
492
493 let jsx_runtime_options = get_jsx_transform_options(
501 project_path.clone(),
502 mode,
503 None,
504 false,
505 next_config,
506 tsconfig_path.clone(),
507 )
508 .to_resolved()
509 .await?;
510 let rsc_jsx_runtime_options = get_jsx_transform_options(
511 project_path.clone(),
512 mode,
513 None,
514 true,
515 next_config,
516 tsconfig_path,
517 )
518 .to_resolved()
519 .await?;
520
521 let source_transform_rules: Vec<ModuleRule> = vec![
523 get_remove_console_transform_rule(next_config).await?,
524 get_react_remove_properties_transform_rule(next_config).await?,
525 get_emotion_transform_rule(next_config).await?,
526 get_relay_transform_rule(next_config, project_path.clone()).await?,
527 get_swc_ecma_transform_plugin_rule(next_config, project_path.clone()).await?,
528 ]
529 .into_iter()
530 .flatten()
531 .collect();
532
533 let page_transform_rules: Vec<ModuleRule> = vec![
535 get_styled_components_transform_rule(next_config).await?,
536 get_styled_jsx_transform_rule(next_config, client_environment.runtime_versions()).await?,
539 ]
540 .into_iter()
541 .flatten()
542 .collect();
543
544 let source_maps = *next_config.server_source_maps().await?;
545 let module_options_context = ModuleOptionsContext {
546 ecmascript: EcmascriptOptionsContext {
547 enable_typeof_window_inlining: Some(TypeofWindow::Undefined),
548 enable_import_as_bytes: *next_config.turbopack_import_type_bytes().await?,
549 import_externals: *next_config.import_externals().await?,
550 ignore_dynamic_requests: true,
551 source_maps,
552 infer_module_side_effects: *next_config.turbopack_infer_module_side_effects().await?,
553 cjs_tree_shaking: *next_config.turbopack_cjs_tree_shaking().await?,
554 mangle_export_names: *next_config.turbopack_mangle_export_names(mode).await?,
555 cjs_scope_hoisting: *next_config.turbopack_cjs_scope_hoisting().await?,
556 cross_module_constants: *next_config.turbopack_cross_module_constants().await?,
557 ..Default::default()
558 },
559 execution_context: Some(execution_context),
560 environment: Some(environment),
561 css: CssOptionsContext {
562 source_maps,
563 module_css_condition: Some(module_styles_rule_condition()),
564 lightningcss_features: *next_config.lightningcss_feature_flags().await?,
565 module_css_debuggable_idents: next_mode.is_development(),
566 ..Default::default()
567 },
568 follow_reexports: true,
569 module_fragments_enabled: module_fragments_enabled_for_user_code,
570 side_effect_free_packages: Some(
571 side_effect_free_packages_glob(next_config.optimize_package_imports())
572 .to_resolved()
573 .await?,
574 ),
575 analyze_mode: if enable_tracing {
576 AnalyzeMode::CodeGenerationAndTracing
577 } else {
578 AnalyzeMode::CodeGeneration
579 },
580 enable_externals_tracing: if enable_tracing {
581 Some(
582 ExternalsTracingOptions {
583 tracing_root: project_path,
584 compile_time_info: get_tracing_compile_time_info().to_resolved().await?,
585 }
586 .resolved_cell(),
587 )
588 } else {
589 None
590 },
591 keep_last_successful_parse: next_mode.is_development(),
592
593 ..Default::default()
594 };
595
596 let module_options_context = match ty {
597 ServerContextType::Pages { .. } | ServerContextType::PagesApi { .. } => {
598 next_server_rules.extend(source_transform_rules);
599 if let ServerContextType::Pages { .. } = ty {
600 next_server_rules.push(
601 get_next_react_server_components_transform_rule(next_config, false, None)
602 .await?,
603 );
604 }
605 next_server_rules.extend(page_transform_rules);
606
607 foreign_next_server_rules.extend(internal_custom_rules);
608
609 let (url_rewrite_behavior, static_url_tag) = {
610 if let ServerContextType::PagesApi { .. } = ty {
612 (Some(UrlRewriteBehavior::Full), None)
613 } else {
614 (Some(UrlRewriteBehavior::Relative), Some(rcstr!("client")))
615 }
616 };
617
618 let module_options_context = ModuleOptionsContext {
619 ecmascript: EcmascriptOptionsContext {
620 esm_url_rewrite_behavior: url_rewrite_behavior,
621 ..module_options_context.ecmascript
622 },
623 static_url_tag,
624 ..module_options_context
625 };
626
627 let foreign_code_module_options_context = ModuleOptionsContext {
628 module_rules: foreign_next_server_rules.clone(),
629 enable_webpack_loaders: foreign_enable_webpack_loaders,
630 enable_postcss_transform: enable_foreign_postcss_transform,
632 follow_reexports: true,
633 module_fragments_enabled: module_fragments_enabled_for_foreign_code,
634 ..module_options_context.clone()
635 };
636
637 let internal_module_options_context = ModuleOptionsContext {
638 ecmascript: EcmascriptOptionsContext {
639 enable_typescript_transform: Some(
640 TypescriptTransformOptions::default().resolved_cell(),
641 ),
642 enable_jsx: Some(JsxTransformOptions::default().resolved_cell()),
643 ..module_options_context.ecmascript.clone()
644 },
645 module_rules: foreign_next_server_rules,
646 ..module_options_context.clone()
647 };
648
649 ModuleOptionsContext {
650 ecmascript: EcmascriptOptionsContext {
651 enable_jsx: Some(jsx_runtime_options),
652 enable_typescript_transform: Some(tsconfig),
653 enable_decorators: Some(decorators_options.to_resolved().await?),
654 enable_rust_react_compiler: None,
655 ..module_options_context.ecmascript
656 },
657 enable_webpack_loaders,
658 enable_postcss_transform,
659 enable_mdx_rs,
660 rules: vec![
661 (
662 foreign_code_context_condition,
663 foreign_code_module_options_context.resolved_cell(),
664 ),
665 (
666 internal_assets_conditions().await?,
667 internal_module_options_context.resolved_cell(),
668 ),
669 ],
670 module_rules: next_server_rules,
671 ..module_options_context
672 }
673 }
674 ServerContextType::AppSSR { app_dir, .. } => {
675 foreign_next_server_rules.extend(internal_custom_rules);
676
677 next_server_rules.extend(source_transform_rules);
678 next_server_rules.push(
679 get_next_react_server_components_transform_rule(next_config, false, Some(app_dir))
680 .await?,
681 );
682 next_server_rules.extend(page_transform_rules.clone());
683
684 let module_options_context = ModuleOptionsContext {
685 ecmascript: EcmascriptOptionsContext {
686 esm_url_rewrite_behavior: Some(UrlRewriteBehavior::Relative),
687 ..module_options_context.ecmascript
688 },
689 static_url_tag: Some(rcstr!("client")),
690 ..module_options_context
691 };
692
693 let foreign_code_module_options_context = ModuleOptionsContext {
694 module_rules: foreign_next_server_rules.clone(),
695 enable_webpack_loaders: foreign_enable_webpack_loaders,
696 enable_postcss_transform: enable_foreign_postcss_transform,
698 follow_reexports: true,
699 module_fragments_enabled: module_fragments_enabled_for_foreign_code,
700 ..module_options_context.clone()
701 };
702 let internal_module_options_context = ModuleOptionsContext {
703 ecmascript: EcmascriptOptionsContext {
704 enable_typescript_transform: Some(
705 TypescriptTransformOptions::default().resolved_cell(),
706 ),
707 ..module_options_context.ecmascript.clone()
708 },
709 module_rules: foreign_next_server_rules,
710 ..module_options_context.clone()
711 };
712
713 ModuleOptionsContext {
714 ecmascript: EcmascriptOptionsContext {
715 enable_jsx: Some(jsx_runtime_options),
716 enable_typescript_transform: Some(tsconfig),
717 enable_decorators: Some(decorators_options.to_resolved().await?),
718 enable_rust_react_compiler: None,
720 ..module_options_context.ecmascript
721 },
722 enable_webpack_loaders,
723 enable_postcss_transform,
724 enable_mdx_rs,
725 rules: vec![
726 (
727 foreign_code_context_condition,
728 foreign_code_module_options_context.resolved_cell(),
729 ),
730 (
731 internal_assets_conditions().await?,
732 internal_module_options_context.resolved_cell(),
733 ),
734 ],
735 module_rules: next_server_rules,
736 ..module_options_context
737 }
738 }
739 ServerContextType::AppRSC {
740 app_dir,
741 ecmascript_client_reference_transition_name,
742 ..
743 } => {
744 let client_directive_transformer =
745 if let Some(name) = ecmascript_client_reference_transition_name {
746 Some(get_ecma_transform_rule(
747 client_directive_transform_plugin(name)
748 .to_resolved()
749 .await?,
750 enable_mdx_rs.is_some(),
751 EcmascriptTransformStage::Preprocess,
752 ))
753 } else {
754 None
755 };
756
757 foreign_next_server_rules.extend(internal_custom_rules);
758 foreign_next_server_rules.extend(client_directive_transformer.clone());
759
760 next_server_rules.extend(source_transform_rules);
761 next_server_rules.push(
762 get_next_react_server_components_transform_rule(next_config, true, Some(app_dir))
763 .await?,
764 );
765 next_server_rules.extend(client_directive_transformer.clone());
766 next_server_rules.extend(page_transform_rules);
767
768 let module_options_context = ModuleOptionsContext {
769 ecmascript: EcmascriptOptionsContext {
770 esm_url_rewrite_behavior: Some(UrlRewriteBehavior::Relative),
771 ..module_options_context.ecmascript
772 },
773 static_url_tag: Some(rcstr!("client")),
774 ..module_options_context
775 };
776
777 let foreign_code_module_options_context = ModuleOptionsContext {
778 module_rules: foreign_next_server_rules.clone(),
779 enable_webpack_loaders: foreign_enable_webpack_loaders,
780 enable_postcss_transform: enable_foreign_postcss_transform,
782 follow_reexports: true,
783 module_fragments_enabled: module_fragments_enabled_for_foreign_code,
784 ..module_options_context.clone()
785 };
786 let internal_module_options_context = ModuleOptionsContext {
787 ecmascript: EcmascriptOptionsContext {
788 enable_typescript_transform: Some(
789 TypescriptTransformOptions::default().resolved_cell(),
790 ),
791 ..module_options_context.ecmascript.clone()
792 },
793 module_rules: foreign_next_server_rules,
794 ..module_options_context.clone()
795 };
796 ModuleOptionsContext {
797 ecmascript: EcmascriptOptionsContext {
798 enable_jsx: Some(rsc_jsx_runtime_options),
799 enable_typescript_transform: Some(tsconfig),
800 enable_decorators: Some(decorators_options.to_resolved().await?),
801 enable_rust_react_compiler: None,
802 ..module_options_context.ecmascript
803 },
804 enable_webpack_loaders,
805 enable_postcss_transform,
806 enable_mdx_rs,
807 rules: vec![
808 (
809 foreign_code_context_condition,
810 foreign_code_module_options_context.resolved_cell(),
811 ),
812 (
813 internal_assets_conditions().await?,
814 internal_module_options_context.resolved_cell(),
815 ),
816 ],
817 module_rules: next_server_rules,
818 ..module_options_context
819 }
820 }
821 ServerContextType::AppRoute {
822 app_dir,
823 ecmascript_client_reference_transition_name,
824 } => {
825 let mut common_next_server_rules = vec![
826 get_next_react_server_components_transform_rule(next_config, true, Some(app_dir))
827 .await?,
828 ];
829
830 if let Some(ecmascript_client_reference_transition_name) =
831 ecmascript_client_reference_transition_name
832 {
833 common_next_server_rules.push(get_ecma_transform_rule(
834 client_directive_transform_plugin(ecmascript_client_reference_transition_name)
835 .to_resolved()
836 .await?,
837 enable_mdx_rs.is_some(),
838 EcmascriptTransformStage::Preprocess,
839 ));
840 }
841
842 next_server_rules.extend(common_next_server_rules.iter().cloned());
843 internal_custom_rules.extend(common_next_server_rules);
844 foreign_next_server_rules.extend(internal_custom_rules.clone());
845
846 next_server_rules.extend(source_transform_rules);
847
848 let module_options_context = ModuleOptionsContext {
849 ecmascript: EcmascriptOptionsContext {
850 esm_url_rewrite_behavior: Some(UrlRewriteBehavior::Full),
851 ..module_options_context.ecmascript
852 },
853 ..module_options_context
854 };
855 let foreign_code_module_options_context = ModuleOptionsContext {
856 module_rules: foreign_next_server_rules.clone(),
857 enable_webpack_loaders: foreign_enable_webpack_loaders,
858 enable_postcss_transform: enable_foreign_postcss_transform,
860 follow_reexports: true,
861 module_fragments_enabled: module_fragments_enabled_for_foreign_code,
862 ..module_options_context.clone()
863 };
864 let internal_module_options_context = ModuleOptionsContext {
865 ecmascript: EcmascriptOptionsContext {
866 enable_typescript_transform: Some(
867 TypescriptTransformOptions::default().resolved_cell(),
868 ),
869 ..module_options_context.ecmascript.clone()
870 },
871 module_rules: internal_custom_rules,
872 ..module_options_context.clone()
873 };
874 ModuleOptionsContext {
875 ecmascript: EcmascriptOptionsContext {
876 enable_jsx: Some(rsc_jsx_runtime_options),
877 enable_typescript_transform: Some(tsconfig),
878 enable_decorators: Some(decorators_options.to_resolved().await?),
879 enable_rust_react_compiler: None,
880 ..module_options_context.ecmascript
881 },
882 enable_webpack_loaders,
883 enable_postcss_transform,
884 enable_mdx_rs,
885 rules: vec![
886 (
887 foreign_code_context_condition,
888 foreign_code_module_options_context.resolved_cell(),
889 ),
890 (
891 internal_assets_conditions().await?,
892 internal_module_options_context.resolved_cell(),
893 ),
894 ],
895 module_rules: next_server_rules,
896 ..module_options_context
897 }
898 }
899 ServerContextType::Middleware {
900 app_dir,
901 ecmascript_client_reference_transition_name,
902 }
903 | ServerContextType::Instrumentation {
904 app_dir,
905 ecmascript_client_reference_transition_name,
906 } => {
907 let directive_transform_rule =
908 if let Some(name) = ecmascript_client_reference_transition_name {
909 get_ecma_transform_rule(
910 client_directive_transform_plugin(name)
911 .to_resolved()
912 .await?,
913 enable_mdx_rs.is_some(),
914 EcmascriptTransformStage::Preprocess,
915 )
916 } else {
917 get_ecma_transform_rule(
918 client_disallowed_directive_transform_plugin(rcstr!(
919 "next/dist/client/use-client-disallowed.js"
920 ))
921 .to_resolved()
922 .await?,
923 enable_mdx_rs.is_some(),
924 EcmascriptTransformStage::Preprocess,
925 )
926 };
927 let custom_source_transform_rules: Vec<ModuleRule> = vec![
928 directive_transform_rule,
929 get_next_react_server_components_transform_rule(next_config, true, app_dir).await?,
930 ];
931
932 internal_custom_rules.extend(custom_source_transform_rules.iter().cloned());
933
934 next_server_rules.extend(custom_source_transform_rules);
935 next_server_rules.extend(source_transform_rules);
936
937 let module_options_context = ModuleOptionsContext {
938 ecmascript: EcmascriptOptionsContext {
939 esm_url_rewrite_behavior: Some(UrlRewriteBehavior::Full),
940 ..module_options_context.ecmascript
941 },
942 ..module_options_context
943 };
944 let foreign_code_module_options_context = ModuleOptionsContext {
945 module_rules: internal_custom_rules.clone(),
946 enable_webpack_loaders: foreign_enable_webpack_loaders,
947 enable_postcss_transform: enable_foreign_postcss_transform,
949 follow_reexports: true,
950 module_fragments_enabled: module_fragments_enabled_for_foreign_code,
951 ..module_options_context.clone()
952 };
953 let internal_module_options_context = ModuleOptionsContext {
954 ecmascript: EcmascriptOptionsContext {
955 enable_typescript_transform: Some(
956 TypescriptTransformOptions::default().resolved_cell(),
957 ),
958 ..module_options_context.ecmascript.clone()
959 },
960 module_rules: internal_custom_rules,
961 ..module_options_context.clone()
962 };
963 ModuleOptionsContext {
964 ecmascript: EcmascriptOptionsContext {
965 enable_jsx: Some(jsx_runtime_options),
966 enable_typescript_transform: Some(tsconfig),
967 enable_decorators: Some(decorators_options.to_resolved().await?),
968 enable_rust_react_compiler: None,
969 ..module_options_context.ecmascript
970 },
971 enable_webpack_loaders,
972 enable_postcss_transform,
973 enable_mdx_rs,
974 rules: vec![
975 (
976 foreign_code_context_condition,
977 foreign_code_module_options_context.resolved_cell(),
978 ),
979 (
980 internal_assets_conditions().await?,
981 internal_module_options_context.resolved_cell(),
982 ),
983 ],
984 module_rules: next_server_rules,
985 ..module_options_context
986 }
987 }
988 }
989 .cell();
990
991 Ok(module_options_context)
992}
993
994#[turbo_tasks::function]
995fn client_directive_transform_plugin(transition_name: RcStr) -> Vc<TransformPlugin> {
996 Vc::cell(Box::new(ClientDirectiveTransformer::new(transition_name))
997 as Box<dyn CustomTransformer + Send + Sync>)
998}
999
1000#[turbo_tasks::function]
1001fn client_disallowed_directive_transform_plugin(error_proxy_module: RcStr) -> Vc<TransformPlugin> {
1002 Vc::cell(Box::new(ClientDisallowedDirectiveTransformer::new(
1003 error_proxy_module.to_string(),
1004 )) as Box<dyn CustomTransformer + Send + Sync>)
1005}
1006
1007#[turbo_tasks::task_input(contains_unresolved_vcs)]
1008#[derive(Clone, Debug, PartialEq, Eq, Hash, TraceRawVcs, Encode, Decode)]
1009pub struct ServerChunkingContextOptions {
1010 pub mode: Vc<NextMode>,
1011 pub root_path: FileSystemPath,
1012 pub node_root: FileSystemPath,
1013 pub node_root_to_root_path: RcStr,
1014 pub environment: Vc<Environment>,
1015 pub module_id_strategy: Vc<ModuleIdStrategy>,
1016 pub export_usage: Vc<OptionBindingUsageInfo>,
1017 pub unused_references: Vc<UnusedReferences>,
1018 pub minify: Vc<bool>,
1019 pub source_maps: Vc<SourceMapsType>,
1020 pub no_mangling: Vc<bool>,
1021 pub scope_hoisting: Vc<bool>,
1022 pub nested_async_chunking: Vc<bool>,
1023 pub debug_ids: Vc<bool>,
1024 pub client_root: FileSystemPath,
1025 pub client_static_folder_name: RcStr,
1026 pub asset_prefix: RcStr,
1027 pub css_url_suffix: Vc<Option<RcStr>>,
1028 pub hash_salt: ResolvedVc<RcStr>,
1029 pub style_groups_algorithm: StyleGroupsAlgorithm,
1030 pub per_page_module_graph: Vc<bool>,
1031}
1032
1033#[turbo_tasks::function]
1035pub async fn get_server_chunking_context_with_client_assets(
1036 options: ServerChunkingContextOptions,
1037) -> Result<Vc<NodeJsChunkingContext>> {
1038 let ServerChunkingContextOptions {
1039 mode,
1040 root_path,
1041 node_root,
1042 node_root_to_root_path,
1043 environment,
1044 module_id_strategy,
1045 export_usage,
1046 unused_references,
1047 minify,
1048 source_maps,
1049 no_mangling,
1050 scope_hoisting,
1051 nested_async_chunking,
1052 debug_ids,
1053 client_root,
1054 client_static_folder_name,
1055 asset_prefix,
1056 css_url_suffix,
1057 hash_salt,
1058 style_groups_algorithm,
1059 per_page_module_graph,
1060 } = options;
1061 let css_url_suffix = css_url_suffix.to_resolved().await?;
1062
1063 let next_mode = mode.await?;
1064 let mut builder = NodeJsChunkingContext::builder(
1068 root_path,
1069 node_root.clone(),
1070 node_root_to_root_path,
1071 client_root.clone(),
1072 node_root.join("server/chunks/ssr")?,
1073 client_root
1074 .join(&client_static_folder_name)?
1075 .join("media")?,
1076 environment.to_resolved().await?,
1077 next_mode.runtime_type(),
1078 )
1079 .asset_prefix(Some(asset_prefix))
1080 .url_behavior_override(
1081 rcstr!("client"),
1082 UrlBehavior {
1083 suffix: AssetSuffix::FromGlobal(rcstr!("NEXT_CLIENT_ASSET_SUFFIX")),
1084 static_suffix: css_url_suffix,
1085 },
1086 )
1087 .default_url_behavior(UrlBehavior {
1088 suffix: AssetSuffix::Inferred,
1089 static_suffix: ResolvedVc::cell(None),
1090 })
1091 .minify_type(if *minify.await? {
1092 MinifyType::Minify {
1093 mangle: (!*no_mangling.await?).then_some(MangleType::Deterministic),
1095 }
1096 } else {
1097 MinifyType::NoMinify
1098 })
1099 .source_maps(*source_maps.await?)
1100 .module_id_strategy(module_id_strategy.to_resolved().await?)
1101 .export_usage(*export_usage.await?)
1102 .unused_references(unused_references.to_resolved().await?)
1103 .debug_ids(*debug_ids.await?)
1104 .hash_salt(hash_salt)
1105 .nested_async_availability(*nested_async_chunking.await?)
1106 .shared_runtime_chunk(*per_page_module_graph.await?)
1109 .worker_forwarded_globals(worker_forwarded_globals());
1110
1111 builder = builder.source_map_source_type(if next_mode.is_development() {
1112 SourceMapSourceType::AbsoluteFileUri
1113 } else {
1114 SourceMapSourceType::RelativeUri
1115 });
1116 if next_mode.is_production() {
1117 builder = builder
1118 .chunking_config(
1119 Vc::<EcmascriptChunkType>::default().to_resolved().await?,
1120 ChunkingConfig {
1121 min_chunk_size: 20_000,
1122 max_chunk_count_per_group: 100,
1123 max_merge_chunk_size: 100_000,
1124 ..Default::default()
1125 },
1126 )
1127 .chunking_config(
1128 Vc::<CssChunkType>::default().to_resolved().await?,
1129 ChunkingConfig {
1130 max_merge_chunk_size: 100_000,
1131 style_groups_algorithm: style_groups_algorithm.clone(),
1132 ..Default::default()
1133 },
1134 )
1135 .module_merging(*scope_hoisting.await?);
1136 }
1137
1138 Ok(builder.build())
1139}
1140
1141#[turbo_tasks::function]
1143pub async fn get_server_chunking_context(
1144 options: ServerChunkingContextOptions,
1145) -> Result<Vc<NodeJsChunkingContext>> {
1146 let ServerChunkingContextOptions {
1147 mode,
1148 root_path,
1149 node_root,
1150 node_root_to_root_path,
1151 environment,
1152 module_id_strategy,
1153 export_usage,
1154 unused_references,
1155 minify,
1156 source_maps,
1157 no_mangling,
1158 scope_hoisting,
1159 nested_async_chunking,
1160 debug_ids,
1161 client_root,
1162 client_static_folder_name,
1163 asset_prefix,
1164 css_url_suffix,
1165 hash_salt,
1166 style_groups_algorithm,
1167 per_page_module_graph,
1168 } = options;
1169 let css_url_suffix = css_url_suffix.to_resolved().await?;
1170 let next_mode = mode.await?;
1171 let mut builder = NodeJsChunkingContext::builder(
1175 root_path,
1176 node_root.clone(),
1177 node_root_to_root_path,
1178 node_root.clone(),
1179 node_root.join("server/chunks")?,
1180 node_root.join("server/assets")?,
1181 environment.to_resolved().await?,
1182 next_mode.runtime_type(),
1183 )
1184 .client_roots_override(rcstr!("client"), client_root.clone())
1185 .asset_root_path_override(
1186 rcstr!("client"),
1187 client_root
1188 .join(&client_static_folder_name)?
1189 .join("media")?,
1190 )
1191 .asset_prefix_override(rcstr!("client"), asset_prefix)
1192 .url_behavior_override(
1193 rcstr!("client"),
1194 UrlBehavior {
1195 suffix: AssetSuffix::FromGlobal(rcstr!("NEXT_CLIENT_ASSET_SUFFIX")),
1196 static_suffix: css_url_suffix,
1197 },
1198 )
1199 .default_url_behavior(UrlBehavior {
1200 suffix: AssetSuffix::Inferred,
1201 static_suffix: ResolvedVc::cell(None),
1202 })
1203 .minify_type(if *minify.await? {
1204 MinifyType::Minify {
1205 mangle: (!*no_mangling.await?).then_some(MangleType::OptimalSize),
1206 }
1207 } else {
1208 MinifyType::NoMinify
1209 })
1210 .source_maps(*source_maps.await?)
1211 .module_id_strategy(module_id_strategy.to_resolved().await?)
1212 .export_usage(*export_usage.await?)
1213 .unused_references(unused_references.to_resolved().await?)
1214 .debug_ids(*debug_ids.await?)
1215 .hash_salt(hash_salt)
1216 .nested_async_availability(*nested_async_chunking.await?)
1217 .shared_runtime_chunk(*per_page_module_graph.await?)
1220 .worker_forwarded_globals(worker_forwarded_globals());
1221
1222 if next_mode.is_development() {
1223 builder = builder.source_map_source_type(SourceMapSourceType::AbsoluteFileUri);
1224 } else {
1225 builder = builder
1226 .source_map_source_type(SourceMapSourceType::RelativeUri)
1227 .chunking_config(
1228 Vc::<EcmascriptChunkType>::default().to_resolved().await?,
1229 ChunkingConfig {
1230 min_chunk_size: 20_000,
1231 max_chunk_count_per_group: 100,
1232 max_merge_chunk_size: 100_000,
1233 ..Default::default()
1234 },
1235 )
1236 .chunking_config(
1237 Vc::<CssChunkType>::default().to_resolved().await?,
1238 ChunkingConfig {
1239 max_merge_chunk_size: 100_000,
1240 style_groups_algorithm: style_groups_algorithm.clone(),
1241 ..Default::default()
1242 },
1243 )
1244 .module_merging(*scope_hoisting.await?);
1245 }
1246
1247 Ok(builder.build())
1248}