1use std::collections::BTreeSet;
2
3use anyhow::{Result, bail};
4use bincode::{Decode, Encode};
5use turbo_rcstr::{RcStr, rcstr};
6use turbo_tasks::{ResolvedVc, TaskInput, 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 ChunkingConfig, MangleType, MinifyType, SourceMapSourceType, SourceMapsType,
19 module_id_strategies::ModuleIdStrategy,
20 },
21 compile_time_defines,
22 compile_time_info::{CompileTimeDefines, CompileTimeInfo, FreeVarReferences},
23 environment::{Environment, ExecutionEnvironment, NodeJsEnvironment, NodeJsVersion},
24 free_var_references,
25 module_graph::binding_usage_info::OptionBindingUsageInfo,
26 target::CompileTarget,
27};
28use turbopack_css::chunk::CssChunkType;
29use turbopack_ecmascript::{
30 AnalyzeMode, TypeofWindow, chunk::EcmascriptChunkType, references::esm::UrlRewriteBehavior,
31};
32use turbopack_ecmascript_plugins::transform::directives::{
33 client::ClientDirectiveTransformer, client_disallowed::ClientDisallowedDirectiveTransformer,
34};
35use turbopack_node::{
36 execution_context::ExecutionContext,
37 transforms::postcss::{PostCssConfigLocation, PostCssTransformOptions},
38};
39use turbopack_nodejs::NodeJsChunkingContext;
40use turbopack_resolve::resolve_options_context::ResolveOptionsContext;
41
42use crate::{
43 app_structure::CollectedRootParams,
44 mode::NextMode,
45 next_build::get_postcss_package_mapping,
46 next_config::NextConfig,
47 next_font::local::NextFontLocalResolvePlugin,
48 next_import_map::{get_next_edge_and_server_fallback_import_map, get_next_server_import_map},
49 next_server::{
50 resolve::{ExternalCjsModulesResolvePlugin, ExternalPredicate},
51 transforms::{get_next_server_internal_transforms_rules, get_next_server_transforms_rules},
52 },
53 next_shared::{
54 resolve::{
55 ModuleFeatureReportResolvePlugin, NextExternalResolvePlugin,
56 NextNodeSharedRuntimeResolvePlugin, get_invalid_client_only_resolve_plugin,
57 get_invalid_styled_jsx_resolve_plugin,
58 },
59 transforms::{
60 EcmascriptTransformStage, emotion::get_emotion_transform_rule, get_ecma_transform_rule,
61 next_react_server_components::get_next_react_server_components_transform_rule,
62 react_remove_properties::get_react_remove_properties_transform_rule,
63 relay::get_relay_transform_rule, remove_console::get_remove_console_transform_rule,
64 styled_components::get_styled_components_transform_rule,
65 styled_jsx::get_styled_jsx_transform_rule,
66 swc_ecma_transform_plugins::get_swc_ecma_transform_plugin_rule,
67 },
68 webpack_rules::{WebpackLoaderBuiltinCondition, webpack_loader_options},
69 },
70 transform_options::{
71 get_decorators_transform_options, get_jsx_transform_options,
72 get_typescript_transform_options,
73 },
74 util::{
75 NextRuntime, OptionEnvMap, defines, foreign_code_context_condition,
76 get_transpiled_packages, internal_assets_conditions, load_next_js_jsonc_file,
77 module_styles_rule_condition,
78 },
79};
80
81#[turbo_tasks::value(shared)]
82#[derive(Debug, Clone, Hash, TaskInput)]
83pub enum ServerContextType {
84 Pages {
85 pages_dir: FileSystemPath,
86 },
87 PagesApi {
88 pages_dir: FileSystemPath,
89 },
90 AppSSR {
91 app_dir: FileSystemPath,
92 },
93 AppRSC {
94 app_dir: FileSystemPath,
95 ecmascript_client_reference_transition_name: Option<RcStr>,
96 client_transition: Option<ResolvedVc<Box<dyn Transition>>>,
97 },
98 AppRoute {
99 app_dir: FileSystemPath,
100 ecmascript_client_reference_transition_name: Option<RcStr>,
101 },
102 Middleware {
103 app_dir: Option<FileSystemPath>,
104 ecmascript_client_reference_transition_name: Option<RcStr>,
105 },
106 Instrumentation {
107 app_dir: Option<FileSystemPath>,
108 ecmascript_client_reference_transition_name: Option<RcStr>,
109 },
110}
111
112impl ServerContextType {
113 pub fn should_use_react_server_condition(&self) -> bool {
114 matches!(
115 self,
116 ServerContextType::AppRSC { .. }
117 | ServerContextType::AppRoute { .. }
118 | ServerContextType::Middleware { .. }
119 | ServerContextType::Instrumentation { .. }
120 )
121 }
122}
123
124#[turbo_tasks::function]
125pub async fn get_server_resolve_options_context(
126 project_path: FileSystemPath,
127 ty: ServerContextType,
128 mode: Vc<NextMode>,
129 next_config: Vc<NextConfig>,
130 execution_context: Vc<ExecutionContext>,
131 collected_root_params: Option<Vc<CollectedRootParams>>,
132) -> Result<Vc<ResolveOptionsContext>> {
133 let next_server_import_map = get_next_server_import_map(
134 project_path.clone(),
135 ty.clone(),
136 next_config,
137 mode,
138 execution_context,
139 collected_root_params,
140 )
141 .to_resolved()
142 .await?;
143 let next_server_fallback_import_map =
144 get_next_edge_and_server_fallback_import_map(project_path.clone(), NextRuntime::NodeJs)
145 .to_resolved()
146 .await?;
147
148 let foreign_code_context_condition =
149 foreign_code_context_condition(next_config, project_path.clone()).await?;
150 let root_dir = project_path.root().owned().await?;
151 let module_feature_report_resolve_plugin =
152 ModuleFeatureReportResolvePlugin::new(project_path.clone())
153 .to_resolved()
154 .await?;
155 let invalid_client_only_resolve_plugin =
156 get_invalid_client_only_resolve_plugin(project_path.clone())
157 .to_resolved()
158 .await?;
159 let invalid_styled_jsx_client_only_resolve_plugin =
160 get_invalid_styled_jsx_resolve_plugin(project_path.clone())
161 .to_resolved()
162 .await?;
163
164 let mut external_packages: Vec<RcStr> = load_next_js_jsonc_file(
166 project_path.clone(),
167 rcstr!("dist/lib/server-external-packages.jsonc"),
168 )
169 .await?;
170
171 let mut transpiled_packages = get_transpiled_packages(next_config, project_path.clone())
172 .owned()
173 .await?;
174
175 transpiled_packages.extend(
176 (*next_config.optimize_package_imports().await?)
177 .iter()
178 .cloned(),
179 );
180
181 let server_external_packages = &*next_config.server_external_packages().await?;
182
183 let conflicting_packages = transpiled_packages
184 .iter()
185 .filter(|package| server_external_packages.contains(package))
186 .collect::<Vec<_>>();
187
188 if !conflicting_packages.is_empty() {
189 bail!(
190 "The packages specified in the 'transpilePackages' conflict with the \
191 'serverExternalPackages': {:?}",
192 conflicting_packages
193 );
194 }
195
196 external_packages.extend(server_external_packages.iter().cloned());
198
199 external_packages.retain(|item| !transpiled_packages.contains(item));
200
201 let server_external_packages_plugin = ExternalCjsModulesResolvePlugin::new(
202 project_path.root().owned().await?,
203 ExternalPredicate::Only(ResolvedVc::cell(external_packages)).cell(),
204 *next_config.import_externals().await?,
205 )
206 .to_resolved()
207 .await?;
208
209 let mut custom_conditions: Vec<_> = mode.await?.custom_resolve_conditions().collect();
210 custom_conditions.extend(NextRuntime::NodeJs.custom_resolve_conditions());
211
212 if ty.should_use_react_server_condition() {
213 custom_conditions.push(rcstr!("react-server"));
214 };
215
216 if *next_config.enable_cache_components().await?
217 && !matches!(ty, ServerContextType::Middleware { .. } | ServerContextType::Instrumentation { .. })
219 {
220 custom_conditions.push(rcstr!("next-js"));
221 };
222
223 let external_cjs_modules_plugin = if *next_config.bundle_pages_router_dependencies().await? {
224 server_external_packages_plugin
225 } else {
226 ExternalCjsModulesResolvePlugin::new(
227 project_path.root().owned().await?,
228 ExternalPredicate::AllExcept(ResolvedVc::cell(transpiled_packages)).cell(),
229 *next_config.import_externals().await?,
230 )
231 .to_resolved()
232 .await?
233 };
234
235 let next_external_plugin = NextExternalResolvePlugin::new(project_path.clone())
236 .to_resolved()
237 .await?;
238 let next_node_shared_runtime_plugin =
239 NextNodeSharedRuntimeResolvePlugin::new(project_path.clone(), ty.clone())
240 .to_resolved()
241 .await?;
242
243 let mut before_resolve_plugins = match &ty {
244 ServerContextType::Pages { .. }
245 | ServerContextType::AppSSR { .. }
246 | ServerContextType::AppRSC { .. } => {
247 vec![
248 ResolvedVc::upcast(
249 NextFontLocalResolvePlugin::new(project_path.clone())
250 .to_resolved()
251 .await?,
252 ),
253 ResolvedVc::upcast(module_feature_report_resolve_plugin),
254 ]
255 }
256 ServerContextType::PagesApi { .. }
257 | ServerContextType::AppRoute { .. }
258 | ServerContextType::Middleware { .. }
259 | ServerContextType::Instrumentation { .. } => {
260 vec![ResolvedVc::upcast(module_feature_report_resolve_plugin)]
261 }
262 };
263
264 let after_resolve_plugins = match ty {
265 ServerContextType::Pages { .. } | ServerContextType::PagesApi { .. } => {
266 vec![
267 ResolvedVc::upcast(next_node_shared_runtime_plugin),
268 ResolvedVc::upcast(external_cjs_modules_plugin),
269 ResolvedVc::upcast(next_external_plugin),
270 ]
271 }
272 ServerContextType::AppSSR { .. }
273 | ServerContextType::AppRSC { .. }
274 | ServerContextType::AppRoute { .. } => {
275 vec![
276 ResolvedVc::upcast(next_node_shared_runtime_plugin),
277 ResolvedVc::upcast(server_external_packages_plugin),
278 ResolvedVc::upcast(next_external_plugin),
279 ]
280 }
281 ServerContextType::Middleware { .. } | ServerContextType::Instrumentation { .. } => {
282 vec![
283 ResolvedVc::upcast(next_node_shared_runtime_plugin),
284 ResolvedVc::upcast(server_external_packages_plugin),
285 ResolvedVc::upcast(next_external_plugin),
286 ]
287 }
288 };
289
290 match ty {
298 ServerContextType::Pages { .. } | ServerContextType::PagesApi { .. } => {
299 }
301 ServerContextType::AppRSC { .. }
302 | ServerContextType::AppRoute { .. }
303 | ServerContextType::Middleware { .. }
304 | ServerContextType::Instrumentation { .. } => {
305 before_resolve_plugins.push(ResolvedVc::upcast(invalid_client_only_resolve_plugin));
306 before_resolve_plugins.push(ResolvedVc::upcast(
307 invalid_styled_jsx_client_only_resolve_plugin,
308 ));
309 }
310 ServerContextType::AppSSR { .. } => {
311 }
314 }
315
316 let resolve_options_context = ResolveOptionsContext {
317 enable_node_modules: Some(root_dir.clone()),
318 enable_node_externals: true,
319 enable_node_native_modules: true,
320 module: true,
321 custom_conditions,
322 import_map: Some(next_server_import_map),
323 fallback_import_map: Some(next_server_fallback_import_map),
324 before_resolve_plugins,
325 after_resolve_plugins,
326 ..Default::default()
327 };
328
329 let tsconfig_path = next_config
330 .typescript_tsconfig_path()
331 .await?
332 .as_ref()
333 .or(Some(&RcStr::from("tsconfig.json")))
336 .map(|p| project_path.join(p))
337 .transpose()?;
338
339 Ok(ResolveOptionsContext {
340 enable_typescript: true,
341 enable_react: true,
342 enable_mjs_extension: true,
343 custom_extensions: next_config.resolve_extension().owned().await?,
344 tsconfig_path,
345 rules: vec![(
346 foreign_code_context_condition,
347 resolve_options_context.clone().resolved_cell(),
348 )],
349 ..resolve_options_context
350 }
351 .cell())
352}
353
354#[turbo_tasks::function]
355async fn next_server_defines(define_env: Vc<OptionEnvMap>) -> Result<Vc<CompileTimeDefines>> {
356 Ok(defines(&*define_env.await?).cell())
357}
358
359#[turbo_tasks::function]
360async fn next_server_free_vars(define_env: Vc<OptionEnvMap>) -> Result<Vc<FreeVarReferences>> {
361 Ok(free_var_references!(..defines(&*define_env.await?).into_iter()).cell())
362}
363
364#[turbo_tasks::function]
365pub async fn get_server_compile_time_info(
366 cwd: Vc<FileSystemPath>,
367 define_env: Vc<OptionEnvMap>,
368 node_version: ResolvedVc<NodeJsVersion>,
369) -> Result<Vc<CompileTimeInfo>> {
370 CompileTimeInfo::builder(
371 Environment::new(ExecutionEnvironment::NodeJsLambda(
372 NodeJsEnvironment {
373 compile_target: CompileTarget::current().to_resolved().await?,
374 node_version,
375 cwd: ResolvedVc::cell(Some(cwd.owned().await?)),
376 }
377 .resolved_cell(),
378 ))
379 .to_resolved()
380 .await?,
381 )
382 .defines(next_server_defines(define_env).to_resolved().await?)
383 .free_var_references(next_server_free_vars(define_env).to_resolved().await?)
384 .cell()
385 .await
386}
387
388#[turbo_tasks::function]
389pub async fn get_tracing_compile_time_info() -> Result<Vc<CompileTimeInfo>> {
390 CompileTimeInfo::builder(
391 Environment::new(ExecutionEnvironment::NodeJsLambda(
392 NodeJsEnvironment::default().resolved_cell(),
393 ))
394 .to_resolved()
395 .await?,
396 )
397 .defines(
421 compile_time_defines!(
422 process.env.TURBOPACK = "1",
423 )
425 .resolved_cell(),
426 )
427 .cell()
428 .await
429}
430
431#[turbo_tasks::function]
432pub async fn get_server_module_options_context(
433 project_path: FileSystemPath,
434 execution_context: ResolvedVc<ExecutionContext>,
435 ty: ServerContextType,
436 mode: Vc<NextMode>,
437 next_config: Vc<NextConfig>,
438 next_runtime: NextRuntime,
439 encryption_key: ResolvedVc<RcStr>,
440 environment: ResolvedVc<Environment>,
441 client_environment: ResolvedVc<Environment>,
442) -> Result<Vc<ModuleOptionsContext>> {
443 let next_mode = mode.await?;
444 let mut next_server_rules = get_next_server_transforms_rules(
445 next_config,
446 ty.clone(),
447 mode,
448 false,
449 next_runtime,
450 encryption_key,
451 )
452 .await?;
453 let mut foreign_next_server_rules = get_next_server_transforms_rules(
454 next_config,
455 ty.clone(),
456 mode,
457 true,
458 next_runtime,
459 encryption_key,
460 )
461 .await?;
462 let mut internal_custom_rules = get_next_server_internal_transforms_rules(
463 ty.clone(),
464 next_config.mdx_rs().await?.is_some(),
465 )
466 .await?;
467
468 let foreign_code_context_condition =
469 foreign_code_context_condition(next_config, project_path.clone()).await?;
470 let postcss_transform_options = PostCssTransformOptions {
471 postcss_package: Some(
472 get_postcss_package_mapping(project_path.clone())
473 .to_resolved()
474 .await?,
475 ),
476 config_location: PostCssConfigLocation::ProjectPathOrLocalPath,
477 ..Default::default()
478 };
479 let postcss_foreign_transform_options = PostCssTransformOptions {
480 config_location: PostCssConfigLocation::ProjectPath,
484 ..postcss_transform_options.clone()
485 };
486 let enable_postcss_transform = Some(postcss_transform_options.resolved_cell());
487 let enable_foreign_postcss_transform = Some(postcss_foreign_transform_options.resolved_cell());
488
489 let mut loader_conditions = BTreeSet::new();
490 loader_conditions.extend(mode.await?.webpack_loader_conditions());
491 loader_conditions.extend(next_runtime.webpack_loader_conditions());
492
493 let mut foreign_conditions = loader_conditions.clone();
497 foreign_conditions.insert(WebpackLoaderBuiltinCondition::Foreign);
498 let foreign_enable_webpack_loaders =
499 *webpack_loader_options(project_path.clone(), next_config, foreign_conditions).await?;
500
501 let enable_webpack_loaders =
503 *webpack_loader_options(project_path.clone(), next_config, loader_conditions).await?;
504
505 let tree_shaking_mode_for_user_code = *next_config
506 .tree_shaking_mode_for_user_code(next_mode.is_development())
507 .await?;
508 let tree_shaking_mode_for_foreign_code = *next_config
509 .tree_shaking_mode_for_foreign_code(next_mode.is_development())
510 .await?;
511
512 let tsconfig_path = next_config
513 .typescript_tsconfig_path()
514 .await?
515 .as_ref()
516 .map(|p| project_path.join(p))
517 .transpose()?;
518
519 let tsconfig = get_typescript_transform_options(project_path.clone(), tsconfig_path.clone())
521 .to_resolved()
522 .await?;
523 let decorators_options =
524 get_decorators_transform_options(project_path.clone(), tsconfig_path.clone());
525 let enable_mdx_rs = *next_config.mdx_rs().await?;
526
527 let jsx_runtime_options = get_jsx_transform_options(
535 project_path.clone(),
536 mode,
537 None,
538 false,
539 next_config,
540 tsconfig_path.clone(),
541 )
542 .to_resolved()
543 .await?;
544 let rsc_jsx_runtime_options = get_jsx_transform_options(
545 project_path.clone(),
546 mode,
547 None,
548 true,
549 next_config,
550 tsconfig_path,
551 )
552 .to_resolved()
553 .await?;
554
555 let source_transform_rules: Vec<ModuleRule> = vec![
557 get_swc_ecma_transform_plugin_rule(next_config, project_path.clone()).await?,
558 get_relay_transform_rule(next_config, project_path.clone()).await?,
559 get_emotion_transform_rule(next_config).await?,
560 get_react_remove_properties_transform_rule(next_config).await?,
561 get_remove_console_transform_rule(next_config).await?,
562 ]
563 .into_iter()
564 .flatten()
565 .collect();
566
567 let page_transform_rules: Vec<ModuleRule> = vec![
569 get_styled_components_transform_rule(next_config).await?,
570 get_styled_jsx_transform_rule(next_config, client_environment.runtime_versions()).await?,
573 ]
574 .into_iter()
575 .flatten()
576 .collect();
577
578 let source_maps = *next_config.server_source_maps().await?;
579 let module_options_context = ModuleOptionsContext {
580 ecmascript: EcmascriptOptionsContext {
581 enable_typeof_window_inlining: Some(TypeofWindow::Undefined),
582 import_externals: *next_config.import_externals().await?,
583 ignore_dynamic_requests: true,
584 source_maps,
585 infer_module_side_effects: *next_config.turbopack_infer_module_side_effects().await?,
586 ..Default::default()
587 },
588 execution_context: Some(execution_context),
589 environment: Some(environment),
590 css: CssOptionsContext {
591 source_maps,
592 module_css_condition: Some(module_styles_rule_condition()),
593 ..Default::default()
594 },
595 tree_shaking_mode: tree_shaking_mode_for_user_code,
596 side_effect_free_packages: Some(
597 side_effect_free_packages_glob(next_config.optimize_package_imports())
598 .to_resolved()
599 .await?,
600 ),
601 analyze_mode: if next_mode.is_development() {
602 AnalyzeMode::CodeGeneration
603 } else {
604 AnalyzeMode::CodeGenerationAndTracing
605 },
606 enable_externals_tracing: if next_mode.is_production() {
607 Some(
608 ExternalsTracingOptions {
609 tracing_root: project_path,
610 compile_time_info: get_tracing_compile_time_info().to_resolved().await?,
611 }
612 .resolved_cell(),
613 )
614 } else {
615 None
616 },
617 keep_last_successful_parse: next_mode.is_development(),
618
619 ..Default::default()
620 };
621
622 let module_options_context = match ty {
623 ServerContextType::Pages { .. } | ServerContextType::PagesApi { .. } => {
624 next_server_rules.extend(page_transform_rules);
625 if let ServerContextType::Pages { .. } = ty {
626 next_server_rules.push(
627 get_next_react_server_components_transform_rule(next_config, false, None)
628 .await?,
629 );
630 }
631
632 next_server_rules.extend(source_transform_rules);
633
634 foreign_next_server_rules.extend(internal_custom_rules);
635
636 let url_rewrite_behavior = Some(
637 if let ServerContextType::PagesApi { .. } = ty {
639 UrlRewriteBehavior::Full
640 } else {
641 UrlRewriteBehavior::Relative
642 },
643 );
644
645 let module_options_context = ModuleOptionsContext {
646 ecmascript: EcmascriptOptionsContext {
647 esm_url_rewrite_behavior: url_rewrite_behavior,
648 ..module_options_context.ecmascript
649 },
650 ..module_options_context
651 };
652
653 let foreign_code_module_options_context = ModuleOptionsContext {
654 module_rules: foreign_next_server_rules.clone(),
655 enable_webpack_loaders: foreign_enable_webpack_loaders,
656 enable_postcss_transform: enable_foreign_postcss_transform,
658 tree_shaking_mode: tree_shaking_mode_for_foreign_code,
659 ..module_options_context.clone()
660 };
661
662 let internal_module_options_context = ModuleOptionsContext {
663 ecmascript: EcmascriptOptionsContext {
664 enable_typescript_transform: Some(
665 TypescriptTransformOptions::default().resolved_cell(),
666 ),
667 enable_jsx: Some(JsxTransformOptions::default().resolved_cell()),
668 ..module_options_context.ecmascript.clone()
669 },
670 module_rules: foreign_next_server_rules,
671 ..module_options_context.clone()
672 };
673
674 ModuleOptionsContext {
675 ecmascript: EcmascriptOptionsContext {
676 enable_jsx: Some(jsx_runtime_options),
677 enable_typescript_transform: Some(tsconfig),
678 enable_decorators: Some(decorators_options.to_resolved().await?),
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(page_transform_rules.clone());
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(source_transform_rules);
707
708 let foreign_code_module_options_context = ModuleOptionsContext {
709 module_rules: foreign_next_server_rules.clone(),
710 enable_webpack_loaders: foreign_enable_webpack_loaders,
711 enable_postcss_transform: enable_foreign_postcss_transform,
713 tree_shaking_mode: tree_shaking_mode_for_foreign_code,
714 ..module_options_context.clone()
715 };
716 let internal_module_options_context = ModuleOptionsContext {
717 ecmascript: EcmascriptOptionsContext {
718 enable_typescript_transform: Some(
719 TypescriptTransformOptions::default().resolved_cell(),
720 ),
721 ..module_options_context.ecmascript.clone()
722 },
723 module_rules: foreign_next_server_rules,
724 ..module_options_context.clone()
725 };
726
727 ModuleOptionsContext {
728 ecmascript: EcmascriptOptionsContext {
729 enable_jsx: Some(jsx_runtime_options),
730 enable_typescript_transform: Some(tsconfig),
731 enable_decorators: Some(decorators_options.to_resolved().await?),
732 ..module_options_context.ecmascript
733 },
734 enable_webpack_loaders,
735 enable_postcss_transform,
736 enable_mdx_rs,
737 rules: vec![
738 (
739 foreign_code_context_condition,
740 foreign_code_module_options_context.resolved_cell(),
741 ),
742 (
743 internal_assets_conditions().await?,
744 internal_module_options_context.resolved_cell(),
745 ),
746 ],
747 module_rules: next_server_rules,
748 ..module_options_context
749 }
750 }
751 ServerContextType::AppRSC {
752 app_dir,
753 ecmascript_client_reference_transition_name,
754 ..
755 } => {
756 next_server_rules.extend(page_transform_rules);
757
758 let client_directive_transformer = ecmascript_client_reference_transition_name.map(
759 |ecmascript_client_reference_transition_name| {
760 get_ecma_transform_rule(
761 Box::new(ClientDirectiveTransformer::new(
762 ecmascript_client_reference_transition_name,
763 )),
764 enable_mdx_rs.is_some(),
765 EcmascriptTransformStage::Preprocess,
766 )
767 },
768 );
769
770 foreign_next_server_rules.extend(client_directive_transformer.clone());
771 foreign_next_server_rules.extend(internal_custom_rules);
772
773 next_server_rules.extend(client_directive_transformer.clone());
774 next_server_rules.push(
775 get_next_react_server_components_transform_rule(next_config, true, Some(app_dir))
776 .await?,
777 );
778
779 next_server_rules.extend(source_transform_rules);
780
781 let foreign_code_module_options_context = ModuleOptionsContext {
782 module_rules: foreign_next_server_rules.clone(),
783 enable_webpack_loaders: foreign_enable_webpack_loaders,
784 enable_postcss_transform: enable_foreign_postcss_transform,
786 tree_shaking_mode: tree_shaking_mode_for_foreign_code,
787 ..module_options_context.clone()
788 };
789 let internal_module_options_context = ModuleOptionsContext {
790 ecmascript: EcmascriptOptionsContext {
791 enable_typescript_transform: Some(
792 TypescriptTransformOptions::default().resolved_cell(),
793 ),
794 ..module_options_context.ecmascript.clone()
795 },
796 module_rules: foreign_next_server_rules,
797 ..module_options_context.clone()
798 };
799 ModuleOptionsContext {
800 ecmascript: EcmascriptOptionsContext {
801 enable_jsx: Some(rsc_jsx_runtime_options),
802 enable_typescript_transform: Some(tsconfig),
803 enable_decorators: Some(decorators_options.to_resolved().await?),
804 ..module_options_context.ecmascript
805 },
806 enable_webpack_loaders,
807 enable_postcss_transform,
808 enable_mdx_rs,
809 rules: vec![
810 (
811 foreign_code_context_condition,
812 foreign_code_module_options_context.resolved_cell(),
813 ),
814 (
815 internal_assets_conditions().await?,
816 internal_module_options_context.resolved_cell(),
817 ),
818 ],
819 module_rules: next_server_rules,
820 ..module_options_context
821 }
822 }
823 ServerContextType::AppRoute {
824 app_dir,
825 ecmascript_client_reference_transition_name,
826 } => {
827 next_server_rules.extend(source_transform_rules);
828
829 let mut common_next_server_rules = vec![
830 get_next_react_server_components_transform_rule(next_config, true, Some(app_dir))
831 .await?,
832 ];
833
834 if let Some(ecmascript_client_reference_transition_name) =
835 ecmascript_client_reference_transition_name
836 {
837 common_next_server_rules.push(get_ecma_transform_rule(
838 Box::new(ClientDirectiveTransformer::new(
839 ecmascript_client_reference_transition_name,
840 )),
841 enable_mdx_rs.is_some(),
842 EcmascriptTransformStage::Preprocess,
843 ));
844 }
845
846 next_server_rules.extend(common_next_server_rules.iter().cloned());
847 internal_custom_rules.extend(common_next_server_rules);
848
849 let module_options_context = ModuleOptionsContext {
850 ecmascript: EcmascriptOptionsContext {
851 esm_url_rewrite_behavior: Some(UrlRewriteBehavior::Full),
852 ..module_options_context.ecmascript
853 },
854 ..module_options_context
855 };
856 let foreign_code_module_options_context = ModuleOptionsContext {
857 module_rules: internal_custom_rules.clone(),
858 enable_webpack_loaders: foreign_enable_webpack_loaders,
859 enable_postcss_transform: enable_foreign_postcss_transform,
861 tree_shaking_mode: tree_shaking_mode_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 ..module_options_context.ecmascript
880 },
881 enable_webpack_loaders,
882 enable_postcss_transform,
883 enable_mdx_rs,
884 rules: vec![
885 (
886 foreign_code_context_condition,
887 foreign_code_module_options_context.resolved_cell(),
888 ),
889 (
890 internal_assets_conditions().await?,
891 internal_module_options_context.resolved_cell(),
892 ),
893 ],
894 module_rules: next_server_rules,
895 ..module_options_context
896 }
897 }
898 ServerContextType::Middleware {
899 app_dir,
900 ecmascript_client_reference_transition_name,
901 }
902 | ServerContextType::Instrumentation {
903 app_dir,
904 ecmascript_client_reference_transition_name,
905 } => {
906 let custom_source_transform_rules: Vec<ModuleRule> = vec![
907 if let Some(ecmascript_client_reference_transition_name) =
908 ecmascript_client_reference_transition_name
909 {
910 get_ecma_transform_rule(
911 Box::new(ClientDirectiveTransformer::new(
912 ecmascript_client_reference_transition_name,
913 )),
914 enable_mdx_rs.is_some(),
915 EcmascriptTransformStage::Preprocess,
916 )
917 } else {
918 get_ecma_transform_rule(
919 Box::new(ClientDisallowedDirectiveTransformer::new(
920 "next/dist/client/use-client-disallowed.js".to_string(),
921 )),
922 enable_mdx_rs.is_some(),
923 EcmascriptTransformStage::Preprocess,
924 )
925 },
926 get_next_react_server_components_transform_rule(next_config, true, app_dir).await?,
927 ];
928
929 internal_custom_rules.extend(custom_source_transform_rules.iter().cloned());
930
931 next_server_rules.extend(custom_source_transform_rules);
932 next_server_rules.extend(source_transform_rules);
933
934 let module_options_context = ModuleOptionsContext {
935 ecmascript: EcmascriptOptionsContext {
936 esm_url_rewrite_behavior: Some(UrlRewriteBehavior::Full),
937 ..module_options_context.ecmascript
938 },
939 ..module_options_context
940 };
941 let foreign_code_module_options_context = ModuleOptionsContext {
942 module_rules: internal_custom_rules.clone(),
943 enable_webpack_loaders: foreign_enable_webpack_loaders,
944 enable_postcss_transform: enable_foreign_postcss_transform,
946 tree_shaking_mode: tree_shaking_mode_for_foreign_code,
947 ..module_options_context.clone()
948 };
949 let internal_module_options_context = ModuleOptionsContext {
950 ecmascript: EcmascriptOptionsContext {
951 enable_typescript_transform: Some(
952 TypescriptTransformOptions::default().resolved_cell(),
953 ),
954 ..module_options_context.ecmascript.clone()
955 },
956 module_rules: internal_custom_rules,
957 ..module_options_context.clone()
958 };
959 ModuleOptionsContext {
960 ecmascript: EcmascriptOptionsContext {
961 enable_jsx: Some(jsx_runtime_options),
962 enable_typescript_transform: Some(tsconfig),
963 enable_decorators: Some(decorators_options.to_resolved().await?),
964 ..module_options_context.ecmascript
965 },
966 enable_webpack_loaders,
967 enable_postcss_transform,
968 enable_mdx_rs,
969 rules: vec![
970 (
971 foreign_code_context_condition,
972 foreign_code_module_options_context.resolved_cell(),
973 ),
974 (
975 internal_assets_conditions().await?,
976 internal_module_options_context.resolved_cell(),
977 ),
978 ],
979 module_rules: next_server_rules,
980 ..module_options_context
981 }
982 }
983 }
984 .cell();
985
986 Ok(module_options_context)
987}
988
989#[derive(Clone, Debug, PartialEq, Eq, Hash, TaskInput, TraceRawVcs, Encode, Decode)]
990pub struct ServerChunkingContextOptions {
991 pub mode: Vc<NextMode>,
992 pub root_path: FileSystemPath,
993 pub node_root: FileSystemPath,
994 pub node_root_to_root_path: RcStr,
995 pub environment: Vc<Environment>,
996 pub module_id_strategy: Vc<Box<dyn ModuleIdStrategy>>,
997 pub export_usage: Vc<OptionBindingUsageInfo>,
998 pub unused_references: Vc<OptionBindingUsageInfo>,
999 pub minify: Vc<bool>,
1000 pub source_maps: Vc<SourceMapsType>,
1001 pub no_mangling: Vc<bool>,
1002 pub scope_hoisting: Vc<bool>,
1003 pub nested_async_chunking: Vc<bool>,
1004 pub debug_ids: Vc<bool>,
1005 pub client_root: FileSystemPath,
1006 pub asset_prefix: RcStr,
1007}
1008
1009#[turbo_tasks::function]
1011pub async fn get_server_chunking_context_with_client_assets(
1012 options: ServerChunkingContextOptions,
1013) -> Result<Vc<NodeJsChunkingContext>> {
1014 let ServerChunkingContextOptions {
1015 mode,
1016 root_path,
1017 node_root,
1018 node_root_to_root_path,
1019 environment,
1020 module_id_strategy,
1021 export_usage,
1022 unused_references,
1023 minify,
1024 source_maps,
1025 no_mangling,
1026 scope_hoisting,
1027 nested_async_chunking,
1028 debug_ids,
1029 client_root,
1030 asset_prefix,
1031 } = options;
1032
1033 let next_mode = mode.await?;
1034 let mut builder = NodeJsChunkingContext::builder(
1038 root_path,
1039 node_root.clone(),
1040 node_root_to_root_path,
1041 client_root.clone(),
1042 node_root.join("server/chunks/ssr")?,
1043 client_root.join("static/media")?,
1044 environment.to_resolved().await?,
1045 next_mode.runtime_type(),
1046 )
1047 .asset_prefix(Some(asset_prefix))
1048 .minify_type(if *minify.await? {
1049 MinifyType::Minify {
1050 mangle: (!*no_mangling.await?).then_some(MangleType::Deterministic),
1052 }
1053 } else {
1054 MinifyType::NoMinify
1055 })
1056 .source_maps(*source_maps.await?)
1057 .module_id_strategy(module_id_strategy.to_resolved().await?)
1058 .export_usage(*export_usage.await?)
1059 .unused_references(*unused_references.await?)
1060 .file_tracing(next_mode.is_production())
1061 .debug_ids(*debug_ids.await?)
1062 .nested_async_availability(*nested_async_chunking.await?);
1063
1064 builder = builder.source_map_source_type(if next_mode.is_development() {
1065 SourceMapSourceType::AbsoluteFileUri
1066 } else {
1067 SourceMapSourceType::RelativeUri
1068 });
1069 if next_mode.is_production() {
1070 builder = builder
1071 .chunking_config(
1072 Vc::<EcmascriptChunkType>::default().to_resolved().await?,
1073 ChunkingConfig {
1074 min_chunk_size: 20_000,
1075 max_chunk_count_per_group: 100,
1076 max_merge_chunk_size: 100_000,
1077 ..Default::default()
1078 },
1079 )
1080 .chunking_config(
1081 Vc::<CssChunkType>::default().to_resolved().await?,
1082 ChunkingConfig {
1083 max_merge_chunk_size: 100_000,
1084 ..Default::default()
1085 },
1086 )
1087 .module_merging(*scope_hoisting.await?);
1088 }
1089
1090 Ok(builder.build())
1091}
1092
1093#[turbo_tasks::function]
1095pub async fn get_server_chunking_context(
1096 options: ServerChunkingContextOptions,
1097) -> Result<Vc<NodeJsChunkingContext>> {
1098 let ServerChunkingContextOptions {
1099 mode,
1100 root_path,
1101 node_root,
1102 node_root_to_root_path,
1103 environment,
1104 module_id_strategy,
1105 export_usage,
1106 unused_references,
1107 minify,
1108 source_maps,
1109 no_mangling,
1110 scope_hoisting,
1111 nested_async_chunking,
1112 debug_ids,
1113 client_root,
1114 asset_prefix,
1115 } = options;
1116 let next_mode = mode.await?;
1117 let mut builder = NodeJsChunkingContext::builder(
1121 root_path,
1122 node_root.clone(),
1123 node_root_to_root_path,
1124 node_root.clone(),
1125 node_root.join("server/chunks")?,
1126 node_root.join("server/assets")?,
1127 environment.to_resolved().await?,
1128 next_mode.runtime_type(),
1129 )
1130 .client_roots_override(rcstr!("client"), client_root.clone())
1131 .asset_root_path_override(rcstr!("client"), client_root.join("static/media")?)
1132 .asset_prefix_override(rcstr!("client"), asset_prefix)
1133 .minify_type(if *minify.await? {
1134 MinifyType::Minify {
1135 mangle: (!*no_mangling.await?).then_some(MangleType::OptimalSize),
1136 }
1137 } else {
1138 MinifyType::NoMinify
1139 })
1140 .source_maps(*source_maps.await?)
1141 .module_id_strategy(module_id_strategy.to_resolved().await?)
1142 .export_usage(*export_usage.await?)
1143 .unused_references(*unused_references.await?)
1144 .file_tracing(next_mode.is_production())
1145 .debug_ids(*debug_ids.await?)
1146 .nested_async_availability(*nested_async_chunking.await?);
1147
1148 if next_mode.is_development() {
1149 builder = builder.source_map_source_type(SourceMapSourceType::AbsoluteFileUri);
1150 } else {
1151 builder = builder
1152 .source_map_source_type(SourceMapSourceType::RelativeUri)
1153 .chunking_config(
1154 Vc::<EcmascriptChunkType>::default().to_resolved().await?,
1155 ChunkingConfig {
1156 min_chunk_size: 20_000,
1157 max_chunk_count_per_group: 100,
1158 max_merge_chunk_size: 100_000,
1159 ..Default::default()
1160 },
1161 )
1162 .chunking_config(
1163 Vc::<CssChunkType>::default().to_resolved().await?,
1164 ChunkingConfig {
1165 max_merge_chunk_size: 100_000,
1166 ..Default::default()
1167 },
1168 )
1169 .module_merging(*scope_hoisting.await?);
1170 }
1171
1172 Ok(builder.build())
1173}