Skip to content

Commit 58c7d97

Browse files
committed
Improve perf by splitting important declarations into a separate array
1 parent 9f93ab0 commit 58c7d97

File tree

9 files changed

+176
-161
lines changed

9 files changed

+176
-161
lines changed

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,8 @@ cssnano: 542.956ms
9090
esbuild: 17.411ms
9191
160332 bytes
9292
93-
parcel-css: 4.74ms
94-
143985 bytes
93+
parcel-css: 4.602ms
94+
143154 bytes
9595
9696
9797
$ node bench.js animate.css
@@ -101,7 +101,7 @@ cssnano: 283.105ms
101101
esbuild: 11.858ms
102102
72183 bytes
103103
104-
parcel-css: 1.989ms
104+
parcel-css: 1.973ms
105105
23666 bytes
106106
107107
@@ -112,6 +112,6 @@ cssnano: 2.198s
112112
esbuild: 107.668ms
113113
1961642 bytes
114114
115-
parcel-css: 45.701ms
116-
1799209 bytes
115+
parcel-css: 43.368ms
116+
1824130 bytes
117117
```

src/declaration.rs

Lines changed: 76 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,27 @@ use crate::error::{ParserError, PrinterError};
2727

2828
#[derive(Debug, PartialEq)]
2929
pub struct DeclarationBlock {
30-
pub declarations: Vec<Declaration>
30+
pub important_declarations: Vec<Property>,
31+
pub declarations: Vec<Property>
3132
}
3233

3334
impl DeclarationBlock {
3435
pub fn parse<'i, 't>(input: &mut Parser<'i, 't>, options: &ParserOptions) -> Result<Self, ParseError<'i, ParserError<'i>>> {
35-
let mut parser = DeclarationListParser::new(input, PropertyDeclarationParser { options });
36-
let mut declarations = vec![];
37-
while let Some(decl) = parser.next() {
38-
match decl {
39-
Ok(decl) => declarations.push(decl),
40-
Err((err, _)) => return Err(err)
36+
let mut important_declarations = DeclarationList::new();
37+
let mut declarations = DeclarationList::new();
38+
let mut parser = DeclarationListParser::new(input, PropertyDeclarationParser {
39+
important_declarations: &mut important_declarations,
40+
declarations: &mut declarations,
41+
options
42+
});
43+
while let Some(res) = parser.next() {
44+
if let Err((err, _)) = res {
45+
return Err(err)
4146
}
4247
}
4348

4449
Ok(DeclarationBlock {
50+
important_declarations,
4551
declarations
4652
})
4753
}
@@ -52,14 +58,26 @@ impl ToCss for DeclarationBlock {
5258
dest.whitespace()?;
5359
dest.write_char('{')?;
5460
dest.indent();
55-
let len = self.declarations.len();
56-
for (i, decl) in self.declarations.iter().enumerate() {
57-
dest.newline()?;
58-
decl.to_css(dest)?;
59-
if i != len - 1 || !dest.minify {
60-
dest.write_char(';')?;
61-
}
61+
62+
let mut i = 0;
63+
let len = self.declarations.len() + self.important_declarations.len();
64+
65+
macro_rules! write {
66+
($decls: expr, $important: literal) => {
67+
for decl in &$decls {
68+
dest.newline()?;
69+
decl.to_css(dest, $important)?;
70+
if i != len - 1 || !dest.minify {
71+
dest.write_char(';')?;
72+
}
73+
i += 1;
74+
}
75+
};
6276
}
77+
78+
write!(self.declarations, false);
79+
write!(self.important_declarations, true);
80+
6381
dest.dedent();
6482
dest.newline()?;
6583
dest.write_char('}')
@@ -68,94 +86,76 @@ impl ToCss for DeclarationBlock {
6886

6987
impl DeclarationBlock {
7088
pub(crate) fn minify(&mut self, handler: &mut DeclarationHandler, important_handler: &mut DeclarationHandler) {
71-
let mut decls: Vec<Declaration> = vec![];
72-
for decl in self.declarations.iter() {
73-
let handled =
74-
(decl.important && important_handler.handle_property(decl)) ||
75-
(!decl.important && handler.handle_property(decl));
76-
77-
if !handled {
78-
decls.push(decl.clone());
79-
}
89+
macro_rules! handle {
90+
($decls: expr, $handler: expr) => {
91+
for decl in $decls.iter() {
92+
let handled = $handler.handle_property(decl);
93+
94+
if !handled {
95+
$handler.decls.push(decl.clone());
96+
}
97+
}
98+
};
8099
}
81100

82-
decls.extend(handler.finalize());
83-
decls.extend(important_handler.finalize());
84-
self.declarations = decls;
101+
handle!(self.important_declarations, important_handler);
102+
handle!(self.declarations, handler);
103+
104+
handler.finalize();
105+
important_handler.finalize();
106+
self.important_declarations = std::mem::take(&mut important_handler.decls);
107+
self.declarations = std::mem::take(&mut handler.decls);
85108
}
86109
}
87110

88111
struct PropertyDeclarationParser<'a> {
112+
important_declarations: &'a mut Vec<Property>,
113+
declarations: &'a mut Vec<Property>,
89114
options: &'a ParserOptions
90115
}
91116

92117
/// Parse a declaration within {} block: `color: blue`
93118
impl<'a, 'i> cssparser::DeclarationParser<'i> for PropertyDeclarationParser<'a> {
94-
type Declaration = Declaration;
119+
type Declaration = ();
95120
type Error = ParserError<'i>;
96121

97122
fn parse_value<'t>(
98123
&mut self,
99124
name: CowRcStr<'i>,
100125
input: &mut cssparser::Parser<'i, 't>,
101126
) -> Result<Self::Declaration, cssparser::ParseError<'i, Self::Error>> {
102-
Declaration::parse(name, input, self.options)
127+
parse_declaration(name, input, &mut self.declarations, &mut self.important_declarations, &self.options)
103128
}
104129
}
105130

106131
/// Default methods reject all at rules.
107132
impl<'a, 'i> AtRuleParser<'i> for PropertyDeclarationParser<'a> {
108133
type Prelude = ();
109-
type AtRule = Declaration;
134+
type AtRule = ();
110135
type Error = ParserError<'i>;
111136
}
112137

113-
#[derive(Debug, Clone, PartialEq)]
114-
pub struct Declaration {
115-
pub property: Property,
116-
pub important: bool
117-
}
118-
119-
impl Declaration {
120-
pub fn parse<'i, 't>(name: CowRcStr<'i>, input: &mut Parser<'i, 't>, options: &ParserOptions) -> Result<Self, ParseError<'i, ParserError<'i>>> {
121-
let property = input.parse_until_before(Delimiter::Bang, |input| Property::parse(name, input, options))?;
122-
let important = input.try_parse(|input| {
123-
input.expect_delim('!')?;
124-
input.expect_ident_matching("important")
125-
}).is_ok();
126-
Ok(Declaration { property, important })
127-
}
128-
}
129-
130-
impl ToCss for Declaration {
131-
fn to_css<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError> where W: std::fmt::Write {
132-
self.property.to_css(dest, self.important)
138+
pub(crate) fn parse_declaration<'i, 't>(
139+
name: CowRcStr<'i>,
140+
input: &mut cssparser::Parser<'i, 't>,
141+
declarations: &mut DeclarationList,
142+
important_declarations: &mut DeclarationList,
143+
options: &ParserOptions
144+
) -> Result<(), cssparser::ParseError<'i, ParserError<'i>>> {
145+
let property = input.parse_until_before(Delimiter::Bang, |input| Property::parse(name, input, options))?;
146+
let important = input.try_parse(|input| {
147+
input.expect_delim('!')?;
148+
input.expect_ident_matching("important")
149+
}).is_ok();
150+
if important {
151+
important_declarations.push(property);
152+
} else {
153+
declarations.push(property);
133154
}
155+
Ok(())
134156
}
135157

136-
#[derive(Default)]
137-
pub(crate) struct DeclarationList {
138-
important: bool,
139-
pub declarations: Vec<Declaration>
140-
}
141-
142-
impl DeclarationList {
143-
pub fn new(important: bool) -> DeclarationList {
144-
DeclarationList {
145-
important,
146-
declarations: Vec::new()
147-
}
148-
}
149-
150-
pub fn push(&mut self, property: Property) {
151-
self.declarations.push(Declaration { property, important: self.important })
152-
}
153-
154-
pub fn extend(&mut self, properties: &mut Vec<Property>) {
155-
let important = self.important;
156-
self.declarations.extend(properties.drain(..).map(|property| Declaration { property, important }))
157-
}
158-
}
158+
pub(crate) type DeclarationList = Vec<Property>;
159159

160160
#[derive(Default)]
161161
pub(crate) struct DeclarationHandler {
@@ -184,7 +184,7 @@ pub(crate) struct DeclarationHandler {
184184
}
185185

186186
impl DeclarationHandler {
187-
pub fn new(important: bool, targets: Option<Browsers>) -> Self {
187+
pub fn new(targets: Option<Browsers>) -> Self {
188188
DeclarationHandler {
189189
background: BackgroundHandler::new(targets),
190190
border: BorderHandler::new(targets),
@@ -198,13 +198,12 @@ impl DeclarationHandler {
198198
transform: TransformHandler::new(targets),
199199
text: TextDecorationHandler::new(targets),
200200
prefix: PrefixHandler::new(targets),
201-
decls: DeclarationList::new(important),
201+
decls: DeclarationList::new(),
202202
..DeclarationHandler::default()
203203
}
204204
}
205205

206-
pub fn handle_property(&mut self, decl: &Declaration) -> bool {
207-
let property = &decl.property;
206+
pub fn handle_property(&mut self, property: &Property) -> bool {
208207
self.background.handle_property(property, &mut self.decls) ||
209208
self.border.handle_property(property, &mut self.decls) ||
210209
self.outline.handle_property(property, &mut self.decls) ||
@@ -228,7 +227,7 @@ impl DeclarationHandler {
228227
self.prefix.handle_property(property, &mut self.decls)
229228
}
230229

231-
pub fn finalize(&mut self) -> Vec<Declaration> {
230+
pub fn finalize(&mut self) {
232231
self.background.finalize(&mut self.decls);
233232
self.border.finalize(&mut self.decls);
234233
self.outline.finalize(&mut self.decls);
@@ -250,6 +249,5 @@ impl DeclarationHandler {
250249
self.overflow.finalize(&mut self.decls);
251250
self.transform.finalize(&mut self.decls);
252251
self.prefix.finalize(&mut self.decls);
253-
std::mem::take(&mut self.decls.declarations)
254252
}
255253
}

0 commit comments

Comments
 (0)