Skip to content

Commit 7e3e9ad

Browse files
committed
fix: stability and improvements
1 parent e7efd1f commit 7e3e9ad

File tree

4 files changed

+123
-101
lines changed

4 files changed

+123
-101
lines changed

src/plugin.js

Lines changed: 70 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
import webpack from 'webpack';
22
import env from 'std-env';
3+
import prettyTime from 'pretty-time';
34

45
import { LogReporter, BarsReporter, ProfileReporter } from './reporters';
56
import Profile from './profile';
67
import { startCase } from './utils';
7-
import { consola } from './utils/cli';
88
import { parseRequest } from './utils/request';
99

10+
// Use bars when possible as default
11+
const useBars = !(env.ci || env.test || !env.tty);
12+
1013
// Default plugin options
1114
const DEFAULTS = {
1215
name: 'webpack',
@@ -15,11 +18,22 @@ const DEFAULTS = {
1518
stream: process.stdout,
1619
reporters: [],
1720
reporter: null,
18-
log: !!env.minimalCLI,
19-
bars: !env.minimalCLI,
21+
log: !useBars,
22+
bars: useBars,
23+
};
24+
25+
// Default state object
26+
const DEFAULT_STATE = {
27+
start: null,
28+
progress: -1,
29+
message: '',
30+
details: [],
31+
request: null,
32+
stats: null,
33+
hasErrors: false,
2034
};
2135

22-
// Mapping from name => { isRunning, details, progress, msg, request }
36+
// Mapping from name => State
2337
const globalStates = {};
2438

2539
export default class WebpackBarPlugin extends webpack.ProgressPlugin {
@@ -30,14 +44,14 @@ export default class WebpackBarPlugin extends webpack.ProgressPlugin {
3044
this.name = startCase(options.name);
3145

3246
// this.handler will be called by webpack.ProgressPlugin
33-
this.handler = (percent, msg, ...details) =>
34-
this.updateProgress(percent, msg, details);
47+
this.handler = (percent, message, ...details) =>
48+
this.updateProgress(percent, message, details);
3549

3650
// Keep our state in shared ojbect
3751
this.states = globalStates;
3852
if (!this.states[this.name]) {
3953
this.states[this.name] = {
40-
isRunning: false,
54+
...DEFAULT_STATE,
4155
color: this.options.color,
4256
profile: this.options.profile ? new Profile(this.name) : null,
4357
};
@@ -70,71 +84,81 @@ export default class WebpackBarPlugin extends webpack.ProgressPlugin {
7084
try {
7185
reporter[fn](this, payload);
7286
} catch (e) {
73-
consola.error(e);
87+
process.stdout.write(e.stack + '\n');
7488
}
7589
}
7690
}
7791
}
7892

79-
hasRunning() {
80-
return Object.values(this.states).some((state) => state.isRunning);
93+
get hasRunning() {
94+
return Object.values(this.states).some((state) => state.progress !== 100);
8195
}
8296

83-
hasErrors() {
84-
return Object.values(this.states).some(
85-
(state) => state.stats && state.stats.hasErrors()
86-
);
97+
get hasErrors() {
98+
return Object.values(this.states).some((state) => state.hasErrors);
8799
}
88100

89101
apply(compiler) {
90102
super.apply(compiler);
91103

92-
const hook = (stats) => {
93-
this.state.stats = stats;
94-
try {
95-
if (!this.hasRunning()) {
96-
this.callReporters('done');
97-
}
98-
} catch (e) {
99-
consola.error(e);
104+
// Hook helper for webpack 3 + 4 support
105+
function hook(hookName, fn) {
106+
if (compiler.hooks) {
107+
compiler.hooks[hookName].tap('WebpackBar:' + hookName, fn);
108+
} else {
109+
compiler.plugin(hookName, fn);
100110
}
101-
};
102-
103-
if (compiler.hooks) {
104-
compiler.hooks.done.tap('WebpackBar', hook);
105-
} else {
106-
compiler.plugin('done', hook);
107111
}
112+
113+
// Adds a hook right before compiler.run() is executed
114+
hook('beforeCompile', () => {
115+
Object.assign(this.state, {
116+
...DEFAULT_STATE,
117+
start: process.hrtime(),
118+
_allDoneCalled: false,
119+
});
120+
121+
this.callReporters('beforeRun');
122+
});
123+
124+
// Compilation has completed
125+
hook('done', (stats) => {
126+
const time = prettyTime(process.hrtime(this.state.start), 2);
127+
const hasErrors = stats.hasErrors();
128+
const status = hasErrors ? 'with some errors' : 'succesfuly';
129+
130+
Object.assign(this.state, {
131+
...DEFAULT_STATE,
132+
stats,
133+
progress: 100,
134+
message: `Compiled ${status} in ${time}`,
135+
hasErrors,
136+
});
137+
138+
this.callReporters('progress');
139+
this.callReporters('done');
140+
141+
if (!this.hasRunning) {
142+
this.callReporters('beforeAllDone');
143+
this.callReporters('allDone');
144+
}
145+
});
108146
}
109147

110-
updateProgress(percent, msg, details = []) {
148+
updateProgress(percent = 0, message = '', details = []) {
111149
const progress = Math.floor(percent * 100);
112-
const isRunning = progress < 100;
113-
114-
const wasRunning = this.state.isRunning;
115150

116151
Object.assign(this.state, {
117-
details,
118152
progress,
119-
msg: isRunning && msg ? msg : '',
153+
message: message || '',
154+
details,
120155
request: parseRequest(details[2]),
121-
elapsed: process.hrtime(this.state.start),
122-
isRunning,
123156
});
124157

125-
if (!wasRunning && isRunning) {
126-
// Started
127-
this.state.start = process.hrtime();
128-
this.callReporters('compiling');
129-
} else if (wasRunning && !isRunning) {
130-
// Finished
131-
this.callReporters('compiled');
132-
}
133-
134158
if (this.options.profile) {
135159
this.state.profile.onRequest(this.state.request);
136160
}
137161

138-
this.callReporters('update');
162+
this.callReporters('progress');
139163
}
140164
}

src/reporters/bars.js

Lines changed: 44 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,43 @@
11
/* eslint-disable no-console */
2-
import Consola from 'consola';
32
import chalk from 'chalk';
4-
import prettyTime from 'pretty-time';
3+
import consola from 'consola';
54

65
import { renderBar, colorize, ellipsisLeft } from '../utils/cli';
76
import { formatRequest } from '../utils/request';
8-
import { BULLET, TICK } from '../utils/consts';
7+
import { BULLET, TICK, CROSS } from '../utils/consts';
98
import LogUpdate from '../utils/log-update';
109

1110
let lastRender = Date.now();
1211

13-
let logUpdate = null;
12+
const logUpdate = new LogUpdate();
1413

1514
export default class BarsReporter {
16-
compiling() {
17-
logUpdate = logUpdate || new LogUpdate();
18-
Consola.pause();
15+
beforeRun() {
16+
consola.pause();
1917
}
2018

21-
done() {
22-
logUpdate.done();
23-
Consola.resume();
19+
done(context) {
20+
this._renderStates(context.states);
2421
}
2522

26-
compiled(context) {
27-
this._renderStates(context);
23+
beforeAllDone() {
24+
logUpdate.done();
25+
consola.resume();
2826
}
2927

30-
update(context) {
31-
if (Date.now() - lastRender > 200) {
32-
this._renderStates(context);
28+
progress(context) {
29+
if (Date.now() - lastRender > 50) {
30+
this._renderStates(context.states);
3331
}
3432
}
3533

36-
_renderStates(context) {
34+
_renderStates(states) {
3735
lastRender = Date.now();
3836

39-
const renderedStates = Object.keys(context.states)
37+
const renderedStates = Object.keys(states)
4038
.sort((n1, n2) => n1.localeCompare(n2))
41-
.map((name) => ({ name, state: context.states[name] }))
39+
.map((name) => ({ name, state: states[name] }))
40+
.filter((c) => c.state.progress !== -1)
4241
.map((c) => this._renderState(c))
4342
.join('\n\n');
4443

@@ -48,38 +47,36 @@ export default class BarsReporter {
4847
_renderState({ name, state }) {
4948
const color = colorize(state.color);
5049

51-
if (!state.isRunning) {
52-
// Not started yet
53-
if (!state.time) {
54-
const line1 = chalk.grey(`${BULLET} ${name}`);
55-
const line2 = chalk.grey(` Waiting to start...`);
56-
return line1 + '\n' + line2;
57-
}
58-
50+
let line1;
51+
let line2;
52+
53+
if (state.progress >= 0 && state.progress < 100) {
54+
// Running
55+
line1 = [
56+
color(BULLET),
57+
color(name),
58+
renderBar(state.progress, state.color),
59+
state.message,
60+
`(${state.progress || 0}%)`,
61+
chalk.grey(state.details[0] || ''),
62+
chalk.grey(state.details[1] || ''),
63+
].join(' ');
64+
65+
line2 = state.request
66+
? ' ' +
67+
chalk.grey(
68+
ellipsisLeft(formatRequest(state.request), logUpdate.columns)
69+
)
70+
: '';
71+
} else if (state.progress === 100) {
5972
// Finished
60-
const line1 = color(`${TICK} ${name}`);
61-
const time = prettyTime(state.time, 2);
62-
const line2 = chalk.grey(` Compiled succesfuly in ${time}`);
63-
return line1 + '\n' + line2;
73+
line1 = color(`${state.hasErrors ? CROSS : TICK} ${name}`);
74+
line2 = chalk.grey(' ' + state.message);
75+
} else {
76+
// Invalid state
77+
return '';
6478
}
6579

66-
const line1 = [
67-
color(BULLET),
68-
color(name),
69-
renderBar(state.progress, state.color),
70-
state.msg,
71-
`(${state.progress || 0}%)`,
72-
chalk.grey((state.details && state.details[0]) || ''),
73-
chalk.grey((state.details && state.details[1]) || ''),
74-
].join(' ');
75-
76-
const line2 = state.request
77-
? ' ' +
78-
chalk.grey(
79-
ellipsisLeft(formatRequest(state.request), logUpdate.columns)
80-
)
81-
: '';
82-
8380
return line1 + '\n' + line2;
8481
}
8582
}

src/utils/consts.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export const nodeModules = `${path.delimiter}node_modules${path.delimiter}`;
77
export const BAR_LENGTH = 25;
88
export const BLOCK_CHAR = '█';
99
export const BLOCK_CHAR2 = '█';
10-
export const NEXT = chalk.blue(figures(' › '));
11-
export const BULLET = figures('●');
12-
export const TICK = figures('✔');
10+
export const NEXT = ' ' + chalk.blue(figures.pointerSmall) + ' ';
11+
export const BULLET = figures.bullet;
12+
export const TICK = figures.tick;
13+
export const CROSS = figures.cross;

src/utils/log-update.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,16 @@ export default class LogUpdate {
2828
return (process.stderr.columns || 80) - 2;
2929
}
3030

31-
clear() {
32-
this.write(ansiEscapes.eraseLines(this.prevLineCount));
33-
this.prevLineCount = 0;
34-
}
35-
3631
write(data) {
3732
fs.writeSync(2, data);
3833
fs.fsyncSync(2);
3934
}
4035

36+
clear() {
37+
this.write(ansiEscapes.eraseLines(this.prevLineCount));
38+
this.prevLineCount = 0;
39+
}
40+
4141
done() {
4242
this.prevLineCount = 0;
4343
}

0 commit comments

Comments
 (0)