2013-01-31 01:49:25 +08:00
/ *
MIT License http : //www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @ sokra
* /
2017-01-04 13:53:37 +08:00
"use strict" ;
2013-01-31 01:49:25 +08:00
2017-01-04 13:53:37 +08:00
const SourceMapConsumer = require ( "source-map" ) . SourceMapConsumer ;
const SourceMapSource = require ( "webpack-sources" ) . SourceMapSource ;
const RawSource = require ( "webpack-sources" ) . RawSource ;
const RequestShortener = require ( "../RequestShortener" ) ;
const ModuleFilenameHelpers = require ( "../ModuleFilenameHelpers" ) ;
const uglify = require ( "uglify-js" ) ;
class UglifyJsPlugin {
constructor ( options ) {
if ( typeof options !== "object" || Array . isArray ( options ) ) options = { } ;
if ( typeof options . compressor !== "undefined" ) options . compress = options . compressor ;
this . options = options ;
2013-01-31 01:49:25 +08:00
}
2014-10-30 18:29:33 +08:00
2017-01-04 13:53:37 +08:00
apply ( compiler ) {
let options = this . options ;
options . test = options . test || /\.js($|\?)/i ;
2014-10-30 18:29:33 +08:00
2017-01-04 13:53:37 +08:00
let requestShortener = new RequestShortener ( compiler . context ) ;
compiler . plugin ( "compilation" , ( compilation ) => {
if ( options . sourceMap ) {
compilation . plugin ( "build-module" , ( module ) => {
// to get detailed location info about errors
module . useSourceMap = true ;
2013-01-31 01:49:25 +08:00
} ) ;
2017-01-04 13:53:37 +08:00
}
compilation . plugin ( "optimize-chunk-assets" , ( chunks , callback ) => {
let files = [ ] ;
chunks . forEach ( ( chunk ) => files . push . apply ( files , chunk . files ) ) ;
files . push . apply ( files , compilation . additionalChunkAssets ) ;
files = files . filter ( ModuleFilenameHelpers . matchObject . bind ( undefined , options ) ) ;
files . forEach ( ( file ) => {
let oldWarnFunction = uglify . AST _Node . warn _function ;
let warnings = [ ] ;
let sourceMap ;
try {
let asset = compilation . assets [ file ] ;
if ( asset . _ _UglifyJsPlugin ) {
compilation . assets [ file ] = asset . _ _UglifyJsPlugin ;
return ;
}
let input ;
let inputSourceMap ;
if ( options . sourceMap ) {
if ( asset . sourceAndMap ) {
let sourceAndMap = asset . sourceAndMap ( ) ;
inputSourceMap = sourceAndMap . map ;
input = sourceAndMap . source ;
} else {
inputSourceMap = asset . map ( ) ;
input = asset . source ( ) ;
}
sourceMap = new SourceMapConsumer ( inputSourceMap ) ;
uglify . AST _Node . warn _function = ( warning ) => { // eslint-disable-line camelcase
let match = /\[.+:([0-9]+),([0-9]+)\]/ . exec ( warning ) ;
let line = + match [ 1 ] ;
let column = + match [ 2 ] ;
let original = sourceMap . originalPositionFor ( {
line : line ,
column : column
} ) ;
if ( ! original || ! original . source || original . source === file ) return ;
warnings . push ( warning . replace ( /\[.+:([0-9]+),([0-9]+)\]/ , "" ) +
"[" + requestShortener . shorten ( original . source ) + ":" + original . line + "," + original . column + "]" ) ;
} ;
2015-04-03 18:38:56 +08:00
} else {
2016-01-19 08:52:28 +08:00
input = asset . source ( ) ;
2017-01-04 13:53:37 +08:00
uglify . AST _Node . warn _function = ( warning ) => { // eslint-disable-line camelcase
warnings . push ( warning ) ;
} ;
}
uglify . base54 . reset ( ) ;
let ast = uglify . parse ( input , {
filename : file
} ) ;
if ( options . compress !== false ) {
ast . figure _out _scope ( ) ;
let compress = uglify . Compressor ( options . compress || {
warnings : false
} ) ; // eslint-disable-line new-cap
ast = ast . transform ( compress ) ;
}
if ( options . mangle !== false ) {
ast . figure _out _scope ( options . mangle || { } ) ;
ast . compute _char _frequency ( options . mangle || { } ) ;
ast . mangle _names ( options . mangle || { } ) ;
if ( options . mangle && options . mangle . props ) {
uglify . mangle _properties ( ast , options . mangle . props ) ;
}
2015-04-03 18:38:56 +08:00
}
2017-01-04 13:53:37 +08:00
let output = { } ;
output . comments = Object . prototype . hasOwnProperty . call ( options , "comments" ) ? options . comments : /^\**!|@preserve|@license/ ;
output . beautify = options . beautify ;
for ( let k in options . output ) {
output [ k ] = options . output [ k ] ;
}
let map ;
if ( options . sourceMap ) {
map = uglify . SourceMap ( { // eslint-disable-line new-cap
file : file ,
root : ""
2014-10-31 19:46:18 +08:00
} ) ;
2017-01-04 13:53:37 +08:00
output . source _map = map ; // eslint-disable-line camelcase
2016-02-06 17:06:48 +08:00
}
2017-01-04 13:53:37 +08:00
let stream = uglify . OutputStream ( output ) ; // eslint-disable-line new-cap
ast . print ( stream ) ;
if ( map ) map = map + "" ;
stream = stream + "" ;
asset . _ _UglifyJsPlugin = compilation . assets [ file ] = ( map ?
new SourceMapSource ( stream , file , JSON . parse ( map ) , input , inputSourceMap ) :
new RawSource ( stream ) ) ;
if ( warnings . length > 0 ) {
compilation . warnings . push ( new Error ( file + " from UglifyJs\n" + warnings . join ( "\n" ) ) ) ;
2013-12-17 07:53:22 +08:00
}
2017-01-04 13:53:37 +08:00
} catch ( err ) {
if ( err . line ) {
let original = sourceMap && sourceMap . originalPositionFor ( {
line : err . line ,
column : err . col
} ) ;
if ( original && original . source ) {
compilation . errors . push ( new Error ( file + " from UglifyJs\n" + err . message + " [" + requestShortener . shorten ( original . source ) + ":" + original . line + "," + original . column + "][" + file + ":" + err . line + "," + err . col + "]" ) ) ;
} else {
compilation . errors . push ( new Error ( file + " from UglifyJs\n" + err . message + " [" + file + ":" + err . line + "," + err . col + "]" ) ) ;
}
} else if ( err . msg ) {
compilation . errors . push ( new Error ( file + " from UglifyJs\n" + err . msg ) ) ;
} else
compilation . errors . push ( new Error ( file + " from UglifyJs\n" + err . stack ) ) ;
} finally {
uglify . AST _Node . warn _function = oldWarnFunction ; // eslint-disable-line camelcase
}
} ) ;
callback ( ) ;
2013-01-31 01:49:25 +08:00
} ) ;
} ) ;
2017-01-04 13:53:37 +08:00
}
}
module . exports = UglifyJsPlugin ;