Skip to content

Commit

Permalink
feat: extract-css-plugin supports layer
Browse files Browse the repository at this point in the history
  • Loading branch information
JSerFeng committed Aug 15, 2024
1 parent a5e3212 commit 44d7833
Show file tree
Hide file tree
Showing 28 changed files with 111 additions and 95 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/node_binding/binding.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export class JsCompilation {
addMissingDependencies(deps: Array<string>): void
addBuildDependencies(deps: Array<string>): void
rebuildModule(moduleIdentifiers: Array<string>, f: (...args: any[]) => any): void
importModule(request: string, publicPath: JsFilename | undefined | null, baseUri: string | undefined | null, originalModule: string | undefined | null, originalModuleContext: string | undefined | null, callback: (...args: any[]) => any): void
importModule(request: string, layer: string | undefined | null, publicPath: JsFilename | undefined | null, baseUri: string | undefined | null, originalModule: string | undefined | null, originalModuleContext: string | undefined | null, callback: (...args: any[]) => any): void
get entries(): JsEntries
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use rspack_error::Result;
use rspack_hook::{plugin, plugin_hook};
use rspack_loader_runner::AdditionalData;
use rspack_napi::{threadsafe_js_value_ref::ThreadsafeJsValueRef, JsCallback, NapiResultExt};
use rspack_plugin_extract_css::{CssExtractJsonData, CssExtractJsonDataList};
use rspack_plugin_extract_css::CssExtractJsonDataList;
use tokio::sync::oneshot;

#[plugin]
Expand Down Expand Up @@ -43,37 +43,14 @@ async fn additional_data(&self, additional_data: &mut AdditionalData) -> Result<
&& let Ok(data) = data.coerce_to_object()
&& let Ok(Some(data)) = data.get::<_, String>("css-extract-rspack-plugin")
{
let mut list = data.split("__RSPACK_CSS_EXTRACT_SEP__");
let mut data_list = vec![];
while let Some(identifier) = list.next() {
#[allow(clippy::unwrap_used)]
{
// parse the css data from js loader
// data:
// [identifier]__RSPACK_CSS_EXTRACT_SEP__
// [content]__RSPACK_CSS_EXTRACT_SEP__
// [context]__RSPACK_CSS_EXTRACT_SEP__
// [media]__RSPACK_CSS_EXTRACT_SEP__
// [supports]__RSPACK_CSS_EXTRACT_SEP__
// [sourceMap]__RSPACK_CSS_EXTRACT_SEP__
// [identifier]__RSPACK_CSS_EXTRACT_SEP__ ... repeated
// [content]__RSPACK_CSS_EXTRACT_SEP__
data_list.push(CssExtractJsonData {
identifier: identifier.into(),
content: list.next().unwrap().into(),
context: list.next().unwrap().into(),
media: list.next().unwrap().into(),
supports: list.next().unwrap().into(),
source_map: list.next().unwrap().into(),
identifier_index: list
.next()
.unwrap()
.parse()
.expect("Cannot parse identifier_index, this should never happen"),
filepath: list.next().unwrap().into(),
});
}
}
let data_list: Vec<rspack_plugin_extract_css::CssExtractJsonData> = data
.split("__RSPACK_CSS_EXTRACT_SEP__")
.map(|info| {
serde_json::from_str(info)
.unwrap_or_else(|e| panic!("failed to parse CssExtractJsonData: {}", e))
})
.collect();

old_data.insert(CssExtractJsonDataList(data_list));
};
tx.send(old_data)
Expand Down
2 changes: 2 additions & 0 deletions crates/rspack_binding_values/src/compilation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,7 @@ impl JsCompilation {
&'static self,
env: Env,
request: String,
layer: Option<String>,
public_path: Option<JsFilename>,
base_uri: Option<String>,
original_module: Option<String>,
Expand All @@ -485,6 +486,7 @@ impl JsCompilation {
let result = module_executor
.import_module(
request,
layer,
public_path.map(|p| p.into()),
base_uri,
original_module_context.map(rspack_core::Context::from),
Expand Down
4 changes: 3 additions & 1 deletion crates/rspack_core/src/compiler/module_executor/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ pub struct ExecuteModuleResult {
#[derive(Debug)]
pub struct ExecuteTask {
pub entry_dep_id: DependencyId,
pub layer: Option<String>,
pub public_path: Option<PublicPath>,
pub base_uri: Option<String>,
pub result_sender: Sender<(
Expand All @@ -63,6 +64,7 @@ impl Task<MakeTaskContext> for ExecuteTask {
fn sync_run(self: Box<Self>, context: &mut MakeTaskContext) -> TaskResult<MakeTaskContext> {
let Self {
entry_dep_id,
layer,
public_path,
base_uri,
result_sender,
Expand Down Expand Up @@ -118,7 +120,7 @@ impl Task<MakeTaskContext> for ExecuteTask {
filename: None,
library: None,
depend_on: None,
layer: None,
layer,
}),
});

Expand Down
2 changes: 2 additions & 0 deletions crates/rspack_core/src/compiler/module_executor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ impl ModuleExecutor {
pub async fn import_module(
&self,
request: String,
layer: Option<String>,
public_path: Option<PublicPath>,
base_uri: Option<String>,
original_module_context: Option<Context>,
Expand Down Expand Up @@ -198,6 +199,7 @@ impl ModuleExecutor {
param,
ExecuteTask {
entry_dep_id: dep_id,
layer,
public_path,
base_uri,
result_sender: tx,
Expand Down
1 change: 1 addition & 0 deletions crates/rspack_plugin_extract_css/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ rspack_plugin_javascript = { version = "0.1.0", path = "../rspack_plugin_javascr
rspack_plugin_runtime = { version = "0.1.0", path = "../rspack_plugin_runtime" }
rspack_util = { version = "0.1.0", path = "../rspack_util" }
rustc-hash = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
tracing = { workspace = true }
ustr = { workspace = true }
Expand Down
19 changes: 13 additions & 6 deletions crates/rspack_plugin_extract_css/src/css_dependency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ pub struct CssDependency {
pub(crate) identifier: String,
pub(crate) content: String,
pub(crate) context: String,
pub(crate) media: String,
pub(crate) supports: String,
pub(crate) source_map: String,
pub(crate) media: Option<String>,
pub(crate) supports: Option<String>,
pub(crate) source_map: Option<String>,
pub(crate) layer: Option<String>,

// One module can be split apart by using `@import` in the middle of one module
pub(crate) identifier_index: u32,
Expand All @@ -37,11 +38,12 @@ impl CssDependency {
#[allow(clippy::too_many_arguments)]
pub(crate) fn new(
identifier: String,
layer: Option<String>,
content: String,
context: String,
media: String,
supports: String,
source_map: String,
media: Option<String>,
supports: Option<String>,
source_map: Option<String>,
identifier_index: u32,
order_index: u32,
cacheable: bool,
Expand All @@ -55,6 +57,7 @@ impl CssDependency {
id: DependencyId::new(),
identifier,
content,
layer,
context,
media,
supports,
Expand Down Expand Up @@ -110,6 +113,10 @@ impl Dependency for CssDependency {
end: self.order_index + 1,
})
}

fn get_layer(&self) -> Option<&rspack_core::ModuleLayer> {
self.layer.as_ref()
}
}

impl ModuleDependency for CssDependency {
Expand Down
41 changes: 30 additions & 11 deletions crates/rspack_plugin_extract_css/src/css_module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ pub(crate) struct CssModule {
pub(crate) identifier: String,
pub(crate) content: String,
pub(crate) _context: String,
pub(crate) media: String,
pub(crate) supports: String,
pub(crate) source_map: String,
pub(crate) media: Option<String>,
pub(crate) supports: Option<String>,
pub(crate) source_map: Option<String>,
pub(crate) layer: Option<String>,
pub(crate) identifier_index: u32,

factory_meta: Option<FactoryMeta>,
Expand All @@ -52,14 +53,19 @@ pub(crate) struct CssModule {
impl CssModule {
pub fn new(dep: CssDependency) -> Self {
let identifier__ = format!(
"css|{}|{}|{}|{}}}",
dep.identifier, dep.identifier_index, dep.supports, dep.media,
"css|{}|{}|{}|{}|{}}}",
dep.identifier,
dep.identifier_index,
dep.layer.as_deref().unwrap_or_default(),
dep.supports.as_deref().unwrap_or_default(),
dep.media.as_deref().unwrap_or_default(),
)
.into();

Self {
identifier: dep.identifier,
content: dep.content,
layer: dep.layer.clone(),
_context: dep.context,
media: dep.media,
supports: dep.supports,
Expand All @@ -84,8 +90,12 @@ impl CssModule {
let mut hasher = RspackHash::from(&options.output);

self.content.hash(&mut hasher);
if let Some(layer) = &self.layer {
layer.hash(&mut hasher);
}
self.supports.hash(&mut hasher);
self.media.hash(&mut hasher);
self.source_map.hash(&mut hasher);

hasher.digest(&options.output.hash_digest)
}
Expand All @@ -97,22 +107,31 @@ impl Module for CssModule {

fn readable_identifier(&self, context: &rspack_core::Context) -> std::borrow::Cow<str> {
std::borrow::Cow::Owned(format!(
"css {}{}{}{}",
"css {}{}{}{}{}",
context.shorten(&self.identifier),
if self.identifier_index > 0 {
format!("({})", self.identifier_index)
} else {
"".into()
},
if self.supports.is_empty() {
"".into()
if let Some(layer) = &self.layer {
format!(" (layer {})", layer)
} else {
format!(" (supports {})", self.supports)
"".into()
},
if self.media.is_empty() {
if let Some(supports) = &self.supports
&& !supports.is_empty()
{
format!(" (supports {})", supports)
} else {
"".into()
},
if let Some(media) = &self.media
&& !media.is_empty()
{
format!(" (media {})", media)
} else {
format!(" (media {})", self.media)
"".into()
}
))
}
Expand Down
17 changes: 9 additions & 8 deletions crates/rspack_plugin_extract_css/src/parser_plugin.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
use std::path::PathBuf;

use rspack_core::BoxDependency;
use rspack_plugin_javascript::{visitors::JavascriptParser, JavascriptParserPlugin};
use rspack_util::fx_hash::FxDashMap;
use serde::Deserialize;

use crate::css_dependency::CssDependency;

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[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: String,
pub supports: String,
pub source_map: String,
pub media: Option<String>,
pub supports: Option<String>,
pub source_map: Option<String>,
pub identifier_index: u32,
pub filepath: PathBuf,
pub layer: Option<String>,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
Expand Down Expand Up @@ -48,11 +48,12 @@ impl JavascriptParserPlugin for PluginCssExtractParserPlugin {
supports,
source_map,
identifier_index,
..
layer,
},
)| {
Box::new(CssDependency::new(
identifier.into(),
layer.clone(),
content.clone(),
context.clone(),
media.clone(),
Expand Down
43 changes: 29 additions & 14 deletions crates/rspack_plugin_extract_css/src/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,30 +344,39 @@ impl PluginCssExtract {
if let Some(header) = header {
external_source.add(header);
}
if !module.media.is_empty() {
if let Some(media) = &module.media {
static MEDIA_RE: LazyLock<Regex> =
LazyLock::new(|| Regex::new(r#";|\s*$"#).expect("should compile"));
let new_content = MEDIA_RE.replace_all(content.as_ref(), &module.media);
let new_content = MEDIA_RE.replace_all(content.as_ref(), media);
external_source.add(RawSource::from(new_content.to_string() + "\n"));
} else {
external_source.add(RawSource::from(content.to_string() + "\n"));
}
} else {
let mut need_supports = false;
let mut need_media = false;

if let Some(header) = header {
source.add(header);
}
if !module.supports.is_empty() {
source.add(RawSource::from(format!(
"@supports ({}) {{\n",
&module.supports
)));

if let Some(supports) = &module.supports
&& !supports.is_empty()
{
need_supports = true;
source.add(RawSource::from(format!("@supports ({}) {{\n", supports)));
}

if !module.media.is_empty() {
source.add(RawSource::from(format!("@media {} {{\n", &module.media)));
if let Some(media) = &module.media
&& !media.is_empty()
{
need_media = true;
source.add(RawSource::from(format!("@media {} {{\n", media)));
}

// TODO: layer support
if let Some(layer) = &module.layer {
source.add(RawSource::from(format!("@layer {} {{\n", layer)));
}

let undo_path = get_undo_path(
&filename,
Expand All @@ -391,21 +400,27 @@ impl PluginCssExtract {
.unwrap_or(&undo_path),
);

if !module.source_map.is_empty() {
if let Some(source_map) = &module.source_map {
source.add(SourceMapSource::new(WithoutOriginalOptions {
value: content.to_string(),
name: readable_identifier,
source_map: SourceMap::from_json(&module.source_map).expect("invalid sourcemap"),
source_map: SourceMap::from_json(source_map).expect("invalid sourcemap"),
}))
} else {
source.add(RawSource::from(content.to_string()));
}

source.add(RawSource::from("\n"));
if !module.media.is_empty() {

if need_media {
source.add(RawSource::from("}\n"));
}
if !module.supports.is_empty() {

if need_supports {
source.add(RawSource::from("}\n"));
}

if module.layer.is_some() {
source.add(RawSource::from("}\n"));
}
}
Expand Down
Loading

0 comments on commit 44d7833

Please sign in to comment.