Skip to main content

turbopack_resolve/
resolve_options_context.rs

1use anyhow::Result;
2use bincode::{Decode, Encode};
3use turbo_rcstr::RcStr;
4use turbo_tasks::{NonLocalValue, ResolvedVc, ValueDefault, Vc, trace::TraceRawVcs};
5use turbo_tasks_fs::FileSystemPath;
6use turbopack_core::{
7    condition::ContextCondition,
8    environment::Environment,
9    resolve::{
10        options::{ConditionValue, ImportMap, ResolvedMap},
11        plugin::{AfterResolvePlugin, BeforeResolvePlugin},
12    },
13};
14
15#[derive(Default, Debug, Clone, TraceRawVcs, PartialEq, Eq, NonLocalValue, Encode, Decode)]
16pub enum TsConfigHandling {
17    /// Ignore tsconfig and jsconfig files.
18    Disabled,
19    #[default]
20    /// Find corresponding tsconfig files based on the location of the file.
21    ContextFile,
22    /// Use the provided config file for all files if it exists, otherwise fall back to the
23    /// [`Self::ContextFile`] behavior.
24    Fixed(FileSystemPath),
25}
26
27#[turbo_tasks::value(shared)]
28#[derive(Default, Clone)]
29pub struct ResolveOptionsContext {
30    /// - Overrides `options.node_externals`
31    /// - Appends `environment.resolve_conditions`
32    /// - Overrides `options.extensions`
33    pub emulate_environment: Option<ResolvedVc<Environment>>,
34    pub enable_types: bool,
35    pub enable_typescript: bool,
36    pub enable_react: bool,
37    pub enable_node_native_modules: bool,
38    // Enable resolving of .mjs files without the .mjs extension
39    pub enable_mjs_extension: bool,
40    /// Enable resolving of the node_modules folder when within the provided
41    /// directory
42    pub enable_node_modules: Option<FileSystemPath>,
43    /// A specific path to a tsconfig.json file to use for resolving modules. If `None`, one will
44    /// be looked up through the filesystem
45    pub tsconfig_path: TsConfigHandling,
46    /// Mark well-known Node.js modules as external imports and load them using
47    /// native `require`. e.g. url, querystring, os
48    pub enable_node_externals: bool,
49    /// Mark well-known Edge modules as external imports and load them using
50    /// native `require`. e.g. buffer, events, assert
51    pub enable_edge_node_externals: bool,
52    /// Enables the "browser" field and export condition in package.json
53    pub browser: bool,
54    /// Enables the "module" field and export condition in package.json
55    pub module: bool,
56    /// Enables the "module-sync" export condition in package.json
57    pub module_sync: ConditionValue,
58    pub custom_conditions: Vec<RcStr>,
59    pub custom_extensions: Option<Vec<RcStr>>,
60    /// An additional import map to use when resolving modules.
61    ///
62    /// If set, this import map will be applied to `ResolveOption::import_map`.
63    /// It is always applied last, so any mapping defined within will take
64    /// precedence over any other (e.g. tsconfig.json `compilerOptions.paths`).
65    pub import_map: Option<ResolvedVc<ImportMap>>,
66    /// An import map to fall back to when a request could not be resolved.
67    ///
68    /// If set, this import map will be applied to
69    /// `ResolveOption::fallback_import_map`. It is always applied last, so
70    /// any mapping defined within will take precedence over any other.
71    pub fallback_import_map: Option<ResolvedVc<ImportMap>>,
72    /// An additional resolved map to use after modules have been resolved.
73    pub resolved_map: Option<ResolvedVc<ResolvedMap>>,
74    /// A list of rules to use a different resolve option context for certain
75    /// context paths. The first matching is used.
76    pub rules: Vec<(ContextCondition, ResolvedVc<ResolveOptionsContext>)>,
77    /// Plugins which get applied before and after resolving.
78    pub after_resolve_plugins: Vec<ResolvedVc<Box<dyn AfterResolvePlugin>>>,
79    pub before_resolve_plugins: Vec<ResolvedVc<Box<dyn BeforeResolvePlugin>>>,
80    /// Warn instead of error for resolve errors
81    pub loose_errors: bool,
82    /// Collect affecting sources for each resolve result.  Useful for tracing.
83    pub collect_affecting_sources: bool,
84    /// The directory that a request starting with `/` resolves from, e.g. `/dir/file.js`. When
85    /// unset, such a request isn't supported and reports an issue saying so.
86    ///
87    /// Sets [`ResolveOptions::server_relative_root`].
88    ///
89    /// [`ResolveOptions::server_relative_root`]:
90    ///     turbopack_core::resolve::options::ResolveOptions::server_relative_root
91    pub server_relative_root: Option<FileSystemPath>,
92
93    pub placeholder_for_future_extensions: (),
94}
95
96#[turbo_tasks::value_impl]
97impl ResolveOptionsContext {
98    #[turbo_tasks::function]
99    pub async fn with_types_enabled(self: Vc<Self>) -> Result<Vc<Self>> {
100        let mut clone = self.owned().await?;
101        clone.enable_types = true;
102        clone.enable_typescript = true;
103        Ok(Self::cell(clone))
104    }
105
106    /// Returns a new [`Vc<ResolveOptionsContext>`][Self] with its import map extended to include
107    /// the given import map.
108    #[turbo_tasks::function]
109    pub async fn with_extended_import_map(
110        self: Vc<Self>,
111        import_map: Vc<ImportMap>,
112    ) -> Result<Vc<Self>> {
113        let mut resolve_options_context = self.owned().await?;
114        resolve_options_context.import_map = Some(
115            resolve_options_context
116                .import_map
117                .map(|current_import_map| current_import_map.extend(import_map))
118                .unwrap_or(import_map)
119                .to_resolved()
120                .await?,
121        );
122        Ok(resolve_options_context.cell())
123    }
124
125    /// Returns a new [`Vc<ResolveOptionsContext>`][Self] with its fallback import map extended to
126    /// include the given import map.
127    #[turbo_tasks::function]
128    pub async fn with_extended_fallback_import_map(
129        self: Vc<Self>,
130        fallback_import_map: Vc<ImportMap>,
131    ) -> Result<Vc<Self>> {
132        let mut resolve_options_context = self.owned().await?;
133        resolve_options_context.fallback_import_map = Some(
134            resolve_options_context
135                .fallback_import_map
136                .map(|current_fallback_import_map| {
137                    current_fallback_import_map.extend(fallback_import_map)
138                })
139                .unwrap_or(fallback_import_map)
140                .to_resolved()
141                .await?,
142        );
143        Ok(resolve_options_context.cell())
144    }
145}
146
147#[turbo_tasks::value_impl]
148impl ValueDefault for ResolveOptionsContext {
149    #[turbo_tasks::function]
150    fn value_default() -> Vc<Self> {
151        Self::cell(Default::default())
152    }
153}