rspack_plugin_extract_css/
parser_plugin.rs

1use rspack_core::{BoxDependency, DependencyRange};
2use rspack_plugin_javascript::{JavascriptParserPlugin, visitors::JavascriptParser};
3use rspack_util::fx_hash::FxDashMap;
4use serde::Deserialize;
5
6use crate::{css_dependency::CssDependency, plugin::PLUGIN_NAME};
7
8#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize)]
9#[serde(rename_all = "camelCase")]
10pub struct CssExtractJsonData {
11  pub identifier: String,
12  pub content: String,
13  pub context: String,
14  pub media: Option<String>,
15  pub supports: Option<String>,
16  pub source_map: Option<String>,
17  pub identifier_index: u32,
18  pub layer: Option<String>,
19}
20
21#[derive(Debug, Default)]
22pub struct PluginCssExtractParserPlugin {
23  cache: FxDashMap<String, Vec<BoxDependency>>,
24}
25
26impl JavascriptParserPlugin for PluginCssExtractParserPlugin {
27  fn finish(&self, parser: &mut JavascriptParser) -> Option<bool> {
28    let deps = if let Some(data_str) = parser.parse_meta.remove(PLUGIN_NAME)
29      && let Ok(data_str) = (data_str as Box<dyn std::any::Any>)
30        .downcast::<String>()
31        .map(|i| *i)
32    {
33      if let Some(deps) = self.cache.get(&data_str) {
34        deps.clone()
35      } else if let Ok(data) = serde_json::from_str::<Vec<CssExtractJsonData>>(&data_str) {
36        let deps = data
37          .iter()
38          .enumerate()
39          .map(
40            |(
41              index,
42              CssExtractJsonData {
43                identifier,
44                content,
45                context,
46                media,
47                supports,
48                source_map,
49                identifier_index,
50                layer,
51              },
52            )| {
53              Box::new(CssDependency::new(
54                identifier.into(),
55                parser.get_module_layer().cloned(),
56                layer.clone(),
57                content.clone(),
58                context.clone(),
59                media.clone(),
60                supports.clone(),
61                source_map.clone(),
62                *identifier_index,
63                DependencyRange::new(index as u32, (index + 1) as u32),
64                parser.build_info.cacheable,
65                parser.build_info.file_dependencies.clone(),
66                parser.build_info.context_dependencies.clone(),
67                parser.build_info.missing_dependencies.clone(),
68                parser.build_info.build_dependencies.clone(),
69              )) as BoxDependency
70            },
71          )
72          .collect::<Vec<_>>();
73        self.cache.insert(data_str, deps.clone());
74        parser.build_info.strict = true;
75        deps
76      } else {
77        vec![]
78      }
79    } else {
80      vec![]
81    };
82    parser.add_dependencies(deps);
83    None
84  }
85}