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