@@ -2,10 +2,12 @@ import webpack from 'webpack';
2
2
import chalk from 'chalk' ;
3
3
import _ from 'lodash' ;
4
4
import logUpdate from 'log-update' ;
5
- import isCI from 'is-ci' ;
5
+ import env from 'std-env' ;
6
+ import prettyTime from 'pretty-time' ;
6
7
import Profile from './profile' ;
7
8
import {
8
9
BULLET ,
10
+ TICK ,
9
11
parseRequst ,
10
12
formatRequest ,
11
13
renderBar ,
@@ -18,74 +20,45 @@ const sharedState = {};
18
20
const defaults = {
19
21
name : 'webpack' ,
20
22
color : 'green' ,
21
- stream : process . stdout ,
22
23
profile : false ,
23
- clear : true ,
24
- showCursor : false ,
25
- enabled : process . stdout . isTTY && ! isCI ,
24
+ compiledIn : true ,
26
25
done : null ,
27
- buildTitle : 'BUILDING' ,
26
+ minimal : env . minimalCLI ,
27
+ stream : process . stderr ,
28
28
} ;
29
29
30
+ const hasRunning = ( ) => Object . values ( sharedState ) . find ( ( s ) => s . isRunning ) ;
31
+
30
32
export default class WebpackBarPlugin extends webpack . ProgressPlugin {
31
33
constructor ( options ) {
32
34
super ( ) ;
33
35
34
36
this . options = Object . assign ( { } , defaults , options ) ;
35
37
36
- if ( ! this . options . enabled ) {
37
- return ;
38
- }
39
-
40
38
// this.handler will be called by webpack.ProgressPlugin
41
39
this . handler = ( percent , msg , ...details ) =>
42
40
this . updateProgress ( percent , msg , details ) ;
43
41
44
42
this . _render = _ . throttle ( this . render , 25 ) ;
45
43
46
- this . logUpdate =
47
- this . options . logUpdate ||
48
- logUpdate . create ( this . options . stream , {
49
- showCursor : this . options . showCursor ,
50
- } ) ;
44
+ this . logUpdate = this . options . logUpdate || logUpdate ;
51
45
52
- if ( ! sharedState [ this . options . name ] ) {
46
+ if ( ! this . state ) {
53
47
sharedState [ this . options . name ] = {
48
+ isRunning : false ,
54
49
color : this . options . color ,
55
50
profile : this . options . profile ? new Profile ( this . options . name ) : null ,
56
51
} ;
57
52
}
58
53
}
59
54
60
- apply ( compiler ) {
61
- if ( ! this . options . enabled ) {
62
- return ;
63
- }
64
-
65
- super . apply ( compiler ) ;
66
-
67
- if ( compiler . hooks ) {
68
- // Webpack >= 4
69
- compiler . hooks . done . tap ( 'webpackbar' , ( ) => this . done ( ) ) ;
70
- } else {
71
- // Webpack < 4
72
- compiler . plugin ( 'done' , ( ) => this . done ( ) ) ;
73
- }
55
+ get state ( ) {
56
+ return sharedState [ this . options . name ] ;
74
57
}
75
58
76
59
done ( ) {
77
- if ( ! this . options . enabled ) {
78
- return ;
79
- }
80
-
81
- if ( Object . values ( sharedState ) . find ( ( s ) => s . isRunning ) ) {
82
- return ;
83
- }
84
-
85
- this . render ( ) ;
86
-
87
60
if ( this . options . profile ) {
88
- const stats = sharedState [ this . options . name ] . profile . getStats ( ) ;
61
+ const stats = this . state . profile . getStats ( ) ;
89
62
printStats ( stats ) ;
90
63
}
91
64
@@ -95,80 +68,92 @@ export default class WebpackBarPlugin extends webpack.ProgressPlugin {
95
68
}
96
69
97
70
updateProgress ( percent , msg , details ) {
98
- if ( ! this . options . enabled ) {
99
- return ;
100
- }
101
-
102
71
const progress = Math . floor ( percent * 100 ) ;
103
- const isRunning = progress && progress !== 100 ;
72
+ const isRunning = progress < 100 ;
104
73
105
- Object . assign ( sharedState [ this . options . name ] , {
74
+ const wasRunning = this . state . isRunning ;
75
+
76
+ Object . assign ( this . state , {
106
77
progress,
107
- msg : isRunning ? msg || '' : 'done ' ,
78
+ msg : isRunning && msg ? msg : '' ,
108
79
details : details || [ ] ,
109
80
request : parseRequst ( details [ 2 ] ) ,
110
81
isRunning,
111
82
} ) ;
112
83
84
+ if ( ! wasRunning && isRunning ) {
85
+ // Started
86
+ this . state . start = process . hrtime ( ) ;
87
+ if ( this . options . minimal ) {
88
+ this . stream . write ( `Compiling ${ this . options . name } \n` ) ;
89
+ }
90
+ delete this . state . time ;
91
+ } else if ( wasRunning && ! isRunning ) {
92
+ // Finished
93
+ const time = process . hrtime ( this . state . start ) ;
94
+ if ( this . options . minimal ) {
95
+ this . stream . write (
96
+ `Compiled ${ this . options . name } in ${ prettyTime ( this . state . time ) } \n`
97
+ ) ;
98
+ } else {
99
+ this . logUpdate . clear ( ) ;
100
+ if ( this . options . compiledIn ) {
101
+ process . stdout . write (
102
+ `${ [
103
+ TICK ,
104
+ this . options . name ,
105
+ 'compiled in' ,
106
+ prettyTime ( time , 'ms' ) ,
107
+ ] . join ( ' ' ) } \n`
108
+ ) ;
109
+ }
110
+ }
111
+ delete this . state . start ;
112
+ }
113
+
113
114
if ( this . options . profile ) {
114
- sharedState [ this . options . name ] . profile . onRequest (
115
- sharedState [ this . options . name ] . request
116
- ) ;
115
+ this . state . profile . onRequest ( this . state . request ) ;
117
116
}
118
117
119
- this . _render ( ) ;
118
+ if ( hasRunning ( ) ) {
119
+ this . _render ( ) ;
120
+ } else {
121
+ this . logUpdate . clear ( ) ;
122
+ this . done ( ) ;
123
+ }
120
124
}
121
125
122
126
render ( ) {
123
- const shouldClear = this . options . clear ;
124
- let someRunning = false ;
125
-
126
- const lines = [ ] ;
127
-
128
- _ . sortBy ( Object . keys ( sharedState ) , ( s ) => s . name )
129
- . reverse ( )
130
- . forEach ( ( name ) => {
131
- const state = sharedState [ name ] ;
132
-
133
- if ( state . isRunning ) {
134
- someRunning = true ;
135
- } else if ( shouldClear ) {
136
- // Skip done jobs
137
- return ;
138
- }
139
-
140
- const lColor = colorize ( state . color ) ;
141
- const lIcon = lColor ( BULLET ) ;
142
- const lName = lColor ( _ . startCase ( name ) ) ;
143
- const lBar = renderBar ( state . progress , state . color ) ;
144
- const lMsg = _ . startCase ( state . msg ) ;
145
- const lProgress = `(${ state . progress || 0 } %)` ;
146
- const lDetail1 = chalk . grey ( ( state . details && state . details [ 0 ] ) || '' ) ;
147
- const lDetail2 = chalk . grey ( ( state . details && state . details [ 1 ] ) || '' ) ;
148
- const lRequest = state . request ? formatRequest ( state . request ) : '' ;
149
-
150
- lines . push (
151
- `${ [ lIcon , lName , lBar , lMsg , lProgress , lDetail1 , lDetail2 ] . join (
152
- ' '
153
- ) } \n ${ lRequest } `
154
- ) ;
155
- } ) ;
156
-
157
- if ( shouldClear && ! someRunning ) {
158
- this . logUpdate . clear ( ) ;
127
+ if ( this . options . minimal ) {
159
128
return ;
160
129
}
161
130
162
- const lLines = lines . join ( '\n\n' ) ;
131
+ const stateLines = _ . sortBy ( Object . keys ( sharedState ) , ( n ) => n )
132
+ . filter ( ( s ) => sharedState [ s ] . isRunning || sharedState [ s ] . start )
133
+ . map ( ( name ) => {
134
+ const state = sharedState [ name ] ;
135
+ const color = colorize ( state . color ) ;
163
136
164
- if ( this . options . buildTitle ) {
165
- const title = someRunning
166
- ? ` ${ chalk . bgBlue . black ( ` ${ this . options . buildTitle } ` ) } `
167
- : '' ;
137
+ if ( ! state . isRunning ) {
138
+ return `${ [ chalk . grey ( BULLET ) , name ] . join ( ' ' ) } ` ;
139
+ }
168
140
169
- this . logUpdate ( `\n${ title } \n\n${ lLines } ` ) ;
170
- } else {
171
- this . logUpdate ( `\n${ lLines } ` ) ;
141
+ return `${ [
142
+ color ( BULLET ) ,
143
+ color ( name ) ,
144
+ renderBar ( state . progress , state . color ) ,
145
+ state . msg ,
146
+ `(${ state . progress || 0 } %)` ,
147
+ chalk . grey ( ( state . details && state . details [ 0 ] ) || '' ) ,
148
+ chalk . grey ( ( state . details && state . details [ 1 ] ) || '' ) ,
149
+ ] . join ( ' ' ) } \n ${ state . request ? formatRequest ( state . request ) : '' } \n`;
150
+ } )
151
+ . filter ( Boolean ) ;
152
+
153
+ if ( stateLines . length ) {
154
+ const title = chalk . underline . blue ( 'Compiling' ) ;
155
+ const log = `\n${ title } \n\n${ stateLines . join ( '\n' ) } ` ;
156
+ this . logUpdate ( log ) ;
172
157
}
173
158
}
174
159
}
0 commit comments