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