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