1 | const path = require('path');
|
2 | const PluginError = require('plugin-error');
|
3 | const es = require('event-stream');
|
4 | const through = require('through2');
|
5 | const useref = require('useref');
|
6 | const getGlobs = require('./lib/getGlobs');
|
7 | const addFilesFromExtStreams = require('./lib/addFilesFromExtStreams');
|
8 | const addHtmlToStream = require('./lib/addHtmlToStream');
|
9 | const unprocessedCounter = require('./lib/unprocessedCounter')();
|
10 | const end = require('./lib/end')();
|
11 | const additionalFiles = [];
|
12 | let transforms;
|
13 | let pluginOptions;
|
14 |
|
15 | function handleAdditionalStreams(additionalStreams) {
|
16 | let _additionalStreams = additionalStreams;
|
17 |
|
18 | if (!Array.isArray(additionalStreams)) {
|
19 | _additionalStreams = [ additionalStreams ];
|
20 | }
|
21 |
|
22 |
|
23 | return _additionalStreams.map(stream => stream.pipe(es.through(file => {
|
24 | additionalFiles.push(file);
|
25 | })));
|
26 | }
|
27 |
|
28 | function addAssetsToStream(paths, files) {
|
29 | const self = this;
|
30 | const gulpif = require('gulp-if');
|
31 | const concat = require('gulp-concat');
|
32 | const vfs = require('vinyl-fs');
|
33 | const extend = require('extend');
|
34 | let src;
|
35 | let globs;
|
36 | const name = paths.name;
|
37 | const basePath = paths.basePath;
|
38 | const filepaths = files[name].assets;
|
39 | const type = paths.type;
|
40 | const options = extend({}, pluginOptions);
|
41 | const gulpConcatOptions = {};
|
42 |
|
43 | if (!filepaths.length) {
|
44 | return;
|
45 | }
|
46 |
|
47 | unprocessedCounter.increment();
|
48 |
|
49 |
|
50 | globs = filepaths
|
51 | .filter(url => !/^(?:\w+:)?\/\//.test(url))
|
52 | .map(filepath => {
|
53 | paths.filepath = filepath;
|
54 |
|
55 | return getGlobs(paths, files);
|
56 | });
|
57 |
|
58 | src = vfs.src(globs, {
|
59 | base: basePath,
|
60 | nosort: true
|
61 | })
|
62 | .on('error', err => {
|
63 | self.emit('error', new Error(err));
|
64 | });
|
65 |
|
66 |
|
67 | src = addFilesFromExtStreams.call(self, additionalFiles, globs, src);
|
68 |
|
69 |
|
70 | transforms.forEach(fn => {
|
71 | src = src.pipe(fn(name));
|
72 | });
|
73 |
|
74 |
|
75 | if (Object.prototype.hasOwnProperty.call(options, 'newLine')) {
|
76 | if (options.newLine === ';' && type === 'css') {
|
77 | options.newLine = null;
|
78 | }
|
79 | gulpConcatOptions.newLine = options.newLine;
|
80 | }
|
81 |
|
82 |
|
83 |
|
84 | src
|
85 | .pipe(gulpif(!options.noconcat, concat(name, gulpConcatOptions)))
|
86 | .pipe(through.obj((newFile, encoding, callback) => {
|
87 |
|
88 | if (options.base) {
|
89 | newFile.path = path.join(options.base, name);
|
90 | newFile.base = options.base;
|
91 | }
|
92 |
|
93 |
|
94 | self.push(newFile);
|
95 | callback();
|
96 | }))
|
97 | .on('finish', () => {
|
98 | const unprocessed = unprocessedCounter.decrement();
|
99 |
|
100 | if (unprocessed === 0 && end.get()) {
|
101 |
|
102 | end.fn();
|
103 | }
|
104 | });
|
105 | }
|
106 |
|
107 | function processAssets({ cwd }, basePath, data) {
|
108 | const self = this;
|
109 | const types = pluginOptions.types || [ 'css', 'js' ];
|
110 |
|
111 | types.forEach(type => {
|
112 | const files = data[type];
|
113 | let name;
|
114 |
|
115 | if (!files) {
|
116 | return;
|
117 | }
|
118 |
|
119 | for (name in files) {
|
120 | addAssetsToStream.call(self, {
|
121 | name,
|
122 | basePath,
|
123 | searchPath: pluginOptions.searchPath,
|
124 | cwd,
|
125 | transformPath: pluginOptions.transformPath,
|
126 | type
|
127 | }, files);
|
128 | }
|
129 | });
|
130 | }
|
131 |
|
132 | module.exports = function (options) {
|
133 | const opts = options || {};
|
134 | let waitForAssets;
|
135 | let additionalStreams;
|
136 |
|
137 | pluginOptions = opts;
|
138 | transforms = Array.prototype.slice.call(arguments, 1);
|
139 |
|
140 |
|
141 | if (opts.additionalStreams) {
|
142 | additionalStreams = handleAdditionalStreams(opts.additionalStreams);
|
143 |
|
144 |
|
145 | waitForAssets = es.merge(additionalStreams).pipe(through.obj());
|
146 | } else {
|
147 |
|
148 | waitForAssets = through.obj();
|
149 | }
|
150 |
|
151 | return through.obj(function (file, enc, cb) {
|
152 | const self = this;
|
153 |
|
154 | waitForAssets.pipe(es.wait(() => {
|
155 | let output;
|
156 |
|
157 |
|
158 |
|
159 | const _basePath = path.dirname(file.path);
|
160 |
|
161 | if (file.isNull()) {
|
162 | return cb(null, file);
|
163 | }
|
164 |
|
165 | if (file.isStream()) {
|
166 | return cb(new PluginError('gulp-useref', 'Streaming not supported'));
|
167 | }
|
168 |
|
169 | output = useref(file.contents.toString(), opts);
|
170 |
|
171 | addHtmlToStream.call(self, file, output[0]);
|
172 |
|
173 | if (!opts.noAssets) {
|
174 | processAssets.call(self, file, _basePath, output[1]);
|
175 | }
|
176 |
|
177 | return cb();
|
178 | }));
|
179 |
|
180 |
|
181 |
|
182 | if (!additionalStreams) {
|
183 | waitForAssets.emit('end');
|
184 | }
|
185 | }, cb => {
|
186 | const unprocessed = unprocessedCounter.get();
|
187 | let fn = () => {};
|
188 |
|
189 | end.set(cb);
|
190 |
|
191 | if (unprocessed === 0) {
|
192 | fn = cb;
|
193 | }
|
194 |
|
195 | return fn();
|
196 | });
|
197 | };
|