Skip to content

Instantly share code, notes, and snippets.

@jamlfy
Last active January 29, 2019 21:29
Show Gist options
  • Save jamlfy/98c9324e1494c0968e8fb3f3fce1fce0 to your computer and use it in GitHub Desktop.
Save jamlfy/98c9324e1494c0968e8fb3f3fce1fce0 to your computer and use it in GitHub Desktop.
Compressor the rules in CSS
const css = require('css');
const fs = require('fs');
const path = require('path');
const fileIn = path.join(__dirname, 'style.css');
const fileOut = path.join(__dirname, 'out.css');
Object.fromEntries = Object.fromEntries || ((x) => x.reduce((p,c) => {p[c[0]]=c[1];return p;},{}));
fs.readFile(fileIn, {encoding: 'utf-8'}, function(err,data){
if (!err) {
let cssIn = css.parse(data);
let cssOut = JSON.parse(JSON.stringify(cssIn));
let exlcude = [];
cssOut.stylesheet.rules = [];
for (let i = 0; i < cssIn.stylesheet.rules.length; i++) {
if(cssIn.stylesheet.rules[i].type == 'rule' ){
if(!exlcude.find(e => JSON.stringify(e) == JSON.stringify(cssIn.stylesheet.rules[i]))){
let style = cssIn.stylesheet.rules[i].selectors.sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0);
let same = cssIn.stylesheet.rules.filter(rule => JSON.stringify(
(rule.selectors || [] ).sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0)) === JSON.stringify(style));
cssOut.stylesheet.rules.push({
type: 'rule',
declarations : [].concat.apply([], same.map(e => e.declarations )),
selectors : cssIn.stylesheet.rules[i].selectors
});
exlcude = exlcude.concat(same);
}
} else {
cssOut.stylesheet.rules.push(cssIn.stylesheet.rules[i]);
}
}
console.log("css:same", cssIn.stylesheet.rules.length, cssOut.stylesheet.rules.length);
cssIn = JSON.parse(JSON.stringify(cssOut));
cssOut = JSON.parse(JSON.stringify(cssOut));
exlcude = [];
cssOut.stylesheet.rules = [];
for (let i = 0; i < cssIn.stylesheet.rules.length; i++) {
if(cssIn.stylesheet.rules[i].type == 'rule' ){
if(!exlcude.find(e => JSON.stringify(e) == JSON.stringify(cssIn.stylesheet.rules[i]))){
let style = Object.fromEntries(cssIn.stylesheet.rules[i].declarations.map(e => ([ e.property, e.value ])).sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0));
let same = cssIn.stylesheet.rules.filter(rule => JSON.stringify(Object.fromEntries(
(rule.declarations || [] ).map(
e => ([ e.property, e.value ])).sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0))) === JSON.stringify(style));
cssOut.stylesheet.rules.push({
type: 'rule',
declarations : cssIn.stylesheet.rules[i].declarations,
selectors : [].concat.apply([], same.map(e => e.selectors ))
});
exlcude = exlcude.concat(same);
}
} else {
cssOut.stylesheet.rules.push(cssIn.stylesheet.rules[i]);
}
}
console.log("css:rules", cssIn.stylesheet.rules.length, cssOut.stylesheet.rules.length);
cssIn = JSON.parse(JSON.stringify(cssOut));
cssOut = JSON.parse(JSON.stringify(cssOut));
exlcude = 0;
let exlcd = 0;
cssOut.stylesheet.rules = [];
for (let i = 0; i < cssIn.stylesheet.rules.length; i++) {
if(cssIn.stylesheet.rules[i].type == 'rule' ){
var declarations = [];
exlcude += cssIn.stylesheet.rules[i].declarations.length ;
for (let z = cssIn.stylesheet.rules[i].declarations.length - 1; z >= 0; z--) {
if(!declarations.find(e => e.property === cssIn.stylesheet.rules[i].declarations[z].property)){
declarations.push( cssIn.stylesheet.rules[i].declarations[z] );
} else {
exlcd++;
}
}
cssOut.stylesheet.rules.push({
...cssIn.stylesheet.rules[i],
declarations,
});
} else {
cssOut.stylesheet.rules.push(cssIn.stylesheet.rules[i]);
}
}
console.log("css:declarations", exlcude, exlcd);
fs.writeFile(fileOut, css.stringify(cssOut), function(err) {
if(err) {
return console.log(err);
}
console.log("The file was saved!");
});
} else {
console.log(err);
}
});
const browserless = require('browserless')();
const DOMAIN = 'http://URL.EXT/';
const AMP = 'amp';
const URLS = [
'my-url-test'
];
var result = {};
var testers = [
(line) => /\{$/.test(line),
(line) => !/^\@media/.test(line),
(line) => !/\/\*/.test(line)
];
var clean = [
(line) => line.split(/\,/gim),
(line) => line.replace(/\{$/gim, ''),
(line) => line.replace(/\:\w+/gim, ''),
(line) => [ line ].concat(line.split(/\,|\s|\>|\+|\~/gim))
];
const nextOpen = browserless
.evaluate(async (page, response) => {
Array.concatAll = (args) => {
return (args) = [].concat(...args);
}
Array.Flatten = (arr) => {
return Array.concatAll(arr.map(x => Array.isArray(x) ? Array.Flatten(x) : x ))
};
try {
const styleHandle = await page.$('style[amp-custom]');
const innerHTML = await page.evaluate(body => body.innerHTML, styleHandle);
const file = innerHTML.split(/\n/gim);
let lines = [];
for (let line = 0; line < file.length; line++) {
if(testers.every(e => e(file[line]))){
let select = [ file[line] ];
let last = [];
for (let i = clean.length - 1; i >= 0; i--) {
let array = select.map((e) => clean[i](e));
select = Array.Flatten(array.filter((e, i) => e && array.indexOf(e) == i ));
}
let invalids = 0;
for (var i = select.length - 1; i >= 0; i--) {
try {
result[select[i]] = result[select[i]] || 1;
let me = await page.$(select[i]);
if(me){
result[select[i]]++;
}
} catch(e){
invalids++;
//console.log("catch");
} finally {
//console.log("finally");
}
}
lines.push(invalids);
}
}
return Promise.resolve(lines);
} catch(e){
console.log("log", e);
return Promise.resolve([]);
}
});
;(async () => {
for (var i = URLS.length - 1; i >= 0; i--) {
try {
const info = await nextOpen( DOMAIN + URLS[i] + AMP);
console.log("Info", URLS[i], info.reduce((accumulator, currentValue) => accumulator + currentValue, 0));
} catch(e) {
console.log("Fail", URLS[i]);
}
}
console.log('--- Result ---');
console.log(JSON.stringify(result, null, '\t'));
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment