rspack_plugin_extract_css 0.100.0-rc.1

rspack extract css plugin
Documentation
use rspack_core::{BoxDependency, DependencyRange};
use rspack_plugin_javascript::{JavascriptParserPlugin, visitors::JavascriptParser};
use rspack_util::fx_hash::FxDashMap;
use serde::Deserialize;

use crate::{css_dependency::CssDependency, plugin::PLUGIN_NAME};

#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CssExtractJsonData {
  pub identifier: String,
  pub content: String,
  pub context: String,
  pub media: Option<String>,
  pub supports: Option<String>,
  pub source_map: Option<String>,
  pub identifier_index: u32,
  pub layer: Option<String>,
}

#[derive(Debug, Default)]
pub struct PluginCssExtractParserPlugin {
  cache: FxDashMap<String, Vec<CssExtractJsonData>>,
}

#[rspack_plugin_javascript::implemented_javascript_parser_hooks]
impl JavascriptParserPlugin for PluginCssExtractParserPlugin {
  fn finish(&self, parser: &mut JavascriptParser) -> Option<bool> {
    let deps = if let Some(data_str) = parser.parse_meta.remove(PLUGIN_NAME)
      && let Ok(data_str) = (data_str as Box<dyn std::any::Any>)
        .downcast::<String>()
        .map(|i| *i)
    {
      let data = if let Some(data) = self.cache.get(&data_str) {
        data.clone()
      } else if let Ok(data) = serde_json::from_str::<Vec<CssExtractJsonData>>(&data_str) {
        self.cache.insert(data_str, data.clone());
        data
      } else {
        vec![]
      };
      if data.is_empty() {
        vec![]
      } else {
        parser.build_info.strict = true;
        data
          .iter()
          .enumerate()
          .map(
            |(
              index,
              CssExtractJsonData {
                identifier,
                content,
                context,
                media,
                supports,
                source_map,
                identifier_index,
                layer,
              },
            )| {
              Box::new(CssDependency::new(
                identifier.into(),
                parser.get_module_layer().cloned(),
                layer.clone(),
                content.clone(),
                context.clone(),
                media.clone(),
                supports.clone(),
                source_map.clone(),
                *identifier_index,
                DependencyRange::new(index as u32, (index + 1) as u32),
                parser.build_info.cacheable,
                parser.build_info.file_dependencies.clone(),
                parser.build_info.context_dependencies.clone(),
                parser.build_info.missing_dependencies.clone(),
                parser.build_info.build_dependencies.clone(),
              )) as BoxDependency
            },
          )
          .collect::<Vec<_>>()
      }
    } else {
      vec![]
    };
    parser.add_dependencies(deps);
    None
  }
}