Skip to main content

turbopack/
evaluate_context.rs

1use anyhow::Result;
2use turbo_rcstr::{RcStr, rcstr};
3use turbo_tasks::Vc;
4use turbo_tasks_env::ProcessEnv;
5use turbo_tasks_fs::FileSystem;
6use turbopack_core::{
7    compile_time_defines,
8    compile_time_info::CompileTimeInfo,
9    condition::ContextCondition,
10    context::AssetContext,
11    environment::{Environment, ExecutionEnvironment, NodeJsEnvironment},
12    ident::Layer,
13    resolve::options::{ImportMap, ImportMapping},
14};
15use turbopack_ecmascript::{TreeShakingMode, references::esm::UrlRewriteBehavior};
16use turbopack_node::execution_context::ExecutionContext;
17use turbopack_resolve::resolve_options_context::ResolveOptionsContext;
18
19use crate::{
20    ModuleAssetContext, externals_tracing_module_context,
21    module_options::{EcmascriptOptionsContext, ModuleOptionsContext, TypescriptTransformOptions},
22    transition::TransitionOptions,
23};
24
25#[turbo_tasks::function]
26pub fn node_build_environment() -> Vc<Environment> {
27    Environment::new(ExecutionEnvironment::NodeJsBuildTime(
28        NodeJsEnvironment::default().resolved_cell(),
29    ))
30}
31
32async fn node_env_value(env: Vc<Box<dyn ProcessEnv>>) -> Result<RcStr> {
33    if let Some(node_env) = &*env.read(rcstr!("NODE_ENV")).await? {
34        Ok(node_env.clone())
35    } else {
36        Ok(rcstr!("development"))
37    }
38}
39
40#[turbo_tasks::function]
41pub async fn node_evaluate_asset_context(
42    execution_context: Vc<ExecutionContext>,
43    import_map: Option<Vc<ImportMap>>,
44    transitions: Option<Vc<TransitionOptions>>,
45    layer: Layer,
46    ignore_dynamic_requests: bool,
47) -> Result<Vc<Box<dyn AssetContext>>> {
48    let mut import_map = if let Some(import_map) = import_map {
49        import_map.owned().await?
50    } else {
51        ImportMap::empty()
52    };
53    import_map.insert_wildcard_alias(
54        rcstr!("@vercel/turbopack-node/"),
55        ImportMapping::PrimaryAlternative(
56            rcstr!("./*"),
57            Some(turbopack_node::embed_js::embed_fs().root().owned().await?),
58        )
59        .resolved_cell(),
60    );
61    let import_map = import_map.resolved_cell();
62    let node_env = node_env_value(execution_context.env()).await?;
63
64    // base context used for node_modules (and context for app code will be derived
65    // from this)
66    let resolve_options_context = ResolveOptionsContext {
67        enable_node_modules: Some(
68            execution_context
69                .project_path()
70                .await?
71                .root()
72                .owned()
73                .await?,
74        ),
75        enable_node_externals: true,
76        enable_node_native_modules: true,
77        custom_conditions: vec![node_env.clone(), rcstr!("node")],
78        ..Default::default()
79    };
80    // app code context, includes a rule to switch to the node_modules context
81    let resolve_options_context = ResolveOptionsContext {
82        enable_typescript: true,
83        import_map: Some(import_map),
84        rules: vec![(
85            ContextCondition::InNodeModules,
86            resolve_options_context.clone().resolved_cell(),
87        )],
88        ..resolve_options_context
89    }
90    .cell();
91
92    Ok(Vc::upcast(ModuleAssetContext::new(
93        transitions.unwrap_or_default(),
94        CompileTimeInfo::builder(node_build_environment().to_resolved().await?)
95            .defines(
96                compile_time_defines!(
97                    process.turbopack = true,
98                    process.env.NODE_ENV = node_env.into_owned(),
99                    process.env.TURBOPACK = "1"
100                )
101                .resolved_cell(),
102            )
103            .cell()
104            .await?,
105        ModuleOptionsContext {
106            tree_shaking_mode: Some(TreeShakingMode::ReexportsOnly),
107            ecmascript: EcmascriptOptionsContext {
108                esm_url_rewrite_behavior: Some(UrlRewriteBehavior::Full),
109                enable_typescript_transform: Some(
110                    TypescriptTransformOptions::default().resolved_cell(),
111                ),
112                ignore_dynamic_requests,
113                ..Default::default()
114            },
115            ..Default::default()
116        }
117        .cell(),
118        resolve_options_context,
119        layer,
120    )))
121}
122
123#[turbo_tasks::function]
124pub async fn config_tracing_module_context(
125    execution_context: Vc<ExecutionContext>,
126) -> Result<Vc<Box<dyn AssetContext>>> {
127    let node_env = node_env_value(execution_context.env()).await?;
128
129    Ok(Vc::upcast(externals_tracing_module_context(
130        CompileTimeInfo::builder(node_build_environment().to_resolved().await?)
131            .defines(
132                compile_time_defines!(
133                    process.turbopack = true,
134                    process.env.NODE_ENV = node_env.into_owned(),
135                    process.env.TURBOPACK = "1"
136                )
137                .resolved_cell(),
138            )
139            .cell()
140            .await?,
141    )))
142}