Skip to content

Instantly share code, notes, and snippets.

@iammerrick
Last active June 5, 2016 03:36
Show Gist options
  • Save iammerrick/bfe7b61e5184834a2aa00e80e4e47347 to your computer and use it in GitHub Desktop.
Save iammerrick/bfe7b61e5184834a2aa00e80e4e47347 to your computer and use it in GitHub Desktop.
Search for every CSS Selector.

This is a very slow, very ghetto proof of concept. If you author your CSS using BEM you can make certain assumptions about the use of your classes and their application which allows you to confidentally delete CSS. This little script simply searches your code bases for all CSS classes and if a CSS class isn't use will inform you.

Run node unused-classnames.js in the root of your project. It will grab all your css files, parse for css classes, remove phseudo selectors and search your code for uses using Ag.

Running this in my project I get the following output:

Unused selector .icon-clock
Unused selector .icon-chevron-up
Unused selector .icon-chevron-down
Unused selector .icon-link
Unused selector .OptionBoolean__Label
Unused selector .AppHandler__Icon
Unused selector .Share__Label

Which, thankfully are all unused class names. :-)

const glob = require('glob');
const css = require('css');
const fs = require('fs');
const _ = require('lodash');
const exec = require('child_process').exec;
const files = glob.sync('**/*.css', {
ignore: 'node_modules/**/*',
nodir: true
});
files.forEach((file) => {
const source = fs.readFileSync(file, 'utf8');
const selectors = css.parse(source);
const classes = _.map(_.filter(_.compact(_.flatten(selectors.stylesheet.rules.map((rule) => (
rule.selectors
)))), (selector) => selector.startsWith('.')), (selector) => selector.replace('.', '').replace(/:(.+)/,''));
classes.forEach((cl) => {
exec(`ag "((\\\s|'|\\\"|{|})${cl}(\\\s|'|\\\"|{|})|(\\\s|'|\\\"|{|})${cl}(\\\s|'|\\\"|{|}))"`, (err, stdout, stderr)=> {
if (stdout === '') {
console.log(`Unused selector .${cl}`);
}
});
});
});
@statianzo
Copy link

👍 for taking advantage of BEM's constant-like naming

Lines 16-18 burn my eyes though.

Maybe bring in lodash/fp and do something like

const _ = require('lodash/fp');
const readClasses =  _.compose(
  _.map((selector) => selector.replace('.', '').replace(/:(.+)/,'')),
  _.filter((selector) => selector.startsWith('.')),
  _.compact,
  _.flatMap((rule) => rule.selectors)
);

//...
const classes = readClasses(selectors.stylesheets.rules);

It puts the iterator beside the function taking place.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment