UNPKG

5.7 kBJavaScriptView Raw
1const path = require('path');
2const PluginError = require('plugin-error');
3const es = require('event-stream');
4const through = require('through2');
5const useref = require('useref');
6const getGlobs = require('./lib/getGlobs');
7const addFilesFromExtStreams = require('./lib/addFilesFromExtStreams');
8const addHtmlToStream = require('./lib/addHtmlToStream');
9const unprocessedCounter = require('./lib/unprocessedCounter')();
10const end = require('./lib/end')();
11const additionalFiles = [];
12let transforms;
13let pluginOptions;
14
15function handleAdditionalStreams(additionalStreams) {
16 let _additionalStreams = additionalStreams;
17
18 if (!Array.isArray(additionalStreams)) {
19 _additionalStreams = [ additionalStreams ];
20 }
21
22 // filters stream to select needed files
23 return _additionalStreams.map(stream => stream.pipe(es.through(file => {
24 additionalFiles.push(file);
25 })));
26}
27
28function 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 // Get relative file paths and join with search paths to send to vinyl-fs
50 globs = filepaths
51 .filter(url => !/^(?:\w+:)?\/\//.test(url)) // test if url is relative
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 // add files from external streams
67 src = addFilesFromExtStreams.call(self, additionalFiles, globs, src);
68
69 // If any external transforms were included, pipe all files to them first
70 transforms.forEach(fn => {
71 src = src.pipe(fn(name));
72 });
73
74 // option for newLine in gulp-concat
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 // Add assets to the stream
83 // If noconcat option is false, concat the files first.
84 src
85 .pipe(gulpif(!options.noconcat, concat(name, gulpConcatOptions)))
86 .pipe(through.obj((newFile, encoding, callback) => {
87 // specify an output path relative to the cwd
88 if (options.base) {
89 newFile.path = path.join(options.base, name);
90 newFile.base = options.base;
91 }
92
93 // add file to the asset stream
94 self.push(newFile);
95 callback();
96 }))
97 .on('finish', () => {
98 const unprocessed = unprocessedCounter.decrement();
99
100 if (unprocessed === 0 && end.get()) {
101 // end the asset stream
102 end.fn();
103 }
104 });
105}
106
107function 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
132module.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 // If any external streams were included, add matched files to src
141 if (opts.additionalStreams) {
142 additionalStreams = handleAdditionalStreams(opts.additionalStreams);
143
144 // If we have additional streams, wait for them to run before continuing
145 waitForAssets = es.merge(additionalStreams).pipe(through.obj());
146 } else {
147 // Else, create a fake stream
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 // Cache the file base path relative to the cwd
158 // Use later when it could be dropped
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 // If no external streams were included,
181 // emit 'end' on the empty stream
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};