1 |
|
2 | (function() {
|
3 | var CleanCSS, RootsUtil, _, crypto, fs, minimatch, path, yaml;
|
4 |
|
5 | fs = require('fs');
|
6 |
|
7 | path = require('path');
|
8 |
|
9 | _ = require('lodash');
|
10 |
|
11 | minimatch = require('minimatch');
|
12 |
|
13 | CleanCSS = require('clean-css');
|
14 |
|
15 | crypto = require('crypto');
|
16 |
|
17 | RootsUtil = require('roots-util');
|
18 |
|
19 | yaml = require('js-yaml');
|
20 |
|
21 | module.exports = function(opts) {
|
22 | var CSSPipeline;
|
23 | opts = _.defaults(opts, {
|
24 | files: 'assets/css/**',
|
25 | manifest: false,
|
26 | out: false,
|
27 | minify: false,
|
28 | hash: false,
|
29 | opts: {}
|
30 | });
|
31 | opts.files = Array.prototype.concat(opts.files);
|
32 | return CSSPipeline = (function() {
|
33 |
|
34 | |
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 | var get_output_paths, load_manifest_file;
|
43 |
|
44 | function CSSPipeline(roots) {
|
45 | var base;
|
46 | this.roots = roots;
|
47 | this.category = 'css-pipeline';
|
48 | this.file_map = {};
|
49 | this.util = new RootsUtil(this.roots);
|
50 | if (opts.manifest) {
|
51 | this.roots.config.ignores.push(opts.manifest);
|
52 | this.manifest = load_manifest_file.call(this, opts.manifest);
|
53 | }
|
54 | this.files = this.manifest || opts.files;
|
55 | if ((base = this.roots.config).locals == null) {
|
56 | base.locals = {};
|
57 | }
|
58 | this.roots.config.locals.css = (function(_this) {
|
59 | return function(prefix) {
|
60 | var i, len, matcher, paths, ref;
|
61 | if (prefix == null) {
|
62 | prefix = '';
|
63 | }
|
64 | paths = [];
|
65 | if (opts.out) {
|
66 | paths.push("" + prefix + opts.out);
|
67 | } else {
|
68 | ref = _this.files;
|
69 | for (i = 0, len = ref.length; i < len; i++) {
|
70 | matcher = ref[i];
|
71 | paths = paths.concat(get_output_paths.call(_this, matcher, prefix));
|
72 | }
|
73 | }
|
74 | return paths.map(function(p) {
|
75 | return "<link rel='stylesheet' href='" + p + "' />";
|
76 | }).join("\n");
|
77 | };
|
78 | })(this);
|
79 | }
|
80 |
|
81 |
|
82 | |
83 |
|
84 |
|
85 |
|
86 | CSSPipeline.prototype.fs = function() {
|
87 | return {
|
88 | extract: true,
|
89 | detect: (function(_this) {
|
90 | return function(f) {
|
91 | return _.any(_this.files, minimatch.bind(_this, f.relative));
|
92 | };
|
93 | })(this)
|
94 | };
|
95 | };
|
96 |
|
97 |
|
98 | |
99 |
|
100 |
|
101 |
|
102 |
|
103 | CSSPipeline.prototype.compile_hooks = function() {
|
104 | return {
|
105 | write: function() {
|
106 | return !opts.out;
|
107 | },
|
108 | after_file: (function(_this) {
|
109 | return function(ctx) {
|
110 | if (opts.out) {
|
111 | return _this.file_map[ctx.file.relative] = ctx.content;
|
112 | }
|
113 | };
|
114 | })(this)
|
115 | };
|
116 | };
|
117 |
|
118 |
|
119 | |
120 |
|
121 |
|
122 |
|
123 | CSSPipeline.prototype.category_hooks = function() {
|
124 | return {
|
125 | after: (function(_this) {
|
126 | return function(ctx) {
|
127 | var all_contents, content, file, hash, i, len, matcher, ref, ref1, res;
|
128 | if (!opts.out) {
|
129 | return;
|
130 | }
|
131 | all_contents = '';
|
132 | ref = _this.files;
|
133 | for (i = 0, len = ref.length; i < len; i++) {
|
134 | matcher = ref[i];
|
135 | ref1 = _this.file_map;
|
136 | for (file in ref1) {
|
137 | content = ref1[file];
|
138 | if (minimatch(file, matcher)) {
|
139 | all_contents += content;
|
140 | }
|
141 | }
|
142 | }
|
143 | if (opts.minify) {
|
144 | all_contents = (new CleanCSS(opts.opts)).minify(all_contents).toString();
|
145 | }
|
146 | if (opts.hash) {
|
147 | hash = crypto.createHash('md5').update(all_contents, 'utf8');
|
148 | res = opts.out.split('.');
|
149 | res.splice(-1, 0, hash.digest('hex'));
|
150 | opts.out = res.join('.');
|
151 | }
|
152 | return _this.util.write(opts.out, all_contents);
|
153 | };
|
154 | })(this)
|
155 | };
|
156 | };
|
157 |
|
158 |
|
159 | |
160 |
|
161 |
|
162 |
|
163 | load_manifest_file = function(f) {
|
164 | var res;
|
165 | res = yaml.safeLoad(fs.readFileSync(path.join(this.roots.root, f), 'utf8'));
|
166 | return res.map(function(m) {
|
167 | return path.join(path.dirname(f), m);
|
168 | });
|
169 | };
|
170 |
|
171 | get_output_paths = function(files, prefix) {
|
172 | return this.util.files(files).map((function(_this) {
|
173 | return function(f) {
|
174 | var fN, filePath;
|
175 | filePath = _this.util.output_path(f.relative).relative;
|
176 | fN = path.join(prefix, filePath.replace(path.extname(filePath), '.css'));
|
177 | return fN.replace(new RegExp('\\' + path.sep, 'g'), '/');
|
178 | };
|
179 | })(this));
|
180 | };
|
181 |
|
182 | return CSSPipeline;
|
183 |
|
184 | })();
|
185 | };
|
186 |
|
187 | }).call(this);
|