UNPKG

5.33 kBJavaScriptView Raw
1'use strict';
2
3var gutil = require('gulp-util');
4var File = require('vinyl');
5var MemoryFileSystem = require('memory-fs');
6var through = require('through');
7var ProgressPlugin = require('webpack/lib/ProgressPlugin');
8var clone = require('lodash.clone');
9var applySourceMap = require('vinyl-sourcemaps-apply');
10
11var defaultStatsOptions = {
12 colors: gutil.colors.supportsColor,
13 hash: false,
14 timings: false,
15 chunks: false,
16 chunkModules: false,
17 modules: false,
18 children: true,
19 version: true,
20 cached: false,
21 cachedAssets: false,
22 reasons: false,
23 source: false,
24 errorDetails: false
25};
26
27module.exports = function (options, wp, done) {
28 options = clone(options) || {};
29 if (typeof done !== 'function') {
30 var callingDone = false;
31 done = function (err, stats) {
32 if (err) {
33 // The err is here just to match the API but isnt used
34 return;
35 }
36 stats = stats || {};
37 if (options.quiet || callingDone) {
38 return;
39 }
40 // Debounce output a little for when in watch mode
41 if (options.watch) {
42 callingDone = true;
43 setTimeout(function () {
44 callingDone = false;
45 }, 500);
46 }
47 if (options.verbose) {
48 gutil.log(stats.toString({
49 colors: gutil.colors.supportsColor
50 }));
51 } else {
52 var statsOptions = options && options.stats || {};
53
54 Object.keys(defaultStatsOptions).forEach(function (key) {
55 if (typeof statsOptions[key] === 'undefined') {
56 statsOptions[key] = defaultStatsOptions[key];
57 }
58 });
59
60 gutil.log(stats.toString(statsOptions));
61 }
62 };
63 }
64
65 var webpack = wp || require('webpack');
66 var entry = [];
67 var entries = Object.create(null);
68
69 var stream = through(function (file) {
70 if (file.isNull()) {
71 return;
72 }
73 if ('named' in file) {
74 if (!Array.isArray(entries[file.named])) {
75 entries[file.named] = [];
76 }
77 entries[file.named].push(file.path);
78 } else {
79 entry = entry || [];
80 entry.push(file.path);
81 }
82 }, function () {
83 var self = this;
84 options.output = options.output || {};
85
86 // Determine pipe'd in entry
87 if (Object.keys(entries).length > 0) {
88 entry = entries;
89 if (!options.output.filename) {
90 // Better output default for multiple chunks
91 options.output.filename = '[name].js';
92 }
93 } else if (entry.length < 2) {
94 entry = entry[0] || entry;
95 }
96
97 options.entry = options.entry || entry;
98 options.output.path = options.output.path || process.cwd();
99 options.output.filename = options.output.filename || '[hash].js';
100 entry = [];
101
102 if (!options.entry || options.entry.length < 1) {
103 gutil.log('webpack-stream - No files given; aborting compilation');
104 return self.emit('end');
105 }
106
107 var compiler = webpack(options, function (err, stats) {
108 if (err) {
109 self.emit('error', new gutil.PluginError('webpack-stream', err));
110 }
111 if (!options.watch) {
112 self.queue(null);
113 }
114 done(err, stats);
115 if (options.watch && !options.quiet) {
116 gutil.log('webpack is watching for changes');
117 }
118 });
119
120 // In watch mode webpack returns a wrapper object so we need to get
121 // the underlying compiler
122 if (options.watch) {
123 compiler = compiler.compiler;
124 }
125
126 if (options.progress) {
127 compiler.apply(new ProgressPlugin(function (percentage, msg) {
128 percentage = Math.floor(percentage * 100);
129 msg = percentage + '% ' + msg;
130 if (percentage < 10) msg = ' ' + msg;
131 gutil.log('webpack', msg);
132 }));
133 }
134
135 var fs = compiler.outputFileSystem = new MemoryFileSystem();
136
137 compiler.plugin('after-emit', function (compilation, callback) {
138 var assetNames = Object.keys(compilation.assets);
139 assetNames
140 // Webpack emits the source map, but Gulp will read that for us
141 .filter(function (outname) {
142 return !/\.map$/.test(outname);
143 })
144 .forEach(function (outname) {
145 if (compilation.assets[outname].emitted) {
146 var file = prepareFile(fs, compiler, outname, assetNames);
147 self.queue(file);
148 }
149 });
150 callback();
151 });
152 });
153
154 // If entry point manually specified, trigger that
155 if (options.entry) {
156 stream.end();
157 }
158
159 return stream;
160};
161
162// Prepare vinyl files with source maps
163function prepareFile (fs, compiler, outname, assetNames) {
164 var path = fs.join(compiler.outputPath, outname);
165 if (path.indexOf('?') !== -1) {
166 path = path.split('?')[0];
167 }
168 var contents = fs.readFileSync(path);
169 var file = new File({
170 base: compiler.outputPath,
171 path: path,
172 // Remove the source map comment as gulp will handle that
173 contents: new Buffer(contents.toString().replace(/\n\/\/#.*$/, ''))
174 });
175 var sourceMapPath = outname + '.map';
176 var hasSourceMap = assetNames.some(function (assetName) {
177 return assetName === sourceMapPath;
178 });
179 if (hasSourceMap) {
180 var sourceMap = JSON.parse(fs.readFileSync(fs.join(compiler.outputPath, sourceMapPath)));
181 applySourceMap(file, sourceMap);
182 }
183 return file;
184}
185
186// Expose webpack if asked
187Object.defineProperty(module.exports, 'webpack', {
188 get: function () {
189 return require('webpack');
190 }
191});