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;
16use turbopack_node::execution_context::ExecutionContext;
17use turbopack_resolve::resolve_options_context::ResolveOptionsContext;
18
19use crate::{
20    ModuleAssetContext,
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
32#[turbo_tasks::function]
33pub async fn node_evaluate_asset_context(
34    execution_context: Vc<ExecutionContext>,
35    import_map: Option<Vc<ImportMap>>,
36    transitions: Option<Vc<TransitionOptions>>,
37    layer: Layer,
38    ignore_dynamic_requests: bool,
39) -> Result<Vc<Box<dyn AssetContext>>> {
40    let mut import_map = if let Some(import_map) = import_map {
41        import_map.owned().await?
42    } else {
43        ImportMap::empty()
44    };
45    import_map.insert_wildcard_alias(
46        "@vercel/turbopack-node/",
47        ImportMapping::PrimaryAlternative(
48            rcstr!("./*"),
49            Some(
50                turbopack_node::embed_js::embed_fs()
51                    .root()
52                    .await?
53                    .clone_value(),
54            ),
55        )
56        .resolved_cell(),
57    );
58    let import_map = import_map.resolved_cell();
59    let node_env: RcStr =
60        if let Some(node_env) = &*execution_context.env().read(rcstr!("NODE_ENV")).await? {
61            node_env.clone()
62        } else {
63            rcstr!("development")
64        };
65
66    // base context used for node_modules (and context for app code will be derived
67    // from this)
68    let resolve_options_context = ResolveOptionsContext {
69        enable_node_modules: Some(
70            execution_context
71                .project_path()
72                .await?
73                .root()
74                .await?
75                .clone_value(),
76        ),
77        enable_node_externals: true,
78        enable_node_native_modules: true,
79        custom_conditions: vec![node_env.clone(), rcstr!("node")],
80        ..Default::default()
81    };
82    // app code context, includes a rule to switch to the node_modules context
83    let resolve_options_context = ResolveOptionsContext {
84        enable_typescript: true,
85        import_map: Some(import_map),
86        rules: vec![(
87            ContextCondition::InDirectory("node_modules".to_string()),
88            resolve_options_context.clone().resolved_cell(),
89        )],
90        ..resolve_options_context
91    }
92    .cell();
93
94    Ok(Vc::upcast(ModuleAssetContext::new(
95        transitions.unwrap_or_default(),
96        CompileTimeInfo::builder(node_build_environment().to_resolved().await?)
97            .defines(
98                compile_time_defines!(
99                    process.turbopack = true,
100                    process.env.NODE_ENV = node_env.into_owned(),
101                    process.env.TURBOPACK = true
102                )
103                .resolved_cell(),
104            )
105            .cell()
106            .await?,
107        ModuleOptionsContext {
108            tree_shaking_mode: Some(TreeShakingMode::ReexportsOnly),
109            ecmascript: EcmascriptOptionsContext {
110                enable_typescript_transform: Some(
111                    TypescriptTransformOptions::default().resolved_cell(),
112                ),
113                ignore_dynamic_requests,
114                ..Default::default()
115            },
116            ..Default::default()
117        }
118        .cell(),
119        resolve_options_context,
120        layer,
121    )))
122}