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 EcmascriptInputTransform, EcmascriptInputTransforms, EcmascriptOptions, SpecifiedModuleType,
31 bytes_source_transform::BytesSourceTransform, json_source_transform::JsonSourceTransform,
32 text_source_transform::TextSourceTransform, transform::PresetEnvConfig,
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_rust_react_compiler,
235 rust_react_compiler_target,
236 enable_types,
237 ref enable_typescript_transform,
238 ref enable_decorators,
239 ignore_dynamic_requests,
240 import_externals,
241 esm_url_rewrite_behavior,
242 enable_typeof_window_inlining,
243 enable_exports_info_inlining,
244 enable_import_as_bytes,
245 source_maps: ecmascript_source_maps,
246 inline_helpers,
247 infer_module_side_effects,
248 cjs_tree_shaking,
249 mangle_export_names,
250 mangle_via_materialized_namespace_object,
251 cjs_scope_hoisting,
252 cross_module_constants,
253 lazy_compilation,
254 ref preset_env_config,
255 ..
256 },
257 enable_mdx,
258 enable_mdx_rs,
259 css:
260 CssOptionsContext {
261 enable_raw_css,
262 source_maps: css_source_maps,
263 ref module_css_condition,
264 lightningcss_features,
265 module_css_debuggable_idents,
266 ..
267 },
268 ref static_url_tag,
269 ref enable_postcss_transform,
270 ref enable_webpack_loaders,
271 environment,
272 ref module_rules,
273 execution_context,
274 follow_reexports,
275 module_fragments_enabled,
276 keep_last_successful_parse,
277 analyze_mode,
278 ..
279 } = *module_options_context.await?;
280
281 let module_css_condition = module_css_condition.clone().unwrap_or_else(|| {
282 RuleCondition::any(vec![
283 RuleCondition::ResourcePathEndsWith(".module.css".to_string()),
284 RuleCondition::ContentTypeStartsWith("text/css+module".to_string()),
285 ])
286 });
287
288 let module_css_external_transform_conditions = RuleCondition::Any(vec![
300 RuleCondition::not(module_css_condition.clone()),
301 RuleCondition::ReferenceType(ReferenceTypeCondition::Css(Some(
302 CssReferenceSubType::Inner,
303 ))),
304 RuleCondition::ReferenceType(ReferenceTypeCondition::Css(Some(
305 CssReferenceSubType::Analyze,
306 ))),
307 ]);
308
309 let mut ecma_preprocess = vec![];
310 let mut postprocess = vec![];
311
312 if let Some(options) = enable_rust_react_compiler {
313 ecma_preprocess.push(EcmascriptInputTransform::ReactCompilerRust {
314 options,
315 target: rust_react_compiler_target,
316 });
317 }
318
319 if let Some(enable_jsx) = enable_jsx {
324 let jsx = enable_jsx.await?;
325
326 postprocess.push(EcmascriptInputTransform::React {
327 development: jsx.development,
328 refresh: jsx.react_refresh,
329 import_source: ResolvedVc::cell(jsx.import_source.clone()),
330 runtime: ResolvedVc::cell(jsx.runtime.clone()),
331 });
332 }
333
334 let ecmascript_options = EcmascriptOptions {
335 follow_reexports,
336 module_fragments_enabled,
337 url_rewrite_behavior: esm_url_rewrite_behavior,
338 import_externals,
339 ignore_dynamic_requests,
340 extract_source_map: matches!(ecmascript_source_maps, SourceMapsType::Full),
341 keep_last_successful_parse,
342 analyze_mode,
343 enable_typeof_window_inlining,
344 enable_exports_info_inlining,
345 inline_helpers,
346 infer_module_side_effects,
347 cjs_tree_shaking,
348 mangle_export_names,
349 mangle_via_materialized_namespace_object,
350 cjs_scope_hoisting,
351 cross_module_constants,
352 lazy_compilation,
353 ..Default::default()
354 };
355 let ecmascript_options_vc = ecmascript_options.resolved_cell();
356
357 if let Some(environment) = environment {
358 let env_config = match preset_env_config {
359 Some(c) => *c,
360 None => PresetEnvConfig::default().resolved_cell(),
361 };
362 postprocess.push(EcmascriptInputTransform::PresetEnv(environment, env_config));
363 }
364
365 let decorators_transform = if let Some(options) = &enable_decorators {
366 let options = options.await?;
367 options
368 .decorators_kind
369 .as_ref()
370 .map(|kind| EcmascriptInputTransform::Decorators {
371 is_legacy: kind == &DecoratorsKind::Legacy,
372 is_ecma: kind == &DecoratorsKind::Ecma,
373 emit_decorators_metadata: options.emit_decorators_metadata,
374 use_define_for_class_fields: options.use_define_for_class_fields,
375 })
376 } else {
377 None
378 };
379
380 let extra_preprocess = ecma_preprocess.clone();
382
383 if let Some(decorators_transform) = &decorators_transform {
384 ecma_preprocess.push(decorators_transform.clone());
395 }
396
397 let ecma_preprocess = ResolvedVc::cell(ecma_preprocess);
398 let main = ResolvedVc::<EcmascriptInputTransforms>::cell(vec![]);
399 let postprocess = ResolvedVc::cell(postprocess);
400 let empty = ResolvedVc::<EcmascriptInputTransforms>::cell(vec![]);
401
402 let mut rules = vec![];
403
404 let is_only_tracing = !analyze_mode.is_codegen;
410
411 if enable_import_as_bytes {
415 rules.push(ModuleRule::new(
416 RuleCondition::ReferenceType(ReferenceTypeCondition::EcmaScriptModules(Some(
417 EcmaScriptModulesReferenceSubType::ImportWithType("bytes".into()),
418 ))),
419 if is_only_tracing {
420 vec![ModuleRuleEffect::ModuleType(ModuleType::Raw)]
421 } else {
422 vec![ModuleRuleEffect::SourceTransforms(ResolvedVc::cell(vec![
423 ResolvedVc::upcast(BytesSourceTransform::new().to_resolved().await?),
424 ]))]
425 },
426 ));
427 }
428
429 rules.push(ModuleRule::new(
430 RuleCondition::ReferenceType(ReferenceTypeCondition::EcmaScriptModules(Some(
431 EcmaScriptModulesReferenceSubType::ImportWithType("text".into()),
432 ))),
433 if is_only_tracing {
434 vec![ModuleRuleEffect::ModuleType(ModuleType::Raw)]
435 } else {
436 vec![ModuleRuleEffect::SourceTransforms(ResolvedVc::cell(vec![
437 ResolvedVc::upcast(TextSourceTransform::new().to_resolved().await?),
438 ]))]
439 },
440 ));
441
442 if let Some(webpack_loaders_options) = enable_webpack_loaders {
443 let webpack_loaders_options = webpack_loaders_options.await?;
444 let execution_context =
445 execution_context.context("execution_context is required for webpack_loaders")?;
446 let import_map = if let Some(loader_runner_package) =
447 webpack_loaders_options.loader_runner_package
448 {
449 package_import_map_from_import_mapping(
450 rcstr!("loader-runner"),
451 *loader_runner_package,
452 )
453 } else {
454 package_import_map_from_context(
455 rcstr!("loader-runner"),
456 path.clone()
457 .context("need_path in ModuleOptions::new is incorrect")?,
458 )
459 };
460 let builtin_conditions = webpack_loaders_options
461 .builtin_conditions
462 .into_trait_ref()
463 .await?;
464 for (key, rule) in webpack_loaders_options.rules.await?.iter() {
465 let mut rule_conditions = Vec::new();
466
467 rule_conditions.push(
470 rule_condition_from_webpack_condition_glob(execution_context, key).await?,
471 );
472
473 if let Some(condition) = &rule.condition {
474 rule_conditions.push(
475 rule_condition_from_webpack_condition(
476 execution_context,
477 &*builtin_conditions,
478 condition,
479 )
480 .await?,
481 )
482 }
483
484 rule_conditions.push(RuleCondition::not(RuleCondition::ResourceIsVirtualSource));
485 rule_conditions.push(module_css_external_transform_conditions.clone());
486
487 let mut all_rule_condition = RuleCondition::All(rule_conditions);
488 all_rule_condition.flatten();
489 if !matches!(all_rule_condition, RuleCondition::False) {
490 let mut effects = Vec::new();
491
492 if !rule.loaders.await?.is_empty() {
494 effects.push(ModuleRuleEffect::SourceTransforms(ResolvedVc::cell(vec![
495 ResolvedVc::upcast(
496 WebpackLoaders::new(
497 node_evaluate_asset_context(
498 *execution_context,
499 Some(import_map),
500 None,
501 Layer::new(rcstr!("webpack_loaders")),
502 false,
503 ),
504 *execution_context,
505 *rule.loaders,
506 *webpack_loaders_options.target,
507 webpack_loaders_options.mode.clone(),
508 rule.rename_as.clone(),
509 resolve_options_context,
510 matches!(ecmascript_source_maps, SourceMapsType::Full),
511 config_tracing_module_context(*execution_context),
512 )
513 .to_resolved()
514 .await?,
515 ),
516 ])));
517 }
518
519 if let Some(type_str) = rule.module_type.as_ref() {
521 effects.push(
522 ConfiguredModuleType::parse(type_str)?
523 .into_effect(
524 ecma_preprocess,
525 main,
526 postprocess,
527 ecmascript_options_vc,
528 environment,
529 lightningcss_features,
530 )
531 .await?,
532 )
533 }
534
535 if !effects.is_empty() {
536 rules.push(ModuleRule::new(all_rule_condition, effects));
537 }
538 }
539 }
540 }
541
542 rules.extend(module_rules.iter().cloned());
543
544 if enable_mdx || enable_mdx_rs.is_some() {
545 let (jsx_runtime, jsx_import_source, development) = if let Some(enable_jsx) = enable_jsx
546 {
547 let jsx = enable_jsx.await?;
548 (
549 jsx.runtime.clone(),
550 jsx.import_source.clone(),
551 jsx.development,
552 )
553 } else {
554 (None, None, false)
555 };
556
557 let mdx_options = &*enable_mdx_rs
558 .unwrap_or_else(|| MdxTransformOptions::default().resolved_cell())
559 .await?;
560
561 let mdx_transform_options = (MdxTransformOptions {
562 development: Some(development),
563 jsx: Some(false),
564 jsx_runtime,
565 jsx_import_source,
566 ..(mdx_options.clone())
567 })
568 .cell();
569
570 rules.push(ModuleRule::new(
571 RuleCondition::any(vec![
572 RuleCondition::ResourcePathEndsWith(".md".to_string()),
573 RuleCondition::ResourcePathEndsWith(".mdx".to_string()),
574 RuleCondition::ContentTypeStartsWith("text/markdown".to_string()),
575 ]),
576 vec![ModuleRuleEffect::SourceTransforms(ResolvedVc::cell(vec![
577 ResolvedVc::upcast(
578 MdxTransform::new(mdx_transform_options)
579 .to_resolved()
580 .await?,
581 ),
582 ]))],
583 ));
584 }
585
586 rules.extend([
588 ModuleRule::new(
589 RuleCondition::ReferenceType(ReferenceTypeCondition::Url(Some(
590 UrlReferenceSubType::CssUrl,
591 ))),
592 vec![ModuleRuleEffect::ModuleType(ModuleType::StaticUrlCss {
593 tag: static_url_tag.clone(),
594 })],
595 ),
596 ModuleRule::new(
597 RuleCondition::ReferenceType(ReferenceTypeCondition::Url(Some(
598 UrlReferenceSubType::Undefined,
599 ))),
600 vec![ModuleRuleEffect::ModuleType(ModuleType::StaticUrlJs {
601 tag: static_url_tag.clone(),
602 })],
603 ),
604 ModuleRule::new(
605 RuleCondition::ReferenceType(ReferenceTypeCondition::Url(Some(
606 UrlReferenceSubType::EcmaScriptNewUrl,
607 ))),
608 vec![ModuleRuleEffect::ModuleType(ModuleType::StaticUrlJs {
609 tag: static_url_tag.clone(),
610 })],
611 ),
612 ModuleRule::new(
613 RuleCondition::ReferenceType(ReferenceTypeCondition::EcmaScriptModules(Some(
614 EcmaScriptModulesReferenceSubType::ImportWithType("json".into()),
615 ))),
616 if is_only_tracing {
617 vec![ModuleRuleEffect::ModuleType(ModuleType::Raw)]
618 } else {
619 vec![ModuleRuleEffect::SourceTransforms(ResolvedVc::cell(vec![
620 ResolvedVc::upcast(JsonSourceTransform::new_esm().to_resolved().await?),
622 ]))]
623 },
624 ),
625 ]);
626
627 rules.extend([
629 ModuleRule::new_all(
630 RuleCondition::any(vec![
631 RuleCondition::ResourcePathEndsWith(".json".to_string()),
632 RuleCondition::ContentTypeStartsWith("application/json".to_string()),
633 ]),
634 if is_only_tracing {
635 vec![ModuleRuleEffect::ModuleType(ModuleType::Raw)]
636 } else {
637 vec![ModuleRuleEffect::SourceTransforms(ResolvedVc::cell(vec![
638 ResolvedVc::upcast(JsonSourceTransform::new_cjs().to_resolved().await?),
640 ]))]
641 },
642 ),
643 ModuleRule::new_all(
644 RuleCondition::any(vec![
645 RuleCondition::ResourcePathEndsWith(".js".to_string()),
646 RuleCondition::ResourcePathEndsWith(".jsx".to_string()),
647 RuleCondition::ContentTypeStartsWith("application/javascript".to_string()),
648 RuleCondition::ContentTypeStartsWith("text/javascript".to_string()),
649 ]),
650 vec![ModuleRuleEffect::ModuleType(ModuleType::Ecmascript {
651 preprocess: ecma_preprocess,
652 main,
653 postprocess,
654 options: ecmascript_options_vc,
655 })],
656 ),
657 ModuleRule::new_all(
658 RuleCondition::ResourcePathEndsWith(".mjs".to_string()),
659 vec![ModuleRuleEffect::ModuleType(ModuleType::Ecmascript {
660 preprocess: ecma_preprocess,
661 main,
662 postprocess,
663 options: EcmascriptOptions {
664 specified_module_type: SpecifiedModuleType::EcmaScript,
665 ..ecmascript_options
666 }
667 .resolved_cell(),
668 })],
669 ),
670 ModuleRule::new_all(
671 RuleCondition::ResourcePathEndsWith(".cjs".to_string()),
672 vec![ModuleRuleEffect::ModuleType(ModuleType::Ecmascript {
673 preprocess: ecma_preprocess,
674 main,
675 postprocess,
676 options: EcmascriptOptions {
677 specified_module_type: SpecifiedModuleType::CommonJs,
678 ..ecmascript_options
679 }
680 .resolved_cell(),
681 })],
682 ),
683 ModuleRule::new(
684 RuleCondition::ResourcePathEndsWith(".d.ts".to_string()),
685 vec![ModuleRuleEffect::ModuleType(
686 ModuleType::TypescriptDeclaration {
687 preprocess: empty,
688 main: empty,
689 postprocess: empty,
690 options: ecmascript_options_vc,
691 },
692 )],
693 ),
694 ModuleRule::new(
695 RuleCondition::any(vec![RuleCondition::ResourcePathEndsWith(
696 ".node".to_string(),
697 )]),
698 vec![ModuleRuleEffect::ModuleType(ModuleType::NodeAddon)],
699 ),
700 ModuleRule::new(
706 RuleCondition::any(vec![
707 RuleCondition::ResourcePathEndsWith(".wasm".to_string()),
708 RuleCondition::ContentTypeStartsWith("application/wasm".to_string()),
709 ]),
710 if is_only_tracing {
711 vec![ModuleRuleEffect::ModuleType(ModuleType::Raw)]
712 } else {
713 vec![ModuleRuleEffect::ModuleType(ModuleType::WebAssembly {
714 source_ty: WebAssemblySourceType::Binary,
715 })]
716 },
717 ),
718 ModuleRule::new(
719 RuleCondition::any(vec![RuleCondition::ResourcePathEndsWith(
720 ".wat".to_string(),
721 )]),
722 if is_only_tracing {
723 vec![ModuleRuleEffect::ModuleType(ModuleType::Raw)]
724 } else {
725 vec![ModuleRuleEffect::ModuleType(ModuleType::WebAssembly {
726 source_ty: WebAssemblySourceType::Text,
727 })]
728 },
729 ),
730 ModuleRule::new(
731 RuleCondition::any(vec![
732 RuleCondition::ResourcePathEndsWith(".apng".to_string()),
733 RuleCondition::ResourcePathEndsWith(".avif".to_string()),
734 RuleCondition::ResourcePathEndsWith(".gif".to_string()),
735 RuleCondition::ResourcePathEndsWith(".ico".to_string()),
736 RuleCondition::ResourcePathEndsWith(".jpg".to_string()),
737 RuleCondition::ResourcePathEndsWith(".jpeg".to_string()),
738 RuleCondition::ResourcePathEndsWith(".png".to_string()),
739 RuleCondition::ResourcePathEndsWith(".svg".to_string()),
740 RuleCondition::ResourcePathEndsWith(".webp".to_string()),
741 RuleCondition::ResourcePathEndsWith(".woff2".to_string()),
742 ]),
743 vec![ModuleRuleEffect::ModuleType(ModuleType::StaticUrlJs {
744 tag: static_url_tag.clone(),
745 })],
746 ),
747 ModuleRule::new(
748 RuleCondition::all(vec![
749 RuleCondition::ResourcePathHasNoExtension,
751 RuleCondition::ContentTypeEmpty,
752 ]),
753 vec![ModuleRuleEffect::ModuleType(
754 ModuleType::EcmascriptExtensionless {
755 preprocess: empty,
756 main: empty,
757 postprocess: empty,
758 options: ecmascript_options_vc,
759 },
760 )],
761 ),
762 ]);
763
764 if let Some(options) = enable_typescript_transform {
765 let options = options.await?;
766 let ts_preprocess = ResolvedVc::cell(
769 extra_preprocess
770 .into_iter()
771 .chain(decorators_transform.clone())
772 .chain(std::iter::once(EcmascriptInputTransform::TypeScript {
773 use_define_for_class_fields: options.use_define_for_class_fields,
774 verbatim_module_syntax: options.verbatim_module_syntax,
775 }))
776 .collect(),
777 );
778
779 rules.extend([
780 ModuleRule::new_all(
781 RuleCondition::ResourcePathEndsWith(".ts".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: ecmascript_options_vc,
789 })],
790 ),
791 ModuleRule::new_all(
792 RuleCondition::ResourcePathEndsWith(".tsx".to_string()),
793 vec![ModuleRuleEffect::ModuleType(ModuleType::Typescript {
794 preprocess: ts_preprocess,
795 main,
796 postprocess,
797 tsx: true,
798 analyze_types: enable_types,
799 options: ecmascript_options_vc,
800 })],
801 ),
802 ModuleRule::new_all(
803 RuleCondition::ResourcePathEndsWith(".mts".to_string()),
804 vec![ModuleRuleEffect::ModuleType(ModuleType::Typescript {
805 preprocess: ts_preprocess,
806 main,
807 postprocess,
808 tsx: false,
809 analyze_types: enable_types,
810 options: EcmascriptOptions {
811 specified_module_type: SpecifiedModuleType::EcmaScript,
812 ..ecmascript_options
813 }
814 .resolved_cell(),
815 })],
816 ),
817 ModuleRule::new_all(
818 RuleCondition::ResourcePathEndsWith(".mtsx".to_string()),
819 vec![ModuleRuleEffect::ModuleType(ModuleType::Typescript {
820 preprocess: ts_preprocess,
821 main,
822 postprocess,
823 tsx: true,
824 analyze_types: enable_types,
825 options: EcmascriptOptions {
826 specified_module_type: SpecifiedModuleType::EcmaScript,
827 ..ecmascript_options
828 }
829 .resolved_cell(),
830 })],
831 ),
832 ModuleRule::new_all(
833 RuleCondition::ResourcePathEndsWith(".cts".to_string()),
834 vec![ModuleRuleEffect::ModuleType(ModuleType::Typescript {
835 preprocess: ts_preprocess,
836 main,
837 postprocess,
838 tsx: false,
839 analyze_types: enable_types,
840 options: EcmascriptOptions {
841 specified_module_type: SpecifiedModuleType::CommonJs,
842 ..ecmascript_options
843 }
844 .resolved_cell(),
845 })],
846 ),
847 ModuleRule::new_all(
848 RuleCondition::ResourcePathEndsWith(".ctsx".to_string()),
849 vec![ModuleRuleEffect::ModuleType(ModuleType::Typescript {
850 preprocess: ts_preprocess,
851 main,
852 postprocess,
853 tsx: true,
854 analyze_types: enable_types,
855 options: EcmascriptOptions {
856 specified_module_type: SpecifiedModuleType::CommonJs,
857 ..ecmascript_options
858 }
859 .resolved_cell(),
860 })],
861 ),
862 ]);
863 }
864
865 if enable_raw_css {
866 rules.extend([
867 ModuleRule::new(
868 module_css_condition.clone(),
869 vec![ModuleRuleEffect::ModuleType(ModuleType::Css {
870 ty: CssModuleType::Module,
871 environment,
872 lightningcss_features,
873 module_css_debuggable_idents,
874 })],
875 ),
876 ModuleRule::new(
877 RuleCondition::any(vec![
878 RuleCondition::ResourcePathEndsWith(".css".to_string()),
879 RuleCondition::ContentTypeStartsWith("text/css".to_string()),
880 ]),
881 vec![ModuleRuleEffect::ModuleType(ModuleType::Css {
882 ty: CssModuleType::Default,
883 environment,
884 lightningcss_features,
885 module_css_debuggable_idents,
886 })],
887 ),
888 ]);
889 } else {
890 if let Some(options) = enable_postcss_transform {
891 let options = options.await?;
892 let execution_context = execution_context
893 .context("execution_context is required for the postcss_transform")?;
894
895 let import_map = if let Some(postcss_package) = options.postcss_package {
896 package_import_map_from_import_mapping(rcstr!("postcss"), *postcss_package)
897 } else {
898 package_import_map_from_context(
899 rcstr!("postcss"),
900 path.clone()
901 .context("need_path in ModuleOptions::new is incorrect")?,
902 )
903 };
904
905 rules.push(ModuleRule::new(
906 RuleCondition::All(vec![
907 RuleCondition::Any(vec![
908 RuleCondition::ResourcePathEndsWith(".css".to_string()),
910 RuleCondition::ContentTypeStartsWith("text/css".to_string()),
911 module_css_condition.clone(),
912 ]),
913 module_css_external_transform_conditions.clone(),
914 ]),
915 vec![ModuleRuleEffect::SourceTransforms(ResolvedVc::cell(vec![
916 ResolvedVc::upcast(
917 PostCssTransform::new(
918 node_evaluate_asset_context(
919 *execution_context,
920 Some(import_map),
921 None,
922 Layer::new(rcstr!("postcss")),
923 true,
924 ),
925 config_tracing_module_context(*execution_context),
926 *execution_context,
927 options.config_location,
928 matches!(css_source_maps, SourceMapsType::Full),
929 )
930 .to_resolved()
931 .await?,
932 ),
933 ]))],
934 ));
935 }
936
937 rules.extend([
938 ModuleRule::new(
939 RuleCondition::all(vec![
940 module_css_condition.clone(),
941 RuleCondition::ReferenceType(ReferenceTypeCondition::Css(Some(
943 CssReferenceSubType::AtImport(None),
944 ))),
945 ]),
946 vec![ModuleRuleEffect::ModuleType(ModuleType::Css {
947 ty: CssModuleType::Module,
948 environment,
949 lightningcss_features,
950 module_css_debuggable_idents,
951 })],
952 ),
953 ModuleRule::new(
955 RuleCondition::all(vec![
956 module_css_condition.clone(),
957 RuleCondition::ReferenceType(ReferenceTypeCondition::Css(Some(
958 CssReferenceSubType::Inner,
959 ))),
960 ]),
961 vec![ModuleRuleEffect::ModuleType(ModuleType::Css {
962 ty: CssModuleType::Module,
963 environment,
964 lightningcss_features,
965 module_css_debuggable_idents,
966 })],
967 ),
968 ModuleRule::new(
970 RuleCondition::all(vec![
971 module_css_condition.clone(),
972 RuleCondition::ReferenceType(ReferenceTypeCondition::Css(Some(
973 CssReferenceSubType::Analyze,
974 ))),
975 ]),
976 vec![ModuleRuleEffect::ModuleType(ModuleType::Css {
977 ty: CssModuleType::Module,
978 environment,
979 lightningcss_features,
980 module_css_debuggable_idents,
981 })],
982 ),
983 ModuleRule::new(
984 RuleCondition::all(vec![module_css_condition.clone()]),
985 vec![ModuleRuleEffect::ModuleType(ModuleType::CssModule)],
986 ),
987 ModuleRule::new_all(
988 RuleCondition::Any(vec![
989 RuleCondition::ResourcePathEndsWith(".css".to_string()),
990 RuleCondition::ContentTypeStartsWith("text/css".to_string()),
991 ]),
992 vec![ModuleRuleEffect::ModuleType(ModuleType::Css {
993 ty: CssModuleType::Default,
994 environment,
995 lightningcss_features,
996 module_css_debuggable_idents,
997 })],
998 ),
999 ]);
1000 }
1001
1002 Ok(ModuleOptions::cell(ModuleOptions { rules }))
1003 }
1004}