css-pipeline
Version:
roots extension for handling css production builds
188 lines (160 loc) • 5.3 kB
JavaScript
// Generated by CoffeeScript 1.9.1
(function() {
var CleanCSS, RootsUtil, _, crypto, fs, minimatch, path, yaml;
fs = require('fs');
path = require('path');
_ = require('lodash');
minimatch = require('minimatch');
CleanCSS = require('clean-css');
crypto = require('crypto');
RootsUtil = require('roots-util');
yaml = require('js-yaml');
module.exports = function(opts) {
var CSSPipeline;
opts = _.defaults(opts, {
files: 'assets/css/**',
manifest: false,
out: false,
minify: false,
hash: false,
opts: {}
});
opts.files = Array.prototype.concat(opts.files);
return CSSPipeline = (function() {
/**
* Sets up the custom category and view function.
* The view function grabs either the single output path or collects
* all non-ignored output paths for the input files and returns them
* as html link tags.
*
* @param {Function} @roots - Roots class instance
*/
var get_output_paths, load_manifest_file;
function CSSPipeline(roots) {
var base;
this.roots = roots;
this.category = 'css-pipeline';
this.file_map = {};
this.util = new RootsUtil(this.roots);
if (opts.manifest) {
this.roots.config.ignores.push(opts.manifest);
this.manifest = load_manifest_file.call(this, opts.manifest);
}
this.files = this.manifest || opts.files;
if ((base = this.roots.config).locals == null) {
base.locals = {};
}
this.roots.config.locals.css = (function(_this) {
return function(prefix) {
var i, len, matcher, paths, ref;
if (prefix == null) {
prefix = '';
}
paths = [];
if (opts.out) {
paths.push("" + prefix + opts.out);
} else {
ref = _this.files;
for (i = 0, len = ref.length; i < len; i++) {
matcher = ref[i];
paths = paths.concat(get_output_paths.call(_this, matcher, prefix));
}
}
return paths.map(function(p) {
return "<link rel='stylesheet' href='" + p + "' />";
}).join("\n");
};
})(this);
}
/**
* Minimatch runs against each path, quick and easy.
*/
CSSPipeline.prototype.fs = function() {
return {
extract: true,
detect: (function(_this) {
return function(f) {
return _.any(_this.files, minimatch.bind(_this, f.relative));
};
})(this)
};
};
/**
* After compile, if concat is happening, grab the contents and save them
* away, then prevent write.
*/
CSSPipeline.prototype.compile_hooks = function() {
return {
write: function() {
return !opts.out;
},
after_file: (function(_this) {
return function(ctx) {
if (opts.out) {
return _this.file_map[ctx.file.relative] = ctx.content;
}
};
})(this)
};
};
/**
* Write the output file if necessary.
*/
CSSPipeline.prototype.category_hooks = function() {
return {
after: (function(_this) {
return function(ctx) {
var all_contents, content, file, hash, i, len, matcher, ref, ref1, res;
if (!opts.out) {
return;
}
all_contents = '';
ref = _this.files;
for (i = 0, len = ref.length; i < len; i++) {
matcher = ref[i];
ref1 = _this.file_map;
for (file in ref1) {
content = ref1[file];
if (minimatch(file, matcher)) {
all_contents += content;
}
}
}
if (opts.minify) {
all_contents = (new CleanCSS(opts.opts)).minify(all_contents).styles;
}
if (opts.hash) {
hash = crypto.createHash('md5').update(all_contents, 'utf8');
res = opts.out.split('.');
res.splice(-1, 0, hash.digest('hex'));
opts.out = res.join('.');
}
return _this.util.write(opts.out, all_contents);
};
})(this)
};
};
/**
* @private
*/
load_manifest_file = function(f) {
var res;
res = yaml.safeLoad(fs.readFileSync(path.join(this.roots.root, f), 'utf8'));
return res.map(function(m) {
return path.join(path.dirname(f), m);
});
};
get_output_paths = function(files, prefix) {
return this.util.files(files).map((function(_this) {
return function(f) {
var fN, filePath;
filePath = _this.util.output_path(f.relative).relative;
fN = path.join(prefix, filePath.split('.')[0] + '.css');
return fN.replace(new RegExp('\\' + path.sep, 'g'), '/');
};
})(this));
};
return CSSPipeline;
})();
};
}).call(this);