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