turbopack/module_options/
module_options_context.rs

1use std::fmt::Debug;
2
3use serde::{Deserialize, Serialize};
4use turbo_esregex::EsRegex;
5use turbo_rcstr::RcStr;
6use turbo_tasks::{FxIndexMap, NonLocalValue, ResolvedVc, ValueDefault, Vc, trace::TraceRawVcs};
7use turbo_tasks_fs::FileSystemPath;
8use turbopack_core::{
9    chunk::SourceMapsType, compile_time_info::CompileTimeInfo, condition::ContextCondition,
10    environment::Environment, resolve::options::ImportMapping,
11};
12use turbopack_ecmascript::{TreeShakingMode, references::esm::UrlRewriteBehavior};
13pub use turbopack_mdx::MdxTransformOptions;
14use turbopack_node::{
15    execution_context::ExecutionContext,
16    transforms::{postcss::PostCssTransformOptions, webpack::WebpackLoaderItems},
17};
18
19use super::ModuleRule;
20use crate::module_options::RuleCondition;
21
22#[derive(Clone, PartialEq, Eq, Debug, TraceRawVcs, Serialize, Deserialize, NonLocalValue)]
23pub struct LoaderRuleItem {
24    pub loaders: ResolvedVc<WebpackLoaderItems>,
25    pub rename_as: Option<RcStr>,
26    pub condition: Option<ConditionItem>,
27}
28
29/// This is a list of instructions for the rule engine to process. The first element in each tuple
30/// is a glob to match against, and the second is a rule to execute if that glob matches.
31///
32/// This is not a map, since multiple rules can be configured for the same glob, and since execution
33/// order matters.
34#[derive(Default)]
35#[turbo_tasks::value(transparent)]
36pub struct WebpackRules(Vec<(RcStr, LoaderRuleItem)>);
37
38#[derive(Default)]
39#[turbo_tasks::value(transparent)]
40pub struct WebpackConditions(pub FxIndexMap<RcStr, ConditionItem>);
41
42#[derive(Default)]
43#[turbo_tasks::value(transparent)]
44pub struct OptionWebpackConditions(Option<ResolvedVc<WebpackConditions>>);
45
46#[derive(Clone, PartialEq, Eq, Debug, TraceRawVcs, Serialize, Deserialize, NonLocalValue)]
47pub enum ConditionPath {
48    Glob(RcStr),
49    Regex(ResolvedVc<EsRegex>),
50}
51
52#[turbo_tasks::value(shared)]
53#[derive(Clone, Debug)]
54pub enum ConditionItem {
55    All(Box<[ConditionItem]>),
56    Any(Box<[ConditionItem]>),
57    Not(Box<ConditionItem>),
58    Builtin(RcStr),
59    Base {
60        path: Option<ConditionPath>,
61        content: Option<ResolvedVc<EsRegex>>,
62    },
63}
64
65#[turbo_tasks::value(shared)]
66#[derive(Clone, Debug)]
67pub struct WebpackLoadersOptions {
68    pub rules: ResolvedVc<WebpackRules>,
69    pub conditions: ResolvedVc<OptionWebpackConditions>,
70    pub builtin_conditions: ResolvedVc<Box<dyn WebpackLoaderBuiltinConditionSet>>,
71    pub loader_runner_package: Option<ResolvedVc<ImportMapping>>,
72}
73
74pub enum WebpackLoaderBuiltinConditionSetMatch {
75    Matched,
76    Unmatched,
77    /// The given condition is not supported by the framework.
78    Invalid,
79}
80
81/// A collection of framework-provided conditions for user (or framework) specified loader rules
82/// ([`WebpackRules`]) to match against.
83#[turbo_tasks::value_trait]
84pub trait WebpackLoaderBuiltinConditionSet {
85    /// Determines if the string representation of this condition is in the set. If it's not valid,
86    /// an issue will be emitted as a collectible.
87    fn match_condition(&self, condition: &str) -> WebpackLoaderBuiltinConditionSetMatch;
88}
89
90/// A no-op implementation of `WebpackLoaderBuiltinConditionSet` that always returns
91/// `WebpackLoaderBuiltinConditionSetMatch::Invalid`.
92#[turbo_tasks::value]
93pub struct EmptyWebpackLoaderBuiltinConditionSet;
94
95#[turbo_tasks::value_impl]
96impl EmptyWebpackLoaderBuiltinConditionSet {
97    #[turbo_tasks::function]
98    fn new() -> Vc<Box<dyn WebpackLoaderBuiltinConditionSet>> {
99        Vc::upcast::<Box<dyn WebpackLoaderBuiltinConditionSet>>(
100            EmptyWebpackLoaderBuiltinConditionSet.cell(),
101        )
102    }
103}
104
105#[turbo_tasks::value_impl]
106impl WebpackLoaderBuiltinConditionSet for EmptyWebpackLoaderBuiltinConditionSet {
107    fn match_condition(&self, _condition: &str) -> WebpackLoaderBuiltinConditionSetMatch {
108        WebpackLoaderBuiltinConditionSetMatch::Invalid
109    }
110}
111
112/// The kind of decorators transform to use.
113/// [TODO]: might need bikeshed for the name (Ecma)
114#[derive(Clone, PartialEq, Eq, Debug, TraceRawVcs, Serialize, Deserialize, NonLocalValue)]
115pub enum DecoratorsKind {
116    Legacy,
117    Ecma,
118}
119
120/// The types when replacing `typeof window` with a constant.
121#[derive(Copy, Clone, PartialEq, Eq, Debug, TraceRawVcs, Serialize, Deserialize, NonLocalValue)]
122pub enum TypeofWindow {
123    Object,
124    Undefined,
125}
126
127/// Configuration options for the decorators transform.
128///
129/// This is not part of Typescript transform: while there are typescript
130/// specific transforms (legay decorators), there is an ecma decorator transform
131/// as well for the JS.
132#[turbo_tasks::value(shared)]
133#[derive(Default, Clone, Debug)]
134pub struct DecoratorsOptions {
135    pub decorators_kind: Option<DecoratorsKind>,
136    /// Option to control whether to emit decorator metadata.
137    /// (https://www.typescriptlang.org/tsconfig#emitDecoratorMetadata)
138    /// This'll be applied only if `decorators_type` and
139    /// `enable_typescript_transform` is enabled.
140    pub emit_decorators_metadata: bool,
141    /// Mimic babel's `decorators.decoratorsBeforeExport` option.
142    /// This'll be applied only if `decorators_type` is enabled.
143    /// ref: https://github.com/swc-project/swc/blob/d4ebb5e6efbed0758f25e46e8f74d7c47ec6cb8f/crates/swc_ecma_parser/src/lib.rs#L327
144    /// [TODO]: this option is not actively being used currently.
145    pub decorators_before_export: bool,
146    pub use_define_for_class_fields: bool,
147}
148
149#[turbo_tasks::value_impl]
150impl ValueDefault for DecoratorsOptions {
151    #[turbo_tasks::function]
152    fn value_default() -> Vc<Self> {
153        Self::default().cell()
154    }
155}
156
157/// Subset of Typescript options configured via tsconfig.json or jsconfig.json,
158/// which affects the runtime transform output.
159#[turbo_tasks::value(shared)]
160#[derive(Default, Clone, Debug)]
161pub struct TypescriptTransformOptions {
162    pub use_define_for_class_fields: bool,
163}
164
165#[turbo_tasks::value_impl]
166impl ValueDefault for TypescriptTransformOptions {
167    #[turbo_tasks::function]
168    fn value_default() -> Vc<Self> {
169        Self::default().cell()
170    }
171}
172
173#[turbo_tasks::value(shared)]
174#[derive(Default, Clone, Debug)]
175pub struct JsxTransformOptions {
176    pub development: bool,
177    pub react_refresh: bool,
178    pub import_source: Option<RcStr>,
179    pub runtime: Option<RcStr>,
180}
181
182#[turbo_tasks::value(shared)]
183#[derive(Clone, Debug)]
184pub struct ExternalsTracingOptions {
185    /// The directory from which the bundled files will require the externals at runtime.
186    pub tracing_root: FileSystemPath,
187    pub compile_time_info: ResolvedVc<CompileTimeInfo>,
188}
189
190#[turbo_tasks::value(shared)]
191#[derive(Clone, Default)]
192#[serde(default)]
193pub struct ModuleOptionsContext {
194    pub ecmascript: EcmascriptOptionsContext,
195    pub css: CssOptionsContext,
196
197    pub enable_postcss_transform: Option<ResolvedVc<PostCssTransformOptions>>,
198    pub enable_webpack_loaders: Option<ResolvedVc<WebpackLoadersOptions>>,
199    // [Note]: currently mdx, and mdx_rs have different configuration entrypoint from next.config.js,
200    // however we might want to unify them in the future.
201    pub enable_mdx: bool,
202    pub enable_mdx_rs: Option<ResolvedVc<MdxTransformOptions>>,
203
204    pub environment: Option<ResolvedVc<Environment>>,
205    pub execution_context: Option<ResolvedVc<ExecutionContext>>,
206    pub side_effect_free_packages: Vec<RcStr>,
207    pub tree_shaking_mode: Option<TreeShakingMode>,
208
209    /// Generate (non-emitted) output assets for static assets and externals, to facilitate
210    /// generating a list of all non-bundled files that will be required at runtime.
211    pub enable_externals_tracing: Option<ResolvedVc<ExternalsTracingOptions>>,
212
213    /// If true, it stores the last successful parse result in state and keeps using it when
214    /// parsing fails. This is useful to keep the module graph structure intact when syntax errors
215    /// are temporarily introduced.
216    pub keep_last_successful_parse: bool,
217
218    /// Custom rules to be applied after all default rules.
219    pub module_rules: Vec<ModuleRule>,
220    /// A list of rules to use a different module option context for certain
221    /// context paths. The first matching is used.
222    pub rules: Vec<(ContextCondition, ResolvedVc<ModuleOptionsContext>)>,
223
224    /// Whether the modules in this context are never chunked/codegen-ed, but only used for
225    /// tracing.
226    pub is_tracing: bool,
227
228    pub placeholder_for_future_extensions: (),
229}
230
231#[turbo_tasks::value(shared)]
232#[derive(Clone, Default)]
233#[serde(default)]
234pub struct EcmascriptOptionsContext {
235    pub enable_typeof_window_inlining: Option<TypeofWindow>,
236    pub enable_jsx: Option<ResolvedVc<JsxTransformOptions>>,
237    /// Follow type references and resolve declaration files in additional to
238    /// normal resolution.
239    pub enable_types: bool,
240    pub enable_typescript_transform: Option<ResolvedVc<TypescriptTransformOptions>>,
241    pub enable_decorators: Option<ResolvedVc<DecoratorsOptions>>,
242    pub esm_url_rewrite_behavior: Option<UrlRewriteBehavior>,
243    /// References to externals from ESM imports should use `import()` and make
244    /// async modules.
245    pub import_externals: bool,
246    /// Ignore very dynamic requests which doesn't have any static known part.
247    /// If false, they will reference the whole directory. If true, they won't
248    /// reference anything and lead to an runtime error instead.
249    pub ignore_dynamic_requests: bool,
250    /// Specifies how Source Maps are handled.
251    pub source_maps: SourceMapsType,
252
253    pub placeholder_for_future_extensions: (),
254}
255
256#[turbo_tasks::value(shared)]
257#[derive(Clone, Default)]
258#[serde(default)]
259pub struct CssOptionsContext {
260    /// This skips `GlobalCss` and `ModuleCss` module assets from being
261    /// generated in the module graph, generating only `Css` module assets.
262    ///
263    /// This is useful for node-file-trace, which tries to emit all assets in
264    /// the module graph, but neither asset types can be emitted directly.
265    pub enable_raw_css: bool,
266
267    /// Specifies how Source Maps are handled.
268    pub source_maps: SourceMapsType,
269
270    /// Override the conditions for module CSS (doesn't have any effect if `enable_raw_css` is
271    /// true). By default (for `None`), it uses
272    /// `Any(ResourcePathEndsWith(".module.css"), ContentTypeStartsWith("text/css+module"))`
273    pub module_css_condition: Option<RuleCondition>,
274
275    pub placeholder_for_future_extensions: (),
276}
277
278#[turbo_tasks::value_impl]
279impl ValueDefault for ModuleOptionsContext {
280    #[turbo_tasks::function]
281    fn value_default() -> Vc<Self> {
282        Self::cell(Default::default())
283    }
284}