Skip to content

Instantly share code, notes, and snippets.

@byrichardpowell
Last active April 18, 2016 16:22
Show Gist options
  • Save byrichardpowell/17227066383d916854178ccedf6ddea7 to your computer and use it in GitHub Desktop.
Save byrichardpowell/17227066383d916854178ccedf6ddea7 to your computer and use it in GitHub Desktop.
Super simple node script to find CSS that is no longer in use. The results should be considered as safe as a global find and replace (not very), so use your judgement
var walk = require('walk');
var fs = require('fs');
var classesOrIds = [];
var viewsAndTemplates = []
var walkers = [];
var maybeUnusedClassesOrIds = [];
var compleWalkersCount = 0;
var classesToFileMap = {}
// Calback Function every time a walker ends
var onWalkerEnd = function(walkerId) {
compleWalkersCount++
// All walkers are complete
// We can only perform this logic once we have all the data
if (compleWalkersCount === walkers.length) {
// Loop through all the classes or IDs
for (i = 0; i < classesOrIds.length; i++) {
// The class or ID we are looking for
classOrId = classesOrIds[i]
// Loop through all the views and Templates
for (ii = 0; ii < viewsAndTemplates.length; ii++) {
// We found this class or ID in a view or template
if (viewsAndTemplates[ii].indexOf(classOrId.substring(1)) > -1) {
break;
}
// We didnt find this class or id inside any view or template
if (ii === viewsAndTemplates.length -1) {
maybeUnusedClassesOrIds.push(classOrId)
}
}
}
console.log("Found " + classesOrIds.length + " CSS classes or ids");
console.log(maybeUnusedClassesOrIds.length + " of those might not be in use anymore:");
console.log(" ");
// Log each class or ID that we couldnt find
maybeUnusedClassesOrIds.forEach(function(classOrId) {
logString = classOrId
// Right Pad the string so we a nice column of locations
for (i = 0; i < 40 - classOrId.length; i++) {
logString += " "
}
console.log(logString + classesToFileMap[classOrId]);
})
}
};
// Gets all the CSS Classes or Ids
walkers.push(walk.walk('./app/assets/css', { followLinks: false }).on('file', function(root, stat, next) {
// Opens each file
// Note this will open other files as well
fs.readFile(root + '/' + stat.name, 'utf8', function(error, data) {
// Assume the CSS is unminified
// If so we assume that each selector starts on a new line
data.split('\n').forEach(function(line) {
// Find Class selectors
// Assume that lines starting with a . are a class selectors
// Note this won't catch instances of element.class
if (line[0] === '.') {
name = line.split('.')[1].split(' ')[0].split(':')[0].split('\t')[0].split(',')[0].split('[')[0];
if (classesOrIds.indexOf("." + name) === -1) {
classesOrIds.push("." + name);
classesToFileMap["." + name] = root + '/' + stat.name;
}
}
// Find ID selectors
// Assume that lines starting with a # are ID selectors
// Note this won't catch instances of element#id
if (line[0] === '#') {
name = line.split('#')[1].split(' ')[0].split(':')[0].split('\t')[0].split(',')[0].split('[')[0].split('.')[0];
if (classesOrIds.indexOf("#" + name) === -1) {
classesOrIds.push("#" + name);
classesToFileMap["#" + name] = root + '/' + stat.name;
}
}
})
next();
});
}).on('end', onWalkerEnd));
// Gets all the mustache templates
walkers.push(walk.walk('./app/templates', { followLinks: false }).on('file', function(root, stat, next) {
// Read & save the content of the mustache template
// We'll check this for classes or ids later
fs.readFile(root + '/' + stat.name, 'utf8', function(error, data) {
viewsAndTemplates.push(data);
next();
});
}).on('end', onWalkerEnd));
// Gets all the views/components
walkers.push(walk.walk('./app/coffeescript/views', { followLinks: false }).on('file', function(root, stat, next) {
// Read & save the content of the view
// We'll check this for classes or ids later
fs.readFile(root + '/' + stat.name, 'utf8', function(error, data) {
viewsAndTemplates.push(data)
next();
});
}).on('end', onWalkerEnd));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment