Skip to content

Commit fb288cf

Browse files
committed
[demos] whitelist accumulation
1 parent 3808b07 commit fb288cf

File tree

2 files changed

+143
-1
lines changed

2 files changed

+143
-1
lines changed

README.md

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ An exceptionally fast, thorough and tiny unused-CSS cleaner _(MIT Licensed)_
77

88
DropCSS is an exceptionally fast, thorough and tiny ([~9 KB min](https://github.com/leeoniya/dropcss/tree/master/dist/dropcss.min.js)) unused-CSS cleaner; it takes your HTML and CSS as input and returns only the used CSS as output. Its custom HTML and CSS parsers are highly optimized for the 99% use case and thus avoid the overhead of handling malformed markup or stylesheets, so you must provide well-formed input. There is minimal handling for complex escaping rules, so there will always exist cases of valid input that cannot be processed by DropCSS; for these infrequent cases, please [start a discussion](https://github.com/leeoniya/dropcss/issues).
99

10-
As a bonus, DropCSS will also remove unused `@keyframes` and `@font-face` blocks - an out-of-scope, purely intra-CSS optimization. Speaking of which, it's a good idea to run your CSS through a structural optimizer like [clean-css](https://github.com/jakubpawlowicz/clean-css), [csso](https://github.com/css/csso), [cssnano](https://github.com/cssnano/cssnano) or [crass](https://github.com/mattbasta/crass) to re-group selectors, merge redundant rules, etc. It probably makes sense to do this after DropCSS, which can leave redundant blocks, e.g. `.foo, .bar { color: red; }; .bar { width: 50%; }` -> `.bar { color: red; }; .bar { width: 50%; }` if `.foo` is absent from your markup.
10+
As a bonus, DropCSS will also remove unused `@keyframes` and `@font-face` blocks - an out-of-scope, purely intra-CSS optimization. Speaking of which, it's a good idea to run your CSS through a structural optimizer like [clean-css](https://github.com/jakubpawlowicz/clean-css), [csso](https://github.com/css/csso), [cssnano](https://github.com/cssnano/cssnano) or [crass](https://github.com/mattbasta/crass) to re-group selectors, merge redundant rules, etc. It probably makes sense to do this after DropCSS, which can leave redundant blocks, e.g. `.foo, .bar { color: red; } .bar { width: 50%; }` -> `.bar { color: red; } .bar { width: 50%; }` if `.foo` is absent from your markup.
1111

1212
More on this project's backstory & discussions: v0.1.0 alpha: [/r/javascript](https://old.reddit.com/r/javascript/comments/b3mcu8/dropcss_010_a_minimal_and_thorough_unused_css/), [Hacker News](https://news.ycombinator.com/item?id=19469080) and v1.0.0 release: [/r/javascript](https://old.reddit.com/r/javascript/comments/bb7im2/dropcss_v100_an_exceptionally_fast_thorough_and/).
1313

@@ -230,6 +230,84 @@ server.listen(8080);
230230
})();
231231
```
232232

233+
---
234+
### Accumulating a Whitelist
235+
236+
Perhaps you want to take one giant CSS file and purge it against multiple HTML sources, thus retaining any selectors that appear in any HTML source. This also applies when using Puppeteer to invoke different application states to ensure that DropCSS takes every provided application state into account before cleaning the CSS. The idea is rather simple:
237+
238+
1. Run DropCSS against each HTML source.
239+
2. Accumulate a whitelist from each result.
240+
3. Run DropCSS against an empty HTML string, relying only on the accumulated whitelist.
241+
242+
See [/demos/accumulate.js](/demos/accumulate.js):
243+
244+
```js
245+
const dropcss = require('dropcss');
246+
247+
// super mega-huge combined stylesheet
248+
let css = `
249+
em {
250+
color: red;
251+
}
252+
253+
p {
254+
font-weight: bold;
255+
}
256+
257+
.foo {
258+
font-size: 10pt;
259+
}
260+
`;
261+
262+
// html of page (or state) A
263+
let htmlA = `
264+
<html>
265+
<head></head>
266+
<body>
267+
<em>Hello World!</em>
268+
</body>
269+
</html>
270+
`;
271+
272+
// html of page (or state) B
273+
let htmlB = `
274+
<html>
275+
<head></head>
276+
<body>
277+
<p>Soft Kitties!</p>
278+
</body>
279+
</html>
280+
`;
281+
282+
// whitelist
283+
let whitelist = new Set();
284+
285+
let resA = dropcss({
286+
css,
287+
html: htmlA,
288+
});
289+
290+
// accumulate retained A selectors
291+
resA.sels.forEach(sel => whitelist.add(sel));
292+
293+
let resB = dropcss({
294+
css,
295+
html: htmlB,
296+
});
297+
298+
// accumulate retained B selectors
299+
resB.sels.forEach(sel => whitelist.add(sel));
300+
301+
// final purge relying only on accumulated whitelist
302+
let cleaned = dropcss({
303+
html: '',
304+
css,
305+
shouldDrop: sel => !whitelist.has(sel),
306+
});
307+
308+
console.log(cleaned.css);
309+
```
310+
233311
---
234312
### Special / Escaped Sequences
235313

demos/accumulate.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
const dropcss = require('../dist/dropcss.cjs.js');
2+
3+
// super mega-huge combined stylesheet
4+
let css = `
5+
em {
6+
color: red;
7+
}
8+
9+
p {
10+
font-weight: bold;
11+
}
12+
13+
.foo {
14+
font-size: 10pt;
15+
}
16+
`;
17+
18+
// html of page (or state) A
19+
let htmlA = `
20+
<html>
21+
<head></head>
22+
<body>
23+
<em>Hello World!</em>
24+
</body>
25+
</html>
26+
`;
27+
28+
// html of page (or state) B
29+
let htmlB = `
30+
<html>
31+
<head></head>
32+
<body>
33+
<p>Soft Kitties!</p>
34+
</body>
35+
</html>
36+
`;
37+
38+
// whitelist
39+
let whitelist = new Set();
40+
41+
let resA = dropcss({
42+
css,
43+
html: htmlA,
44+
});
45+
46+
// accumulate retained A selectors
47+
resA.sels.forEach(sel => whitelist.add(sel));
48+
49+
let resB = dropcss({
50+
css,
51+
html: htmlB,
52+
});
53+
54+
// accumulate retained B selectors
55+
resB.sels.forEach(sel => whitelist.add(sel));
56+
57+
// final purge relying only on accumulated whitelist
58+
let cleaned = dropcss({
59+
html: '',
60+
css,
61+
shouldDrop: sel => !whitelist.has(sel),
62+
});
63+
64+
console.log(cleaned.css);

0 commit comments

Comments
 (0)