Permalink
Browse files

Updated grunt wrapper to be able to hook into uglify's new object pro…

…perty name mangling functionality, the ability to pass files containing property and variable name exceptions and the ability to use a cache to coordinate symbol mangling across multiple calls to uglify.

See uglifyjs v2.4.18 https://www.npmjs.com/package/uglify-js for more info.
  • Loading branch information...
1 parent eaa82c5 commit 809fb2e80a2aac13b14e7a1752c78a17563aaca5 @jrhite jrhite committed Mar 24, 2015
View
@@ -1,7 +1,7 @@
root = true
[*]
-indent_style = spaces
+indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
View
@@ -269,14 +269,70 @@ module.exports = function(grunt) {
mangle: false,
compress: false
}
+ },
+ mangleprops: {
+ files: {
+ 'tmp/mangleprops.js': ['test/fixtures/src/mangleprops.js']
+ },
+ options: {
+ mangleProperties: true
+ }
+ },
+ mangleprops_withExcept: {
+ files: {
+ 'tmp/mangleprops_withExcept.js': ['test/fixtures/src/mangleprops.js']
+ },
+ options: {
+ mangle: {
+ except: ['dontMangleMeVariable']
+ },
+ mangleProperties: true
+ }
+ },
+ mangleprops_withExceptionsFiles: {
+ files: {
+ 'tmp/mangleprops_withExceptionsFiles.js': ['test/fixtures/src/mangleprops.js']
+ },
+ options: {
+ mangle: {
+ toplevel: true
+ },
+ mangleProperties: true,
+ exceptionsFiles: ['test/fixtures/src/exceptionsfile1.json', 'test/fixtures/src/exceptionsfile2.json']
+ }
+ },
+ mangleprops_withExceptAndExceptionsFiles: {
+ files: {
+ 'tmp/mangleprops_withExceptAndExceptionsFiles.js': ['test/fixtures/src/mangleprops.js']
+ },
+ options: {
+ mangle: {
+ toplevel: true,
+ except: ['dontMangleMeVariable']
+ },
+ mangleProperties: true,
+ exceptionsFiles: ['test/fixtures/src/exceptionsfile1.json', 'test/fixtures/src/exceptionsfile2.json']
+ }
+ },
+ mangleprops_withNameCacheFile: {
+ files: {
+ 'tmp/mangleprops_withNameCacheFile1.js': ['test/fixtures/src/mangleprops.js'],
+ 'tmp/mangleprops_withNameCacheFile2.js': ['test/fixtures/src/mangleprops_withNameCache.js']
+ },
+ options: {
+ mangle: {
+ toplevel: true
+ },
+ mangleProperties: true,
+ nameCache: 'tmp/uglify_name_cache.json'
+ }
}
},
// Unit tests.
nodeunit: {
tests: ['test/*_test.js']
}
-
});
// task that expects its argument (another task) to fail
@@ -339,6 +395,11 @@ module.exports = function(grunt) {
'uglify:sourcemapin_sources',
'uglify:expression_json',
'uglify:expression_js',
+ 'uglify:mangleprops',
+ 'uglify:mangleprops_withExcept',
+ 'uglify:mangleprops_withExceptionsFiles',
+ 'uglify:mangleprops_withExceptAndExceptionsFiles',
+ 'uglify:mangleprops_withNameCacheFile',
'nodeunit'
]);
@@ -237,3 +237,53 @@ grunt.initConfig({
}
});
```
+
+## Turn on object property name mangling
+
+This configuration will turn on object property name mangling, but not mangle built-in browser object properties.
+Additionally, variables and object properties listed in the `myExceptionsFile.json` will be mangled. For more info,
+on the format of the exception file format please see the [UglifyJS docs](https://www.npmjs.com/package/uglify-js).
+
+```js
+// Project configuration.
+grunt.initConfig({
+ uglify: {
+ options: {
+ mangleProperties: true,
+ reserveDOMCache: true,
+ exceptionsFiles: [ 'myExceptionsFile.json' ]
+ },
+ my_target: {
+ files: {
+ 'dest/output.min.js': ['src/input.js']
+ }
+ }
+ }
+});
+```
+
+## Turn on use of name mangling cache
+
+Turn on use of name mangling cache to coordinate mangled symbols between outputted uglify files. uglify will the
+generate a JSON cache file with the name provided in the options. Note: this generated file uses the same JSON format
+as the `exceptionsFiles` files.
+
+```js
+// Project configuration.
+grunt.initConfig({
+ uglify: {
+ options: {
+ nameCache: '.tmp/grunt-uglify-cache.json',
+ },
+ my_target: {
+ files: {
+ 'dest/output1.min.js': ['src/input1.js'],
+ 'dest/output2.min.js': ['src/input2.js']
+ }
+ }
+ }
+});
+```
+
+
+
@@ -31,7 +31,7 @@ Turns on beautification of the generated source code. An `Object` will be merged
#### expression
-Type: `Boolean`
+Type: `Boolean`
Default: `false`
Parse a single expression, rather than a program (for parsing JSON)
@@ -64,13 +64,13 @@ uglify source is passed as the argument and the return value will be used as the
when there's one source file.
## sourceMapIncludeSources
-Type: `Boolean`
+Type: `Boolean`
Default: `false`
Pass this flag if you want to include the content of source files in the source map as sourcesContent property.
#### sourceMapRoot
-Type: `String`
+Type: `String`
Default: `undefined`
With this option you can customize root URL that browser will use when looking for sources.
@@ -93,13 +93,13 @@ For variables that need to be public `exports` and `global` variables are made a
The value of wrap is the global variable exports will be available as.
## maxLineLen
-Type: `Number`
+Type: `Number`
Default: `32000`
Limit the line length in symbols. Pass maxLineLen = 0 to disable this safety feature.
## ASCIIOnly
-Type: `Boolean`
+Type: `Boolean`
Default: `false`
Enables to encode non-ASCII characters as \uXXXX.
@@ -135,7 +135,35 @@ Default: empty string
This string will be appended to the minified output. Template strings (e.g. `<%= config.value %>` will be expanded automatically.
## screwIE8
-Type: `Boolean`
+Type: `Boolean`
Default: false
Pass this flag if you don't care about full compliance with Internet Explorer 6-8 quirks.
+
+## mangleProperties
+Type: `Boolean`
+Default: false
+
+Use this flag to turn on object property name mangling.
+
+## reserveDOMProperties
+Type: `Boolean`
+Default: false
+
+Use this flag in conjunction with `mangleProperties` to prevent built-in browser object properties from being mangled.
+
+## exceptionsFiles
+Type: `Array`
+Default: []
+
+Use this with `mangleProperties` to pass one or more JSON files containing a list of variables and object properties
+that should not be mangled. See the [UglifyJS docs](https://www.npmjs.com/package/uglify-js) for more info on the file syntax.
+
+## nameCache
+Type: `String`
+Default: empty string
+
+A string that is a path to a JSON cache file that uglify will create and use to coordinate symbol mangling between
+multiple runs of uglify. Note: this generated file uses the same JSON format as the `exceptionsFiles` files.
+
+
View
@@ -23,7 +23,7 @@
"chalk": "^1.0.0",
"lodash": "^3.2.0",
"maxmin": "^1.0.0",
- "uglify-js": "2.4.17",
+ "uglify-js": "^2.4.19",
"uri-path": "0.0.2"
},
"devDependencies": {
View
@@ -70,10 +70,15 @@ exports.init = function(grunt) {
topLevel = topLevel.wrap_enclose(argParamList);
}
+ var topLevelCache = null;
+ if (options.nameCache) {
+ topLevelCache = UglifyJS.readNameCache(options.nameCache, 'vars');
+ }
+
// Need to call this before we mangle or compress,
// and call after any compression or ast altering
if (options.expression === false) {
- topLevel.figure_out_scope({screw_ie8: options.screwIE8});
+ topLevel.figure_out_scope({ screw_ie8: options.screwIE8, cache: topLevelCache });
}
if (options.compress !== false) {
@@ -87,7 +92,45 @@ exports.init = function(grunt) {
topLevel = topLevel.transform(compressor);
// Need to figure out scope again after source being altered
- topLevel.figure_out_scope({screw_ie8: options.screwIE8});
+ if (options.expression === false) {
+ topLevel.figure_out_scope({screw_ie8: options.screwIE8, cache: topLevelCache});
+ }
+ }
+
+ var mangleExclusions = { vars: [], props: [] };
+ if (options.reserveDOMProperties) {
+ mangleExclusions = UglifyJS.readDefaultReservedFile();
+ }
+
+ if (options.exceptionsFiles) {
+ try {
+ options.exceptionsFiles.forEach(function(filename) {
+ mangleExclusions = UglifyJS.readReservedFile(filename, mangleExclusions);
+ });
+ } catch (ex) {
+ grunt.warn(ex);
+ }
+ }
+
+ var cache = null;
+ if (options.nameCache) {
+ cache = UglifyJS.readNameCache(options.nameCache, 'props');
+ }
+
+ if (options.mangleProperties === true) {
+ topLevel = UglifyJS.mangle_properties(topLevel, {
+ reserved: mangleExclusions ? mangleExclusions.props : null,
+ cache: cache
+ });
+
+ if (options.nameCache) {
+ UglifyJS.writeNameCache(options.nameCache, 'props', cache);
+ }
+
+ // Need to figure out scope again since topLevel has been altered
+ if (options.expression === false) {
+ topLevel.figure_out_scope({screw_ie8: options.screwIE8, cache: topLevelCache});
+ }
}
if (options.mangle !== false) {
@@ -97,9 +140,20 @@ exports.init = function(grunt) {
// // compute_char_frequency optimizes names for compression
// topLevel.compute_char_frequency(options.mangle);
+ options.mangle.cache = topLevelCache;
+
+ options.mangle.except = options.mangle.except ? options.mangle.except : [];
+ if (mangleExclusions.vars) {
+ mangleExclusions.vars.forEach(function(name){
+ UglifyJS.push_uniq(options.mangle.except, name);
+ });
+ }
+
// Requires previous call to figure_out_scope
// and should always be called after compressor transform
topLevel.mangle_names(options.mangle);
+
+ UglifyJS.writeNameCache(options.nameCache, 'vars', options.mangle.cache);
}
if (options.sourceMap && options.sourceMapIncludeSources) {
@@ -0,0 +1 @@
+var myObj={a:function(a){a++},b:function(){},c:function(){}},dontMangleMeVariable2=function(){},dontMangleMeVariable3=function(){};
@@ -0,0 +1 @@
+var myObj={a:function(dontMangleMeVariable){dontMangleMeVariable++},b:function(){},c:function(){}},dontMangleMeVariable2=function(){},dontMangleMeVariable3=function(){};
@@ -0,0 +1 @@
+var a={a:function(dontMangleMeVariable){dontMangleMeVariable++},dontMangleMeProperty:function(){},b:function(){}},dontMangleMeVariable2=function(){},dontMangleMeVariable3=function(){};
@@ -0,0 +1 @@
+var a={a:function(a){a++},dontMangleMeProperty:function(){},b:function(){}},dontMangleMeVariable2=function(){},dontMangleMeVariable3=function(){};
@@ -0,0 +1 @@
+var a={a:function(a){a++},b:function(){},c:function(){}},b=function(){},c=function(){};
@@ -0,0 +1 @@
+var d=10;a.a(d);
@@ -0,0 +1,19 @@
+{
+ "props": {
+ "cname": 2,
+ "props": {
+ "$myFunction": "a",
+ "$dontMangleMeProperty": "b",
+ "$dontMangleMeProperty2": "c"
+ }
+ },
+ "vars": {
+ "cname": 3,
+ "props": {
+ "$myObj": "a",
+ "$dontMangleMeVariable2": "b",
+ "$dontMangleMeVariable3": "c",
+ "$myNumber": "d"
+ }
+ }
+}
@@ -0,0 +1,4 @@
+{
+ "vars": ["dontMangleMeVariable2"],
+ "props": ["dontMangleMeProperty"]
+}
@@ -0,0 +1,5 @@
+{
+ "vars": ["dontMangleMeVariable3"],
+ "props": []
+}
+
@@ -0,0 +1,8 @@
+var myObj = {
+ myFunction: function(dontMangleMeVariable) { dontMangleMeVariable++; },
+ dontMangleMeProperty: function() {},
+ dontMangleMeProperty2: function() {}
+};
+
+var dontMangleMeVariable2 = function() {};
+var dontMangleMeVariable3 = function() {};
@@ -0,0 +1,2 @@
+var myNumber = 10;
+myObj.myFunction(myNumber);
View
@@ -49,7 +49,14 @@ exports.contrib_uglify = {
'sourcemaps_multiple2_fnName.js',
'sourcemaps_multiple2_fnName.js.fn.map',
'expression.json',
- 'expression.js'
+ 'expression.js',
+ 'mangleprops.js',
+ 'mangleprops_withExcept.js',
+ 'mangleprops_withExceptionsFiles.js',
+ 'mangleprops_withExceptAndExceptionsFiles.js',
+ 'mangleprops_withNameCacheFile1.js',
+ 'mangleprops_withNameCacheFile2.js',
+ 'uglify_name_cache.json'
];
test.expect(files.length);

0 comments on commit 809fb2e

Please sign in to comment.