Uglify-js doesn't mangle variable names - javascript

Trying to prepare good build environment for my js library. According to reviews on the web UglifyJS seems to be one of the best compressing modules out there, working under NodeJS. So here is best recommended way of minifying the code:
var jsp = require("uglify-js").parser;
var pro = require("uglify-js").uglify;
var orig_code = "... JS code here";
var ast = jsp.parse(orig_code); // parse code and get the initial AST
ast = pro.ast_mangle(ast); // get a new AST with mangled names
ast = pro.ast_squeeze(ast); // get an AST with compression optimizations
var final_code = pro.gen_code(ast); // compressed code here
As seen here, pro.ast_mangle(ast) should mangle variable names, but it doesn't. All I get out of this pipe is javascript code, with no spaces. At first I thought that my code was not optimized for compression, but then I tried it with Google Closure and got quite a compression (with mangled variable names and everything).
UglifyJS experts, any hint to what I'm doing wrong?
UPDATE:
Actual code is too large to reference here, but even a snippet like this doesn't get mangled:
;(function(window, document, undefined) {
function o(id) {
if (typeof id !== 'string') {
return id;
}
return document.getElementById(id);
}
// ...
/** #namespace */
window.mOxie = o;
}(window, document));
This is what I get (only spaces get stripped I guess):
(function(window,document,undefined){function o(id){return typeof id!="string"?id:document.getElementById(id)}window.mOxie=window.o=o})(window,document)

Ok, it seems that the latest version of Uglify JS requires mangle option to be explicitly passed as true, otherwise it won't mangle anything. Like this:
var jsp = require("uglify-js").parser;
var pro = require("uglify-js").uglify;
var orig_code = "... JS code here";
var options = {
mangle: true
};
var ast = jsp.parse(orig_code); // parse code and get the initial AST
ast = pro.ast_mangle(ast, options); // get a new AST with mangled names
ast = pro.ast_squeeze(ast); // get an AST with compression optimizations
var final_code = pro.gen_code(ast); // compressed code here

By default uglify won't mangle toplevel names, maybe thats what you seen?
Try:
-mt or --mangle-toplevel — mangle names in the toplevel scope too (by default we don’t do this).

If you're using Uglify2, you can use TopLevel.figure_out_scope(). http://lisperator.net/uglifyjs/scope
If you're using Uglify1, it's a little more complicated. Here's some code I put together by modifying the code from Uglify's squeeze_more.js file:
function eachGlobalFunctionCall(ast, callback) {
var w = uglify.uglify.ast_walker(),
walk = w.walk,
MAP = uglify.uglify.MAP,
scope;
function with_scope(s, cont) {
var save = scope, ret;
scope = s;
ret = cont();
scope = save;
return ret;
}
function _lambda(name, args, body) {
return [ this[0], name, args, with_scope(body.scope, curry(MAP, body, walk)) ];
}
w.with_walkers({
"function": _lambda,
"defun": _lambda,
"toplevel": function(body) {
return [ this[0], with_scope(this.scope, curry(MAP, body, walk)) ];
},
"call": function(expr, args) {
var fnName = expr[1];
if (!scope.has(fnName)) { // <--- here's the important part
callback(fnName, args, scope);
}
}
}, function() {
return walk(uglify.uglify.ast_add_scope(ast));
});
}
This one above only works on global function calls, but it gives you a callback which is executed as the walker finds a call to an unknown (global) method.
For example, given the following input:
function foo () {
bar(1);
(function () {
function bar() { }
bar(2);
(function () {
bar(3);
}());
}());
}
It would find the call bar(1) but not bar(2) or bar(3).

Variables in global scope are available to any other script, so Uglify won't change them without special switch, in case you really need them to be visible. You can either use -mt/toplevel switch/setting, or, better, yet, stop polluting global scope and clearly indicate that you don't intend for those variables to be seen outside, but framing your code into anonymous self-invoking function that will serve as private scope.

Related

Should I create accessor methods in my JavaScript app

I used this form to structure my JS code
window.APP = window.APP || (function (global) {'use strict';
return {
operation: '',
operand: 0,
result: '',
init: function () {
}
};
}(window.document));
There is better way like this:
var APP = APP || (function (global) {
return {
init: function () {
}
};
}(window.document));
But this way JSLint complains that APP was not initialized in the second call of APP, specifically this part: "var APP = APP"
So window.APP works and JSLint finds APP object in the window namespace.
If you check the first code block I have three application wide properties, operation, operand and result. I need those three accessible trough all my other subfunctions and subobjects. So far I used this form to access them:
window.APP.operand = global.getElementById("operand").value;
This works but the problem is, the code overall looks very ugly and cluttered with extra unnecessary text. In my 250 lines of code I have this "window.APP" prefix everywhere.
My questions is, should I create special accessor methods to get/set each of those properties or is there a better way to avoid that window.APP prefix?
Let me know your thoughts.
You should be able to mix the two approaches and use
var APP = window.APP || (function(doc) { "use strict";
…
return {…};
}(document));
This seems promising:
var APP = APP || (function (global) {
var operand = 0,
operation = '',
result = '';
return {
init: function () {
}
};
}(window.document));
Have to try it though. I have some objects defined afterwards like
APP.namespace('Aritmetic', {
// properties/methods
});
namespace function creates subobjects of APP. In the example above Aritmetic will become subobject of APP and will contain all properties methods defined in the second parameter of namespace() function.
I changed the second parameter of namespace function to this:
APP.namespace('Aritmetic', (function () {
var parent = window.APP;
return {
test: function () {
parent.operand = "2"; // all properties/methods from window.APP are accessible trough parent.
}
};
}());
This might not be the most elegant solution to the problem but it works. If somebody knows better solution, let me know.

Check the existence of variable in the global namespace without alternate name

As a newbie in Design Patterns in Javascript, I came across the Module Pattern but I don't get something with namespace.
In the namespacing part of Addy Osmani's online book about JS Design Patterns, Addy explains those 5 ways of checking for variable / namespace existence:
// This doesn't check for existence of "myApplication" in
// the global namespace. Bad practice as we can easily
// clobber an existing variable/namespace with the same name
var myApplication = {};
// The following options *do* check for variable/namespace existence.
// If already defined, we use that instance, otherwise we assign a new
// object literal to myApplication.
//
// Option 1: var myApplication = myApplication || {};
// Option 2 if( !MyApplication ){ MyApplication = {} };
// Option 3: window.myApplication || ( window.myApplication = {} );
// Option 4: var myApplication = $.fn.myApplication = function() {};
// Option 5: var myApplication = myApplication === undefined ? {} : myApplication;
What I really don't get is how it solves the problem of naming.
Let's say myApplication is set up before my code tries to use myApplication. Using Option 1 for example (or actually all of the options), does not seem to change anything in case myApplication was already in use but only overwrite the previous values for myApplication:
// Higher in some script, where I don't know about it
var myApplication = 'whatever string or object used by the script';
// A bit of code later, where I come with my little Module Pattern
var myApplication = myApplication || {}; // Using Option 1
myApplication = (function($) {
var myAppVariable = 'blabla';
var myAppFunction = function() {
// Doing a few things here
};
return myAppFunction;
}) (jQuery);
// Using the module
myApplication.myAppFunction();
To me it is very confusing because I don't see how it prevents me for also stepping on other's toes.
When you load a module in javascript, you're probably (depending on the code I guess) going to have to overwrite whatever variable is already in your modules namespace. A popular pattern for preserving whatever may have held your modules name before load is the noConflict() pattern. The idea behind this pattern is you hold the original value of your namespace in a variable and if noConflict is called, you replace your namespace with the original value and return your library. The pattern can be written more or less elegantly like this:
myModule = "some stuff ya";
(function(namespace, undefined) {
var _module = "myModule";
var __originalModule = namespace[_module];//holds the original value in case you wish to restore it
/****** Code your module here following whichever module pattern you wish to follow ****/
var module = {
log: function() {
if(console.log) {
console.log(arguments);
}
}
}
/****** End of your module ****/
//calling this method will remove your module from the namespace and replace it with whatever
// originally held your module name.
//This function returns your module
module.noConflict = function() {
namespace[_module] = __originalModule;
return module;
}
namespace[_module] = module; //add your module to the namespace
})(window);
console.log(window.myModule); // => {log: function...}
var myMod = window.myModule.noConflict();
console.log(window.myModule); // => "some stuff ya"

Node.js double call to require()

//lib.js
var opt = 0
exports.set = function(arg) {
opt = arg
}
exports.prn = function() {
console.log(opt)
}
///prog.js
var lib = require('./lib')
var lib2 = require('./lib')
lib.set(222)
lib2.set(333)
lib.prn()
lib2.prn()
prog.js will output:
333
333
but I need it to output:
222
333
In ohter words, opt must be unique to variable lib and to variable lib2. How to achieve that?
That's because normally nodejs caches its modules which are got via require. You may use the following helper:
// RequireUncached.js
module.exports = function(module) {
delete require.cache[require.resolve(module)]
return require(module);
}
and the usage of the helper:
var requireUncached = require('RequireUncached.js');
requireUncached("./lib");
Have in mind that this approach is considered as bad practice and should not be used. I'll suggest to wrap your logic into a function, require the module and call the function. So, every time you get a new instance.
require will not load scripts multiple times, but always yield the same instance.
If you need different environments, make your module a constructor function that allows to be instantiated multiple times. Store opt on each object for that instead of in the (global) module scope.
// lib.js
module.exports = function constr() {
var opt = 0
this.set = function(arg) {
opt = arg
};
this.print = function() {
console.log(opt)
};
};
// prog.js
var lib = require('./lib'),
inst1 = new lib(),
inst2 = new lib();
/* or short:
var inst1 = new require('./lib')(),
inst2 = new require('./lib')(); */
inst1.set(222)
inst2.set(333)
inst1.print()
inst2.print()
The way the NodeJS module system works, the output is correct and your expectations contradict the design principle here.
Each module is loaded once and only once, and subsequent calls to require simply return the reference to the pre-existing module.
Maybe what you need to do is create a class you can create one or more instances of instead of using module-level globals.
Adding to Bergi's answer, You may also try it like
// prog.js
var lib = require('./lib')(),
lib2 = require('./lib')();
lib.set(222)
lib2.set(333)
lib.print()
lib2.print()
// lib.js
module.exports = function constr() {
var opt = 0
return { set : function(arg) {
opt = arg
},
print : function() {
console.log(opt)
}
}
};
Add this line as first line of your lib.js
delete require.cache[__filename]
now your module becomes in a separate namespace each time you require it.

How to write simple, extensible, modular Javascript

I need a mechanism whereby people can extend my base code with their own modules - but I'm struggling to come-up with a simple mechanism to do that.
Example: a function called 'test' which users can extend. Each user module is loaded after the original - so each one needs to build on the last (the order they're loaded should not matter or can be controlled by naming)
I started to play with something like this
var test = function() { // the master function
console.log("1");
}
var ltest = test; // module 1
var test = function() {
ltest();
console.log("2");
}
var ltest2 = test; // module 2
var test = function() {
ltest2();
console.log("3");
}
Then, when 'test' is called, it will run everyone's code (assuming no-one forgot their callback!!)
That works, but it relies on each module declaring it's own, unique 'callback' variable (ltest, ltest2) - if someone uses the same variable, we'll get a 'call stack exceeded' as those variables are global in scope...
Can anyone suggest a cleverer/better system - or point me to some examples of the same thing?
There's loads of material on inheritance but I don't want to create new things which extend the old one - I just want to extend the old one!!
p.s. taking the anonymous function stuff from the module pattern - I got this
var test = function() {
console.log("1");
}
(function() {
var oldtest = test;
test = function() {
oldtest();
console.log("2");
}
}())
(function() {
var oldtest = test;
test = function() {
oldtest();
console.log("3");
}
}())
Which is probably the simplest solution to my question - but not necessarily the best system to use (as it's dependant on the author to remember to callback the code - a dodgy module would break everything)
The Module Pattern is what you need.
In particular the 'Augmentation' or 'Loose Augmentation' patterns :
var MODULE = (function (my) {
var old_moduleMethod = my.moduleMethod;
my.moduleMethod = function () {
// method override, has access to old through old_moduleMethod...
};
return my;
}(MODULE || {}));
You could make a function like this
function extendFunction(fn, pre, post) {
return function () {
var arg = arguments;
if (pre) arg = pre.apply(this, arg); // call pre with arguments
arg = fn.apply(this, arg); // call fn with return of pre
if (post) arg = post.apply(this, arg); // call post with return of fn
return arg;
};
}
then extend as follows
var test = function () { // the master function
console.log("1");
};
test = extendFunction(
test, // function to extend
null, // thing to do first
function() {console.log("2");} // thing to do after
);
test = extendFunction(
test,
null,
function() {console.log("3");}
);
test(); // 1, 2, 3
This is very different to the normal meaning of "extend" though, where you give new properties to Objects or set up prototype chains, and to "module" which normally involves wrapping all your code in a function expression so that you don't pollute the namespace.

javascript organisation

I came across this Q/A on javascript code organisation.
var DED = (function() {
var private_var;
function private_method()
{
// do stuff here
}
return {
method_1 : function()
{
// do stuff here
},
method_2 : function()
{
// do stuff here
}
};
})();
Currently I do this,
var DED = new Object;
DED = {
sidebar : {
method_1 : function (data){
//some stuff
},
method_2 : function(data){
//do more
}
},
main : {
//.......
},
globalVariables : {
//...
}
}
What is the advantage of one over the other?
Warning: newbie here.
As indicated, that method uses closures to implement private functions and data. It's an alternative to the constructor method (below). E.g.
var DED = new (function()
{
var private_var;
function private_method()
{
// do stuff here
}
this.method_1 = function()
{
// do stuff here
};
this.method_2 = function()
{
// do stuff here
};
})();
With the DED method shown in your question, there is no constructor. Rather the function returns an object created from an object literal. The functions in that object have the private variable and method closed into them.
What you return from the anonymous self-calling function (function(){})() is the interface you publish for your "module" (DED).
DED.method_1() is public. private_method/private_var are not accessible from outside but everything inside of your self-calling function has access to them.
If you like this kind of access-control this is a good way to prevent other developer from accidentally messing with the internals of your module. In a lot of cases i'd just go for a naming convention like a leading underscore to indicate internals.
Javascript is very dynamic and if someone really wants to mess with code they have no write-access to they will be able to do so. Edit: This turns out to be a wrong assuption and not the case for private data in constructors or closures. Please, see: http://www.crockford.com/javascript/private.html

Categories

Resources