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