Skip to content

Commit f1ecb0e

Browse files
author
evilebottnawi
committed
refactor: internal
1 parent a27fe7f commit f1ecb0e

2 files changed

Lines changed: 128 additions & 62 deletions

File tree

__tests__/index.test.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ describe("execa-webpack-plugin", () => {
198198
});
199199
});
200200

201+
// Need async test
201202
it("should throw error with `bail: true` option", () => {
202203
expect.assertions(1);
203204

@@ -265,6 +266,34 @@ describe("execa-webpack-plugin", () => {
265266
});
266267
});
267268

269+
it("should works with nested commands (async)", () => {
270+
expect.assertions(2);
271+
272+
mkdirSyncSafe(dir);
273+
274+
expect(fs.statSync(dir).isDirectory()).toBe(true);
275+
276+
return run({
277+
onBuildExit: [
278+
{
279+
args: [
280+
{
281+
args: [path.join(resourcesDir, "nested.js")],
282+
cmd: "node"
283+
}
284+
],
285+
cmd: "del"
286+
}
287+
]
288+
}).then(() => {
289+
expect(() => fs.statSync(dir)).toThrow();
290+
291+
unlinkSyncSafe(dir);
292+
293+
return Promise.resolve();
294+
});
295+
});
296+
268297
it("should works when nested commands return nothing and 'bail: false'", () => {
269298
expect.assertions(1);
270299

index.js

Lines changed: 99 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -32,22 +32,83 @@ class ChildProcessWebpackPlugin {
3232
});
3333
}
3434

35-
execute(childProcesses) {
35+
static buildError(error, cmd, args) {
36+
return new Error(
37+
`Process "${cmd}${args.length > 0 ? ` ${args.join(" ")}` : ""}" return ${
38+
error.message
39+
}`
40+
);
41+
}
42+
43+
handleResult(result) {
44+
const { stdout, stderr } = result;
45+
46+
if (stdout) {
47+
this.log.info(stdout);
48+
}
49+
50+
if (stderr) {
51+
this.log.warn(stderr);
52+
}
53+
}
54+
55+
handleError(error, cmd, args) {
56+
this.log.error(ChildProcessWebpackPlugin.buildError(error, cmd, args));
57+
58+
if (this.options.bail) {
59+
throw error;
60+
}
61+
}
62+
63+
runCommand(process, async) {
64+
const { cmd } = process;
65+
const args = process.args || [];
66+
const opts = process.opts || {};
67+
68+
opts.stdio = ["ignore", "pipe", "pipe"];
69+
70+
this.log.info(
71+
`Run process "${cmd}${args.length > 0 ? ` ${args.join(" ")}` : ""}"`
72+
);
73+
74+
if (async) {
75+
return execa(cmd, args, opts)
76+
.then(asyncResult => {
77+
this.handleResult(asyncResult);
78+
79+
return asyncResult;
80+
})
81+
.catch(error => {
82+
this.handleError(error, cmd, args);
83+
84+
return null;
85+
});
86+
}
87+
88+
let result = null;
89+
90+
try {
91+
result = execa.sync(cmd, args, opts);
92+
} catch (error) {
93+
this.handleError(error);
94+
}
95+
96+
this.handleResult(result, cmd, args);
97+
98+
return result;
99+
}
100+
101+
execute(processes, callback) {
36102
const results = [];
103+
const hasCallback = Boolean(callback);
37104

38-
childProcesses.forEach(childProcess => {
39-
const { cmd } = childProcess;
40-
let { args, opts } = childProcess;
105+
processes.forEach(process => {
106+
const args = process.args || [];
41107
let hasFailedNestedChildProcess = false;
42108

43-
if (!args) {
44-
args = [];
45-
}
46-
47109
args.forEach((arg, index) => {
48110
if (typeof arg === "object" && Boolean(arg)) {
49-
const nestedResults = this.execute([arg]);
50-
const [result] = nestedResults;
111+
const result = this.runCommand(arg);
51112

52113
if (!result || !result.stdout) {
53114
hasFailedNestedChildProcess = true;
@@ -57,60 +118,24 @@ class ChildProcessWebpackPlugin {
57118
}
58119
});
59120

60-
let result = null;
61-
62121
if (hasFailedNestedChildProcess) {
63-
results.push(result);
122+
// eslint-disable-next-line prefer-promise-reject-errors
123+
results.push(hasCallback ? Promise.reject() : null);
64124

65125
return;
66126
}
67127

68-
if (!opts) {
69-
opts = {};
70-
}
71-
72-
opts.stdio = ["ignore", "pipe", "pipe"];
73-
74-
this.log.info(
75-
`Run process "${cmd}${args.length > 0 ? ` ${args.join(" ")}` : ""}"`
76-
);
77-
78-
try {
79-
result = execa.sync(cmd, args, opts);
80-
} catch (error) {
81-
this.log.error(
82-
new Error(
83-
`Process "${cmd}${
84-
args.length > 0 ? ` ${args.join(" ")}` : ""
85-
}" return ${error.message}`
86-
)
87-
);
88-
89-
if (this.options.bail) {
90-
throw error;
91-
}
92-
}
93-
94-
if (result) {
95-
const { stdout, stderr } = result;
96-
97-
if (stdout) {
98-
this.log.info(result.stdout);
99-
}
100-
101-
if (stderr) {
102-
this.log.warn(result.stderr);
103-
}
104-
}
128+
const result = this.runCommand(process, hasCallback);
105129

106130
results.push(result);
107131
});
108132

109-
return results;
133+
// eslint-disable-next-line promise/no-callback-in-promise
134+
return hasCallback ? Promise.all(results).then(() => callback()) : results;
110135
}
111136

112137
apply(compiler) {
113-
if (this.options.bail === null) {
138+
if (typeof this.options.bail !== "boolean") {
114139
this.options.bail = compiler.options.bail;
115140
}
116141

@@ -125,6 +150,7 @@ class ChildProcessWebpackPlugin {
125150
}
126151
};
127152

153+
/* istanbul ignore else */
128154
if (compiler.hooks) {
129155
// Information: `beforeRun.asyncTap` in future major
130156
compiler.hooks.compile.tap(plugin, compileFn);
@@ -135,15 +161,20 @@ class ChildProcessWebpackPlugin {
135161

136162
if (this.options.onBuildEnd.length > 0) {
137163
const afterEmitFn = (compilation, callback) => {
138-
this.execute(this.options.onBuildEnd);
164+
const done = () => {
165+
if (this.options.dev) {
166+
this.options.onBuildEnd = [];
167+
}
139168

140-
if (this.options.dev) {
141-
this.options.onBuildEnd = [];
142-
}
169+
callback();
170+
};
143171

144-
callback();
172+
this.execute(this.options.onBuildEnd);
173+
174+
return done();
145175
};
146176

177+
/* istanbul ignore else */
147178
if (compiler.hooks) {
148179
compiler.hooks.afterEmit.tapAsync(plugin, afterEmitFn);
149180
} else {
@@ -153,15 +184,21 @@ class ChildProcessWebpackPlugin {
153184

154185
if (this.options.onBuildExit.length > 0) {
155186
const doneFn = (stats, callback) => {
156-
this.execute(this.options.onBuildExit);
187+
// eslint-disable-next-line consistent-return
188+
const done = () => {
189+
if (this.options.dev) {
190+
this.options.onBuildExit = [];
191+
}
157192

158-
if (this.options.dev) {
159-
this.options.onBuildExit = [];
160-
}
193+
if (callback) {
194+
return callback();
195+
}
196+
};
161197

162-
callback();
198+
this.execute(this.options.onBuildExit, done);
163199
};
164200

201+
/* istanbul ignore else */
165202
if (compiler.hooks) {
166203
// Information: `asyncTap` in future major
167204
compiler.hooks.done.tapAsync(plugin, doneFn);

0 commit comments

Comments
 (0)