Mangle nested classes and variables with uglifyjs

I use uglifyjs to minimize a concatenated set of files that works fine but not good enough. The built-in lib uses namespaces, so classes, functions, and constants are stored in the root namespace variable:

(function() { var root = { api:{}, core:{}, names:{} }; /* util.js file */ root.names.SOME_LONG_NAMED_CONST='Angel'; /* Person.js file */ root.core.Person = function(name) { this.name = name }; /* API.js with the functions we want to expose */ root.api.perform = function(param_for_api) { /* do something */ } window.lib_name.perform = root.api.perform; })(); 

which is minimized to a non-minimum version

 (function(){var a={api:{},core:{},names:{}};a.names.SOME_LONG_NAMED_CONST="Angel",a.core.Person=function(a){this.name=a},a.api.perform=function(){},window.lib_name.perform=a.api.perform})(); 

I understand that uglify probably believes that root var is a data structure that should be stored as it is and cannot be changed. Is there a way to allow uglify to cast nested names in the root namespace?

+6
source share
5 answers

When you minimize Javascript, you can change the names of variables, api, kernel and names - these are not variables, but object properties. If they were changed by the minimizer, you might get unexpected results. What if in the code you would call

 root["api"].perform = function()... 

or even something like

 function doIt(section, method, argument) { root[section][method](argument); } doIt('api','perform', 101); 

All perfectly legal JS, but the minimizer could never understand what was happening.

+8
source

Besides the @JanMisker point (which is perfectly acceptable), overriding properties is unsafe because they can be exposed to code outside the mini-code area.

Although the self-executing function has a scope, and if the code only

 (function() { var root = { api:{}, core:{}, names:{} }; root.names.SOME_LONG_NAMED_CONST='Angel'; alert(root.names.SOME_LONG_NAMED_CONST); // some code that does something })(); 

It is true that outside the function there is no access to the root object, so overriding property names is safe, and the following code will do the same:

 (function() { var a = { b:{}, c:{}, d:{} }; ade='Angel'; alert(ade); })(); 

But even if you are in your private area, you can access and, more importantly, assign variables from the outside area! Imagine the following:

 (function() { var root = { api:{}, core:{}, names:{} }; root.api.perform = function(param_for_api) { /* do something */ } window.lib_name = root.api; })(); 

You not only expose a function, but also an object with a function on it. And the function will be visible from any place where the window will be visible.

So, for example, writing the following in the javascript console will give different results with and without thumbnails:

 window.lib_name.perform(asdf); 

With minimization, you will need to write:

 window.lib_name.f(asdf); 

Or something similar.

Remember that there can always be code outside your minimum.

It is not necessary to have an absolute minimum JS, but if for some reason it is important, for example: aliens have stolen your stepdaughter, and the only way to return it to a minimum is less than 100 characters or so), you can manually replace the unwanted long property name with shorter, just make sure that it will not be displayed anywhere and will not be accessible through an associative array entry ( root['api'] ).

+4
source

I am trying to use --mangle-props for UglifyJS2 and I can tell you: " it creates a mess ."

As someone remarked: “ The developer must decide which properties to cripple, not uglifyjs '

I come to a problem using the following options:

 --mangle-props --mangle-regexp="/_$/" 

A regular expression matches any property with an underscore at the end.

You asked to split the nested names into the root namespace. So your code is:

 (function() { var root = { api:{}, core:{}, names:{} }; root.names.SOME_LONG_NAMED_CONST_='Angel'; root.core.Person_ = function(name) { this.name = name }; root.api.perform_ = function(param_for_api) { } window.lib_name.perform = root.api.perform; })(); 

The result is the following:

 (function() { var n = { api: {}, core: {}, names: {} }; n.names.a = "Angel"; n.core.b = function(n) { this.name = n; }; n.api.c = function(n) {}; window.lib_name.perform = n.api.c; })(); 

Command: uglifyjs --beautify --mangle --mangle-props --mangle-regex="/_$/" -- file.js

If you want to use the first level of the root namespace (api, core, names) , just hover an underscore (api_, core_, names_) on them, you are in control;)

Just a note : when you control properties that can be used by other js files, you must cripple all the files with the same command, so the same identifier will be used in all files.

+4
source

as Jan Jan-Misker explained in his answer, the mangling property is not a good idea, because it could potentially break your code.

However, you can workaround to define property names as local variables and change all .properties to [keys] to reduce file size:

 (function() { var API = 'api'; var CORE = 'core'; var NAMES = 'names'; var SLNC = 'SOME_LONG_NAMED_CONST'; var root = {}; root[API]={}; root[CORE]={}; root[NAMES]={}; /* util.js file */ root[NAMES][SLNC] ='Angel'; /* Person.js file */ root[CORE].Person = function(name) { this.name = name }; /* API.js with the functions we want to expose */ root[API].perform = function(param_for_api) { /* do something */ } window.lib_name.perform = root[API].perform; })(); 

Since now all properties have become a local variable, uglify js will cripple / shorten the variable names and, as a result, the total file size is reduced:

 !function(){var a="api",b="core",c="names",d="SOME_LONG_NAMED_CONST",e={};e[a]={},e[b]={},e[c]={},e[c][d]="Angel",e[b].Person=function(a){this.name=a},e[a].perform=function(){},window.lib_name.perform=e[a].perform}(); 

However, a reduced file size does not mean that you will get shorter loading times on a real server, because usually our HTTP transport is gzipped, most of the repetitions will be compressed by your HTTP server, and it will be better than a person.

+1
source

The latest uglify release (today) has an object property property, see v2.4.18. It also supports reserved files to exclude both object properties and variables that you do not need. Check this.

Use the --mangle-props and --reserved-file filename1.json filename2.json , etc.

+1
source

Source: https://habr.com/ru/post/944110/


All Articles