UNPKG

6.58 kBJavaScriptView Raw
1'use strict';
2
3var fancyLog = require('fancy-log');
4var PluginError = require('plugin-error');
5var supportsColor = require('supports-color');
6var File = require('vinyl');
7var MemoryFileSystem = require('memory-fs');
8var nodePath = require('path');
9var through = require('through');
10var ProgressPlugin = require('webpack/lib/ProgressPlugin');
11var clone = require('lodash.clone');
12var some = require('lodash.some');
13
14var defaultStatsOptions = {
15 colors: supportsColor.stdout.hasBasic,
16 hash: false,
17 timings: false,
18 chunks: false,
19 chunkModules: false,
20 modules: false,
21 children: true,
22 version: true,
23 cached: false,
24 cachedAssets: false,
25 reasons: false,
26 source: false,
27 errorDetails: false
28};
29
30module.exports = function (options, wp, done) {
31 options = clone(options) || {};
32 var config = options.config || options;
33 if (typeof done !== 'function') {
34 var callingDone = false;
35 done = function (err, stats) {
36 if (err) {
37 // The err is here just to match the API but isnt used
38 return;
39 }
40 stats = stats || {};
41 if (options.quiet || callingDone) {
42 return;
43 }
44
45 // Debounce output a little for when in watch mode
46 if (options.watch) {
47 callingDone = true;
48 setTimeout(function () {
49 callingDone = false;
50 }, 500);
51 }
52
53 if (options.verbose) {
54 fancyLog(stats.toString({
55 colors: supportsColor.stdout.hasBasic
56 }));
57 } else {
58 var statsOptions = (options && options.stats) || {};
59
60 Object.keys(defaultStatsOptions).forEach(function (key) {
61 if (typeof statsOptions[key] === 'undefined') {
62 statsOptions[key] = defaultStatsOptions[key];
63 }
64 });
65
66 fancyLog(stats.toString(statsOptions));
67 }
68 };
69 }
70
71 var webpack = wp || require('webpack');
72 var entry = [];
73 var entries = Object.create(null);
74
75 var stream = through(function (file) {
76 if (file.isNull()) {
77 return;
78 }
79 if ('named' in file) {
80 if (!Array.isArray(entries[file.named])) {
81 entries[file.named] = [];
82 }
83 entries[file.named].push(file.path);
84 } else {
85 entry = entry || [];
86 entry.push(file.path);
87 }
88 }, function () {
89 var self = this;
90 var handleConfig = function (config) {
91 config.output = config.output || {};
92 config.watch = !!options.watch;
93
94 // Determine pipe'd in entry
95 if (Object.keys(entries).length > 0) {
96 entry = entries;
97 if (!config.output.filename) {
98 // Better output default for multiple chunks
99 config.output.filename = '[name].js';
100 }
101 } else if (entry.length < 2) {
102 entry = entry[0] || entry;
103 }
104
105 config.entry = config.entry || entry;
106 config.output.path = config.output.path || process.cwd();
107 config.output.filename = config.output.filename || '[hash].js';
108 config.watch = options.watch;
109 entry = [];
110
111 if (!config.entry || config.entry.length < 1) {
112 fancyLog('webpack-stream - No files given; aborting compilation');
113 self.emit('end');
114 return false;
115 }
116 return true;
117 };
118
119 var succeeded;
120 if (Array.isArray(config)) {
121 for (var i = 0; i < config.length; i++) {
122 succeeded = handleConfig(config[i]);
123 if (!succeeded) {
124 return false;
125 }
126 }
127 } else {
128 succeeded = handleConfig(config);
129 if (!succeeded) {
130 return false;
131 }
132 }
133
134 var compiler = webpack(config, function (err, stats) {
135 if (err) {
136 self.emit('error', new PluginError('webpack-stream', err));
137 return;
138 }
139 var jsonStats = stats ? stats.toJson() || {} : {};
140 var errors = jsonStats.errors || [];
141 if (errors.length) {
142 var errorMessage = errors.join('\n');
143 var compilationError = new PluginError('webpack-stream', errorMessage);
144 if (!options.watch) {
145 self.emit('error', compilationError);
146 }
147 self.emit('compilation-error', compilationError);
148 }
149 if (!options.watch) {
150 self.queue(null);
151 }
152 done(err, stats);
153 if (options.watch && !options.quiet) {
154 fancyLog('webpack is watching for changes');
155 }
156 });
157
158 var handleCompiler = function (compiler) {
159 // In watch mode webpack returns a wrapper object so we need to get
160 // the underlying compiler
161 if (options.watch && compiler.compiler) {
162 compiler = compiler.compiler;
163 }
164
165 if (options.progress) {
166 compiler.apply(new ProgressPlugin(function (percentage, msg) {
167 percentage = Math.floor(percentage * 100);
168 msg = percentage + '% ' + msg;
169 if (percentage < 10) msg = ' ' + msg;
170 fancyLog('webpack', msg);
171 }));
172 }
173
174 var fs = compiler.outputFileSystem = new MemoryFileSystem();
175
176 var afterEmitPlugin = compiler.hooks
177 // Webpack 4
178 ? function (callback) { compiler.hooks.afterEmit.tapAsync('WebpackStream', callback); }
179 // Webpack 2/3
180 : function (callback) { compiler.plugin('after-emit', callback); };
181
182 afterEmitPlugin(function (compilation, callback) {
183 Object.keys(compilation.assets).forEach(function (outname) {
184 if (compilation.assets[outname].emitted) {
185 var file = prepareFile(fs, compiler, outname);
186 self.queue(file);
187 }
188 });
189 callback();
190 });
191 };
192
193 if (Array.isArray(options.config) && options.watch) {
194 compiler.watchings.forEach(function (compiler) {
195 handleCompiler(compiler);
196 });
197 } else if (Array.isArray(options.config)) {
198 compiler.compilers.forEach(function (compiler) {
199 handleCompiler(compiler);
200 });
201 } else {
202 handleCompiler(compiler);
203 }
204 });
205
206 // If entry point manually specified, trigger that
207 var hasEntry = Array.isArray(config)
208 ? some(config, function (c) { return c.entry; })
209 : config.entry;
210 if (hasEntry) {
211 stream.end();
212 }
213
214 return stream;
215};
216
217function prepareFile (fs, compiler, outname) {
218 var path = fs.join(compiler.outputPath, outname);
219 if (path.indexOf('?') !== -1) {
220 path = path.split('?')[0];
221 }
222
223 var contents = fs.readFileSync(path);
224
225 var file = new File({
226 base: compiler.outputPath,
227 path: nodePath.join(compiler.outputPath, outname),
228 contents: contents
229 });
230 return file;
231}
232
233// Expose webpack if asked
234Object.defineProperty(module.exports, 'webpack', {
235 get: function () {
236 return require('webpack');
237 }
238});