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