gitlab-org--gitlab-foss/scripts/frontend/startup_css/clean_css.js

84 lines
2.2 KiB
JavaScript

const { memoize, isString, isRegExp } = require('lodash');
const { parse } = require('postcss');
const { CSS_TO_REMOVE } = require('./constants');
const getSelectorRemoveTesters = memoize(() =>
CSS_TO_REMOVE.map((x) => {
if (isString(x)) {
return (selector) => x === selector;
}
if (isRegExp(x)) {
return (selector) => x.test(selector);
}
throw new Error(`Unexpected type in CSS_TO_REMOVE content "${x}". Expected String or RegExp.`);
}),
);
const getRemoveTesters = memoize(() => {
const selectorTesters = getSelectorRemoveTesters();
// These are mostly carried over from the previous project
// https://gitlab.com/gitlab-org/frontend/gitlab-css-statistics/-/blob/2aa00af25dba08fc71081c77206f45efe817ea4b/lib/gl_startup_extract.js
return [
(node) => node.type === 'comment',
(node) =>
node.type === 'atrule' &&
(node.params === 'print' ||
node.params === 'prefers-reduced-motion: reduce' ||
node.name === 'keyframe' ||
node.name === 'charset'),
(node) => node.selector && node.selectors && !node.selectors.length,
(node) => node.selector && selectorTesters.some((fn) => fn(node.selector)),
(node) =>
node.type === 'decl' &&
(node.prop === 'transition' ||
node.prop.indexOf('-webkit-') > -1 ||
node.prop.indexOf('-ms-') > -1),
];
});
const getNodesToRemove = (nodes) => {
const removeTesters = getRemoveTesters();
const remNodes = [];
nodes.forEach((node) => {
if (removeTesters.some((fn) => fn(node))) {
remNodes.push(node);
} else if (node.nodes?.length) {
remNodes.push(...getNodesToRemove(node.nodes));
}
});
return remNodes;
};
const getEmptyNodesToRemove = (nodes) =>
nodes
.filter((node) => node.nodes)
.reduce((acc, node) => {
if (node.nodes.length) {
acc.push(...getEmptyNodesToRemove(node.nodes));
} else {
acc.push(node);
}
return acc;
}, []);
const cleanCSS = (css) => {
const cssRoot = parse(css);
getNodesToRemove(cssRoot.nodes).forEach((node) => {
node.remove();
});
getEmptyNodesToRemove(cssRoot.nodes).forEach((node) => {
node.remove();
});
return cssRoot.toResult().css;
};
module.exports = { cleanCSS };