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