Skip to content

Commit 83839a9

Browse files
authored
Add granular CSS Modules options (parcel-bundler#739)
1 parent 445def9 commit 83839a9

File tree

12 files changed

+299
-64
lines changed

12 files changed

+299
-64
lines changed

Cargo.lock

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ assert_cmd = "2.0"
8686
assert_fs = "1.0"
8787
predicates = "2.1"
8888
serde_json = "1"
89+
pretty_assertions = "1.4.0"
8990

9091
[[test]]
9192
name = "cli_integration_tests"

napi/src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,9 @@ enum CssModulesOption {
605605
struct CssModulesConfig {
606606
pattern: Option<String>,
607607
dashed_idents: Option<bool>,
608+
animation: Option<bool>,
609+
grid: Option<bool>,
610+
custom_idents: Option<bool>,
608611
}
609612

610613
#[cfg(feature = "bundler")]
@@ -713,6 +716,9 @@ fn compile<'i>(
713716
Default::default()
714717
},
715718
dashed_idents: c.dashed_idents.unwrap_or_default(),
719+
animation: c.animation.unwrap_or(true),
720+
grid: c.grid.unwrap_or(true),
721+
custom_idents: c.custom_idents.unwrap_or(true),
716722
}),
717723
}
718724
} else {
@@ -840,6 +846,9 @@ fn compile_bundle<
840846
Default::default()
841847
},
842848
dashed_idents: c.dashed_idents.unwrap_or_default(),
849+
animation: c.animation.unwrap_or(true),
850+
grid: c.grid.unwrap_or(true),
851+
custom_idents: c.custom_idents.unwrap_or(true),
843852
}),
844853
}
845854
} else {

src/css_modules.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,34 @@ use std::hash::{Hash, Hasher};
2525
use std::path::Path;
2626

2727
/// Configuration for CSS modules.
28-
#[derive(Default, Clone, Debug)]
28+
#[derive(Clone, Debug)]
2929
pub struct Config<'i> {
3030
/// The name pattern to use when renaming class names and other identifiers.
3131
/// Default is `[hash]_[local]`.
3232
pub pattern: Pattern<'i>,
3333
/// Whether to rename dashed identifiers, e.g. custom properties.
3434
pub dashed_idents: bool,
35+
/// Whether to scope animation names.
36+
/// Default is `true`.
37+
pub animation: bool,
38+
/// Whether to scope grid names.
39+
/// Default is `true`.
40+
pub grid: bool,
41+
/// Whether to scope custom identifiers
42+
/// Default is `true`.
43+
pub custom_idents: bool,
44+
}
45+
46+
impl<'i> Default for Config<'i> {
47+
fn default() -> Self {
48+
Config {
49+
pattern: Default::default(),
50+
dashed_idents: Default::default(),
51+
animation: true,
52+
grid: true,
53+
custom_idents: true,
54+
}
55+
}
3556
}
3657

3758
/// A CSS modules class name pattern.

src/lib.rs

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ mod tests {
6464
use crate::vendor_prefix::VendorPrefix;
6565
use cssparser::SourceLocation;
6666
use indoc::indoc;
67+
use pretty_assertions::assert_eq;
6768
use std::collections::HashMap;
6869

6970
fn test(source: &str, expected: &str) {
@@ -23053,6 +23054,97 @@ mod tests {
2305323054
Default::default(),
2305423055
);
2305523056

23057+
css_modules_test(
23058+
r#"
23059+
.foo {
23060+
color: red;
23061+
}
23062+
23063+
#id {
23064+
animation: 2s test;
23065+
}
23066+
23067+
@keyframes test {
23068+
from { color: red }
23069+
to { color: yellow }
23070+
}
23071+
"#,
23072+
indoc! {r#"
23073+
.EgL3uq_foo {
23074+
color: red;
23075+
}
23076+
23077+
#EgL3uq_id {
23078+
animation: 2s test;
23079+
}
23080+
23081+
@keyframes test {
23082+
from {
23083+
color: red;
23084+
}
23085+
23086+
to {
23087+
color: #ff0;
23088+
}
23089+
}
23090+
"#},
23091+
map! {
23092+
"foo" => "EgL3uq_foo",
23093+
"id" => "EgL3uq_id"
23094+
},
23095+
HashMap::new(),
23096+
crate::css_modules::Config {
23097+
animation: false,
23098+
// custom_idents: false,
23099+
..Default::default()
23100+
},
23101+
);
23102+
23103+
css_modules_test(
23104+
r#"
23105+
@counter-style circles {
23106+
symbols: Ⓐ Ⓑ Ⓒ;
23107+
}
23108+
23109+
ul {
23110+
list-style: circles;
23111+
}
23112+
23113+
ol {
23114+
list-style-type: none;
23115+
}
23116+
23117+
li {
23118+
list-style-type: disc;
23119+
}
23120+
"#,
23121+
indoc! {r#"
23122+
@counter-style circles {
23123+
symbols: Ⓐ Ⓑ Ⓒ;
23124+
}
23125+
23126+
ul {
23127+
list-style: circles;
23128+
}
23129+
23130+
ol {
23131+
list-style-type: none;
23132+
}
23133+
23134+
li {
23135+
list-style-type: disc;
23136+
}
23137+
"#},
23138+
map! {
23139+
"circles" => "EgL3uq_circles" referenced: true
23140+
},
23141+
HashMap::new(),
23142+
crate::css_modules::Config {
23143+
custom_idents: false,
23144+
..Default::default()
23145+
},
23146+
);
23147+
2305623148
#[cfg(feature = "grid")]
2305723149
css_modules_test(
2305823150
r#"
@@ -23135,6 +23227,46 @@ mod tests {
2313523227
Default::default(),
2313623228
);
2313723229

23230+
#[cfg(feature = "grid")]
23231+
css_modules_test(
23232+
r#"
23233+
.grid {
23234+
grid-template-areas: "foo";
23235+
}
23236+
23237+
.foo {
23238+
grid-area: foo;
23239+
}
23240+
23241+
.bar {
23242+
grid-column-start: foo-start;
23243+
}
23244+
"#,
23245+
indoc! {r#"
23246+
.EgL3uq_grid {
23247+
grid-template-areas: "foo";
23248+
}
23249+
23250+
.EgL3uq_foo {
23251+
grid-area: foo;
23252+
}
23253+
23254+
.EgL3uq_bar {
23255+
grid-column-start: foo-start;
23256+
}
23257+
"#},
23258+
map! {
23259+
"foo" => "EgL3uq_foo",
23260+
"grid" => "EgL3uq_grid",
23261+
"bar" => "EgL3uq_bar"
23262+
},
23263+
HashMap::new(),
23264+
crate::css_modules::Config {
23265+
grid: false,
23266+
..Default::default()
23267+
},
23268+
);
23269+
2313823270
css_modules_test(
2313923271
r#"
2314023272
test {

src/printer.rs

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -267,30 +267,32 @@ impl<'a, 'b, 'c, W: std::fmt::Write + Sized> Printer<'a, 'b, 'c, W> {
267267
/// Writes a CSS identifier to the underlying destination, escaping it
268268
/// as appropriate. If the `css_modules` option was enabled, then a hash
269269
/// is added, and the mapping is added to the CSS module.
270-
pub fn write_ident(&mut self, ident: &str) -> Result<(), PrinterError> {
271-
if let Some(css_module) = &mut self.css_module {
272-
let dest = &mut self.dest;
273-
let mut first = true;
274-
css_module.config.pattern.write(
275-
&css_module.hashes[self.loc.source_index as usize],
276-
&css_module.sources[self.loc.source_index as usize],
277-
ident,
278-
|s| {
279-
self.col += s.len() as u32;
280-
if first {
281-
first = false;
282-
serialize_identifier(s, dest)
283-
} else {
284-
serialize_name(s, dest)
285-
}
286-
},
287-
)?;
270+
pub fn write_ident(&mut self, ident: &str, handle_css_module: bool) -> Result<(), PrinterError> {
271+
if handle_css_module {
272+
if let Some(css_module) = &mut self.css_module {
273+
let dest = &mut self.dest;
274+
let mut first = true;
275+
css_module.config.pattern.write(
276+
&css_module.hashes[self.loc.source_index as usize],
277+
&css_module.sources[self.loc.source_index as usize],
278+
ident,
279+
|s| {
280+
self.col += s.len() as u32;
281+
if first {
282+
first = false;
283+
serialize_identifier(s, dest)
284+
} else {
285+
serialize_name(s, dest)
286+
}
287+
},
288+
)?;
288289

289-
css_module.add_local(&ident, &ident, self.loc.source_index);
290-
} else {
291-
serialize_identifier(ident, self)?;
290+
css_module.add_local(&ident, &ident, self.loc.source_index);
291+
return Ok(());
292+
}
292293
}
293294

295+
serialize_identifier(ident, self)?;
294296
Ok(())
295297
}
296298

src/properties/animation.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,17 +58,24 @@ impl<'i> ToCss for AnimationName<'i> {
5858
where
5959
W: std::fmt::Write,
6060
{
61+
let css_module_animation_enabled =
62+
dest.css_module.as_ref().map_or(false, |css_module| css_module.config.animation);
63+
6164
match self {
6265
AnimationName::None => dest.write_str("none"),
6366
AnimationName::Ident(s) => {
64-
if let Some(css_module) = &mut dest.css_module {
65-
css_module.reference(&s.0, dest.loc.source_index)
67+
if css_module_animation_enabled {
68+
if let Some(css_module) = &mut dest.css_module {
69+
css_module.reference(&s.0, dest.loc.source_index)
70+
}
6671
}
67-
s.to_css(dest)
72+
s.to_css_with_options(dest, css_module_animation_enabled)
6873
}
6974
AnimationName::String(s) => {
70-
if let Some(css_module) = &mut dest.css_module {
71-
css_module.reference(&s, dest.loc.source_index)
75+
if css_module_animation_enabled {
76+
if let Some(css_module) = &mut dest.css_module {
77+
css_module.reference(&s, dest.loc.source_index)
78+
}
7279
}
7380

7481
// CSS-wide keywords and `none` cannot remove quotes.
@@ -78,7 +85,7 @@ impl<'i> ToCss for AnimationName<'i> {
7885
Ok(())
7986
},
8087
_ => {
81-
dest.write_ident(s.as_ref())
88+
dest.write_ident(s.as_ref(), css_module_animation_enabled)
8289
}
8390
}
8491
}

0 commit comments

Comments
 (0)