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