use crate::types::generator::{GenerateContext, GenerateOutput, Generator};
use anyhow::Result;
use rolldown_common::{CssAssetMeta, InstantiatedChunk, InstantiationKind};
use rolldown_error::BuildResult;
use rolldown_sourcemap::{SourceJoiner, SourceMapSource};
use string_wizard::SourceMapOptions;
pub struct CssGenerator;
impl Generator for CssGenerator {
async fn instantiate_chunk(ctx: &mut GenerateContext<'_>) -> Result<BuildResult<GenerateOutput>> {
let mut ordered_css_modules = ctx
.chunk
.modules
.iter()
.filter_map(|&id| ctx.link_output.module_table[id].as_normal())
.filter(|m| m.css_view.is_some())
.collect::<Vec<_>>();
if ordered_css_modules.is_empty() {
return Ok(Ok(GenerateOutput {
chunks: vec![],
warnings: std::mem::take(&mut ctx.warnings),
}));
}
ordered_css_modules.sort_by_key(|m| m.exec_order);
let mut source_joiner = SourceJoiner::default();
let enable_sourcemap = ctx.options.sourcemap.is_some();
source_joiner.enable_sourcemap = enable_sourcemap;
for module in &ordered_css_modules {
let css_view = module.css_view.as_ref().unwrap();
let mut magic_string = string_wizard::MagicString::new(css_view.source.as_str());
for mutation in &css_view.mutations {
mutation.apply(&mut magic_string);
}
if enable_sourcemap {
let content = magic_string.to_string();
let mut sourcemap = magic_string.source_map(SourceMapOptions::default());
sourcemap.set_sources(vec![&module.stable_id]);
let source = SourceMapSource::new(content, sourcemap).with_pre_compute_sourcemap_data(true);
source_joiner.append_source(source);
} else {
source_joiner.append_source(magic_string.to_string());
}
}
source_joiner.append_source("");
let (content, map) = source_joiner.join();
let file_path = ctx.options.cwd.as_path().join(&ctx.options.out_dir).join(
ctx
.chunk
.css_preliminary_filename
.as_deref()
.expect("chunk file name should be generated before rendering")
.as_str(),
);
let file_dir = file_path.parent().expect("chunk file name should have a parent");
let css_asset_meta = CssAssetMeta {
filename: ctx
.chunk
.css_preliminary_filename
.as_deref()
.expect("should have preliminary_filename")
.clone(),
debug_id: 0,
file_dir: file_dir.to_path_buf(),
preliminary_filename: ctx
.chunk
.css_preliminary_filename
.clone()
.expect("should have preliminary filename"),
};
Ok(Ok(GenerateOutput {
chunks: vec![InstantiatedChunk {
originate_from: ctx.chunk_idx,
content: content.into(),
map,
kind: InstantiationKind::from(css_asset_meta),
augment_chunk_hash: None,
preliminary_filename: ctx
.chunk
.css_preliminary_filename
.clone()
.expect("should have preliminary filename"),
}],
warnings: std::mem::take(&mut ctx.warnings),
}))
}
}