2017-02-04 22:37:21 +08:00
/* globals describe, it, beforeEach*/
2017-01-29 00:32:56 +08:00
"use strict" ;
2017-02-04 22:37:21 +08:00
require ( "should" ) ;
2017-01-29 00:32:56 +08:00
const sinon = require ( "sinon" ) ;
2017-01-29 00:41:09 +08:00
const UglifyJsPlugin = require ( "../lib/optimize/UglifyJsPlugin" ) ;
2017-01-29 00:32:56 +08:00
const PluginEnvironment = require ( "./helpers/PluginEnvironment" ) ;
const SourceMapSource = require ( "webpack-sources" ) . SourceMapSource ;
const RawSource = require ( "webpack-sources" ) . RawSource ;
2017-01-29 00:41:09 +08:00
describe ( "UglifyJsPlugin" , function ( ) {
2017-01-29 00:32:56 +08:00
it ( "has apply function" , function ( ) {
2017-01-29 00:41:09 +08:00
( new UglifyJsPlugin ( ) ) . apply . should . be . a . Function ( ) ;
2017-01-29 00:32:56 +08:00
} ) ;
describe ( "when applied with no options" , function ( ) {
let eventBindings ;
let eventBinding ;
beforeEach ( function ( ) {
const pluginEnvironment = new PluginEnvironment ( ) ;
const compilerEnv = pluginEnvironment . getEnvironmentStub ( ) ;
compilerEnv . context = "" ;
2017-01-29 00:41:09 +08:00
const plugin = new UglifyJsPlugin ( ) ;
2017-01-29 00:32:56 +08:00
plugin . apply ( compilerEnv ) ;
eventBindings = pluginEnvironment . getEventBindings ( ) ;
} ) ;
it ( "binds one event handler" , function ( ) {
eventBindings . length . should . be . exactly ( 1 ) ;
} ) ;
describe ( "compilation handler" , function ( ) {
beforeEach ( function ( ) {
eventBinding = eventBindings [ 0 ] ;
} ) ;
it ( "binds to compilation event" , function ( ) {
eventBinding . name . should . be . exactly ( "compilation" ) ;
} ) ;
describe ( "when called" , function ( ) {
let chunkPluginEnvironment ;
let compilationEventBindings ;
let compilationEventBinding ;
let compilation ;
let callback ;
beforeEach ( function ( ) {
chunkPluginEnvironment = new PluginEnvironment ( ) ;
compilation = chunkPluginEnvironment . getEnvironmentStub ( ) ;
compilation . assets = {
"test.js" : {
_ _UglifyJsPlugin : { }
} ,
"test1.js" : "" ,
"test2.js" : {
source : function ( ) {
return "invalid javascript" ;
}
} ,
"test3.js" : {
source : function ( ) {
return "/** @preserve Foo Bar */ function foo(longVariableName) { longVariableName = 1; }" ;
}
}
} ;
compilation . errors = [ ] ;
eventBinding . handler ( compilation ) ;
compilationEventBindings = chunkPluginEnvironment . getEventBindings ( ) ;
} ) ;
it ( "binds one event handler" , function ( ) {
compilationEventBindings . length . should . be . exactly ( 1 ) ;
} ) ;
describe ( "optimize-chunk-assets handler" , function ( ) {
beforeEach ( function ( ) {
compilationEventBinding = compilationEventBindings [ 0 ] ;
} ) ;
it ( "binds to optimize-chunk-assets event" , function ( ) {
compilationEventBinding . name . should . be . exactly ( "optimize-chunk-assets" ) ;
} ) ;
it ( "only calls callback once" , function ( ) {
callback = sinon . spy ( ) ;
compilationEventBinding . handler ( [ "" ] , callback ) ;
callback . callCount . should . be . exactly ( 1 ) ;
} ) ;
it ( "default only parses filenames ending with .js" , function ( ) {
compilationEventBinding . handler ( [ {
files : [ "test" , "test.js" ]
} ] , function ( ) {
Object . keys ( compilation . assets ) . length . should . be . exactly ( 4 ) ;
} ) ;
} ) ;
it ( "early returns if private property is already set" , function ( ) {
compilationEventBinding . handler ( [ {
files : [ "test.js" ]
} ] , function ( ) {
compilation . assets [ "test.js" ] . should . deepEqual ( { } ) ;
} ) ;
} ) ;
it ( "outputs stack trace errors for invalid asset" , function ( ) {
compilationEventBinding . handler ( [ {
files : [ "test1.js" ]
} ] , function ( ) {
compilation . errors . length . should . be . exactly ( 1 ) ;
compilation . errors [ 0 ] . should . be . an . Error ;
compilation . errors [ 0 ] . message . should . have . containEql ( "TypeError" ) ;
} ) ;
} ) ;
it ( "outputs parsing errors for invalid javascript" , function ( ) {
compilationEventBinding . handler ( [ {
files : [ "test2.js" ]
} ] , function ( ) {
compilation . errors . length . should . be . exactly ( 1 ) ;
compilation . errors [ 0 ] . should . be . an . Error ;
2017-03-05 10:31:39 +08:00
compilation . errors [ 0 ] . message . should . have . containEql ( "Unexpected token" ) ;
2017-01-29 00:32:56 +08:00
compilation . errors [ 0 ] . message . should . have . containEql ( "[test2.js:1,8]" ) ;
} ) ;
} ) ;
it ( "outputs no errors for valid javascript" , function ( ) {
compilationEventBinding . handler ( [ {
files : [ "test3.js" ]
} ] , function ( ) {
compilation . errors . length . should . be . exactly ( 0 ) ;
} ) ;
} ) ;
it ( "outputs RawSource for valid javascript" , function ( ) {
compilationEventBinding . handler ( [ {
files : [ "test3.js" ]
} ] , function ( ) {
compilation . assets [ "test3.js" ] . should . be . instanceof ( RawSource ) ;
} ) ;
} ) ;
it ( "outputs mangled javascript" , function ( ) {
compilationEventBinding . handler ( [ {
files : [ "test3.js" ]
} ] , function ( ) {
compilation . assets [ "test3.js" ] . _value . should . not . containEql ( "longVariableName" ) ;
} ) ;
} ) ;
it ( "compresses and does not output beautified javascript" , function ( ) {
compilationEventBinding . handler ( [ {
files : [ "test3.js" ]
} ] , function ( ) {
compilation . assets [ "test3.js" ] . _value . should . not . containEql ( "\n" ) ;
} ) ;
} ) ;
it ( "preserves comments" , function ( ) {
compilationEventBinding . handler ( [ {
files : [ "test3.js" ]
} ] , function ( ) {
compilation . assets [ "test3.js" ] . _value . should . containEql ( "/**" ) ;
} ) ;
} ) ;
} ) ;
} ) ;
} ) ;
} ) ;
describe ( "when applied with invalid options" , function ( ) {
it ( "outputs uglify errors" , function ( ) {
const pluginEnvironment = new PluginEnvironment ( ) ;
const compilerEnv = pluginEnvironment . getEnvironmentStub ( ) ;
compilerEnv . context = "" ;
2017-01-29 00:41:09 +08:00
const plugin = new UglifyJsPlugin ( {
2017-01-29 00:32:56 +08:00
output : {
"invalid-option" : true
}
} ) ;
plugin . apply ( compilerEnv ) ;
const eventBinding = pluginEnvironment . getEventBindings ( ) [ 0 ] ;
const chunkPluginEnvironment = new PluginEnvironment ( ) ;
const compilation = chunkPluginEnvironment . getEnvironmentStub ( ) ;
compilation . assets = {
"test.js" : {
source : function ( ) {
return "var foo = 1;" ;
}
}
} ;
compilation . errors = [ ] ;
eventBinding . handler ( compilation ) ;
const compilationEventBinding = chunkPluginEnvironment . getEventBindings ( ) [ 0 ] ;
compilationEventBinding . handler ( [ {
files : [ "test.js" ]
} ] , function ( ) {
compilation . errors . length . should . be . exactly ( 1 ) ;
compilation . errors [ 0 ] . message . should . have . containEql ( "supported option" ) ;
} ) ;
} ) ;
} ) ;
describe ( "when applied with all options" , function ( ) {
let eventBindings ;
let eventBinding ;
beforeEach ( function ( ) {
const pluginEnvironment = new PluginEnvironment ( ) ;
const compilerEnv = pluginEnvironment . getEnvironmentStub ( ) ;
compilerEnv . context = "" ;
2017-01-29 00:41:09 +08:00
const plugin = new UglifyJsPlugin ( {
2017-01-29 00:32:56 +08:00
sourceMap : true ,
compress : {
warnings : true ,
} ,
mangle : false ,
beautify : true ,
UglifyJsPlugin: extract comments to separate file
License comments use up a lot of space, especially when using many small
libraries with large license blocks. With this addition, you can extract
all license comments to a separate file and remove them from the bundle
files. A small banner points to the file containing all license
information such that the user can find it if needed.
We add a new option extractComments to the UglifyJsPlugin.
It can be omitted, then the behavior does not change, or it can be:
- true: All comments that normally would be preserved by the comments
option will be moved to a separate file. If the original file is
named foo.js, then the comments will be stored to foo.js.LICENSE
- regular expression (given as RegExp or string) or a function
(astNode, comment) -> boolean: All comments that match the given
expression (resp. are evaluated to true by the function) will be
extracted to the separate file. The comments option specifies
whether the comment will be preserved, i.e. it is possible to
preserve some comments (e.g. annotations) while extracting others or
even preserving comments that have been extracted.
- an object consisting of the following keys, all optional:
- condition: regular expression or function (see previous point)
- file: The file where the extracted comments will be stored. Can be
either a string (filename) or function (string) -> string which
will be given the original filename. Default is to append the
suffix .LICENSE to the original filename.
- banner: The banner text that points to the extracted file and will
be added on top of the original file. will be added to the
original file. Can be false (no banner), a string, or a function
(string) -> string that will be called with the filename where
extracted comments have been stored. Will be wrapped into comment.
Default: /*! For license information please see foo.js.LICENSE */
2017-01-30 07:43:09 +08:00
comments : false ,
extractComments : {
condition : 'should be extracted' ,
2017-02-11 06:16:20 +08:00
filename : function ( file ) {
UglifyJsPlugin: extract comments to separate file
License comments use up a lot of space, especially when using many small
libraries with large license blocks. With this addition, you can extract
all license comments to a separate file and remove them from the bundle
files. A small banner points to the file containing all license
information such that the user can find it if needed.
We add a new option extractComments to the UglifyJsPlugin.
It can be omitted, then the behavior does not change, or it can be:
- true: All comments that normally would be preserved by the comments
option will be moved to a separate file. If the original file is
named foo.js, then the comments will be stored to foo.js.LICENSE
- regular expression (given as RegExp or string) or a function
(astNode, comment) -> boolean: All comments that match the given
expression (resp. are evaluated to true by the function) will be
extracted to the separate file. The comments option specifies
whether the comment will be preserved, i.e. it is possible to
preserve some comments (e.g. annotations) while extracting others or
even preserving comments that have been extracted.
- an object consisting of the following keys, all optional:
- condition: regular expression or function (see previous point)
- file: The file where the extracted comments will be stored. Can be
either a string (filename) or function (string) -> string which
will be given the original filename. Default is to append the
suffix .LICENSE to the original filename.
- banner: The banner text that points to the extracted file and will
be added on top of the original file. will be added to the
original file. Can be false (no banner), a string, or a function
(string) -> string that will be called with the filename where
extracted comments have been stored. Will be wrapped into comment.
Default: /*! For license information please see foo.js.LICENSE */
2017-01-30 07:43:09 +08:00
return file . replace ( /(\.\w+)$/ , '.license$1' ) ;
} ,
banner : function ( licenseFile ) {
return 'License information can be found in ' + licenseFile ;
}
}
2017-01-29 00:32:56 +08:00
} ) ;
plugin . apply ( compilerEnv ) ;
eventBindings = pluginEnvironment . getEventBindings ( ) ;
} ) ;
it ( "binds one event handler" , function ( ) {
eventBindings . length . should . be . exactly ( 1 ) ;
} ) ;
describe ( "compilation handler" , function ( ) {
beforeEach ( function ( ) {
eventBinding = eventBindings [ 0 ] ;
} ) ;
it ( "binds to compilation event" , function ( ) {
eventBinding . name . should . be . exactly ( "compilation" ) ;
} ) ;
describe ( "when called" , function ( ) {
let chunkPluginEnvironment ;
let compilationEventBindings ;
let compilationEventBinding ;
let compilation ;
beforeEach ( function ( ) {
chunkPluginEnvironment = new PluginEnvironment ( ) ;
compilation = chunkPluginEnvironment . getEnvironmentStub ( ) ;
compilation . assets = {
"test.js" : {
source : function ( ) {
return "/** @preserve Foo Bar */ function foo(longVariableName) { longVariableName = 1; }" ;
} ,
map : function ( ) {
return {
version : 3 ,
sources : [ "test.js" ] ,
names : [ "foo" , "longVariableName" ] ,
mappings : "AAAA,QAASA,KAAIC,kBACTA,iBAAmB"
} ;
}
} ,
"test1.js" : {
source : function ( ) {
return "invalid javascript" ;
} ,
map : function ( ) {
return {
version : 3 ,
sources : [ "test1.js" ] ,
names : [ "" ] ,
mappings : "AAAA"
} ;
}
} ,
"test2.js" : {
source : function ( ) {
return "function foo(x) { if (x) { return bar(); not_called1(); } }" ;
} ,
map : function ( ) {
return {
version : 3 ,
sources : [ "test1.js" ] ,
names : [ "foo" , "x" , "bar" , "not_called1" ] ,
mappings : "AAAA,QAASA,KAAIC,GACT,GAAIA,EAAG,CACH,MAAOC,MACPC"
} ;
}
} ,
"test3.js" : {
sourceAndMap : function ( ) {
return {
source : "/** @preserve Foo Bar */ function foo(longVariableName) { longVariableName = 1; }" ,
map : {
version : 3 ,
sources : [ "test.js" ] ,
names : [ "foo" , "longVariableName" ] ,
mappings : "AAAA,QAASA,KAAIC,kBACTA,iBAAmB"
}
} ;
} ,
} ,
UglifyJsPlugin: extract comments to separate file
License comments use up a lot of space, especially when using many small
libraries with large license blocks. With this addition, you can extract
all license comments to a separate file and remove them from the bundle
files. A small banner points to the file containing all license
information such that the user can find it if needed.
We add a new option extractComments to the UglifyJsPlugin.
It can be omitted, then the behavior does not change, or it can be:
- true: All comments that normally would be preserved by the comments
option will be moved to a separate file. If the original file is
named foo.js, then the comments will be stored to foo.js.LICENSE
- regular expression (given as RegExp or string) or a function
(astNode, comment) -> boolean: All comments that match the given
expression (resp. are evaluated to true by the function) will be
extracted to the separate file. The comments option specifies
whether the comment will be preserved, i.e. it is possible to
preserve some comments (e.g. annotations) while extracting others or
even preserving comments that have been extracted.
- an object consisting of the following keys, all optional:
- condition: regular expression or function (see previous point)
- file: The file where the extracted comments will be stored. Can be
either a string (filename) or function (string) -> string which
will be given the original filename. Default is to append the
suffix .LICENSE to the original filename.
- banner: The banner text that points to the extracted file and will
be added on top of the original file. will be added to the
original file. Can be false (no banner), a string, or a function
(string) -> string that will be called with the filename where
extracted comments have been stored. Will be wrapped into comment.
Default: /*! For license information please see foo.js.LICENSE */
2017-01-30 07:43:09 +08:00
"test4.js" : {
source : function ( ) {
return "/*! this comment should be extracted */ function foo(longVariableName) { /* this will not be extracted */ longVariableName = 1; } // another comment that should be extracted to a separate file\n function foo2(bar) { return bar; }" ;
} ,
map : function ( ) {
return {
version : 3 ,
sources : [ "test.js" ] ,
names : [ "foo" , "longVariableName" ] ,
mappings : "AAAA,QAASA,KAAIC,kBACTA,iBAAmB"
} ;
}
} ,
2017-01-29 00:32:56 +08:00
} ;
compilation . errors = [ ] ;
compilation . warnings = [ ] ;
eventBinding . handler ( compilation ) ;
compilationEventBindings = chunkPluginEnvironment . getEventBindings ( ) ;
} ) ;
it ( "binds two event handler" , function ( ) {
compilationEventBindings . length . should . be . exactly ( 2 ) ;
} ) ;
describe ( "build-module handler" , function ( ) {
beforeEach ( function ( ) {
compilationEventBinding = compilationEventBindings [ 0 ] ;
} ) ;
it ( "binds to build-module event" , function ( ) {
compilationEventBinding . name . should . be . exactly ( "build-module" ) ;
} ) ;
it ( "sets the useSourceMap flag" , function ( ) {
const obj = { } ;
compilationEventBinding . handler ( obj ) ;
obj . useSourceMap . should . be . equal ( true ) ;
} ) ;
} ) ;
describe ( "optimize-chunk-assets handler" , function ( ) {
beforeEach ( function ( ) {
compilationEventBinding = compilationEventBindings [ 1 ] ;
} ) ;
it ( "binds to optimize-chunk-assets event" , function ( ) {
compilationEventBinding . name . should . be . exactly ( "optimize-chunk-assets" ) ;
} ) ;
it ( "outputs no errors for valid javascript" , function ( ) {
compilationEventBinding . handler ( [ {
files : [ "test.js" ]
} ] , function ( ) {
compilation . errors . length . should . be . exactly ( 0 ) ;
} ) ;
} ) ;
it ( "outputs SourceMapSource for valid javascript" , function ( ) {
compilationEventBinding . handler ( [ {
files : [ "test.js" ]
} ] , function ( ) {
compilation . assets [ "test.js" ] . should . be . instanceof ( SourceMapSource ) ;
} ) ;
} ) ;
it ( "does not output mangled javascript" , function ( ) {
compilationEventBinding . handler ( [ {
files : [ "test.js" ]
} ] , function ( ) {
compilation . assets [ "test.js" ] . _value . should . containEql ( "longVariableName" ) ;
} ) ;
} ) ;
it ( "outputs beautified javascript" , function ( ) {
compilationEventBinding . handler ( [ {
files : [ "test.js" ]
} ] , function ( ) {
compilation . assets [ "test.js" ] . _value . should . containEql ( "\n" ) ;
} ) ;
} ) ;
it ( "does not preserve comments" , function ( ) {
compilationEventBinding . handler ( [ {
files : [ "test.js" ]
} ] , function ( ) {
compilation . assets [ "test.js" ] . _value . should . not . containEql ( "/**" ) ;
} ) ;
} ) ;
it ( "outputs parsing errors" , function ( ) {
compilationEventBinding . handler ( [ {
files : [ "test1.js" ]
} ] , function ( ) {
compilation . errors . length . should . be . exactly ( 1 ) ;
compilation . errors [ 0 ] . should . be . an . Error ;
compilation . errors [ 0 ] . message . should . containEql ( "[test1.js:1,0][test1.js:1,8]" ) ;
} ) ;
} ) ;
it ( "outputs warnings for unreachable code" , function ( ) {
compilationEventBinding . handler ( [ {
files : [ "test2.js" ]
} ] , function ( ) {
compilation . warnings . length . should . be . exactly ( 1 ) ;
compilation . warnings [ 0 ] . should . be . an . Error ;
compilation . warnings [ 0 ] . message . should . containEql ( "Dropping unreachable code" ) ;
} ) ;
} ) ;
it ( "works with sourceAndMap assets as well" , function ( ) {
compilationEventBinding . handler ( [ {
files : [ "test3.js" ]
} ] , function ( ) {
compilation . errors . length . should . be . exactly ( 0 ) ;
compilation . assets [ "test3.js" ] . should . be . instanceof ( SourceMapSource ) ;
} ) ;
} ) ;
2017-02-04 22:37:21 +08:00
describe ( "with warningsFilter set" , function ( ) {
let compilationEventBindings , compilation ;
describe ( "and the filter returns true" , function ( ) {
beforeEach ( function ( ) {
const pluginEnvironment = new PluginEnvironment ( ) ;
const compilerEnv = pluginEnvironment . getEnvironmentStub ( ) ;
compilerEnv . context = "" ;
const plugin = new UglifyJsPlugin ( {
warningsFilter : function ( ) {
return true ;
} ,
sourceMap : true ,
compress : {
warnings : true ,
} ,
mangle : false ,
beautify : true ,
comments : false
} ) ;
plugin . apply ( compilerEnv ) ;
const eventBindings = pluginEnvironment . getEventBindings ( ) ;
const chunkPluginEnvironment = new PluginEnvironment ( ) ;
compilation = chunkPluginEnvironment . getEnvironmentStub ( ) ;
compilation . assets = {
"test2.js" : {
source : function ( ) {
return "function foo(x) { if (x) { return bar(); not_called1(); } }" ;
} ,
map : function ( ) {
return {
version : 3 ,
sources : [ "test1.js" ] ,
names : [ "foo" , "x" , "bar" , "not_called1" ] ,
mappings : "AAAA,QAASA,KAAIC,GACT,GAAIA,EAAG,CACH,MAAOC,MACPC"
} ;
}
} ,
} ;
compilation . errors = [ ] ;
compilation . warnings = [ ] ;
eventBindings [ 0 ] . handler ( compilation ) ;
compilationEventBindings = chunkPluginEnvironment . getEventBindings ( ) ;
} ) ;
it ( "should get all warnings" , function ( ) {
compilationEventBindings [ 1 ] . handler ( [ {
files : [ "test2.js" ]
} ] , function ( ) {
compilation . warnings . length . should . be . exactly ( 1 ) ;
compilation . warnings [ 0 ] . should . be . an . Error ;
compilation . warnings [ 0 ] . message . should . containEql ( "Dropping unreachable code" ) ;
} ) ;
} ) ;
} ) ;
describe ( "and the filter returns false" , function ( ) {
beforeEach ( function ( ) {
const pluginEnvironment = new PluginEnvironment ( ) ;
const compilerEnv = pluginEnvironment . getEnvironmentStub ( ) ;
compilerEnv . context = "" ;
const plugin = new UglifyJsPlugin ( {
warningsFilter : function ( ) {
return false ;
} ,
sourceMap : true ,
compress : {
warnings : true ,
} ,
mangle : false ,
beautify : true ,
comments : false
} ) ;
plugin . apply ( compilerEnv ) ;
const eventBindings = pluginEnvironment . getEventBindings ( ) ;
const chunkPluginEnvironment = new PluginEnvironment ( ) ;
compilation = chunkPluginEnvironment . getEnvironmentStub ( ) ;
compilation . assets = {
"test2.js" : {
source : function ( ) {
return "function foo(x) { if (x) { return bar(); not_called1(); } }" ;
} ,
map : function ( ) {
return {
version : 3 ,
sources : [ "test1.js" ] ,
names : [ "foo" , "x" , "bar" , "not_called1" ] ,
mappings : "AAAA,QAASA,KAAIC,GACT,GAAIA,EAAG,CACH,MAAOC,MACPC"
} ;
}
} ,
} ;
compilation . errors = [ ] ;
compilation . warnings = [ ] ;
eventBindings [ 0 ] . handler ( compilation ) ;
compilationEventBindings = chunkPluginEnvironment . getEventBindings ( ) ;
} ) ;
it ( "should get no warnings" , function ( ) {
compilationEventBindings [ 1 ] . handler ( [ {
files : [ "test2.js" ]
} ] , function ( ) {
compilation . warnings . length . should . be . exactly ( 0 ) ;
} ) ;
} ) ;
} ) ;
} ) ;
UglifyJsPlugin: extract comments to separate file
License comments use up a lot of space, especially when using many small
libraries with large license blocks. With this addition, you can extract
all license comments to a separate file and remove them from the bundle
files. A small banner points to the file containing all license
information such that the user can find it if needed.
We add a new option extractComments to the UglifyJsPlugin.
It can be omitted, then the behavior does not change, or it can be:
- true: All comments that normally would be preserved by the comments
option will be moved to a separate file. If the original file is
named foo.js, then the comments will be stored to foo.js.LICENSE
- regular expression (given as RegExp or string) or a function
(astNode, comment) -> boolean: All comments that match the given
expression (resp. are evaluated to true by the function) will be
extracted to the separate file. The comments option specifies
whether the comment will be preserved, i.e. it is possible to
preserve some comments (e.g. annotations) while extracting others or
even preserving comments that have been extracted.
- an object consisting of the following keys, all optional:
- condition: regular expression or function (see previous point)
- file: The file where the extracted comments will be stored. Can be
either a string (filename) or function (string) -> string which
will be given the original filename. Default is to append the
suffix .LICENSE to the original filename.
- banner: The banner text that points to the extracted file and will
be added on top of the original file. will be added to the
original file. Can be false (no banner), a string, or a function
(string) -> string that will be called with the filename where
extracted comments have been stored. Will be wrapped into comment.
Default: /*! For license information please see foo.js.LICENSE */
2017-01-30 07:43:09 +08:00
it ( "extracts license information to separate file" , function ( ) {
compilationEventBinding . handler ( [ {
files : [ "test4.js" ]
} ] , function ( ) {
compilation . errors . length . should . be . exactly ( 0 ) ;
compilation . assets [ "test4.license.js" ] . _value . should . containEql ( "/*! this comment should be extracted */" ) ;
compilation . assets [ "test4.license.js" ] . _value . should . containEql ( "// another comment that should be extracted to a separate file" ) ;
compilation . assets [ "test4.license.js" ] . _value . should . not . containEql ( "/* this will not be extracted */" ) ;
} ) ;
} ) ;
} ) ;
} ) ;
} ) ;
} ) ;
describe ( "when applied with extract option set to a single file" , function ( ) {
let eventBindings ;
let eventBinding ;
beforeEach ( function ( ) {
const pluginEnvironment = new PluginEnvironment ( ) ;
const compilerEnv = pluginEnvironment . getEnvironmentStub ( ) ;
compilerEnv . context = "" ;
const plugin = new UglifyJsPlugin ( {
comments : "all" ,
extractComments : {
condition : /.*/ ,
2017-02-11 06:16:20 +08:00
filename : "extracted-comments.js"
UglifyJsPlugin: extract comments to separate file
License comments use up a lot of space, especially when using many small
libraries with large license blocks. With this addition, you can extract
all license comments to a separate file and remove them from the bundle
files. A small banner points to the file containing all license
information such that the user can find it if needed.
We add a new option extractComments to the UglifyJsPlugin.
It can be omitted, then the behavior does not change, or it can be:
- true: All comments that normally would be preserved by the comments
option will be moved to a separate file. If the original file is
named foo.js, then the comments will be stored to foo.js.LICENSE
- regular expression (given as RegExp or string) or a function
(astNode, comment) -> boolean: All comments that match the given
expression (resp. are evaluated to true by the function) will be
extracted to the separate file. The comments option specifies
whether the comment will be preserved, i.e. it is possible to
preserve some comments (e.g. annotations) while extracting others or
even preserving comments that have been extracted.
- an object consisting of the following keys, all optional:
- condition: regular expression or function (see previous point)
- file: The file where the extracted comments will be stored. Can be
either a string (filename) or function (string) -> string which
will be given the original filename. Default is to append the
suffix .LICENSE to the original filename.
- banner: The banner text that points to the extracted file and will
be added on top of the original file. will be added to the
original file. Can be false (no banner), a string, or a function
(string) -> string that will be called with the filename where
extracted comments have been stored. Will be wrapped into comment.
Default: /*! For license information please see foo.js.LICENSE */
2017-01-30 07:43:09 +08:00
}
} ) ;
plugin . apply ( compilerEnv ) ;
eventBindings = pluginEnvironment . getEventBindings ( ) ;
} ) ;
it ( "binds one event handler" , function ( ) {
eventBindings . length . should . be . exactly ( 1 ) ;
} ) ;
describe ( "compilation handler" , function ( ) {
beforeEach ( function ( ) {
eventBinding = eventBindings [ 0 ] ;
} ) ;
it ( "binds to compilation event" , function ( ) {
eventBinding . name . should . be . exactly ( "compilation" ) ;
} ) ;
describe ( "when called" , function ( ) {
let chunkPluginEnvironment ;
let compilationEventBindings ;
let compilationEventBinding ;
let compilation ;
beforeEach ( function ( ) {
chunkPluginEnvironment = new PluginEnvironment ( ) ;
compilation = chunkPluginEnvironment . getEnvironmentStub ( ) ;
compilation . assets = {
"test.js" : {
source : function ( ) {
return "/* This is a comment from test.js */ function foo(bar) { return bar; }" ;
}
} ,
"test2.js" : {
source : function ( ) {
return "// This is a comment from test2.js\nfunction foo2(bar) { return bar; }" ;
}
} ,
"test3.js" : {
source : function ( ) {
return "/* This is a comment from test3.js */ function foo3(bar) { return bar; }\n// This is another comment from test3.js\nfunction foobar3(baz) { return baz; }" ;
}
} ,
} ;
compilation . errors = [ ] ;
compilation . warnings = [ ] ;
eventBinding . handler ( compilation ) ;
compilationEventBindings = chunkPluginEnvironment . getEventBindings ( ) ;
} ) ;
it ( "binds one event handler" , function ( ) {
compilationEventBindings . length . should . be . exactly ( 1 ) ;
} ) ;
describe ( "optimize-chunk-assets handler" , function ( ) {
beforeEach ( function ( ) {
compilationEventBinding = compilationEventBindings [ 0 ] ;
} ) ;
it ( "preserves comments" , function ( ) {
compilationEventBinding . handler ( [ {
files : [ "test.js" , "test2.js" , "test3.js" ]
} ] , function ( ) {
compilation . assets [ "test.js" ] . source ( ) . should . containEql ( "/*" ) ;
compilation . assets [ "test2.js" ] . source ( ) . should . containEql ( "//" ) ;
compilation . assets [ "test3.js" ] . source ( ) . should . containEql ( "/*" ) ;
compilation . assets [ "test3.js" ] . source ( ) . should . containEql ( "//" ) ;
} ) ;
} ) ;
it ( "extracts comments to specified file" , function ( ) {
compilationEventBinding . handler ( [ {
files : [ "test.js" , "test2.js" , "test3.js" ]
} ] , function ( ) {
compilation . errors . length . should . be . exactly ( 0 ) ;
compilation . assets [ "extracted-comments.js" ] . source ( ) . should . containEql ( "/* This is a comment from test.js */" ) ;
compilation . assets [ "extracted-comments.js" ] . source ( ) . should . containEql ( "// This is a comment from test2.js" ) ;
compilation . assets [ "extracted-comments.js" ] . source ( ) . should . containEql ( "/* This is a comment from test3.js */" ) ;
compilation . assets [ "extracted-comments.js" ] . source ( ) . should . containEql ( "// This is another comment from test3.js" ) ;
compilation . assets [ "extracted-comments.js" ] . source ( ) . should . not . containEql ( "function" ) ;
} ) ;
} ) ;
2017-01-29 00:32:56 +08:00
} ) ;
} ) ;
} ) ;
} ) ;
} ) ;