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