1use std::collections::BTreeSet;
2
3use anyhow::{Result, bail};
4use serde::{Deserialize, Serialize};
5use turbo_rcstr::{RcStr, rcstr};
6use turbo_tasks::{ResolvedVc, TaskInput, Vc, trace::TraceRawVcs};
7use turbo_tasks_fs::FileSystemPath;
8use turbopack::{
9 css::chunk::CssChunkType,
10 module_options::{
11 CssOptionsContext, EcmascriptOptionsContext, ExternalsTracingOptions, JsxTransformOptions,
12 ModuleOptionsContext, ModuleRule, TypescriptTransformOptions,
13 },
14 resolve_options_context::ResolveOptionsContext,
15 transition::Transition,
16};
17use turbopack_core::{
18 chunk::{
19 ChunkingConfig, MangleType, MinifyType, SourceMapsType,
20 module_id_strategies::ModuleIdStrategy,
21 },
22 compile_time_defines,
23 compile_time_info::{CompileTimeDefines, CompileTimeInfo, FreeVarReferences},
24 environment::{Environment, ExecutionEnvironment, NodeJsEnvironment, NodeJsVersion},
25 free_var_references,
26 module_graph::export_usage::OptionExportUsageInfo,
27 target::CompileTarget,
28};
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;
40
41use super::{
42 resolve::ExternalCjsModulesResolvePlugin,
43 transforms::{get_next_server_internal_transforms_rules, get_next_server_transforms_rules},
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::resolve::ExternalPredicate,
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_templateon,
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_templateon(
166 project_path.clone(),
167 rcstr!("dist/lib/server-external-packages.json"),
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.clone(),
203 project_path.root().owned().await?,
204 ExternalPredicate::Only(ResolvedVc::cell(external_packages)).cell(),
205 *next_config.import_externals().await?,
206 )
207 .to_resolved()
208 .await?;
209
210 let mut custom_conditions: Vec<_> = mode.await?.custom_resolve_conditions().collect();
211 custom_conditions.extend(NextRuntime::NodeJs.custom_resolve_conditions());
212
213 if ty.should_use_react_server_condition() {
214 custom_conditions.push(rcstr!("react-server"));
215 };
216
217 if *next_config.enable_cache_components().await? {
218 custom_conditions.push(rcstr!("next-js"));
219 };
220
221 let external_cjs_modules_plugin = if *next_config.bundle_pages_router_dependencies().await? {
222 server_external_packages_plugin
223 } else {
224 ExternalCjsModulesResolvePlugin::new(
225 project_path.clone(),
226 project_path.root().owned().await?,
227 ExternalPredicate::AllExcept(ResolvedVc::cell(transpiled_packages)).cell(),
228 *next_config.import_externals().await?,
229 )
230 .to_resolved()
231 .await?
232 };
233
234 let next_external_plugin = NextExternalResolvePlugin::new(project_path.clone())
235 .to_resolved()
236 .await?;
237 let next_node_shared_runtime_plugin =
238 NextNodeSharedRuntimeResolvePlugin::new(project_path.clone(), ty.clone())
239 .to_resolved()
240 .await?;
241
242 let mut before_resolve_plugins = match &ty {
243 ServerContextType::Pages { .. }
244 | ServerContextType::AppSSR { .. }
245 | ServerContextType::AppRSC { .. } => {
246 vec![
247 ResolvedVc::upcast(
248 NextFontLocalResolvePlugin::new(project_path.clone())
249 .to_resolved()
250 .await?,
251 ),
252 ResolvedVc::upcast(module_feature_report_resolve_plugin),
253 ]
254 }
255 ServerContextType::PagesApi { .. }
256 | ServerContextType::AppRoute { .. }
257 | ServerContextType::Middleware { .. }
258 | ServerContextType::Instrumentation { .. } => {
259 vec![ResolvedVc::upcast(module_feature_report_resolve_plugin)]
260 }
261 };
262
263 let after_resolve_plugins = match ty {
264 ServerContextType::Pages { .. } | ServerContextType::PagesApi { .. } => {
265 vec![
266 ResolvedVc::upcast(next_node_shared_runtime_plugin),
267 ResolvedVc::upcast(external_cjs_modules_plugin),
268 ResolvedVc::upcast(next_external_plugin),
269 ]
270 }
271 ServerContextType::AppSSR { .. }
272 | ServerContextType::AppRSC { .. }
273 | ServerContextType::AppRoute { .. } => {
274 vec![
275 ResolvedVc::upcast(next_node_shared_runtime_plugin),
276 ResolvedVc::upcast(server_external_packages_plugin),
277 ResolvedVc::upcast(next_external_plugin),
278 ]
279 }
280 ServerContextType::Middleware { .. } | ServerContextType::Instrumentation { .. } => {
281 vec![
282 ResolvedVc::upcast(next_node_shared_runtime_plugin),
283 ResolvedVc::upcast(server_external_packages_plugin),
284 ResolvedVc::upcast(next_external_plugin),
285 ]
286 }
287 };
288
289 match ty {
297 ServerContextType::Pages { .. } | ServerContextType::PagesApi { .. } => {
298 }
300 ServerContextType::AppRSC { .. }
301 | ServerContextType::AppRoute { .. }
302 | ServerContextType::Middleware { .. }
303 | ServerContextType::Instrumentation { .. } => {
304 before_resolve_plugins.push(ResolvedVc::upcast(invalid_client_only_resolve_plugin));
305 before_resolve_plugins.push(ResolvedVc::upcast(
306 invalid_styled_jsx_client_only_resolve_plugin,
307 ));
308 }
309 ServerContextType::AppSSR { .. } => {
310 }
313 }
314
315 let resolve_options_context = ResolveOptionsContext {
316 enable_node_modules: Some(root_dir.clone()),
317 enable_node_externals: true,
318 enable_node_native_modules: true,
319 module: true,
320 custom_conditions,
321 import_map: Some(next_server_import_map),
322 fallback_import_map: Some(next_server_fallback_import_map),
323 before_resolve_plugins,
324 after_resolve_plugins,
325 ..Default::default()
326 };
327
328 let tsconfig_path = next_config
329 .typescript_tsconfig_path()
330 .await?
331 .as_ref()
332 .or(Some(&RcStr::from("tsconfig.json")))
335 .map(|p| project_path.join(p))
336 .transpose()?;
337
338 Ok(ResolveOptionsContext {
339 enable_typescript: true,
340 enable_react: true,
341 enable_mjs_extension: true,
342 custom_extensions: next_config.resolve_extension().owned().await?,
343 tsconfig_path,
344 rules: vec![(
345 foreign_code_context_condition,
346 resolve_options_context.clone().resolved_cell(),
347 )],
348 ..resolve_options_context
349 }
350 .cell())
351}
352
353#[turbo_tasks::function]
354async fn next_server_defines(define_env: Vc<OptionEnvMap>) -> Result<Vc<CompileTimeDefines>> {
355 Ok(defines(&*define_env.await?).cell())
356}
357
358#[turbo_tasks::function]
359async fn next_server_free_vars(define_env: Vc<OptionEnvMap>) -> Result<Vc<FreeVarReferences>> {
360 Ok(free_var_references!(..defines(&*define_env.await?).into_iter()).cell())
361}
362
363#[turbo_tasks::function]
364pub async fn get_server_compile_time_info(
365 cwd: Vc<FileSystemPath>,
366 define_env: Vc<OptionEnvMap>,
367 node_version: ResolvedVc<NodeJsVersion>,
368) -> Result<Vc<CompileTimeInfo>> {
369 CompileTimeInfo::builder(
370 Environment::new(ExecutionEnvironment::NodeJsLambda(
371 NodeJsEnvironment {
372 compile_target: CompileTarget::current().to_resolved().await?,
373 node_version,
374 cwd: ResolvedVc::cell(Some(cwd.owned().await?)),
375 }
376 .resolved_cell(),
377 ))
378 .to_resolved()
379 .await?,
380 )
381 .defines(next_server_defines(define_env).to_resolved().await?)
382 .free_var_references(next_server_free_vars(define_env).to_resolved().await?)
383 .cell()
384 .await
385}
386
387#[turbo_tasks::function]
388pub async fn get_tracing_compile_time_info() -> Result<Vc<CompileTimeInfo>> {
389 CompileTimeInfo::builder(
390 Environment::new(ExecutionEnvironment::NodeJsLambda(
391 NodeJsEnvironment::default().resolved_cell(),
392 ))
393 .to_resolved()
394 .await?,
395 )
396 .defines(
420 compile_time_defines!(
421 process.env.TURBOPACK = true,
422 )
424 .resolved_cell(),
425 )
426 .cell()
427 .await
428}
429
430#[turbo_tasks::function]
431pub async fn get_server_module_options_context(
432 project_path: FileSystemPath,
433 execution_context: ResolvedVc<ExecutionContext>,
434 ty: ServerContextType,
435 mode: Vc<NextMode>,
436 next_config: Vc<NextConfig>,
437 next_runtime: NextRuntime,
438 encryption_key: ResolvedVc<RcStr>,
439 environment: ResolvedVc<Environment>,
440 client_environment: ResolvedVc<Environment>,
441) -> Result<Vc<ModuleOptionsContext>> {
442 let next_mode = mode.await?;
443 let mut next_server_rules = get_next_server_transforms_rules(
444 next_config,
445 ty.clone(),
446 mode,
447 false,
448 next_runtime,
449 encryption_key,
450 )
451 .await?;
452 let mut foreign_next_server_rules = get_next_server_transforms_rules(
453 next_config,
454 ty.clone(),
455 mode,
456 true,
457 next_runtime,
458 encryption_key,
459 )
460 .await?;
461 let mut internal_custom_rules = get_next_server_internal_transforms_rules(
462 ty.clone(),
463 next_config.mdx_rs().await?.is_some(),
464 )
465 .await?;
466
467 let foreign_code_context_condition =
468 foreign_code_context_condition(next_config, project_path.clone()).await?;
469 let postcss_transform_options = PostCssTransformOptions {
470 postcss_package: Some(
471 get_postcss_package_mapping(project_path.clone())
472 .to_resolved()
473 .await?,
474 ),
475 config_location: PostCssConfigLocation::ProjectPathOrLocalPath,
476 ..Default::default()
477 };
478 let postcss_foreign_transform_options = PostCssTransformOptions {
479 config_location: PostCssConfigLocation::ProjectPath,
483 ..postcss_transform_options.clone()
484 };
485 let enable_postcss_transform = Some(postcss_transform_options.resolved_cell());
486 let enable_foreign_postcss_transform = Some(postcss_foreign_transform_options.resolved_cell());
487
488 let mut loader_conditions = BTreeSet::new();
489 loader_conditions.extend(mode.await?.webpack_loader_conditions());
490 loader_conditions.extend(next_runtime.webpack_loader_conditions());
491
492 let mut foreign_conditions = loader_conditions.clone();
496 foreign_conditions.insert(WebpackLoaderBuiltinCondition::Foreign);
497 let foreign_enable_webpack_loaders =
498 *webpack_loader_options(project_path.clone(), next_config, foreign_conditions).await?;
499
500 let enable_webpack_loaders =
502 *webpack_loader_options(project_path.clone(), next_config, loader_conditions).await?;
503
504 let tree_shaking_mode_for_user_code = *next_config
505 .tree_shaking_mode_for_user_code(next_mode.is_development())
506 .await?;
507 let tree_shaking_mode_for_foreign_code = *next_config
508 .tree_shaking_mode_for_foreign_code(next_mode.is_development())
509 .await?;
510
511 let tsconfig_path = next_config
512 .typescript_tsconfig_path()
513 .await?
514 .as_ref()
515 .map(|p| project_path.join(p))
516 .transpose()?;
517
518 let tsconfig = get_typescript_transform_options(project_path.clone(), tsconfig_path.clone())
520 .to_resolved()
521 .await?;
522 let decorators_options =
523 get_decorators_transform_options(project_path.clone(), tsconfig_path.clone());
524 let enable_mdx_rs = *next_config.mdx_rs().await?;
525
526 let jsx_runtime_options = get_jsx_transform_options(
534 project_path.clone(),
535 mode,
536 None,
537 false,
538 next_config,
539 tsconfig_path.clone(),
540 )
541 .to_resolved()
542 .await?;
543 let rsc_jsx_runtime_options = get_jsx_transform_options(
544 project_path.clone(),
545 mode,
546 None,
547 true,
548 next_config,
549 tsconfig_path,
550 )
551 .to_resolved()
552 .await?;
553
554 let source_transform_rules: Vec<ModuleRule> = vec![
556 get_swc_ecma_transform_plugin_rule(next_config, project_path.clone()).await?,
557 get_relay_transform_rule(next_config, project_path.clone()).await?,
558 get_emotion_transform_rule(next_config).await?,
559 get_react_remove_properties_transform_rule(next_config).await?,
560 get_remove_console_transform_rule(next_config).await?,
561 ]
562 .into_iter()
563 .flatten()
564 .collect();
565
566 let page_transform_rules: Vec<ModuleRule> = vec![
568 get_styled_components_transform_rule(next_config).await?,
569 get_styled_jsx_transform_rule(next_config, client_environment.runtime_versions()).await?,
572 ]
573 .into_iter()
574 .flatten()
575 .collect();
576
577 let source_maps = if *next_config.server_source_maps().await? {
578 SourceMapsType::Full
579 } else {
580 SourceMapsType::None
581 };
582 let module_options_context = ModuleOptionsContext {
583 ecmascript: EcmascriptOptionsContext {
584 enable_typeof_window_inlining: Some(TypeofWindow::Undefined),
585 import_externals: *next_config.import_externals().await?,
586 ignore_dynamic_requests: true,
587 source_maps,
588 ..Default::default()
589 },
590 execution_context: Some(execution_context),
591 environment: Some(environment),
592 css: CssOptionsContext {
593 source_maps,
594 module_css_condition: Some(module_styles_rule_condition()),
595 ..Default::default()
596 },
597 tree_shaking_mode: tree_shaking_mode_for_user_code,
598 side_effect_free_packages: next_config.optimize_package_imports().owned().await?,
599 analyze_mode: if next_mode.is_development() {
600 AnalyzeMode::CodeGeneration
601 } else {
602 AnalyzeMode::CodeGenerationAndTracing
603 },
604 enable_externals_tracing: if next_mode.is_production() {
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(page_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
630 next_server_rules.extend(source_transform_rules);
631
632 foreign_next_server_rules.extend(internal_custom_rules);
633
634 let url_rewrite_behavior = Some(
635 if let ServerContextType::PagesApi { .. } = ty {
637 UrlRewriteBehavior::Full
638 } else {
639 UrlRewriteBehavior::Relative
640 },
641 );
642
643 let module_options_context = ModuleOptionsContext {
644 ecmascript: EcmascriptOptionsContext {
645 esm_url_rewrite_behavior: url_rewrite_behavior,
646 ..module_options_context.ecmascript
647 },
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 tree_shaking_mode: tree_shaking_mode_for_foreign_code,
657 ..module_options_context.clone()
658 };
659
660 let internal_module_options_context = ModuleOptionsContext {
661 ecmascript: EcmascriptOptionsContext {
662 enable_typescript_transform: Some(
663 TypescriptTransformOptions::default().resolved_cell(),
664 ),
665 enable_jsx: Some(JsxTransformOptions::default().resolved_cell()),
666 ..module_options_context.ecmascript.clone()
667 },
668 module_rules: foreign_next_server_rules,
669 ..module_options_context.clone()
670 };
671
672 ModuleOptionsContext {
673 ecmascript: EcmascriptOptionsContext {
674 enable_jsx: Some(jsx_runtime_options),
675 enable_typescript_transform: Some(tsconfig),
676 enable_decorators: Some(decorators_options.to_resolved().await?),
677 ..module_options_context.ecmascript
678 },
679 enable_webpack_loaders,
680 enable_postcss_transform,
681 enable_mdx_rs,
682 rules: vec![
683 (
684 foreign_code_context_condition,
685 foreign_code_module_options_context.resolved_cell(),
686 ),
687 (
688 internal_assets_conditions().await?,
689 internal_module_options_context.resolved_cell(),
690 ),
691 ],
692 module_rules: next_server_rules,
693 ..module_options_context
694 }
695 }
696 ServerContextType::AppSSR { app_dir, .. } => {
697 foreign_next_server_rules.extend(internal_custom_rules);
698
699 next_server_rules.extend(page_transform_rules.clone());
700 next_server_rules.push(
701 get_next_react_server_components_transform_rule(next_config, false, Some(app_dir))
702 .await?,
703 );
704 next_server_rules.extend(source_transform_rules);
705
706 let foreign_code_module_options_context = ModuleOptionsContext {
707 module_rules: foreign_next_server_rules.clone(),
708 enable_webpack_loaders: foreign_enable_webpack_loaders,
709 enable_postcss_transform: enable_foreign_postcss_transform,
711 tree_shaking_mode: tree_shaking_mode_for_foreign_code,
712 ..module_options_context.clone()
713 };
714 let internal_module_options_context = ModuleOptionsContext {
715 ecmascript: EcmascriptOptionsContext {
716 enable_typescript_transform: Some(
717 TypescriptTransformOptions::default().resolved_cell(),
718 ),
719 ..module_options_context.ecmascript.clone()
720 },
721 module_rules: foreign_next_server_rules,
722 ..module_options_context.clone()
723 };
724
725 ModuleOptionsContext {
726 ecmascript: EcmascriptOptionsContext {
727 enable_jsx: Some(jsx_runtime_options),
728 enable_typescript_transform: Some(tsconfig),
729 enable_decorators: Some(decorators_options.to_resolved().await?),
730 ..module_options_context.ecmascript
731 },
732 enable_webpack_loaders,
733 enable_postcss_transform,
734 enable_mdx_rs,
735 rules: vec![
736 (
737 foreign_code_context_condition,
738 foreign_code_module_options_context.resolved_cell(),
739 ),
740 (
741 internal_assets_conditions().await?,
742 internal_module_options_context.resolved_cell(),
743 ),
744 ],
745 module_rules: next_server_rules,
746 ..module_options_context
747 }
748 }
749 ServerContextType::AppRSC {
750 app_dir,
751 ecmascript_client_reference_transition_name,
752 ..
753 } => {
754 next_server_rules.extend(page_transform_rules);
755
756 let client_directive_transformer = ecmascript_client_reference_transition_name.map(
757 |ecmascript_client_reference_transition_name| {
758 get_ecma_transform_rule(
759 Box::new(ClientDirectiveTransformer::new(
760 ecmascript_client_reference_transition_name,
761 )),
762 enable_mdx_rs.is_some(),
763 EcmascriptTransformStage::Preprocess,
764 )
765 },
766 );
767
768 foreign_next_server_rules.extend(client_directive_transformer.clone());
769 foreign_next_server_rules.extend(internal_custom_rules);
770
771 next_server_rules.extend(client_directive_transformer.clone());
772 next_server_rules.push(
773 get_next_react_server_components_transform_rule(next_config, true, Some(app_dir))
774 .await?,
775 );
776
777 next_server_rules.extend(source_transform_rules);
778
779 let foreign_code_module_options_context = ModuleOptionsContext {
780 module_rules: foreign_next_server_rules.clone(),
781 enable_webpack_loaders: foreign_enable_webpack_loaders,
782 enable_postcss_transform: enable_foreign_postcss_transform,
784 tree_shaking_mode: tree_shaking_mode_for_foreign_code,
785 ..module_options_context.clone()
786 };
787 let internal_module_options_context = ModuleOptionsContext {
788 ecmascript: EcmascriptOptionsContext {
789 enable_typescript_transform: Some(
790 TypescriptTransformOptions::default().resolved_cell(),
791 ),
792 ..module_options_context.ecmascript.clone()
793 },
794 module_rules: foreign_next_server_rules,
795 ..module_options_context.clone()
796 };
797 ModuleOptionsContext {
798 ecmascript: EcmascriptOptionsContext {
799 enable_jsx: Some(rsc_jsx_runtime_options),
800 enable_typescript_transform: Some(tsconfig),
801 enable_decorators: Some(decorators_options.to_resolved().await?),
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 next_server_rules.extend(source_transform_rules);
826
827 let mut common_next_server_rules = vec![
828 get_next_react_server_components_transform_rule(next_config, true, Some(app_dir))
829 .await?,
830 ];
831
832 if let Some(ecmascript_client_reference_transition_name) =
833 ecmascript_client_reference_transition_name
834 {
835 common_next_server_rules.push(get_ecma_transform_rule(
836 Box::new(ClientDirectiveTransformer::new(
837 ecmascript_client_reference_transition_name,
838 )),
839 enable_mdx_rs.is_some(),
840 EcmascriptTransformStage::Preprocess,
841 ));
842 }
843
844 next_server_rules.extend(common_next_server_rules.iter().cloned());
845 internal_custom_rules.extend(common_next_server_rules);
846
847 let module_options_context = ModuleOptionsContext {
848 ecmascript: EcmascriptOptionsContext {
849 esm_url_rewrite_behavior: Some(UrlRewriteBehavior::Full),
850 ..module_options_context.ecmascript
851 },
852 ..module_options_context
853 };
854 let foreign_code_module_options_context = ModuleOptionsContext {
855 module_rules: internal_custom_rules.clone(),
856 enable_webpack_loaders: foreign_enable_webpack_loaders,
857 enable_postcss_transform: enable_foreign_postcss_transform,
859 tree_shaking_mode: tree_shaking_mode_for_foreign_code,
860 ..module_options_context.clone()
861 };
862 let internal_module_options_context = ModuleOptionsContext {
863 ecmascript: EcmascriptOptionsContext {
864 enable_typescript_transform: Some(
865 TypescriptTransformOptions::default().resolved_cell(),
866 ),
867 ..module_options_context.ecmascript.clone()
868 },
869 module_rules: internal_custom_rules,
870 ..module_options_context.clone()
871 };
872 ModuleOptionsContext {
873 ecmascript: EcmascriptOptionsContext {
874 enable_jsx: Some(rsc_jsx_runtime_options),
875 enable_typescript_transform: Some(tsconfig),
876 enable_decorators: Some(decorators_options.to_resolved().await?),
877 ..module_options_context.ecmascript
878 },
879 enable_webpack_loaders,
880 enable_postcss_transform,
881 enable_mdx_rs,
882 rules: vec![
883 (
884 foreign_code_context_condition,
885 foreign_code_module_options_context.resolved_cell(),
886 ),
887 (
888 internal_assets_conditions().await?,
889 internal_module_options_context.resolved_cell(),
890 ),
891 ],
892 module_rules: next_server_rules,
893 ..module_options_context
894 }
895 }
896 ServerContextType::Middleware {
897 app_dir,
898 ecmascript_client_reference_transition_name,
899 }
900 | ServerContextType::Instrumentation {
901 app_dir,
902 ecmascript_client_reference_transition_name,
903 } => {
904 let custom_source_transform_rules: Vec<ModuleRule> = vec![
905 if let Some(ecmascript_client_reference_transition_name) =
906 ecmascript_client_reference_transition_name
907 {
908 get_ecma_transform_rule(
909 Box::new(ClientDirectiveTransformer::new(
910 ecmascript_client_reference_transition_name,
911 )),
912 enable_mdx_rs.is_some(),
913 EcmascriptTransformStage::Preprocess,
914 )
915 } else {
916 get_ecma_transform_rule(
917 Box::new(ClientDisallowedDirectiveTransformer::new(
918 "next/dist/client/use-client-disallowed.js".to_string(),
919 )),
920 enable_mdx_rs.is_some(),
921 EcmascriptTransformStage::Preprocess,
922 )
923 },
924 get_next_react_server_components_transform_rule(next_config, true, app_dir).await?,
925 ];
926
927 internal_custom_rules.extend(custom_source_transform_rules.iter().cloned());
928
929 next_server_rules.extend(custom_source_transform_rules);
930 next_server_rules.extend(source_transform_rules);
931
932 let module_options_context = ModuleOptionsContext {
933 ecmascript: EcmascriptOptionsContext {
934 esm_url_rewrite_behavior: Some(UrlRewriteBehavior::Full),
935 ..module_options_context.ecmascript
936 },
937 ..module_options_context
938 };
939 let foreign_code_module_options_context = ModuleOptionsContext {
940 module_rules: internal_custom_rules.clone(),
941 enable_webpack_loaders: foreign_enable_webpack_loaders,
942 enable_postcss_transform: enable_foreign_postcss_transform,
944 tree_shaking_mode: tree_shaking_mode_for_foreign_code,
945 ..module_options_context.clone()
946 };
947 let internal_module_options_context = ModuleOptionsContext {
948 ecmascript: EcmascriptOptionsContext {
949 enable_typescript_transform: Some(
950 TypescriptTransformOptions::default().resolved_cell(),
951 ),
952 ..module_options_context.ecmascript.clone()
953 },
954 module_rules: internal_custom_rules,
955 ..module_options_context.clone()
956 };
957 ModuleOptionsContext {
958 ecmascript: EcmascriptOptionsContext {
959 enable_jsx: Some(jsx_runtime_options),
960 enable_typescript_transform: Some(tsconfig),
961 enable_decorators: Some(decorators_options.to_resolved().await?),
962 ..module_options_context.ecmascript
963 },
964 enable_webpack_loaders,
965 enable_postcss_transform,
966 enable_mdx_rs,
967 rules: vec![
968 (
969 foreign_code_context_condition,
970 foreign_code_module_options_context.resolved_cell(),
971 ),
972 (
973 internal_assets_conditions().await?,
974 internal_module_options_context.resolved_cell(),
975 ),
976 ],
977 module_rules: next_server_rules,
978 ..module_options_context
979 }
980 }
981 }
982 .cell();
983
984 Ok(module_options_context)
985}
986
987#[derive(Clone, Debug, PartialEq, Eq, Hash, TaskInput, TraceRawVcs, Serialize, Deserialize)]
988pub struct ServerChunkingContextOptions {
989 pub mode: Vc<NextMode>,
990 pub root_path: FileSystemPath,
991 pub node_root: FileSystemPath,
992 pub node_root_to_root_path: RcStr,
993 pub environment: Vc<Environment>,
994 pub module_id_strategy: Vc<Box<dyn ModuleIdStrategy>>,
995 pub export_usage: Vc<OptionExportUsageInfo>,
996 pub turbo_minify: Vc<bool>,
997 pub turbo_source_maps: Vc<bool>,
998 pub no_mangling: Vc<bool>,
999 pub scope_hoisting: Vc<bool>,
1000 pub debug_ids: Vc<bool>,
1001 pub client_root: FileSystemPath,
1002 pub asset_prefix: RcStr,
1003}
1004
1005#[turbo_tasks::function]
1007pub async fn get_server_chunking_context_with_client_assets(
1008 options: ServerChunkingContextOptions,
1009) -> Result<Vc<NodeJsChunkingContext>> {
1010 let ServerChunkingContextOptions {
1011 mode,
1012 root_path,
1013 node_root,
1014 node_root_to_root_path,
1015 environment,
1016 module_id_strategy,
1017 export_usage,
1018 turbo_minify,
1019 turbo_source_maps,
1020 no_mangling,
1021 scope_hoisting,
1022 debug_ids,
1023 client_root,
1024 asset_prefix,
1025 } = options;
1026
1027 let next_mode = mode.await?;
1028 let mut builder = NodeJsChunkingContext::builder(
1032 root_path,
1033 node_root.clone(),
1034 node_root_to_root_path,
1035 client_root.clone(),
1036 node_root.join("server/chunks/ssr")?,
1037 client_root.join("static/media")?,
1038 environment.to_resolved().await?,
1039 next_mode.runtime_type(),
1040 )
1041 .asset_prefix(Some(asset_prefix))
1042 .minify_type(if *turbo_minify.await? {
1043 MinifyType::Minify {
1044 mangle: (!*no_mangling.await?).then_some(MangleType::Deterministic),
1046 }
1047 } else {
1048 MinifyType::NoMinify
1049 })
1050 .source_maps(if *turbo_source_maps.await? {
1051 SourceMapsType::Full
1052 } else {
1053 SourceMapsType::None
1054 })
1055 .module_id_strategy(module_id_strategy.to_resolved().await?)
1056 .export_usage(*export_usage.await?)
1057 .file_tracing(next_mode.is_production())
1058 .debug_ids(*debug_ids.await?);
1059
1060 if next_mode.is_development() {
1061 builder = builder.use_file_source_map_uris();
1062 } else {
1063 builder = builder
1064 .chunking_config(
1065 Vc::<EcmascriptChunkType>::default().to_resolved().await?,
1066 ChunkingConfig {
1067 min_chunk_size: 20_000,
1068 max_chunk_count_per_group: 100,
1069 max_merge_chunk_size: 100_000,
1070 ..Default::default()
1071 },
1072 )
1073 .chunking_config(
1074 Vc::<CssChunkType>::default().to_resolved().await?,
1075 ChunkingConfig {
1076 max_merge_chunk_size: 100_000,
1077 ..Default::default()
1078 },
1079 )
1080 .module_merging(*scope_hoisting.await?);
1081 }
1082
1083 Ok(builder.build())
1084}
1085
1086#[turbo_tasks::function]
1088pub async fn get_server_chunking_context(
1089 options: ServerChunkingContextOptions,
1090) -> Result<Vc<NodeJsChunkingContext>> {
1091 let ServerChunkingContextOptions {
1092 mode,
1093 root_path,
1094 node_root,
1095 node_root_to_root_path,
1096 environment,
1097 module_id_strategy,
1098 export_usage,
1099 turbo_minify,
1100 turbo_source_maps,
1101 no_mangling,
1102 scope_hoisting,
1103 debug_ids,
1104 client_root,
1105 asset_prefix,
1106 } = options;
1107 let next_mode = mode.await?;
1108 let mut builder = NodeJsChunkingContext::builder(
1112 root_path,
1113 node_root.clone(),
1114 node_root_to_root_path,
1115 node_root.clone(),
1116 node_root.join("server/chunks")?,
1117 node_root.join("server/assets")?,
1118 environment.to_resolved().await?,
1119 next_mode.runtime_type(),
1120 )
1121 .client_roots_override(rcstr!("client"), client_root.clone())
1122 .asset_root_path_override(rcstr!("client"), client_root.join("static/media")?)
1123 .asset_prefix_override(rcstr!("client"), asset_prefix)
1124 .minify_type(if *turbo_minify.await? {
1125 MinifyType::Minify {
1126 mangle: (!*no_mangling.await?).then_some(MangleType::OptimalSize),
1127 }
1128 } else {
1129 MinifyType::NoMinify
1130 })
1131 .source_maps(if *turbo_source_maps.await? {
1132 SourceMapsType::Full
1133 } else {
1134 SourceMapsType::None
1135 })
1136 .module_id_strategy(module_id_strategy.to_resolved().await?)
1137 .export_usage(*export_usage.await?)
1138 .file_tracing(next_mode.is_production())
1139 .debug_ids(*debug_ids.await?);
1140
1141 if next_mode.is_development() {
1142 builder = builder.use_file_source_map_uris()
1143 } else {
1144 builder = builder
1145 .chunking_config(
1146 Vc::<EcmascriptChunkType>::default().to_resolved().await?,
1147 ChunkingConfig {
1148 min_chunk_size: 20_000,
1149 max_chunk_count_per_group: 100,
1150 max_merge_chunk_size: 100_000,
1151 ..Default::default()
1152 },
1153 )
1154 .chunking_config(
1155 Vc::<CssChunkType>::default().to_resolved().await?,
1156 ChunkingConfig {
1157 max_merge_chunk_size: 100_000,
1158 ..Default::default()
1159 },
1160 )
1161 .module_merging(*scope_hoisting.await?);
1162 }
1163
1164 Ok(builder.build())
1165}