Skip to content

Commit 446a848

Browse files
authored
fix(esm-library): handle CSS modules in preserveModules (#13670)
CSS modules (native `experiments.css` or mini-css-extract) under `output.library.preserveModules` caused either "chunk xxx should have at least one file" or "Multiple assets emit different content to the same filename". preserveModules set the JS filename_template on CSS chunks, left chunks nameless so multiple CSS files collapsed onto `.css`, and the ESM render phase emitted `import "__RSPACK_ESM_CHUNK_<id>"` placeholders pointing at CSS-only chunks with no JS file. Classify modules in preserve_modules by source_types and set css_filename_template for CSS modules (preserving the `.css` extension and source path), skip CSS-only modules/chunks in the ESM render paths that emit JS-side requires / cross-chunk imports, and make CssExtractRspackPlugin honor chunk.css_filename_template so preserveModules can override its per-chunk filename.
1 parent 375009f commit 446a848

27 files changed

Lines changed: 603 additions & 130 deletions

File tree

crates/rspack_core/src/normal_module.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,14 @@ impl NormalModule {
304304
pub fn get_generator_options(&self) -> Option<&GeneratorOptions> {
305305
self.generator_options.as_ref()
306306
}
307+
308+
pub fn get_generator_options_mut(&mut self) -> Option<&mut GeneratorOptions> {
309+
self.generator_options.as_mut()
310+
}
311+
312+
pub fn set_generator_options(&mut self, generator_options: Option<GeneratorOptions>) {
313+
self.generator_options = generator_options;
314+
}
307315
}
308316

309317
impl Identifiable for NormalModule {

crates/rspack_core/src/options/module.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,22 @@ impl GeneratorOptions {
544544
.or_else(|| self.get_asset_resource().and_then(|x| x.filename.as_ref()))
545545
}
546546

547+
/// Sets the asset filename on `Asset` / `AssetResource` variants. Returns
548+
/// `true` if the variant supports a per-module filename and it was set.
549+
pub fn set_asset_filename(&mut self, filename: Filename) -> bool {
550+
match self {
551+
Self::Asset(opts) => {
552+
opts.filename = Some(filename);
553+
true
554+
}
555+
Self::AssetResource(opts) => {
556+
opts.filename = Some(filename);
557+
true
558+
}
559+
_ => false,
560+
}
561+
}
562+
547563
pub fn asset_output_path(&self) -> Option<&Filename> {
548564
self
549565
.get_asset()
@@ -630,7 +646,7 @@ impl Default for AssetGeneratorImportMode {
630646
}
631647

632648
#[cacheable]
633-
#[derive(Debug, Clone, MergeFrom)]
649+
#[derive(Debug, Clone, Default, MergeFrom)]
634650
pub struct AssetResourceGeneratorOptions {
635651
pub emit: Option<bool>,
636652
pub filename: Option<Filename>,
@@ -654,7 +670,7 @@ impl From<AssetGeneratorOptions> for AssetResourceGeneratorOptions {
654670
}
655671

656672
#[cacheable]
657-
#[derive(Debug, Clone, MergeFrom)]
673+
#[derive(Debug, Clone, Default, MergeFrom)]
658674
pub struct AssetGeneratorOptions {
659675
pub emit: Option<bool>,
660676
pub filename: Option<Filename>,

0 commit comments

Comments
 (0)