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