Skip to content

Commit 809fb2e

Browse files
committedApr 2, 2015
Updated grunt wrapper to be able to hook into uglify's new object property 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.
1 parent eaa82c5 commit 809fb2e

18 files changed

+256
-12
lines changed
 

‎.editorconfig

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
root = true
22

33
[*]
4-
indent_style = spaces
4+
indent_style = space
55
indent_size = 2
66
end_of_line = lf
77
insert_final_newline = true

‎Gruntfile.js

+62-1
Original file line numberDiff line numberDiff line change
@@ -269,14 +269,70 @@ module.exports = function(grunt) {
269269
mangle: false,
270270
compress: false
271271
}
272+
},
273+
mangleprops: {
274+
files: {
275+
'tmp/mangleprops.js': ['test/fixtures/src/mangleprops.js']
276+
},
277+
options: {
278+
mangleProperties: true
279+
}
280+
},
281+
mangleprops_withExcept: {
282+
files: {
283+
'tmp/mangleprops_withExcept.js': ['test/fixtures/src/mangleprops.js']
284+
},
285+
options: {
286+
mangle: {
287+
except: ['dontMangleMeVariable']
288+
},
289+
mangleProperties: true
290+
}
291+
},
292+
mangleprops_withExceptionsFiles: {
293+
files: {
294+
'tmp/mangleprops_withExceptionsFiles.js': ['test/fixtures/src/mangleprops.js']
295+
},
296+
options: {
297+
mangle: {
298+
toplevel: true
299+
},
300+
mangleProperties: true,
301+
exceptionsFiles: ['test/fixtures/src/exceptionsfile1.json', 'test/fixtures/src/exceptionsfile2.json']
302+
}
303+
},
304+
mangleprops_withExceptAndExceptionsFiles: {
305+
files: {
306+
'tmp/mangleprops_withExceptAndExceptionsFiles.js': ['test/fixtures/src/mangleprops.js']
307+
},
308+
options: {
309+
mangle: {
310+
toplevel: true,
311+
except: ['dontMangleMeVariable']
312+
},
313+
mangleProperties: true,
314+
exceptionsFiles: ['test/fixtures/src/exceptionsfile1.json', 'test/fixtures/src/exceptionsfile2.json']
315+
}
316+
},
317+
mangleprops_withNameCacheFile: {
318+
files: {
319+
'tmp/mangleprops_withNameCacheFile1.js': ['test/fixtures/src/mangleprops.js'],
320+
'tmp/mangleprops_withNameCacheFile2.js': ['test/fixtures/src/mangleprops_withNameCache.js']
321+
},
322+
options: {
323+
mangle: {
324+
toplevel: true
325+
},
326+
mangleProperties: true,
327+
nameCache: 'tmp/uglify_name_cache.json'
328+
}
272329
}
273330
},
274331

275332
// Unit tests.
276333
nodeunit: {
277334
tests: ['test/*_test.js']
278335
}
279-
280336
});
281337

282338
// task that expects its argument (another task) to fail
@@ -339,6 +395,11 @@ module.exports = function(grunt) {
339395
'uglify:sourcemapin_sources',
340396
'uglify:expression_json',
341397
'uglify:expression_js',
398+
'uglify:mangleprops',
399+
'uglify:mangleprops_withExcept',
400+
'uglify:mangleprops_withExceptionsFiles',
401+
'uglify:mangleprops_withExceptAndExceptionsFiles',
402+
'uglify:mangleprops_withNameCacheFile',
342403
'nodeunit'
343404
]);
344405

‎docs/uglify-examples.md

+50
Original file line numberDiff line numberDiff line change
@@ -237,3 +237,53 @@ grunt.initConfig({
237237
}
238238
});
239239
```
240+
241+
## Turn on object property name mangling
242+
243+
This configuration will turn on object property name mangling, but not mangle built-in browser object properties.
244+
Additionally, variables and object properties listed in the `myExceptionsFile.json` will be mangled. For more info,
245+
on the format of the exception file format please see the [UglifyJS docs](https://www.npmjs.com/package/uglify-js).
246+
247+
```js
248+
// Project configuration.
249+
grunt.initConfig({
250+
uglify: {
251+
options: {
252+
mangleProperties: true,
253+
reserveDOMCache: true,
254+
exceptionsFiles: [ 'myExceptionsFile.json' ]
255+
},
256+
my_target: {
257+
files: {
258+
'dest/output.min.js': ['src/input.js']
259+
}
260+
}
261+
}
262+
});
263+
```
264+
265+
## Turn on use of name mangling cache
266+
267+
Turn on use of name mangling cache to coordinate mangled symbols between outputted uglify files. uglify will the
268+
generate a JSON cache file with the name provided in the options. Note: this generated file uses the same JSON format
269+
as the `exceptionsFiles` files.
270+
271+
```js
272+
// Project configuration.
273+
grunt.initConfig({
274+
uglify: {
275+
options: {
276+
nameCache: '.tmp/grunt-uglify-cache.json',
277+
},
278+
my_target: {
279+
files: {
280+
'dest/output1.min.js': ['src/input1.js'],
281+
'dest/output2.min.js': ['src/input2.js']
282+
}
283+
}
284+
}
285+
});
286+
```
287+
288+
289+

‎docs/uglify-options.md

+34-6
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ Turns on beautification of the generated source code. An `Object` will be merged
3131

3232

3333
#### expression
34-
Type: `Boolean`
34+
Type: `Boolean`
3535
Default: `false`
3636

3737
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
6464
when there's one source file.
6565

6666
## sourceMapIncludeSources
67-
Type: `Boolean`
67+
Type: `Boolean`
6868
Default: `false`
6969

7070
Pass this flag if you want to include the content of source files in the source map as sourcesContent property.
7171

7272
#### sourceMapRoot
73-
Type: `String`
73+
Type: `String`
7474
Default: `undefined`
7575

7676
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
9393
The value of wrap is the global variable exports will be available as.
9494

9595
## maxLineLen
96-
Type: `Number`
96+
Type: `Number`
9797
Default: `32000`
9898

9999
Limit the line length in symbols. Pass maxLineLen = 0 to disable this safety feature.
100100

101101
## ASCIIOnly
102-
Type: `Boolean`
102+
Type: `Boolean`
103103
Default: `false`
104104

105105
Enables to encode non-ASCII characters as \uXXXX.
@@ -135,7 +135,35 @@ Default: empty string
135135
This string will be appended to the minified output. Template strings (e.g. `<%= config.value %>` will be expanded automatically.
136136

137137
## screwIE8
138-
Type: `Boolean`
138+
Type: `Boolean`
139139
Default: false
140140

141141
Pass this flag if you don't care about full compliance with Internet Explorer 6-8 quirks.
142+
143+
## mangleProperties
144+
Type: `Boolean`
145+
Default: false
146+
147+
Use this flag to turn on object property name mangling.
148+
149+
## reserveDOMProperties
150+
Type: `Boolean`
151+
Default: false
152+
153+
Use this flag in conjunction with `mangleProperties` to prevent built-in browser object properties from being mangled.
154+
155+
## exceptionsFiles
156+
Type: `Array`
157+
Default: []
158+
159+
Use this with `mangleProperties` to pass one or more JSON files containing a list of variables and object properties
160+
that should not be mangled. See the [UglifyJS docs](https://www.npmjs.com/package/uglify-js) for more info on the file syntax.
161+
162+
## nameCache
163+
Type: `String`
164+
Default: empty string
165+
166+
A string that is a path to a JSON cache file that uglify will create and use to coordinate symbol mangling between
167+
multiple runs of uglify. Note: this generated file uses the same JSON format as the `exceptionsFiles` files.
168+
169+

‎package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"chalk": "^1.0.0",
2424
"lodash": "^3.2.0",
2525
"maxmin": "^1.0.0",
26-
"uglify-js": "2.4.17",
26+
"uglify-js": "^2.4.19",
2727
"uri-path": "0.0.2"
2828
},
2929
"devDependencies": {

‎tasks/lib/uglify.js

+56-2
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,15 @@ exports.init = function(grunt) {
7070
topLevel = topLevel.wrap_enclose(argParamList);
7171
}
7272

73+
var topLevelCache = null;
74+
if (options.nameCache) {
75+
topLevelCache = UglifyJS.readNameCache(options.nameCache, 'vars');
76+
}
77+
7378
// Need to call this before we mangle or compress,
7479
// and call after any compression or ast altering
7580
if (options.expression === false) {
76-
topLevel.figure_out_scope({screw_ie8: options.screwIE8});
81+
topLevel.figure_out_scope({ screw_ie8: options.screwIE8, cache: topLevelCache });
7782
}
7883

7984
if (options.compress !== false) {
@@ -87,7 +92,45 @@ exports.init = function(grunt) {
8792
topLevel = topLevel.transform(compressor);
8893

8994
// Need to figure out scope again after source being altered
90-
topLevel.figure_out_scope({screw_ie8: options.screwIE8});
95+
if (options.expression === false) {
96+
topLevel.figure_out_scope({screw_ie8: options.screwIE8, cache: topLevelCache});
97+
}
98+
}
99+
100+
var mangleExclusions = { vars: [], props: [] };
101+
if (options.reserveDOMProperties) {
102+
mangleExclusions = UglifyJS.readDefaultReservedFile();
103+
}
104+
105+
if (options.exceptionsFiles) {
106+
try {
107+
options.exceptionsFiles.forEach(function(filename) {
108+
mangleExclusions = UglifyJS.readReservedFile(filename, mangleExclusions);
109+
});
110+
} catch (ex) {
111+
grunt.warn(ex);
112+
}
113+
}
114+
115+
var cache = null;
116+
if (options.nameCache) {
117+
cache = UglifyJS.readNameCache(options.nameCache, 'props');
118+
}
119+
120+
if (options.mangleProperties === true) {
121+
topLevel = UglifyJS.mangle_properties(topLevel, {
122+
reserved: mangleExclusions ? mangleExclusions.props : null,
123+
cache: cache
124+
});
125+
126+
if (options.nameCache) {
127+
UglifyJS.writeNameCache(options.nameCache, 'props', cache);
128+
}
129+
130+
// Need to figure out scope again since topLevel has been altered
131+
if (options.expression === false) {
132+
topLevel.figure_out_scope({screw_ie8: options.screwIE8, cache: topLevelCache});
133+
}
91134
}
92135

93136
if (options.mangle !== false) {
@@ -97,9 +140,20 @@ exports.init = function(grunt) {
97140
// // compute_char_frequency optimizes names for compression
98141
// topLevel.compute_char_frequency(options.mangle);
99142

143+
options.mangle.cache = topLevelCache;
144+
145+
options.mangle.except = options.mangle.except ? options.mangle.except : [];
146+
if (mangleExclusions.vars) {
147+
mangleExclusions.vars.forEach(function(name){
148+
UglifyJS.push_uniq(options.mangle.except, name);
149+
});
150+
}
151+
100152
// Requires previous call to figure_out_scope
101153
// and should always be called after compressor transform
102154
topLevel.mangle_names(options.mangle);
155+
156+
UglifyJS.writeNameCache(options.nameCache, 'vars', options.mangle.cache);
103157
}
104158

105159
if (options.sourceMap && options.sourceMapIncludeSources) {

‎test/fixtures/expected/mangleprops.js

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎test/fixtures/expected/mangleprops_withExcept.js

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎test/fixtures/expected/mangleprops_withExceptAndExceptionsFiles.js

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎test/fixtures/expected/mangleprops_withExceptionsFiles.js

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
var a={a:function(a){a++},b:function(){},c:function(){}},b=function(){},c=function(){};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
var d=10;a.a(d);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"props": {
3+
"cname": 2,
4+
"props": {
5+
"$myFunction": "a",
6+
"$dontMangleMeProperty": "b",
7+
"$dontMangleMeProperty2": "c"
8+
}
9+
},
10+
"vars": {
11+
"cname": 3,
12+
"props": {
13+
"$myObj": "a",
14+
"$dontMangleMeVariable2": "b",
15+
"$dontMangleMeVariable3": "c",
16+
"$myNumber": "d"
17+
}
18+
}
19+
}
+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"vars": ["dontMangleMeVariable2"],
3+
"props": ["dontMangleMeProperty"]
4+
}
+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"vars": ["dontMangleMeVariable3"],
3+
"props": []
4+
}
5+

‎test/fixtures/src/mangleprops.js

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
var myObj = {
2+
myFunction: function(dontMangleMeVariable) { dontMangleMeVariable++; },
3+
dontMangleMeProperty: function() {},
4+
dontMangleMeProperty2: function() {}
5+
};
6+
7+
var dontMangleMeVariable2 = function() {};
8+
var dontMangleMeVariable3 = function() {};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
var myNumber = 10;
2+
myObj.myFunction(myNumber);

‎test/uglify_test.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,14 @@ exports.contrib_uglify = {
4949
'sourcemaps_multiple2_fnName.js',
5050
'sourcemaps_multiple2_fnName.js.fn.map',
5151
'expression.json',
52-
'expression.js'
52+
'expression.js',
53+
'mangleprops.js',
54+
'mangleprops_withExcept.js',
55+
'mangleprops_withExceptionsFiles.js',
56+
'mangleprops_withExceptAndExceptionsFiles.js',
57+
'mangleprops_withNameCacheFile1.js',
58+
'mangleprops_withNameCacheFile2.js',
59+
'uglify_name_cache.json'
5360
];
5461

5562
test.expect(files.length);

0 commit comments

Comments
 (0)
Please sign in to comment.