next_core/next_server/
context.rs

1use std::iter::once;
2
3use anyhow::{Result, bail};
4use turbo_rcstr::RcStr;
5use turbo_tasks::{FxIndexMap, OptionVcExt, ResolvedVc, Value, Vc};
6use turbo_tasks_env::{EnvMap, ProcessEnv};
7use turbo_tasks_fs::FileSystemPath;
8use turbopack::{
9    css::chunk::CssChunkType,
10    module_options::{
11        CssOptionsContext, EcmascriptOptionsContext, JsxTransformOptions, ModuleOptionsContext,
12        ModuleRule, TypeofWindow, TypescriptTransformOptions,
13    },
14    resolve_options_context::ResolveOptionsContext,
15    transition::Transition,
16};
17use turbopack_core::{
18    chunk::{
19        ChunkingConfig, MangleType, MinifyType, SourceMapsType,
20        module_id_strategies::ModuleIdStrategy,
21    },
22    compile_time_info::{
23        CompileTimeDefineValue, CompileTimeDefines, CompileTimeInfo, DefineableNameSegment,
24        FreeVarReferences,
25    },
26    environment::{
27        Environment, ExecutionEnvironment, NodeJsEnvironment, NodeJsVersion, RuntimeVersions,
28    },
29    free_var_references,
30    target::CompileTarget,
31};
32use turbopack_ecmascript::{chunk::EcmascriptChunkType, references::esm::UrlRewriteBehavior};
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;
41
42use super::{
43    resolve::ExternalCjsModulesResolvePlugin,
44    transforms::{get_next_server_internal_transforms_rules, get_next_server_transforms_rules},
45};
46use crate::{
47    mode::NextMode,
48    next_build::get_postcss_package_mapping,
49    next_client::RuntimeEntries,
50    next_config::NextConfig,
51    next_font::local::NextFontLocalResolvePlugin,
52    next_import_map::get_next_server_import_map,
53    next_server::resolve::ExternalPredicate,
54    next_shared::{
55        resolve::{
56            ModuleFeatureReportResolvePlugin, NextExternalResolvePlugin,
57            NextNodeSharedRuntimeResolvePlugin, get_invalid_client_only_resolve_plugin,
58            get_invalid_styled_jsx_resolve_plugin,
59        },
60        transforms::{
61            emotion::get_emotion_transform_rule, get_ecma_transform_rule,
62            next_react_server_components::get_next_react_server_components_transform_rule,
63            react_remove_properties::get_react_remove_properties_transform_rule,
64            relay::get_relay_transform_rule, remove_console::get_remove_console_transform_rule,
65            styled_components::get_styled_components_transform_rule,
66            styled_jsx::get_styled_jsx_transform_rule,
67            swc_ecma_transform_plugins::get_swc_ecma_transform_plugin_rule,
68        },
69        webpack_rules::webpack_loader_options,
70    },
71    transform_options::{
72        get_decorators_transform_options, get_jsx_transform_options,
73        get_typescript_transform_options,
74    },
75    util::{
76        NextRuntime, foreign_code_context_condition, get_transpiled_packages,
77        internal_assets_conditions, load_next_js_templateon,
78    },
79};
80
81#[turbo_tasks::value(shared, serialization = "auto_for_input")]
82#[derive(Debug, Copy, Clone, Hash)]
83pub enum ServerContextType {
84    Pages {
85        pages_dir: ResolvedVc<FileSystemPath>,
86    },
87    PagesApi {
88        pages_dir: ResolvedVc<FileSystemPath>,
89    },
90    PagesData {
91        pages_dir: ResolvedVc<FileSystemPath>,
92    },
93    AppSSR {
94        app_dir: ResolvedVc<FileSystemPath>,
95    },
96    AppRSC {
97        app_dir: ResolvedVc<FileSystemPath>,
98        ecmascript_client_reference_transition_name: Option<ResolvedVc<RcStr>>,
99        client_transition: Option<ResolvedVc<Box<dyn Transition>>>,
100    },
101    AppRoute {
102        app_dir: ResolvedVc<FileSystemPath>,
103        ecmascript_client_reference_transition_name: Option<ResolvedVc<RcStr>>,
104    },
105    Middleware {
106        app_dir: Option<ResolvedVc<FileSystemPath>>,
107        ecmascript_client_reference_transition_name: Option<ResolvedVc<RcStr>>,
108    },
109    Instrumentation {
110        app_dir: Option<ResolvedVc<FileSystemPath>>,
111        ecmascript_client_reference_transition_name: Option<ResolvedVc<RcStr>>,
112    },
113}
114
115impl ServerContextType {
116    pub fn supports_react_server(&self) -> bool {
117        matches!(
118            self,
119            ServerContextType::AppRSC { .. }
120                | ServerContextType::AppRoute { .. }
121                | ServerContextType::PagesApi { .. }
122                | ServerContextType::Middleware { .. }
123                | ServerContextType::Instrumentation { .. }
124        )
125    }
126}
127
128#[turbo_tasks::function]
129pub async fn get_server_resolve_options_context(
130    project_path: ResolvedVc<FileSystemPath>,
131    ty: Value<ServerContextType>,
132    mode: Vc<NextMode>,
133    next_config: Vc<NextConfig>,
134    execution_context: Vc<ExecutionContext>,
135) -> Result<Vc<ResolveOptionsContext>> {
136    let next_server_import_map =
137        get_next_server_import_map(*project_path, ty, next_config, execution_context)
138            .to_resolved()
139            .await?;
140    let foreign_code_context_condition =
141        foreign_code_context_condition(next_config, project_path).await?;
142    let root_dir = project_path.root().to_resolved().await?;
143    let module_feature_report_resolve_plugin = ModuleFeatureReportResolvePlugin::new(*project_path)
144        .to_resolved()
145        .await?;
146    let invalid_client_only_resolve_plugin = get_invalid_client_only_resolve_plugin(project_path)
147        .to_resolved()
148        .await?;
149    let invalid_styled_jsx_client_only_resolve_plugin =
150        get_invalid_styled_jsx_resolve_plugin(project_path)
151            .to_resolved()
152            .await?;
153
154    // Always load these predefined packages as external.
155    let mut external_packages: Vec<RcStr> = load_next_js_templateon(
156        project_path,
157        "dist/lib/server-external-packages.json".into(),
158    )
159    .await?;
160
161    let mut transpiled_packages = get_transpiled_packages(next_config, *project_path)
162        .owned()
163        .await?;
164
165    transpiled_packages.extend(
166        (*next_config.optimize_package_imports().await?)
167            .iter()
168            .cloned(),
169    );
170
171    let server_external_packages = &*next_config.server_external_packages().await?;
172
173    let conflicting_packages = transpiled_packages
174        .iter()
175        .filter(|package| server_external_packages.contains(package))
176        .collect::<Vec<_>>();
177
178    if !conflicting_packages.is_empty() {
179        bail!(
180            "The packages specified in the 'transpilePackages' conflict with the \
181             'serverExternalPackages': {:?}",
182            conflicting_packages
183        );
184    }
185
186    // Add the config's own list of external packages.
187    external_packages.extend(server_external_packages.iter().cloned());
188
189    external_packages.retain(|item| !transpiled_packages.contains(item));
190
191    let ty = ty.into_value();
192
193    let server_external_packages_plugin = ExternalCjsModulesResolvePlugin::new(
194        *project_path,
195        project_path.root(),
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?.condition().to_string().into()];
203    custom_conditions.extend(
204        NextRuntime::NodeJs
205            .conditions()
206            .iter()
207            .map(ToString::to_string)
208            .map(RcStr::from),
209    );
210
211    if ty.supports_react_server() {
212        custom_conditions.push("react-server".into());
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,
220            project_path.root(),
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)
229        .to_resolved()
230        .await?;
231    let next_node_shared_runtime_plugin =
232        NextNodeSharedRuntimeResolvePlugin::new(*project_path, Value::new(ty))
233            .to_resolved()
234            .await?;
235
236    let mut before_resolve_plugins = match ty {
237        ServerContextType::Pages { .. }
238        | ServerContextType::AppSSR { .. }
239        | ServerContextType::AppRSC { .. } => {
240            vec![
241                ResolvedVc::upcast(
242                    NextFontLocalResolvePlugin::new(*project_path)
243                        .to_resolved()
244                        .await?,
245                ),
246                ResolvedVc::upcast(module_feature_report_resolve_plugin),
247            ]
248        }
249        ServerContextType::PagesData { .. }
250        | ServerContextType::PagesApi { .. }
251        | ServerContextType::AppRoute { .. }
252        | ServerContextType::Middleware { .. }
253        | ServerContextType::Instrumentation { .. } => {
254            vec![ResolvedVc::upcast(module_feature_report_resolve_plugin)]
255        }
256    };
257
258    let after_resolve_plugins = match ty {
259        ServerContextType::Pages { .. }
260        | ServerContextType::PagesApi { .. }
261        | ServerContextType::PagesData { .. } => {
262            vec![
263                ResolvedVc::upcast(next_node_shared_runtime_plugin),
264                ResolvedVc::upcast(external_cjs_modules_plugin),
265                ResolvedVc::upcast(next_external_plugin),
266            ]
267        }
268        ServerContextType::AppSSR { .. }
269        | ServerContextType::AppRSC { .. }
270        | ServerContextType::AppRoute { .. } => {
271            vec![
272                ResolvedVc::upcast(next_node_shared_runtime_plugin),
273                ResolvedVc::upcast(server_external_packages_plugin),
274                ResolvedVc::upcast(next_external_plugin),
275            ]
276        }
277        ServerContextType::Middleware { .. } | ServerContextType::Instrumentation { .. } => {
278            vec![
279                ResolvedVc::upcast(next_node_shared_runtime_plugin),
280                ResolvedVc::upcast(server_external_packages_plugin),
281                ResolvedVc::upcast(next_external_plugin),
282            ]
283        }
284    };
285
286    // Inject resolve plugin to assert incorrect import to client|server-only for
287    // the corresponding context. Refer https://github.com/vercel/next.js/blob/ad15817f0368ba154bed6d85320335d4b67b7348/packages/next/src/build/webpack-config.ts#L1205-L1235
288    // how it is applied in the webpack config.
289    // Unlike webpack which alias client-only -> runtime code -> build-time error
290    // code, we use resolve plugin to detect original import directly. This
291    // means each resolve plugin must be injected only for the context where the
292    // alias resolves into the error. The alias lives in here: https://github.com/vercel/next.js/blob/0060de1c4905593ea875fa7250d4b5d5ce10897d/packages/next-swc/crates/next-core/src/next_import_map.rs#L534
293    match ty {
294        ServerContextType::Pages { .. } | ServerContextType::PagesApi { .. } => {
295            //noop
296        }
297        ServerContextType::PagesData { .. }
298        | ServerContextType::AppRSC { .. }
299        | ServerContextType::AppRoute { .. }
300        | ServerContextType::Middleware { .. }
301        | ServerContextType::Instrumentation { .. } => {
302            before_resolve_plugins.push(ResolvedVc::upcast(invalid_client_only_resolve_plugin));
303            before_resolve_plugins.push(ResolvedVc::upcast(
304                invalid_styled_jsx_client_only_resolve_plugin,
305            ));
306        }
307        ServerContextType::AppSSR { .. } => {
308            //[TODO] Build error in this context makes rsc-build-error.ts fail which expects runtime error code
309            // looks like webpack and turbopack have different order, webpack runs rsc transform first, turbopack triggers resolve plugin first.
310        }
311    }
312
313    let resolve_options_context = ResolveOptionsContext {
314        enable_node_modules: Some(root_dir),
315        enable_node_externals: true,
316        enable_node_native_modules: true,
317        module: true,
318        custom_conditions,
319        import_map: Some(next_server_import_map),
320        before_resolve_plugins,
321        after_resolve_plugins,
322        ..Default::default()
323    };
324
325    Ok(ResolveOptionsContext {
326        enable_typescript: true,
327        enable_react: true,
328        enable_mjs_extension: true,
329        custom_extensions: next_config.resolve_extension().owned().await?,
330        tsconfig_path: next_config
331            .typescript_tsconfig_path()
332            .await?
333            .as_ref()
334            .map(|p| project_path.join(p.to_owned()))
335            .to_resolved()
336            .await?,
337        rules: vec![(
338            foreign_code_context_condition,
339            resolve_options_context.clone().resolved_cell(),
340        )],
341        ..resolve_options_context
342    }
343    .cell())
344}
345
346fn defines(define_env: &FxIndexMap<RcStr, RcStr>) -> CompileTimeDefines {
347    let mut defines = FxIndexMap::default();
348
349    for (k, v) in define_env {
350        defines
351            .entry(
352                k.split('.')
353                    .map(|s| DefineableNameSegment::Name(s.into()))
354                    .collect::<Vec<_>>(),
355            )
356            .or_insert_with(|| {
357                let val = serde_json::from_str(v);
358                match val {
359                    Ok(serde_json::Value::Bool(v)) => CompileTimeDefineValue::Bool(v),
360                    Ok(serde_json::Value::String(v)) => CompileTimeDefineValue::String(v.into()),
361                    _ => CompileTimeDefineValue::JSON(v.clone()),
362                }
363            });
364    }
365
366    CompileTimeDefines(defines)
367}
368
369#[turbo_tasks::function]
370async fn next_server_defines(define_env: Vc<EnvMap>) -> Result<Vc<CompileTimeDefines>> {
371    Ok(defines(&*define_env.await?).cell())
372}
373
374#[turbo_tasks::function]
375async fn next_server_free_vars(define_env: Vc<EnvMap>) -> Result<Vc<FreeVarReferences>> {
376    Ok(free_var_references!(..defines(&*define_env.await?).into_iter()).cell())
377}
378
379#[turbo_tasks::function]
380pub async fn get_server_compile_time_info(
381    process_env: Vc<Box<dyn ProcessEnv>>,
382    define_env: Vc<EnvMap>,
383    cwd: RcStr,
384) -> Result<Vc<CompileTimeInfo>> {
385    CompileTimeInfo::builder(
386        Environment::new(Value::new(ExecutionEnvironment::NodeJsLambda(
387            NodeJsEnvironment {
388                compile_target: CompileTarget::current().to_resolved().await?,
389                node_version: NodeJsVersion::resolved_cell(NodeJsVersion::Current(
390                    process_env.to_resolved().await?,
391                )),
392                cwd: ResolvedVc::cell(Some(cwd)),
393            }
394            .resolved_cell(),
395        )))
396        .to_resolved()
397        .await?,
398    )
399    .defines(next_server_defines(define_env).to_resolved().await?)
400    .free_var_references(next_server_free_vars(define_env).to_resolved().await?)
401    .cell()
402    .await
403}
404
405#[turbo_tasks::function]
406pub async fn get_server_module_options_context(
407    project_path: ResolvedVc<FileSystemPath>,
408    execution_context: ResolvedVc<ExecutionContext>,
409    ty: Value<ServerContextType>,
410    mode: Vc<NextMode>,
411    next_config: Vc<NextConfig>,
412    next_runtime: NextRuntime,
413    encryption_key: ResolvedVc<RcStr>,
414) -> Result<Vc<ModuleOptionsContext>> {
415    let next_mode = mode.await?;
416    let mut next_server_rules = get_next_server_transforms_rules(
417        next_config,
418        ty.into_value(),
419        mode,
420        false,
421        next_runtime,
422        encryption_key,
423    )
424    .await?;
425    let mut foreign_next_server_rules = get_next_server_transforms_rules(
426        next_config,
427        ty.into_value(),
428        mode,
429        true,
430        next_runtime,
431        encryption_key,
432    )
433    .await?;
434    let mut internal_custom_rules = get_next_server_internal_transforms_rules(
435        ty.into_value(),
436        next_config.mdx_rs().await?.is_some(),
437    )
438    .await?;
439
440    let foreign_code_context_condition =
441        foreign_code_context_condition(next_config, project_path).await?;
442    let postcss_transform_options = PostCssTransformOptions {
443        postcss_package: Some(
444            get_postcss_package_mapping(*project_path)
445                .to_resolved()
446                .await?,
447        ),
448        config_location: PostCssConfigLocation::ProjectPathOrLocalPath,
449        ..Default::default()
450    };
451    let postcss_foreign_transform_options = PostCssTransformOptions {
452        // For node_modules we don't want to resolve postcss config relative to the file
453        // being compiled, instead it only uses the project root postcss
454        // config.
455        config_location: PostCssConfigLocation::ProjectPath,
456        ..postcss_transform_options.clone()
457    };
458    let enable_postcss_transform = Some(postcss_transform_options.resolved_cell());
459    let enable_foreign_postcss_transform = Some(postcss_foreign_transform_options.resolved_cell());
460
461    let mut conditions = vec![mode.await?.condition().into()];
462    conditions.extend(
463        next_runtime
464            .conditions()
465            .iter()
466            .map(ToString::to_string)
467            .map(RcStr::from),
468    );
469
470    // A separate webpack rules will be applied to codes matching
471    // foreign_code_context_condition. This allows to import codes from
472    // node_modules that requires webpack loaders, which next-dev implicitly
473    // does by default.
474    let foreign_enable_webpack_loaders = webpack_loader_options(
475        project_path,
476        next_config,
477        true,
478        conditions
479            .iter()
480            .cloned()
481            .chain(once("foreign".into()))
482            .collect(),
483    )
484    .await?;
485
486    // Now creates a webpack rules that applies to all codes.
487    let enable_webpack_loaders =
488        webpack_loader_options(project_path, next_config, false, conditions).await?;
489
490    let tree_shaking_mode_for_user_code = *next_config
491        .tree_shaking_mode_for_user_code(next_mode.is_development())
492        .await?;
493    let tree_shaking_mode_for_foreign_code = *next_config
494        .tree_shaking_mode_for_foreign_code(next_mode.is_development())
495        .await?;
496    let versions = RuntimeVersions(Default::default()).cell();
497
498    // ModuleOptionsContext related options
499    let tsconfig = get_typescript_transform_options(*project_path)
500        .to_resolved()
501        .await?;
502    let decorators_options = get_decorators_transform_options(*project_path);
503    let enable_mdx_rs = *next_config.mdx_rs().await?;
504
505    // Get the jsx transform options for the `client` side.
506    // This matches to the behavior of existing webpack config, if issuer layer is
507    // ssr or pages-browser (client bundle for the browser)
508    // applies client specific swc transforms.
509    //
510    // This enables correct emotion transform and other hydration between server and
511    // client bundles. ref: https://github.com/vercel/next.js/blob/4bbf9b6c70d2aa4237defe2bebfa790cdb7e334e/packages/next/src/build/webpack-config.ts#L1421-L1426
512    let jsx_runtime_options =
513        get_jsx_transform_options(*project_path, mode, None, false, next_config)
514            .to_resolved()
515            .await?;
516    let rsc_jsx_runtime_options =
517        get_jsx_transform_options(*project_path, mode, None, true, next_config)
518            .to_resolved()
519            .await?;
520
521    // A set of custom ecma transform rules being applied to server context.
522    let source_transform_rules: Vec<ModuleRule> = vec![
523        get_swc_ecma_transform_plugin_rule(next_config, project_path).await?,
524        get_relay_transform_rule(next_config, project_path).await?,
525        get_emotion_transform_rule(next_config).await?,
526        get_react_remove_properties_transform_rule(next_config).await?,
527        get_remove_console_transform_rule(next_config).await?,
528    ]
529    .into_iter()
530    .flatten()
531    .collect();
532
533    // Custom ecma transform rules selectively being applied depends on the server
534    // context type.
535    let styled_components_transform_rule =
536        get_styled_components_transform_rule(next_config).await?;
537    let styled_jsx_transform_rule = get_styled_jsx_transform_rule(next_config, versions).await?;
538
539    let source_maps = if *next_config.server_source_maps().await? {
540        SourceMapsType::Full
541    } else {
542        SourceMapsType::None
543    };
544    let module_options_context = ModuleOptionsContext {
545        ecmascript: EcmascriptOptionsContext {
546            enable_typeof_window_inlining: Some(TypeofWindow::Undefined),
547            import_externals: *next_config.import_externals().await?,
548            ignore_dynamic_requests: true,
549            source_maps,
550            ..Default::default()
551        },
552        execution_context: Some(execution_context),
553        css: CssOptionsContext {
554            source_maps,
555            ..Default::default()
556        },
557        tree_shaking_mode: tree_shaking_mode_for_user_code,
558        side_effect_free_packages: next_config.optimize_package_imports().owned().await?,
559        enable_externals_tracing: if next_mode.is_production() {
560            Some(project_path)
561        } else {
562            None
563        },
564        keep_last_successful_parse: next_mode.is_development(),
565        ..Default::default()
566    };
567
568    let ty = ty.into_value();
569    let module_options_context = match ty {
570        ServerContextType::Pages { .. }
571        | ServerContextType::PagesData { .. }
572        | ServerContextType::PagesApi { .. } => {
573            let mut custom_source_transform_rules: Vec<ModuleRule> =
574                vec![styled_components_transform_rule, styled_jsx_transform_rule]
575                    .into_iter()
576                    .flatten()
577                    .collect();
578
579            if let ServerContextType::Pages { .. } = ty {
580                custom_source_transform_rules.push(
581                    get_next_react_server_components_transform_rule(next_config, false, None)
582                        .await?,
583                );
584            }
585
586            next_server_rules.extend(custom_source_transform_rules.iter().cloned());
587            next_server_rules.extend(source_transform_rules);
588
589            foreign_next_server_rules.extend(custom_source_transform_rules);
590            foreign_next_server_rules.extend(internal_custom_rules);
591
592            let url_rewrite_behavior = Some(
593                //https://github.com/vercel/next.js/blob/bbb730e5ef10115ed76434f250379f6f53efe998/packages/next/src/build/webpack-config.ts#L1384
594                if let ServerContextType::PagesApi { .. } = ty {
595                    UrlRewriteBehavior::Full
596                } else {
597                    UrlRewriteBehavior::Relative
598                },
599            );
600
601            let module_options_context = ModuleOptionsContext {
602                ecmascript: EcmascriptOptionsContext {
603                    esm_url_rewrite_behavior: url_rewrite_behavior,
604                    ..module_options_context.ecmascript
605                },
606                ..module_options_context
607            };
608
609            let foreign_code_module_options_context = ModuleOptionsContext {
610                ecmascript: EcmascriptOptionsContext {
611                    enable_typeof_window_inlining: None,
612                    ..module_options_context.ecmascript
613                },
614                module_rules: foreign_next_server_rules.clone(),
615                enable_webpack_loaders: foreign_enable_webpack_loaders,
616                // NOTE(WEB-1016) PostCSS transforms should also apply to foreign code.
617                enable_postcss_transform: enable_foreign_postcss_transform,
618                tree_shaking_mode: tree_shaking_mode_for_foreign_code,
619                ..module_options_context.clone()
620            };
621
622            let internal_module_options_context = ModuleOptionsContext {
623                ecmascript: EcmascriptOptionsContext {
624                    enable_typescript_transform: Some(
625                        TypescriptTransformOptions::default().resolved_cell(),
626                    ),
627                    enable_jsx: Some(JsxTransformOptions::default().resolved_cell()),
628                    ..module_options_context.ecmascript.clone()
629                },
630                module_rules: foreign_next_server_rules,
631                ..module_options_context.clone()
632            };
633
634            ModuleOptionsContext {
635                ecmascript: EcmascriptOptionsContext {
636                    enable_jsx: Some(jsx_runtime_options),
637                    enable_typescript_transform: Some(tsconfig),
638                    enable_decorators: Some(decorators_options.to_resolved().await?),
639                    ..module_options_context.ecmascript
640                },
641                enable_webpack_loaders,
642                enable_postcss_transform,
643                enable_mdx_rs,
644                rules: vec![
645                    (
646                        foreign_code_context_condition,
647                        foreign_code_module_options_context.resolved_cell(),
648                    ),
649                    (
650                        internal_assets_conditions().await?,
651                        internal_module_options_context.resolved_cell(),
652                    ),
653                ],
654                module_rules: next_server_rules,
655                ..module_options_context
656            }
657        }
658        ServerContextType::AppSSR { app_dir, .. } => {
659            let mut custom_source_transform_rules: Vec<ModuleRule> =
660                vec![styled_components_transform_rule, styled_jsx_transform_rule]
661                    .into_iter()
662                    .flatten()
663                    .collect();
664
665            foreign_next_server_rules.extend(custom_source_transform_rules.iter().cloned());
666            foreign_next_server_rules.extend(internal_custom_rules);
667
668            custom_source_transform_rules.push(
669                get_next_react_server_components_transform_rule(next_config, false, Some(app_dir))
670                    .await?,
671            );
672
673            next_server_rules.extend(custom_source_transform_rules.clone());
674            next_server_rules.extend(source_transform_rules);
675
676            let foreign_code_module_options_context = ModuleOptionsContext {
677                ecmascript: EcmascriptOptionsContext {
678                    enable_typeof_window_inlining: None,
679                    ..module_options_context.ecmascript
680                },
681                module_rules: foreign_next_server_rules.clone(),
682                enable_webpack_loaders: foreign_enable_webpack_loaders,
683                // NOTE(WEB-1016) PostCSS transforms should also apply to foreign code.
684                enable_postcss_transform: enable_foreign_postcss_transform,
685                tree_shaking_mode: tree_shaking_mode_for_foreign_code,
686                ..module_options_context.clone()
687            };
688            let internal_module_options_context = ModuleOptionsContext {
689                ecmascript: EcmascriptOptionsContext {
690                    enable_typescript_transform: Some(
691                        TypescriptTransformOptions::default().resolved_cell(),
692                    ),
693                    ..module_options_context.ecmascript.clone()
694                },
695                module_rules: foreign_next_server_rules,
696                ..module_options_context.clone()
697            };
698
699            ModuleOptionsContext {
700                ecmascript: EcmascriptOptionsContext {
701                    enable_jsx: Some(jsx_runtime_options),
702                    enable_typescript_transform: Some(tsconfig),
703                    enable_decorators: Some(decorators_options.to_resolved().await?),
704                    ..module_options_context.ecmascript
705                },
706                enable_webpack_loaders,
707                enable_postcss_transform,
708                enable_mdx_rs,
709                rules: vec![
710                    (
711                        foreign_code_context_condition,
712                        foreign_code_module_options_context.resolved_cell(),
713                    ),
714                    (
715                        internal_assets_conditions().await?,
716                        internal_module_options_context.resolved_cell(),
717                    ),
718                ],
719                module_rules: next_server_rules,
720                ..module_options_context
721            }
722        }
723        ServerContextType::AppRSC {
724            app_dir,
725            ecmascript_client_reference_transition_name,
726            ..
727        } => {
728            let mut custom_source_transform_rules: Vec<ModuleRule> =
729                vec![styled_components_transform_rule, styled_jsx_transform_rule]
730                    .into_iter()
731                    .flatten()
732                    .collect();
733
734            if let Some(ecmascript_client_reference_transition_name) =
735                ecmascript_client_reference_transition_name
736            {
737                custom_source_transform_rules.push(get_ecma_transform_rule(
738                    Box::new(ClientDirectiveTransformer::new(
739                        ecmascript_client_reference_transition_name,
740                    )),
741                    enable_mdx_rs.is_some(),
742                    true,
743                ));
744            }
745
746            foreign_next_server_rules.extend(custom_source_transform_rules.iter().cloned());
747            foreign_next_server_rules.extend(internal_custom_rules);
748
749            custom_source_transform_rules.push(
750                get_next_react_server_components_transform_rule(next_config, true, Some(app_dir))
751                    .await?,
752            );
753
754            next_server_rules.extend(custom_source_transform_rules.clone());
755            next_server_rules.extend(source_transform_rules);
756
757            let foreign_code_module_options_context = ModuleOptionsContext {
758                module_rules: foreign_next_server_rules.clone(),
759                enable_webpack_loaders: foreign_enable_webpack_loaders,
760                // NOTE(WEB-1016) PostCSS transforms should also apply to foreign code.
761                enable_postcss_transform: enable_foreign_postcss_transform,
762                tree_shaking_mode: tree_shaking_mode_for_foreign_code,
763                ..module_options_context.clone()
764            };
765            let internal_module_options_context = ModuleOptionsContext {
766                ecmascript: EcmascriptOptionsContext {
767                    enable_typescript_transform: Some(
768                        TypescriptTransformOptions::default().resolved_cell(),
769                    ),
770                    ..module_options_context.ecmascript.clone()
771                },
772                module_rules: foreign_next_server_rules,
773                ..module_options_context.clone()
774            };
775            ModuleOptionsContext {
776                ecmascript: EcmascriptOptionsContext {
777                    enable_jsx: Some(rsc_jsx_runtime_options),
778                    enable_typescript_transform: Some(tsconfig),
779                    enable_decorators: Some(decorators_options.to_resolved().await?),
780                    ..module_options_context.ecmascript
781                },
782                enable_webpack_loaders,
783                enable_postcss_transform,
784                enable_mdx_rs,
785                rules: vec![
786                    (
787                        foreign_code_context_condition,
788                        foreign_code_module_options_context.resolved_cell(),
789                    ),
790                    (
791                        internal_assets_conditions().await?,
792                        internal_module_options_context.resolved_cell(),
793                    ),
794                ],
795                module_rules: next_server_rules,
796                ..module_options_context
797            }
798        }
799        ServerContextType::AppRoute {
800            app_dir,
801            ecmascript_client_reference_transition_name,
802        } => {
803            next_server_rules.extend(source_transform_rules);
804
805            let mut common_next_server_rules = vec![
806                get_next_react_server_components_transform_rule(next_config, true, Some(app_dir))
807                    .await?,
808            ];
809
810            if let Some(ecmascript_client_reference_transition_name) =
811                ecmascript_client_reference_transition_name
812            {
813                common_next_server_rules.push(get_ecma_transform_rule(
814                    Box::new(ClientDirectiveTransformer::new(
815                        ecmascript_client_reference_transition_name,
816                    )),
817                    enable_mdx_rs.is_some(),
818                    true,
819                ));
820            }
821
822            next_server_rules.extend(common_next_server_rules.iter().cloned());
823            internal_custom_rules.extend(common_next_server_rules);
824
825            let module_options_context = ModuleOptionsContext {
826                ecmascript: EcmascriptOptionsContext {
827                    esm_url_rewrite_behavior: Some(UrlRewriteBehavior::Full),
828                    ..module_options_context.ecmascript
829                },
830                ..module_options_context
831            };
832            let foreign_code_module_options_context = ModuleOptionsContext {
833                module_rules: internal_custom_rules.clone(),
834                enable_webpack_loaders: foreign_enable_webpack_loaders,
835                // NOTE(WEB-1016) PostCSS transforms should also apply to foreign code.
836                enable_postcss_transform: enable_foreign_postcss_transform,
837                tree_shaking_mode: tree_shaking_mode_for_foreign_code,
838                ..module_options_context.clone()
839            };
840            let internal_module_options_context = ModuleOptionsContext {
841                ecmascript: EcmascriptOptionsContext {
842                    enable_typescript_transform: Some(
843                        TypescriptTransformOptions::default().resolved_cell(),
844                    ),
845                    ..module_options_context.ecmascript.clone()
846                },
847                module_rules: internal_custom_rules,
848                ..module_options_context.clone()
849            };
850            ModuleOptionsContext {
851                ecmascript: EcmascriptOptionsContext {
852                    enable_jsx: Some(rsc_jsx_runtime_options),
853                    enable_typescript_transform: Some(tsconfig),
854                    enable_decorators: Some(decorators_options.to_resolved().await?),
855                    ..module_options_context.ecmascript
856                },
857                enable_webpack_loaders,
858                enable_postcss_transform,
859                enable_mdx_rs,
860                rules: vec![
861                    (
862                        foreign_code_context_condition,
863                        foreign_code_module_options_context.resolved_cell(),
864                    ),
865                    (
866                        internal_assets_conditions().await?,
867                        internal_module_options_context.resolved_cell(),
868                    ),
869                ],
870                module_rules: next_server_rules,
871                ..module_options_context
872            }
873        }
874        ServerContextType::Middleware {
875            app_dir,
876            ecmascript_client_reference_transition_name,
877        }
878        | ServerContextType::Instrumentation {
879            app_dir,
880            ecmascript_client_reference_transition_name,
881        } => {
882            let mut custom_source_transform_rules: Vec<ModuleRule> =
883                vec![styled_components_transform_rule, styled_jsx_transform_rule]
884                    .into_iter()
885                    .flatten()
886                    .collect();
887
888            if let Some(ecmascript_client_reference_transition_name) =
889                ecmascript_client_reference_transition_name
890            {
891                custom_source_transform_rules.push(get_ecma_transform_rule(
892                    Box::new(ClientDirectiveTransformer::new(
893                        ecmascript_client_reference_transition_name,
894                    )),
895                    enable_mdx_rs.is_some(),
896                    true,
897                ));
898            } else {
899                custom_source_transform_rules.push(get_ecma_transform_rule(
900                    Box::new(ClientDisallowedDirectiveTransformer::new(
901                        "next/dist/client/use-client-disallowed.js".to_string(),
902                    )),
903                    enable_mdx_rs.is_some(),
904                    true,
905                ));
906            }
907
908            custom_source_transform_rules.push(
909                get_next_react_server_components_transform_rule(next_config, true, app_dir).await?,
910            );
911
912            internal_custom_rules.extend(custom_source_transform_rules.iter().cloned());
913
914            next_server_rules.extend(custom_source_transform_rules);
915            next_server_rules.extend(source_transform_rules);
916
917            let module_options_context = ModuleOptionsContext {
918                ecmascript: EcmascriptOptionsContext {
919                    esm_url_rewrite_behavior: Some(UrlRewriteBehavior::Full),
920                    ..module_options_context.ecmascript
921                },
922                ..module_options_context
923            };
924            let foreign_code_module_options_context = ModuleOptionsContext {
925                module_rules: internal_custom_rules.clone(),
926                enable_webpack_loaders: foreign_enable_webpack_loaders,
927                // NOTE(WEB-1016) PostCSS transforms should also apply to foreign code.
928                enable_postcss_transform: enable_foreign_postcss_transform,
929                tree_shaking_mode: tree_shaking_mode_for_foreign_code,
930                ..module_options_context.clone()
931            };
932            let internal_module_options_context = ModuleOptionsContext {
933                ecmascript: EcmascriptOptionsContext {
934                    enable_typescript_transform: Some(
935                        TypescriptTransformOptions::default().resolved_cell(),
936                    ),
937                    ..module_options_context.ecmascript.clone()
938                },
939                module_rules: internal_custom_rules,
940                ..module_options_context.clone()
941            };
942            ModuleOptionsContext {
943                ecmascript: EcmascriptOptionsContext {
944                    enable_jsx: Some(jsx_runtime_options),
945                    enable_typescript_transform: Some(tsconfig),
946                    enable_decorators: Some(decorators_options.to_resolved().await?),
947                    ..module_options_context.ecmascript
948                },
949                enable_webpack_loaders,
950                enable_postcss_transform,
951                enable_mdx_rs,
952                rules: vec![
953                    (
954                        foreign_code_context_condition,
955                        foreign_code_module_options_context.resolved_cell(),
956                    ),
957                    (
958                        internal_assets_conditions().await?,
959                        internal_module_options_context.resolved_cell(),
960                    ),
961                ],
962                module_rules: next_server_rules,
963                ..module_options_context
964            }
965        }
966    }
967    .cell();
968
969    Ok(module_options_context)
970}
971
972#[turbo_tasks::function]
973pub fn get_server_runtime_entries(
974    _ty: Value<ServerContextType>,
975    _mode: Vc<NextMode>,
976) -> Vc<RuntimeEntries> {
977    let runtime_entries = vec![];
978    Vc::cell(runtime_entries)
979}
980
981#[turbo_tasks::function]
982pub async fn get_server_chunking_context_with_client_assets(
983    mode: Vc<NextMode>,
984    root_path: ResolvedVc<FileSystemPath>,
985    node_root: ResolvedVc<FileSystemPath>,
986    node_root_to_root_path: ResolvedVc<RcStr>,
987    client_root: ResolvedVc<FileSystemPath>,
988    asset_prefix: ResolvedVc<Option<RcStr>>,
989    environment: ResolvedVc<Environment>,
990    module_id_strategy: ResolvedVc<Box<dyn ModuleIdStrategy>>,
991    turbo_minify: Vc<bool>,
992    turbo_source_maps: Vc<bool>,
993    no_mangling: Vc<bool>,
994) -> Result<Vc<NodeJsChunkingContext>> {
995    let next_mode = mode.await?;
996    // TODO(alexkirsz) This should return a trait that can be implemented by the
997    // different server chunking contexts. OR the build chunking context should
998    // support both production and development modes.
999    let mut builder = NodeJsChunkingContext::builder(
1000        root_path,
1001        node_root,
1002        node_root_to_root_path,
1003        client_root,
1004        node_root
1005            .join("server/chunks/ssr".into())
1006            .to_resolved()
1007            .await?,
1008        client_root
1009            .join("static/media".into())
1010            .to_resolved()
1011            .await?,
1012        environment,
1013        next_mode.runtime_type(),
1014    )
1015    .asset_prefix(asset_prefix)
1016    .minify_type(if *turbo_minify.await? {
1017        MinifyType::Minify {
1018            // React needs deterministic function names to work correctly.
1019            mangle: (!*no_mangling.await?).then_some(MangleType::Deterministic),
1020        }
1021    } else {
1022        MinifyType::NoMinify
1023    })
1024    .source_maps(if *turbo_source_maps.await? {
1025        SourceMapsType::Full
1026    } else {
1027        SourceMapsType::None
1028    })
1029    .module_id_strategy(module_id_strategy)
1030    .file_tracing(next_mode.is_production());
1031
1032    if next_mode.is_development() {
1033        builder = builder.use_file_source_map_uris();
1034    } else {
1035        builder = builder.chunking_config(
1036            Vc::<EcmascriptChunkType>::default().to_resolved().await?,
1037            ChunkingConfig {
1038                min_chunk_size: 20_000,
1039                max_chunk_count_per_group: 100,
1040                max_merge_chunk_size: 100_000,
1041                ..Default::default()
1042            },
1043        );
1044        builder = builder.chunking_config(
1045            Vc::<CssChunkType>::default().to_resolved().await?,
1046            ChunkingConfig {
1047                max_merge_chunk_size: 100_000,
1048                ..Default::default()
1049            },
1050        );
1051    }
1052
1053    Ok(builder.build())
1054}
1055
1056#[turbo_tasks::function]
1057pub async fn get_server_chunking_context(
1058    mode: Vc<NextMode>,
1059    root_path: ResolvedVc<FileSystemPath>,
1060    node_root: ResolvedVc<FileSystemPath>,
1061    node_root_to_root_path: ResolvedVc<RcStr>,
1062    environment: ResolvedVc<Environment>,
1063    module_id_strategy: ResolvedVc<Box<dyn ModuleIdStrategy>>,
1064    turbo_minify: Vc<bool>,
1065    turbo_source_maps: Vc<bool>,
1066    no_mangling: Vc<bool>,
1067) -> Result<Vc<NodeJsChunkingContext>> {
1068    let next_mode = mode.await?;
1069    // TODO(alexkirsz) This should return a trait that can be implemented by the
1070    // different server chunking contexts. OR the build chunking context should
1071    // support both production and development modes.
1072    let mut builder = NodeJsChunkingContext::builder(
1073        root_path,
1074        node_root,
1075        node_root_to_root_path,
1076        node_root,
1077        node_root.join("server/chunks".into()).to_resolved().await?,
1078        node_root.join("server/assets".into()).to_resolved().await?,
1079        environment,
1080        next_mode.runtime_type(),
1081    )
1082    .minify_type(if *turbo_minify.await? {
1083        MinifyType::Minify {
1084            mangle: (!*no_mangling.await?).then_some(MangleType::OptimalSize),
1085        }
1086    } else {
1087        MinifyType::NoMinify
1088    })
1089    .source_maps(if *turbo_source_maps.await? {
1090        SourceMapsType::Full
1091    } else {
1092        SourceMapsType::None
1093    })
1094    .module_id_strategy(module_id_strategy)
1095    .file_tracing(next_mode.is_production());
1096
1097    if next_mode.is_development() {
1098        builder = builder.use_file_source_map_uris()
1099    } else {
1100        builder = builder.chunking_config(
1101            Vc::<EcmascriptChunkType>::default().to_resolved().await?,
1102            ChunkingConfig {
1103                min_chunk_size: 20_000,
1104                max_chunk_count_per_group: 100,
1105                max_merge_chunk_size: 100_000,
1106                ..Default::default()
1107            },
1108        );
1109        builder = builder.chunking_config(
1110            Vc::<CssChunkType>::default().to_resolved().await?,
1111            ChunkingConfig {
1112                max_merge_chunk_size: 100_000,
1113                ..Default::default()
1114            },
1115        );
1116    }
1117
1118    Ok(builder.build())
1119}