1
1
/*
2
- MIT License http://www.opensource.org/licenses/mit-license.php
3
- Author Tobias Koppers @sokra
2
+ MIT License http://www.opensource.org/licenses/mit-license.php
3
+ Author Tobias Koppers @sokra
4
4
*/
5
- "use strict" ;
5
+ /* eslint-disable no-cond-assign, no-plusplus, no-continue, no-param-reassign, no-underscore-dangle, no-loop-func */
6
6
7
7
const SourceMapConsumer = require ( "source-map" ) . SourceMapConsumer ;
8
- const SourceMapSource = require ( "webpack-sources" ) . SourceMapSource ;
9
- const RawSource = require ( "webpack-sources" ) . RawSource ;
10
8
const ConcatSource = require ( "webpack-sources" ) . ConcatSource ;
9
+ const RawSource = require ( "webpack-sources" ) . RawSource ;
10
+ const SourceMapSource = require ( "webpack-sources" ) . SourceMapSource ;
11
11
const RequestShortener = require ( "webpack/lib/RequestShortener" ) ;
12
12
const ModuleFilenameHelpers = require ( "webpack/lib/ModuleFilenameHelpers" ) ;
13
13
const uglify = require ( "uglify-js" ) ;
14
14
15
+ const WARN_PATTERN = / \[ .+ : ( [ 0 - 9 ] + ) , ( [ 0 - 9 ] + ) \] / ;
16
+
17
+ function ensureConditionFunc ( condition , key ) {
18
+ switch ( typeof condition [ key ] ) {
19
+ case "boolean" : {
20
+ const b = condition [ key ] ;
21
+ condition [ key ] = ( ) => b ;
22
+ break ;
23
+ }
24
+ case "function" :
25
+ break ;
26
+ case "string" : {
27
+ if ( condition [ key ] === "all" ) {
28
+ condition [ key ] = ( ) => true ;
29
+ break ;
30
+ }
31
+ const regex = new RegExp ( condition [ key ] ) ;
32
+ condition [ key ] = ( astNode , comment ) => regex . test ( comment . value ) ;
33
+ break ;
34
+ }
35
+ default : {
36
+ const defaultRegex = condition [ key ] ;
37
+ condition [ key ] = ( astNode , comment ) => defaultRegex . test ( comment . value ) ;
38
+ }
39
+ }
40
+ }
41
+
15
42
class UglifyJsPlugin {
16
43
constructor ( options ) {
17
- if ( typeof options !== "object" || Array . isArray ( options ) ) options = { } ;
18
- if ( typeof options . compressor !== "undefined" ) options . compress = options . compressor ;
44
+ if ( typeof options !== "object" || Array . isArray ( options ) ) {
45
+ options = { } ;
46
+ }
47
+ if ( typeof options . compressor !== "undefined" ) {
48
+ options . compress = options . compressor ;
49
+ }
50
+
19
51
this . options = options ;
20
52
}
21
53
@@ -28,27 +60,38 @@ class UglifyJsPlugin {
28
60
compiler . plugin ( "compilation" , ( compilation ) => {
29
61
if ( options . sourceMap ) {
30
62
compilation . plugin ( "build-module" , ( module ) => {
31
- // to get detailed location info about errors
63
+ // to get detailed location info about errors
32
64
module . useSourceMap = true ;
33
65
} ) ;
34
66
}
35
67
compilation . plugin ( "optimize-chunk-assets" , ( chunks , callback ) => {
36
- const files = [ ] ;
37
- chunks . forEach ( ( chunk ) => files . push . apply ( files , chunk . files ) ) ;
38
- files . push . apply ( files , compilation . additionalChunkAssets ) ;
39
- const filteredFiles = files . filter ( ModuleFilenameHelpers . matchObject . bind ( undefined , options ) ) ;
40
- filteredFiles . forEach ( ( file ) => {
41
- const oldWarnFunction = uglify . AST_Node . warn_function ;
42
- const warnings = [ ] ;
43
- let sourceMap ;
68
+ const files = compilation . additionalChunkAssets ;
69
+ let i = chunks . length - 1 ;
70
+ while ( i -- ) {
71
+ // eslint-disable-next-line prefer-spread
72
+ files . push . apply ( files , chunks [ i ] . files ) ;
73
+ }
74
+
75
+ let file ;
76
+ let sourceMap ;
77
+ let input ;
78
+ let inputSourceMap ;
79
+ let map ;
80
+ let oldWarnFunction ;
81
+ const warnings = [ ] ;
82
+ i = files . length ;
83
+
84
+ while ( i -- ) {
85
+ file = files [ i ] ;
86
+ if ( ! ModuleFilenameHelpers . matchObject ( options , file ) ) continue ;
87
+ oldWarnFunction = uglify . AST_Node . warn_function ;
88
+
44
89
try {
45
90
const asset = compilation . assets [ file ] ;
46
91
if ( asset . __UglifyJsPlugin ) {
47
92
compilation . assets [ file ] = asset . __UglifyJsPlugin ;
48
93
return ;
49
94
}
50
- let input ;
51
- let inputSourceMap ;
52
95
if ( options . sourceMap ) {
53
96
if ( asset . sourceAndMap ) {
54
97
const sourceAndMap = asset . sourceAndMap ( ) ;
@@ -60,17 +103,17 @@ class UglifyJsPlugin {
60
103
}
61
104
sourceMap = new SourceMapConsumer ( inputSourceMap ) ;
62
105
uglify . AST_Node . warn_function = ( warning ) => { // eslint-disable-line camelcase
63
- const match = / \[ . + : ( [ 0 - 9 ] + ) , ( [ 0 - 9 ] + ) \] / . exec ( warning ) ;
106
+ const match = WARN_PATTERN . exec ( warning ) ;
64
107
const line = + match [ 1 ] ;
65
108
const column = + match [ 2 ] ;
66
109
const original = sourceMap . originalPositionFor ( {
67
- line : line ,
68
- column : column
110
+ line,
111
+ column,
69
112
} ) ;
70
113
if ( ! original || ! original . source || original . source === file ) return ;
71
114
if ( ! warningsFilter ( original . source ) ) return ;
72
- warnings . push ( warning . replace ( / \[ . + : ( [ 0 - 9 ] + ) , ( [ 0 - 9 ] + ) \] / , "" ) +
73
- "[" + requestShortener . shorten ( original . source ) + ":" + original . line + "," + original . column + "]" ) ;
115
+ warnings . push ( ` ${ warning . replace ( WARN_PATTERN , "" )
116
+ } [ ${ requestShortener . shorten ( original . source ) } : ${ original . line } , ${ original . column } ]` ) ;
74
117
} ;
75
118
} else {
76
119
input = asset . source ( ) ;
@@ -80,12 +123,12 @@ class UglifyJsPlugin {
80
123
}
81
124
uglify . base54 . reset ( ) ;
82
125
let ast = uglify . parse ( input , {
83
- filename : file
126
+ filename : file ,
84
127
} ) ;
85
128
if ( options . compress !== false ) {
86
129
ast . figure_out_scope ( ) ;
87
130
const compress = uglify . Compressor ( options . compress || {
88
- warnings : false
131
+ warnings : false ,
89
132
} ) ; // eslint-disable-line new-cap
90
133
ast = compress . compress ( ast ) ;
91
134
}
@@ -97,136 +140,120 @@ class UglifyJsPlugin {
97
140
uglify . mangle_properties ( ast , options . mangle . props ) ;
98
141
}
99
142
}
100
- const output = { } ;
101
- output . comments = Object . prototype . hasOwnProperty . call ( options , "comments" ) ? options . comments : / ^ \* * ! | @ p r e s e r v e | @ l i c e n s e / ;
143
+ const output = { ... options . output } ;
144
+ output . comments = options . comments || / ^ \* * ! | @ p r e s e r v e | @ l i c e n s e / ;
102
145
output . beautify = options . beautify ;
103
- for ( let k in options . output ) {
104
- output [ k ] = options . output [ k ] ;
105
- }
146
+ // for (const k in options.output) { // eslint-disable-line guard-for-in
147
+ // output[k] = options.output[k];
148
+ // }
106
149
const extractedComments = [ ] ;
107
150
if ( options . extractComments ) {
108
151
const condition = { } ;
109
152
if ( typeof options . extractComments === "string" || options . extractComments instanceof RegExp ) {
110
- // extractComments specifies the extract condition and output.comments specifies the preserve condition
153
+ // extractComments specifies the extract condition and output.comments specifies the preserve condition
111
154
condition . preserve = output . comments ;
112
155
condition . extract = options . extractComments ;
113
156
} else if ( Object . prototype . hasOwnProperty . call ( options . extractComments , "condition" ) ) {
114
- // Extract condition is given in extractComments.condition
157
+ // Extract condition is given in extractComments.condition
115
158
condition . preserve = output . comments ;
116
159
condition . extract = options . extractComments . condition ;
117
160
} else {
118
- // No extract condition is given. Extract comments that match output.comments instead of preserving them
161
+ // No extract condition is given. Extract comments that match output.comments instead of preserving them
119
162
condition . preserve = false ;
120
163
condition . extract = output . comments ;
121
164
}
122
165
123
- // Ensure that both conditions are functions
124
- [ "preserve" , "extract" ] . forEach ( key => {
125
- switch ( typeof condition [ key ] ) {
126
- case "boolean" :
127
- var b = condition [ key ] ;
128
- condition [ key ] = ( ) => b ;
129
- break ;
130
- case "function" :
131
- break ;
132
- case "string" :
133
- if ( condition [ key ] === "all" ) {
134
- condition [ key ] = ( ) => true ;
135
- break ;
136
- }
137
- var regex = new RegExp ( condition [ key ] ) ;
138
- condition [ key ] = ( astNode , comment ) => regex . test ( comment . value ) ;
139
- break ;
140
- default :
141
- regex = condition [ key ] ;
142
- condition [ key ] = ( astNode , comment ) => regex . test ( comment . value ) ;
143
- }
144
- } ) ;
166
+ // Ensure that both conditions are functions
167
+ ensureConditionFunc ( condition , "preserve" ) ;
168
+ ensureConditionFunc ( condition , "extract" ) ;
145
169
146
- // Redefine the comments function to extract and preserve
147
- // comments according to the two conditions
170
+ // Redefine the comments function to extract and preserve
171
+ // comments according to the two conditions
148
172
output . comments = ( astNode , comment ) => {
149
173
if ( condition . extract ( astNode , comment ) ) {
150
174
extractedComments . push (
151
- comment . type === "comment2" ? "/*" + comment . value + "*/" : "//" + comment . value
152
- ) ;
175
+ comment . type === "comment2" ? `/* ${ comment . value } */` : `// ${ comment . value } `
176
+ ) ;
153
177
}
154
178
return condition . preserve ( astNode , comment ) ;
155
179
} ;
156
180
}
157
- let map ;
181
+ map = null ;
158
182
if ( options . sourceMap ) {
159
183
map = uglify . SourceMap ( { // eslint-disable-line new-cap
160
- file : file ,
161
- root : ""
184
+ file,
185
+ root : "" ,
162
186
} ) ;
163
187
output . source_map = map ; // eslint-disable-line camelcase
164
188
}
165
189
const stream = uglify . OutputStream ( output ) ; // eslint-disable-line new-cap
166
190
ast . print ( stream ) ;
167
- if ( map ) map = map + "" ;
168
- const stringifiedStream = stream + "" ;
169
- let outputSource = ( map ?
170
- new SourceMapSource ( stringifiedStream , file , JSON . parse ( map ) , input , inputSourceMap ) :
171
- new RawSource ( stringifiedStream ) ) ;
191
+ if ( map ) map += "" ;
192
+ const stringifiedStream = ` ${ stream } ` ;
193
+ let outputSource = map ? new SourceMapSource (
194
+ stringifiedStream , file , JSON . parse ( map ) , input , inputSourceMap // eslint-disable-line comma-dangle
195
+ ) : new RawSource ( stringifiedStream ) ;
172
196
if ( extractedComments . length > 0 ) {
173
- let commentsFile = options . extractComments . filename || file + " .LICENSE" ;
197
+ let commentsFile = options . extractComments . filename || ` ${ file } .LICENSE` ;
174
198
if ( typeof commentsFile === "function" ) {
175
199
commentsFile = commentsFile ( file ) ;
176
200
}
177
201
178
- // Write extracted comments to commentsFile
179
- const commentsSource = new RawSource ( extractedComments . join ( "\n\n" ) + "\n" ) ;
202
+ // Write extracted comments to commentsFile
203
+ const commentsSource = new RawSource ( ` ${ extractedComments . join ( "\n\n" ) } \n` ) ;
180
204
if ( commentsFile in compilation . assets ) {
181
- // commentsFile already exists, append new comments...
205
+ // commentsFile already exists, append new comments...
182
206
if ( compilation . assets [ commentsFile ] instanceof ConcatSource ) {
183
207
compilation . assets [ commentsFile ] . add ( "\n" ) ;
184
208
compilation . assets [ commentsFile ] . add ( commentsSource ) ;
185
209
} else {
186
210
compilation . assets [ commentsFile ] = new ConcatSource (
187
- compilation . assets [ commentsFile ] , "\n" , commentsSource
188
- ) ;
211
+ compilation . assets [ commentsFile ] , "\n" , commentsSource
212
+ ) ;
189
213
}
190
214
} else {
191
215
compilation . assets [ commentsFile ] = commentsSource ;
192
216
}
193
217
194
- // Add a banner to the original file
218
+ // Add a banner to the original file
195
219
if ( options . extractComments . banner !== false ) {
196
- let banner = options . extractComments . banner || " For license information please see " + commentsFile ;
220
+ let banner = options . extractComments . banner || ` For license information please see ${ commentsFile } ` ;
197
221
if ( typeof banner === "function" ) {
198
222
banner = banner ( commentsFile ) ;
199
223
}
200
224
if ( banner ) {
201
225
outputSource = new ConcatSource (
202
- "/*! " + banner + " * /\n" , outputSource
203
- ) ;
226
+ `/*! ${ banner } * /\n` , outputSource
227
+ ) ;
204
228
}
205
229
}
206
230
}
207
- asset . __UglifyJsPlugin = compilation . assets [ file ] = outputSource ;
208
- if ( warnings . length > 0 ) {
209
- compilation . warnings . push ( new Error ( file + " from UglifyJs\n" + warnings . join ( "\n" ) ) ) ;
231
+ compilation . assets [ file ] = outputSource ;
232
+ asset . __UglifyJsPlugin = outputSource ;
233
+
234
+ if ( warnings . length ) {
235
+ compilation . warnings . push ( new Error ( `${ file } from UglifyJs\n${ warnings . join ( "\n" ) } ` ) ) ;
210
236
}
211
237
} catch ( err ) {
212
238
if ( err . line ) {
213
239
const original = sourceMap && sourceMap . originalPositionFor ( {
214
240
line : err . line ,
215
- column : err . col
241
+ column : err . col ,
216
242
} ) ;
217
243
if ( original && original . source ) {
218
- compilation . errors . push ( new Error ( file + " from UglifyJs\n" + err . message + " [" + requestShortener . shorten ( original . source ) + ":" + original . line + "," + original . column + "][" + file + ":" + err . line + "," + err . col + "]" ) ) ;
244
+ compilation . errors . push ( new Error ( ` ${ file } from UglifyJs\n${ err . message } [ ${ requestShortener . shorten ( original . source ) } : ${ original . line } , ${ original . column } ][ ${ file } : ${ err . line } , ${ err . col } ]` ) ) ;
219
245
} else {
220
- compilation . errors . push ( new Error ( file + " from UglifyJs\n" + err . message + " [" + file + ":" + err . line + "," + err . col + "]" ) ) ;
246
+ compilation . errors . push ( new Error ( ` ${ file } from UglifyJs\n${ err . message } [ ${ file } : ${ err . line } , ${ err . col } ]` ) ) ;
221
247
}
222
248
} else if ( err . msg ) {
223
- compilation . errors . push ( new Error ( file + " from UglifyJs\n" + err . msg ) ) ;
224
- } else
225
- compilation . errors . push ( new Error ( file + " from UglifyJs\n" + err . stack ) ) ;
249
+ compilation . errors . push ( new Error ( `${ file } from UglifyJs\n${ err . msg } ` ) ) ;
250
+ } else {
251
+ compilation . errors . push ( new Error ( `${ file } from UglifyJs\n${ err . stack } ` ) ) ;
252
+ }
226
253
} finally {
227
254
uglify . AST_Node . warn_function = oldWarnFunction ; // eslint-disable-line camelcase
228
255
}
229
- } ) ;
256
+ }
230
257
callback ( ) ;
231
258
} ) ;
232
259
} ) ;
0 commit comments