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