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