1pub(crate) mod custom_module_type;
2pub mod match_mode;
3pub mod module_options_context;
4pub mod module_rule;
5pub mod rule_condition;
6pub mod transition_rule;
7
8use anyhow::{Context, Result};
9pub use custom_module_type::CustomModuleType;
10pub use module_options_context::*;
11pub use module_rule::*;
12pub use rule_condition::*;
13use turbo_rcstr::{RcStr, rcstr};
14use turbo_tasks::{ResolvedVc, TryJoinIterExt, Vc};
15use turbo_tasks_fs::{
16 FileSystemPath,
17 glob::{Glob, GlobOptions},
18};
19use turbopack_core::{
20 chunk::SourceMapsType,
21 ident::Layer,
22 reference_type::{
23 CssReferenceSubType, EcmaScriptModulesReferenceSubType, ReferenceTypeCondition,
24 UrlReferenceSubType,
25 },
26 resolve::options::{ImportMap, ImportMapping},
27};
28use turbopack_css::CssModuleType;
29use turbopack_ecmascript::{
30 AnalyzeMode, EcmascriptInputTransform, EcmascriptInputTransforms, EcmascriptOptions,
31 SpecifiedModuleType, bytes_source_transform::BytesSourceTransform,
32 json_source_transform::JsonSourceTransform, text_source_transform::TextSourceTransform,
33 transform::PresetEnvConfig,
34};
35use turbopack_mdx::MdxTransform;
36use turbopack_node::{
37 execution_context::ExecutionContext,
38 transforms::{postcss::PostCssTransform, webpack::WebpackLoaders},
39};
40use turbopack_resolve::resolve_options_context::ResolveOptionsContext;
41use turbopack_wasm::source::WebAssemblySourceType;
42
43use crate::evaluate_context::{config_tracing_module_context, node_evaluate_asset_context};
44
45#[turbo_tasks::function]
46pub(crate) fn package_import_map_from_import_mapping(
47 package_name: RcStr,
48 package_mapping: ResolvedVc<ImportMapping>,
49) -> Vc<ImportMap> {
50 let mut import_map = ImportMap::default();
51 import_map.insert_exact_alias(
52 RcStr::from(format!("@vercel/turbopack/{package_name}")),
53 package_mapping,
54 );
55 import_map.cell()
56}
57
58#[turbo_tasks::function]
59pub(crate) fn package_import_map_from_context(
60 package_name: RcStr,
61 context_path: FileSystemPath,
62) -> Vc<ImportMap> {
63 let mut import_map = ImportMap::default();
64 import_map.insert_exact_alias(
65 RcStr::from(format!("@vercel/turbopack/{package_name}")),
66 ImportMapping::PrimaryAlternative(package_name, Some(context_path)).resolved_cell(),
67 );
68 import_map.cell()
69}
70
71async fn rule_condition_from_webpack_condition_glob(
72 execution_context: ResolvedVc<ExecutionContext>,
73 glob: &RcStr,
74) -> Result<RuleCondition> {
75 Ok(if glob.contains('/') {
76 RuleCondition::ResourcePathGlob {
77 base: execution_context.project_path().owned().await?,
78 glob: Glob::new(glob.clone(), GlobOptions::default()).await?,
79 }
80 } else {
81 RuleCondition::ResourceBasePathGlob(Glob::new(glob.clone(), GlobOptions::default()).await?)
82 })
83}
84
85async fn rule_condition_from_webpack_condition(
86 execution_context: ResolvedVc<ExecutionContext>,
87 builtin_conditions: &dyn WebpackLoaderBuiltinConditionSet,
88 webpack_loader_condition: &ConditionItem,
89) -> Result<RuleCondition> {
90 Ok(match webpack_loader_condition {
91 ConditionItem::All(conds) => RuleCondition::All(
92 conds
93 .iter()
94 .map(|c| {
95 rule_condition_from_webpack_condition(execution_context, builtin_conditions, c)
96 })
97 .try_join()
98 .await?,
99 ),
100 ConditionItem::Any(conds) => RuleCondition::Any(
101 conds
102 .iter()
103 .map(|c| {
104 rule_condition_from_webpack_condition(execution_context, builtin_conditions, c)
105 })
106 .try_join()
107 .await?,
108 ),
109 ConditionItem::Not(cond) => RuleCondition::Not(Box::new(
110 Box::pin(rule_condition_from_webpack_condition(
111 execution_context,
112 builtin_conditions,
113 cond,
114 ))
115 .await?,
116 )),
117 ConditionItem::Builtin(name) => match builtin_conditions.match_condition(name) {
118 WebpackLoaderBuiltinConditionSetMatch::Matched => RuleCondition::True,
119 WebpackLoaderBuiltinConditionSetMatch::Unmatched => RuleCondition::False,
120 WebpackLoaderBuiltinConditionSetMatch::Invalid => {
121 anyhow::bail!("{name:?} is not a valid built-in condition")
124 }
125 },
126 ConditionItem::Base {
127 path,
128 content,
129 query,
130 content_type,
131 } => {
132 let mut rule_conditions = Vec::new();
133 match &path {
134 Some(ConditionPath::Glob(glob)) => rule_conditions.push(
135 rule_condition_from_webpack_condition_glob(execution_context, glob).await?,
136 ),
137 Some(ConditionPath::Regex(regex)) => {
138 rule_conditions.push(RuleCondition::ResourcePathEsRegex(regex.await?));
139 }
140 None => {}
141 }
142 match &query {
143 Some(ConditionQuery::Constant(value)) => {
144 rule_conditions.push(RuleCondition::ResourceQueryEquals(value.clone().into()));
145 }
146 Some(ConditionQuery::Regex(regex)) => {
147 rule_conditions.push(RuleCondition::ResourceQueryEsRegex(regex.await?));
148 }
149 None => {}
150 }
151 match &content_type {
152 Some(ConditionContentType::Glob(glob)) => {
153 rule_conditions.push(RuleCondition::ContentTypeGlob(
154 Glob::new(glob.clone(), GlobOptions::default()).await?,
155 ));
156 }
157 Some(ConditionContentType::Regex(regex)) => {
158 rule_conditions.push(RuleCondition::ContentTypeEsRegex(regex.await?));
159 }
160 None => {}
161 }
162 if let Some(content) = content {
164 rule_conditions.push(RuleCondition::ResourceContentEsRegex(content.await?));
165 }
166 RuleCondition::All(rule_conditions)
167 }
168 })
169}
170
171#[turbo_tasks::value(cell = "new", eq = "manual")]
172pub struct ModuleOptions {
173 pub rules: Vec<ModuleRule>,
174}
175
176#[turbo_tasks::value_impl]
177impl ModuleOptions {
178 #[turbo_tasks::function]
179 pub async fn new(
180 path: FileSystemPath,
181 module_options_context: Vc<ModuleOptionsContext>,
182 resolve_options_context: Vc<ResolveOptionsContext>,
183 ) -> Result<Vc<ModuleOptions>> {
184 let ModuleOptionsContext {
185 css: CssOptionsContext { enable_raw_css, .. },
186 ref enable_postcss_transform,
187 ref enable_webpack_loaders,
188 ref rules,
189 ..
190 } = *module_options_context.await?;
191
192 if !rules.is_empty() {
193 for (condition, new_context) in rules.iter() {
194 if condition.matches(&path) {
195 return Ok(ModuleOptions::new(
196 path,
197 **new_context,
198 resolve_options_context,
199 ));
200 }
201 }
202 }
203
204 let need_path = (!enable_raw_css
205 && if let Some(options) = enable_postcss_transform {
206 let options = options.await?;
207 options.postcss_package.is_none()
208 } else {
209 false
210 })
211 || if let Some(options) = enable_webpack_loaders {
212 let options = options.await?;
213 options.loader_runner_package.is_none()
214 } else {
215 false
216 };
217
218 Ok(Self::new_internal(
219 need_path.then_some(path),
220 module_options_context,
221 resolve_options_context,
222 ))
223 }
224
225 #[turbo_tasks::function]
226 async fn new_internal(
227 path: Option<FileSystemPath>,
228 module_options_context: Vc<ModuleOptionsContext>,
229 resolve_options_context: Vc<ResolveOptionsContext>,
230 ) -> Result<Vc<ModuleOptions>> {
231 let ModuleOptionsContext {
232 ecmascript:
233 EcmascriptOptionsContext {
234 enable_jsx,
235 enable_rust_react_compiler,
236 rust_react_compiler_target,
237 enable_types,
238 ref enable_typescript_transform,
239 ref enable_decorators,
240 ignore_dynamic_requests,
241 import_externals,
242 esm_url_rewrite_behavior,
243 enable_typeof_window_inlining,
244 enable_exports_info_inlining,
245 enable_import_as_bytes,
246 source_maps: ecmascript_source_maps,
247 inline_helpers,
248 infer_module_side_effects,
249 cjs_tree_shaking,
250 cjs_scope_hoisting,
251 ref preset_env_config,
252 ..
253 },
254 enable_mdx,
255 enable_mdx_rs,
256 css:
257 CssOptionsContext {
258 enable_raw_css,
259 source_maps: css_source_maps,
260 ref module_css_condition,
261 lightningcss_features,
262 ..
263 },
264 ref static_url_tag,
265 ref enable_postcss_transform,
266 ref enable_webpack_loaders,
267 environment,
268 ref module_rules,
269 execution_context,
270 follow_reexports,
271 module_fragments_enabled,
272 keep_last_successful_parse,
273 analyze_mode,
274 ..
275 } = *module_options_context.await?;
276
277 let module_css_condition = module_css_condition.clone().unwrap_or_else(|| {
278 RuleCondition::any(vec![
279 RuleCondition::ResourcePathEndsWith(".module.css".to_string()),
280 RuleCondition::ContentTypeStartsWith("text/css+module".to_string()),
281 ])
282 });
283
284 let module_css_external_transform_conditions = RuleCondition::Any(vec![
296 RuleCondition::not(module_css_condition.clone()),
297 RuleCondition::ReferenceType(ReferenceTypeCondition::Css(Some(
298 CssReferenceSubType::Inner,
299 ))),
300 RuleCondition::ReferenceType(ReferenceTypeCondition::Css(Some(
301 CssReferenceSubType::Analyze,
302 ))),
303 ]);
304
305 let mut ecma_preprocess = vec![];
306 let mut postprocess = vec![];
307
308 if let Some(compilation_mode) = enable_rust_react_compiler {
309 ecma_preprocess.push(EcmascriptInputTransform::ReactCompilerRust {
310 compilation_mode,
311 target: rust_react_compiler_target,
312 });
313 }
314
315 if let Some(enable_jsx) = enable_jsx {
320 let jsx = enable_jsx.await?;
321
322 postprocess.push(EcmascriptInputTransform::React {
323 development: jsx.development,
324 refresh: jsx.react_refresh,
325 import_source: ResolvedVc::cell(jsx.import_source.clone()),
326 runtime: ResolvedVc::cell(jsx.runtime.clone()),
327 });
328 }
329
330 let ecmascript_options = EcmascriptOptions {
331 follow_reexports,
332 module_fragments_enabled,
333 url_rewrite_behavior: esm_url_rewrite_behavior,
334 import_externals,
335 ignore_dynamic_requests,
336 extract_source_map: matches!(ecmascript_source_maps, SourceMapsType::Full),
337 keep_last_successful_parse,
338 analyze_mode,
339 enable_typeof_window_inlining,
340 enable_exports_info_inlining,
341 inline_helpers,
342 infer_module_side_effects,
343 cjs_tree_shaking,
344 cjs_scope_hoisting,
345 ..Default::default()
346 };
347 let ecmascript_options_vc = ecmascript_options.resolved_cell();
348
349 if let Some(environment) = environment {
350 let env_config = match preset_env_config {
351 Some(c) => *c,
352 None => PresetEnvConfig::default().resolved_cell(),
353 };
354 postprocess.push(EcmascriptInputTransform::PresetEnv(environment, env_config));
355 }
356
357 let decorators_transform = if let Some(options) = &enable_decorators {
358 let options = options.await?;
359 options
360 .decorators_kind
361 .as_ref()
362 .map(|kind| EcmascriptInputTransform::Decorators {
363 is_legacy: kind == &DecoratorsKind::Legacy,
364 is_ecma: kind == &DecoratorsKind::Ecma,
365 emit_decorators_metadata: options.emit_decorators_metadata,
366 use_define_for_class_fields: options.use_define_for_class_fields,
367 })
368 } else {
369 None
370 };
371
372 let extra_preprocess = ecma_preprocess.clone();
374
375 if let Some(decorators_transform) = &decorators_transform {
376 ecma_preprocess.push(decorators_transform.clone());
387 }
388
389 let ecma_preprocess = ResolvedVc::cell(ecma_preprocess);
390 let main = ResolvedVc::<EcmascriptInputTransforms>::cell(vec![]);
391 let postprocess = ResolvedVc::cell(postprocess);
392 let empty = ResolvedVc::<EcmascriptInputTransforms>::cell(vec![]);
393
394 let mut rules = vec![];
395
396 let is_tracing = analyze_mode == AnalyzeMode::Tracing;
402
403 if enable_import_as_bytes {
407 rules.push(ModuleRule::new(
408 RuleCondition::ReferenceType(ReferenceTypeCondition::EcmaScriptModules(Some(
409 EcmaScriptModulesReferenceSubType::ImportWithType("bytes".into()),
410 ))),
411 if is_tracing {
412 vec![ModuleRuleEffect::ModuleType(ModuleType::Raw)]
413 } else {
414 vec![ModuleRuleEffect::SourceTransforms(ResolvedVc::cell(vec![
415 ResolvedVc::upcast(BytesSourceTransform::new().to_resolved().await?),
416 ]))]
417 },
418 ));
419 }
420
421 rules.push(ModuleRule::new(
422 RuleCondition::ReferenceType(ReferenceTypeCondition::EcmaScriptModules(Some(
423 EcmaScriptModulesReferenceSubType::ImportWithType("text".into()),
424 ))),
425 if is_tracing {
426 vec![ModuleRuleEffect::ModuleType(ModuleType::Raw)]
427 } else {
428 vec![ModuleRuleEffect::SourceTransforms(ResolvedVc::cell(vec![
429 ResolvedVc::upcast(TextSourceTransform::new().to_resolved().await?),
430 ]))]
431 },
432 ));
433
434 if let Some(webpack_loaders_options) = enable_webpack_loaders {
435 let webpack_loaders_options = webpack_loaders_options.await?;
436 let execution_context =
437 execution_context.context("execution_context is required for webpack_loaders")?;
438 let import_map = if let Some(loader_runner_package) =
439 webpack_loaders_options.loader_runner_package
440 {
441 package_import_map_from_import_mapping(
442 rcstr!("loader-runner"),
443 *loader_runner_package,
444 )
445 } else {
446 package_import_map_from_context(
447 rcstr!("loader-runner"),
448 path.clone()
449 .context("need_path in ModuleOptions::new is incorrect")?,
450 )
451 };
452 let builtin_conditions = webpack_loaders_options
453 .builtin_conditions
454 .into_trait_ref()
455 .await?;
456 for (key, rule) in webpack_loaders_options.rules.await?.iter() {
457 let mut rule_conditions = Vec::new();
458
459 rule_conditions.push(
462 rule_condition_from_webpack_condition_glob(execution_context, key).await?,
463 );
464
465 if let Some(condition) = &rule.condition {
466 rule_conditions.push(
467 rule_condition_from_webpack_condition(
468 execution_context,
469 &*builtin_conditions,
470 condition,
471 )
472 .await?,
473 )
474 }
475
476 rule_conditions.push(RuleCondition::not(RuleCondition::ResourceIsVirtualSource));
477 rule_conditions.push(module_css_external_transform_conditions.clone());
478
479 let mut all_rule_condition = RuleCondition::All(rule_conditions);
480 all_rule_condition.flatten();
481 if !matches!(all_rule_condition, RuleCondition::False) {
482 let mut effects = Vec::new();
483
484 if !rule.loaders.await?.is_empty() {
486 effects.push(ModuleRuleEffect::SourceTransforms(ResolvedVc::cell(vec![
487 ResolvedVc::upcast(
488 WebpackLoaders::new(
489 node_evaluate_asset_context(
490 *execution_context,
491 Some(import_map),
492 None,
493 Layer::new(rcstr!("webpack_loaders")),
494 false,
495 ),
496 *execution_context,
497 *rule.loaders,
498 rule.rename_as.clone(),
499 resolve_options_context,
500 matches!(ecmascript_source_maps, SourceMapsType::Full),
501 )
502 .to_resolved()
503 .await?,
504 ),
505 ])));
506 }
507
508 if let Some(type_str) = rule.module_type.as_ref() {
510 effects.push(
511 ConfiguredModuleType::parse(type_str)?
512 .into_effect(
513 ecma_preprocess,
514 main,
515 postprocess,
516 ecmascript_options_vc,
517 environment,
518 lightningcss_features,
519 )
520 .await?,
521 )
522 }
523
524 if !effects.is_empty() {
525 rules.push(ModuleRule::new(all_rule_condition, effects));
526 }
527 }
528 }
529 }
530
531 rules.extend(module_rules.iter().cloned());
532
533 if enable_mdx || enable_mdx_rs.is_some() {
534 let (jsx_runtime, jsx_import_source, development) = if let Some(enable_jsx) = enable_jsx
535 {
536 let jsx = enable_jsx.await?;
537 (
538 jsx.runtime.clone(),
539 jsx.import_source.clone(),
540 jsx.development,
541 )
542 } else {
543 (None, None, false)
544 };
545
546 let mdx_options = &*enable_mdx_rs
547 .unwrap_or_else(|| MdxTransformOptions::default().resolved_cell())
548 .await?;
549
550 let mdx_transform_options = (MdxTransformOptions {
551 development: Some(development),
552 jsx: Some(false),
553 jsx_runtime,
554 jsx_import_source,
555 ..(mdx_options.clone())
556 })
557 .cell();
558
559 rules.push(ModuleRule::new(
560 RuleCondition::any(vec![
561 RuleCondition::ResourcePathEndsWith(".md".to_string()),
562 RuleCondition::ResourcePathEndsWith(".mdx".to_string()),
563 RuleCondition::ContentTypeStartsWith("text/markdown".to_string()),
564 ]),
565 vec![ModuleRuleEffect::SourceTransforms(ResolvedVc::cell(vec![
566 ResolvedVc::upcast(
567 MdxTransform::new(mdx_transform_options)
568 .to_resolved()
569 .await?,
570 ),
571 ]))],
572 ));
573 }
574
575 rules.extend([
577 ModuleRule::new(
578 RuleCondition::ReferenceType(ReferenceTypeCondition::Url(Some(
579 UrlReferenceSubType::CssUrl,
580 ))),
581 vec![ModuleRuleEffect::ModuleType(ModuleType::StaticUrlCss {
582 tag: static_url_tag.clone(),
583 })],
584 ),
585 ModuleRule::new(
586 RuleCondition::ReferenceType(ReferenceTypeCondition::Url(Some(
587 UrlReferenceSubType::Undefined,
588 ))),
589 vec![ModuleRuleEffect::ModuleType(ModuleType::StaticUrlJs {
590 tag: static_url_tag.clone(),
591 })],
592 ),
593 ModuleRule::new(
594 RuleCondition::ReferenceType(ReferenceTypeCondition::Url(Some(
595 UrlReferenceSubType::EcmaScriptNewUrl,
596 ))),
597 vec![ModuleRuleEffect::ModuleType(ModuleType::StaticUrlJs {
598 tag: static_url_tag.clone(),
599 })],
600 ),
601 ModuleRule::new(
602 RuleCondition::ReferenceType(ReferenceTypeCondition::EcmaScriptModules(Some(
603 EcmaScriptModulesReferenceSubType::ImportWithType("json".into()),
604 ))),
605 if is_tracing {
606 vec![ModuleRuleEffect::ModuleType(ModuleType::Raw)]
607 } else {
608 vec![ModuleRuleEffect::SourceTransforms(ResolvedVc::cell(vec![
609 ResolvedVc::upcast(JsonSourceTransform::new_esm().to_resolved().await?),
611 ]))]
612 },
613 ),
614 ]);
615
616 rules.extend([
618 ModuleRule::new_all(
619 RuleCondition::any(vec![
620 RuleCondition::ResourcePathEndsWith(".json".to_string()),
621 RuleCondition::ContentTypeStartsWith("application/json".to_string()),
622 ]),
623 if is_tracing {
624 vec![ModuleRuleEffect::ModuleType(ModuleType::Raw)]
625 } else {
626 vec![ModuleRuleEffect::SourceTransforms(ResolvedVc::cell(vec![
627 ResolvedVc::upcast(JsonSourceTransform::new_cjs().to_resolved().await?),
629 ]))]
630 },
631 ),
632 ModuleRule::new_all(
633 RuleCondition::any(vec![
634 RuleCondition::ResourcePathEndsWith(".js".to_string()),
635 RuleCondition::ResourcePathEndsWith(".jsx".to_string()),
636 RuleCondition::ContentTypeStartsWith("application/javascript".to_string()),
637 RuleCondition::ContentTypeStartsWith("text/javascript".to_string()),
638 ]),
639 vec![ModuleRuleEffect::ModuleType(ModuleType::Ecmascript {
640 preprocess: ecma_preprocess,
641 main,
642 postprocess,
643 options: ecmascript_options_vc,
644 })],
645 ),
646 ModuleRule::new_all(
647 RuleCondition::ResourcePathEndsWith(".mjs".to_string()),
648 vec![ModuleRuleEffect::ModuleType(ModuleType::Ecmascript {
649 preprocess: ecma_preprocess,
650 main,
651 postprocess,
652 options: EcmascriptOptions {
653 specified_module_type: SpecifiedModuleType::EcmaScript,
654 ..ecmascript_options
655 }
656 .resolved_cell(),
657 })],
658 ),
659 ModuleRule::new_all(
660 RuleCondition::ResourcePathEndsWith(".cjs".to_string()),
661 vec![ModuleRuleEffect::ModuleType(ModuleType::Ecmascript {
662 preprocess: ecma_preprocess,
663 main,
664 postprocess,
665 options: EcmascriptOptions {
666 specified_module_type: SpecifiedModuleType::CommonJs,
667 ..ecmascript_options
668 }
669 .resolved_cell(),
670 })],
671 ),
672 ModuleRule::new(
673 RuleCondition::ResourcePathEndsWith(".d.ts".to_string()),
674 vec![ModuleRuleEffect::ModuleType(
675 ModuleType::TypescriptDeclaration {
676 preprocess: empty,
677 main: empty,
678 postprocess: empty,
679 options: ecmascript_options_vc,
680 },
681 )],
682 ),
683 ModuleRule::new(
684 RuleCondition::any(vec![RuleCondition::ResourcePathEndsWith(
685 ".node".to_string(),
686 )]),
687 vec![ModuleRuleEffect::ModuleType(ModuleType::NodeAddon)],
688 ),
689 ModuleRule::new(
691 RuleCondition::any(vec![
692 RuleCondition::ResourcePathEndsWith(".wasm".to_string()),
693 RuleCondition::ContentTypeStartsWith("application/wasm".to_string()),
694 ]),
695 vec![ModuleRuleEffect::ModuleType(ModuleType::WebAssembly {
696 source_ty: WebAssemblySourceType::Binary,
697 })],
698 ),
699 ModuleRule::new(
700 RuleCondition::any(vec![RuleCondition::ResourcePathEndsWith(
701 ".wat".to_string(),
702 )]),
703 vec![ModuleRuleEffect::ModuleType(ModuleType::WebAssembly {
704 source_ty: WebAssemblySourceType::Text,
705 })],
706 ),
707 ModuleRule::new(
708 RuleCondition::any(vec![
709 RuleCondition::ResourcePathEndsWith(".apng".to_string()),
710 RuleCondition::ResourcePathEndsWith(".avif".to_string()),
711 RuleCondition::ResourcePathEndsWith(".gif".to_string()),
712 RuleCondition::ResourcePathEndsWith(".ico".to_string()),
713 RuleCondition::ResourcePathEndsWith(".jpg".to_string()),
714 RuleCondition::ResourcePathEndsWith(".jpeg".to_string()),
715 RuleCondition::ResourcePathEndsWith(".png".to_string()),
716 RuleCondition::ResourcePathEndsWith(".svg".to_string()),
717 RuleCondition::ResourcePathEndsWith(".webp".to_string()),
718 RuleCondition::ResourcePathEndsWith(".woff2".to_string()),
719 ]),
720 vec![ModuleRuleEffect::ModuleType(ModuleType::StaticUrlJs {
721 tag: static_url_tag.clone(),
722 })],
723 ),
724 ModuleRule::new(
725 RuleCondition::all(vec![
726 RuleCondition::ResourcePathHasNoExtension,
728 RuleCondition::ContentTypeEmpty,
729 ]),
730 vec![ModuleRuleEffect::ModuleType(
731 ModuleType::EcmascriptExtensionless {
732 preprocess: empty,
733 main: empty,
734 postprocess: empty,
735 options: ecmascript_options_vc,
736 },
737 )],
738 ),
739 ]);
740
741 if let Some(options) = enable_typescript_transform {
742 let options = options.await?;
743 let ts_preprocess = ResolvedVc::cell(
746 extra_preprocess
747 .into_iter()
748 .chain(decorators_transform.clone())
749 .chain(std::iter::once(EcmascriptInputTransform::TypeScript {
750 use_define_for_class_fields: options.use_define_for_class_fields,
751 verbatim_module_syntax: options.verbatim_module_syntax,
752 }))
753 .collect(),
754 );
755
756 rules.extend([
757 ModuleRule::new_all(
758 RuleCondition::ResourcePathEndsWith(".ts".to_string()),
759 vec![ModuleRuleEffect::ModuleType(ModuleType::Typescript {
760 preprocess: ts_preprocess,
761 main,
762 postprocess,
763 tsx: false,
764 analyze_types: enable_types,
765 options: ecmascript_options_vc,
766 })],
767 ),
768 ModuleRule::new_all(
769 RuleCondition::ResourcePathEndsWith(".tsx".to_string()),
770 vec![ModuleRuleEffect::ModuleType(ModuleType::Typescript {
771 preprocess: ts_preprocess,
772 main,
773 postprocess,
774 tsx: true,
775 analyze_types: enable_types,
776 options: ecmascript_options_vc,
777 })],
778 ),
779 ModuleRule::new_all(
780 RuleCondition::ResourcePathEndsWith(".mts".to_string()),
781 vec![ModuleRuleEffect::ModuleType(ModuleType::Typescript {
782 preprocess: ts_preprocess,
783 main,
784 postprocess,
785 tsx: false,
786 analyze_types: enable_types,
787 options: EcmascriptOptions {
788 specified_module_type: SpecifiedModuleType::EcmaScript,
789 ..ecmascript_options
790 }
791 .resolved_cell(),
792 })],
793 ),
794 ModuleRule::new_all(
795 RuleCondition::ResourcePathEndsWith(".mtsx".to_string()),
796 vec![ModuleRuleEffect::ModuleType(ModuleType::Typescript {
797 preprocess: ts_preprocess,
798 main,
799 postprocess,
800 tsx: true,
801 analyze_types: enable_types,
802 options: EcmascriptOptions {
803 specified_module_type: SpecifiedModuleType::EcmaScript,
804 ..ecmascript_options
805 }
806 .resolved_cell(),
807 })],
808 ),
809 ModuleRule::new_all(
810 RuleCondition::ResourcePathEndsWith(".cts".to_string()),
811 vec![ModuleRuleEffect::ModuleType(ModuleType::Typescript {
812 preprocess: ts_preprocess,
813 main,
814 postprocess,
815 tsx: false,
816 analyze_types: enable_types,
817 options: EcmascriptOptions {
818 specified_module_type: SpecifiedModuleType::CommonJs,
819 ..ecmascript_options
820 }
821 .resolved_cell(),
822 })],
823 ),
824 ModuleRule::new_all(
825 RuleCondition::ResourcePathEndsWith(".ctsx".to_string()),
826 vec![ModuleRuleEffect::ModuleType(ModuleType::Typescript {
827 preprocess: ts_preprocess,
828 main,
829 postprocess,
830 tsx: true,
831 analyze_types: enable_types,
832 options: EcmascriptOptions {
833 specified_module_type: SpecifiedModuleType::CommonJs,
834 ..ecmascript_options
835 }
836 .resolved_cell(),
837 })],
838 ),
839 ]);
840 }
841
842 if enable_raw_css {
843 rules.extend([
844 ModuleRule::new(
845 module_css_condition.clone(),
846 vec![ModuleRuleEffect::ModuleType(ModuleType::Css {
847 ty: CssModuleType::Module,
848 environment,
849 lightningcss_features,
850 })],
851 ),
852 ModuleRule::new(
853 RuleCondition::any(vec![
854 RuleCondition::ResourcePathEndsWith(".css".to_string()),
855 RuleCondition::ContentTypeStartsWith("text/css".to_string()),
856 ]),
857 vec![ModuleRuleEffect::ModuleType(ModuleType::Css {
858 ty: CssModuleType::Default,
859 environment,
860 lightningcss_features,
861 })],
862 ),
863 ]);
864 } else {
865 if let Some(options) = enable_postcss_transform {
866 let options = options.await?;
867 let execution_context = execution_context
868 .context("execution_context is required for the postcss_transform")?;
869
870 let import_map = if let Some(postcss_package) = options.postcss_package {
871 package_import_map_from_import_mapping(rcstr!("postcss"), *postcss_package)
872 } else {
873 package_import_map_from_context(
874 rcstr!("postcss"),
875 path.clone()
876 .context("need_path in ModuleOptions::new is incorrect")?,
877 )
878 };
879
880 rules.push(ModuleRule::new(
881 RuleCondition::All(vec![
882 RuleCondition::Any(vec![
883 RuleCondition::ResourcePathEndsWith(".css".to_string()),
885 RuleCondition::ContentTypeStartsWith("text/css".to_string()),
886 module_css_condition.clone(),
887 ]),
888 module_css_external_transform_conditions.clone(),
889 ]),
890 vec![ModuleRuleEffect::SourceTransforms(ResolvedVc::cell(vec![
891 ResolvedVc::upcast(
892 PostCssTransform::new(
893 node_evaluate_asset_context(
894 *execution_context,
895 Some(import_map),
896 None,
897 Layer::new(rcstr!("postcss")),
898 true,
899 ),
900 config_tracing_module_context(*execution_context),
901 *execution_context,
902 options.config_location,
903 matches!(css_source_maps, SourceMapsType::Full),
904 )
905 .to_resolved()
906 .await?,
907 ),
908 ]))],
909 ));
910 }
911
912 rules.extend([
913 ModuleRule::new(
914 RuleCondition::all(vec![
915 module_css_condition.clone(),
916 RuleCondition::ReferenceType(ReferenceTypeCondition::Css(Some(
918 CssReferenceSubType::AtImport(None),
919 ))),
920 ]),
921 vec![ModuleRuleEffect::ModuleType(ModuleType::Css {
922 ty: CssModuleType::Module,
923 environment,
924 lightningcss_features,
925 })],
926 ),
927 ModuleRule::new(
929 RuleCondition::all(vec![
930 module_css_condition.clone(),
931 RuleCondition::ReferenceType(ReferenceTypeCondition::Css(Some(
932 CssReferenceSubType::Inner,
933 ))),
934 ]),
935 vec![ModuleRuleEffect::ModuleType(ModuleType::Css {
936 ty: CssModuleType::Module,
937 environment,
938 lightningcss_features,
939 })],
940 ),
941 ModuleRule::new(
943 RuleCondition::all(vec![
944 module_css_condition.clone(),
945 RuleCondition::ReferenceType(ReferenceTypeCondition::Css(Some(
946 CssReferenceSubType::Analyze,
947 ))),
948 ]),
949 vec![ModuleRuleEffect::ModuleType(ModuleType::Css {
950 ty: CssModuleType::Module,
951 environment,
952 lightningcss_features,
953 })],
954 ),
955 ModuleRule::new(
956 RuleCondition::all(vec![module_css_condition.clone()]),
957 vec![ModuleRuleEffect::ModuleType(ModuleType::CssModule)],
958 ),
959 ModuleRule::new_all(
960 RuleCondition::Any(vec![
961 RuleCondition::ResourcePathEndsWith(".css".to_string()),
962 RuleCondition::ContentTypeStartsWith("text/css".to_string()),
963 ]),
964 vec![ModuleRuleEffect::ModuleType(ModuleType::Css {
965 ty: CssModuleType::Default,
966 environment,
967 lightningcss_features,
968 })],
969 ),
970 ]);
971 }
972
973 Ok(ModuleOptions::cell(ModuleOptions { rules }))
974 }
975}