Skip to content

Commit 0d3a044

Browse files
committed
Use child_process.spawn instead of child_process.exec to maintain colors in terminal output
1 parent f57d7d8 commit 0d3a044

File tree

2 files changed

+165
-33
lines changed

2 files changed

+165
-33
lines changed

lib/index.js

Lines changed: 146 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,125 @@
11
'use strict';
22

3-
var babelHelpers = {};
3+
var asyncGenerator = function () {
4+
function AwaitValue(value) {
5+
this.value = value;
6+
}
7+
8+
function AsyncGenerator(gen) {
9+
var front, back;
10+
11+
function send(key, arg) {
12+
return new Promise(function (resolve, reject) {
13+
var request = {
14+
key: key,
15+
arg: arg,
16+
resolve: resolve,
17+
reject: reject,
18+
next: null
19+
};
20+
21+
if (back) {
22+
back = back.next = request;
23+
} else {
24+
front = back = request;
25+
resume(key, arg);
26+
}
27+
});
28+
}
29+
30+
function resume(key, arg) {
31+
try {
32+
var result = gen[key](arg);
33+
var value = result.value;
34+
35+
if (value instanceof AwaitValue) {
36+
Promise.resolve(value.value).then(function (arg) {
37+
resume("next", arg);
38+
}, function (arg) {
39+
resume("throw", arg);
40+
});
41+
} else {
42+
settle(result.done ? "return" : "normal", result.value);
43+
}
44+
} catch (err) {
45+
settle("throw", err);
46+
}
47+
}
48+
49+
function settle(type, value) {
50+
switch (type) {
51+
case "return":
52+
front.resolve({
53+
value: value,
54+
done: true
55+
});
56+
break;
457

5-
babelHelpers.classCallCheck = function (instance, Constructor) {
58+
case "throw":
59+
front.reject(value);
60+
break;
61+
62+
default:
63+
front.resolve({
64+
value: value,
65+
done: false
66+
});
67+
break;
68+
}
69+
70+
front = front.next;
71+
72+
if (front) {
73+
resume(front.key, front.arg);
74+
} else {
75+
back = null;
76+
}
77+
}
78+
79+
this._invoke = send;
80+
81+
if (typeof gen.return !== "function") {
82+
this.return = undefined;
83+
}
84+
}
85+
86+
if (typeof Symbol === "function" && Symbol.asyncIterator) {
87+
AsyncGenerator.prototype[Symbol.asyncIterator] = function () {
88+
return this;
89+
};
90+
}
91+
92+
AsyncGenerator.prototype.next = function (arg) {
93+
return this._invoke("next", arg);
94+
};
95+
96+
AsyncGenerator.prototype.throw = function (arg) {
97+
return this._invoke("throw", arg);
98+
};
99+
100+
AsyncGenerator.prototype.return = function (arg) {
101+
return this._invoke("return", arg);
102+
};
103+
104+
return {
105+
wrap: function (fn) {
106+
return function () {
107+
return new AsyncGenerator(fn.apply(this, arguments));
108+
};
109+
},
110+
await: function (value) {
111+
return new AwaitValue(value);
112+
}
113+
};
114+
}();
115+
116+
var classCallCheck = function (instance, Constructor) {
6117
if (!(instance instanceof Constructor)) {
7118
throw new TypeError("Cannot call a class as a function");
8119
}
9120
};
10121

11-
babelHelpers.createClass = function () {
122+
var createClass = function () {
12123
function defineProperties(target, props) {
13124
for (var i = 0; i < props.length; i++) {
14125
var descriptor = props[i];
@@ -26,9 +137,11 @@ babelHelpers.createClass = function () {
26137
};
27138
}();
28139

29-
babelHelpers;
140+
var toArray = function (arr) {
141+
return Array.isArray(arr) ? arr : Array.from(arr);
142+
};
30143

31-
var exec = require('child_process').exec;
144+
var spawn = require('child_process').spawn;
32145
var defaultOptions = {
33146
onBuildStart: [],
34147
onBuildEnd: [],
@@ -43,9 +156,29 @@ function puts(error, stdout, stderr) {
43156
}
44157
}
45158

46-
function spreadStdoutAndStdErr(proc) {
47-
proc.stdout.pipe(process.stdout);
48-
proc.stderr.pipe(process.stdout);
159+
function serializeScript(script) {
160+
if (typeof script === 'string') {
161+
var _script$split = script.split(' '),
162+
_script$split2 = toArray(_script$split),
163+
_command = _script$split2[0],
164+
_args = _script$split2.slice(1);
165+
166+
return { command: _command, args: _args };
167+
}
168+
var command = script.command,
169+
args = script.args;
170+
171+
return { command: command, args: args };
172+
}
173+
174+
function handleScript(script) {
175+
var _serializeScript = serializeScript(script),
176+
command = _serializeScript.command,
177+
args = _serializeScript.args;
178+
179+
var proc = spawn(command, args, { stdio: 'inherit' });
180+
181+
proc.on('close', puts);
49182
}
50183

51184
function validateInput(options) {
@@ -72,12 +205,12 @@ function mergeOptions(options, defaults) {
72205

73206
var WebpackShellPlugin = function () {
74207
function WebpackShellPlugin(options) {
75-
babelHelpers.classCallCheck(this, WebpackShellPlugin);
208+
classCallCheck(this, WebpackShellPlugin);
76209

77210
this.options = validateInput(mergeOptions(options, defaultOptions));
78211
}
79212

80-
babelHelpers.createClass(WebpackShellPlugin, [{
213+
createClass(WebpackShellPlugin, [{
81214
key: 'apply',
82215
value: function apply(compiler) {
83216
var _this = this;
@@ -88,9 +221,7 @@ var WebpackShellPlugin = function () {
88221
}
89222
if (_this.options.onBuildStart.length) {
90223
console.log('Executing pre-build scripts');
91-
_this.options.onBuildStart.forEach(function (script) {
92-
spreadStdoutAndStdErr(exec(script, puts));
93-
});
224+
_this.options.onBuildStart.forEach(handleScript);
94225
if (_this.options.dev) {
95226
_this.options.onBuildStart = [];
96227
}
@@ -100,9 +231,7 @@ var WebpackShellPlugin = function () {
100231
compiler.plugin('emit', function (compilation, callback) {
101232
if (_this.options.onBuildEnd.length) {
102233
console.log('Executing post-build scripts');
103-
_this.options.onBuildEnd.forEach(function (script) {
104-
spreadStdoutAndStdErr(exec(script, puts));
105-
});
234+
_this.options.onBuildEnd.forEach(handleScript);
106235
if (_this.options.dev) {
107236
_this.options.onBuildEnd = [];
108237
}
@@ -113,9 +242,7 @@ var WebpackShellPlugin = function () {
113242
compiler.plugin('done', function () {
114243
if (_this.options.onBuildExit.length) {
115244
console.log('Executing additional scripts before exit');
116-
_this.options.onBuildExit.forEach(function (script) {
117-
spreadStdoutAndStdErr(exec(script, puts));
118-
});
245+
_this.options.onBuildExit.forEach(handleScript);
119246
}
120247
});
121248
}

src/webpack-shell-plugin.js

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const exec = require('child_process').exec;
1+
const spawn = require('child_process').spawn;
22
const defaultOptions = {
33
onBuildStart: [],
44
onBuildEnd: [],
@@ -13,9 +13,20 @@ function puts(error, stdout, stderr) {
1313
}
1414
}
1515

16-
function spreadStdoutAndStdErr(proc) {
17-
proc.stdout.pipe(process.stdout);
18-
proc.stderr.pipe(process.stdout);
16+
function serializeScript(script) {
17+
if (typeof script === 'string') {
18+
const [command, ...args] = script.split(' ');
19+
return {command, args};
20+
}
21+
const {command, args} = script;
22+
return {command, args};
23+
}
24+
25+
function handleScript(script) {
26+
const {command, args} = serializeScript(script);
27+
const proc = spawn(command, args, {stdio: 'inherit'});
28+
29+
proc.on('close', puts);
1930
}
2031

2132
function validateInput(options) {
@@ -32,7 +43,7 @@ function validateInput(options) {
3243
}
3344

3445
function mergeOptions(options, defaults) {
35-
for (let key in defaults) {
46+
for (const key in defaults) {
3647
if (options.hasOwnProperty(key)) {
3748
defaults[key] = options[key];
3849
}
@@ -53,9 +64,7 @@ export default class WebpackShellPlugin {
5364
}
5465
if (this.options.onBuildStart.length) {
5566
console.log('Executing pre-build scripts');
56-
this.options.onBuildStart.forEach((script) => {
57-
spreadStdoutAndStdErr(exec(script, puts));
58-
});
67+
this.options.onBuildStart.forEach(handleScript);
5968
if (this.options.dev) {
6069
this.options.onBuildStart = [];
6170
}
@@ -65,9 +74,7 @@ export default class WebpackShellPlugin {
6574
compiler.plugin('emit', (compilation, callback) => {
6675
if (this.options.onBuildEnd.length) {
6776
console.log('Executing post-build scripts');
68-
this.options.onBuildEnd.forEach((script) => {
69-
spreadStdoutAndStdErr(exec(script, puts));
70-
});
77+
this.options.onBuildEnd.forEach(handleScript);
7178
if (this.options.dev) {
7279
this.options.onBuildEnd = [];
7380
}
@@ -78,9 +85,7 @@ export default class WebpackShellPlugin {
7885
compiler.plugin('done', () => {
7986
if (this.options.onBuildExit.length) {
8087
console.log('Executing additional scripts before exit');
81-
this.options.onBuildExit.forEach((script) => {
82-
spreadStdoutAndStdErr(exec(script, puts));
83-
});
88+
this.options.onBuildExit.forEach(handleScript);
8489
}
8590
});
8691
}

0 commit comments

Comments
 (0)