Google Closure Compiler's ADVANCED_OPTIMIZATIONS option - javascript

I've been checking out the Google Closure Compiler recently. I downloaded the .jar file and gave it a test drive. So far, I must say that I've been very impressed. I can certainly see its usefulness beyond minimization. Props to the Google team!
I do have one small gripe though. It seems to me that you only get two options as far as optimization goes. It's either SIMPLE_OPTIMIZATIONS or ADVANCED_OPTIMIZATIONS. The former, although adequate, is very simple IMHO. For one thing, unless I'm missing something, it leaves all property names untouched. It also does not remove unreachable code. On the other hand, the latter option is simply too destructive.
Now, I'm fairly new to JavaScript, so it's very probable that I'm missing something. If I say something stupid, feel free to school me. That said, I can understand the issues with renaming in JavaScript. The Google team recommends using the bracket notation (object['property']) instead of the dot notation (object.property) to access the properties that you do not want changed and never mixing the two uses. They also suggest 'exporting' methods by using the following pattern:
MyClass = function(name) {
this.myName = name;
};
MyClass.prototype.myMethod = function() {
alert(this.myName);
};
window['MyClass'] = MyClass; // <-- Constructor
MyClass.prototype['myMethod'] = MyClass.prototype.myMethod;
However, there are legitimate cases that you want to mix the two notations. Let's say we are building a game. The game's code is completely isolated inside a closure. It does not 'export' anything to the global scope, nor does it need to. In fact, it really should not touch the window object. However, it does need to read some in-game properties from XML configuration files.
Sample JavaScript:
var TheGreatAdventure = (function(window) {
function Fighter() {
// Private to application
this.id = 42;
// Accessible to XML configuration system
this.name = 'Generic Jen';
this.hitPoints = 100;
this.onAttack = genericFighterAttack;
this.onSpeak = genericFighterSpeak;
...
}
Fighter.publishedProperties = ['name', 'hitPoints', 'onAttack', 'onSpeak']
function genericFighterAttack() {...}
function genericFighterSpeak() {...}
function cassieAttack() {...}
function cassieSpeak() {...}
...
EntityReader = {
...
function readFromXMLNode(attributes, entityClass, entityInstance) {
for (var i = 0; i < attributes.length; i++) {
var attribute = attributes[i];
if (attribute.nodeName in entityClass.publishedProperties)
entityInstance[attribute.nodeName] = bindContext[attribute.value];
}
}
...
}
}(window));
Sample XML configuration file:
<Fighter name='Custom Cassie' onAttack='cassieAttack' onSpeak='cassieSpeak'/>
Not only would the above system fail to assign the properties, the functions cassieAttack and cassieSpeak would have been eliminated during minimization as dead code!
Now, there's no way I'm accessing all of the 'published' properties using the bracket notation throughout the game's code. Even if there's no run-time penalty in doing so (there should not be any), there's still a lot of extra typing involved and it's (IMO) an eyesore. With such common properties, everything would show up as a string inside a text editor, defeating the purpose of syntax highlighting!
It seems to me that a simple #preserve (or something similar) directive over those properties would allow ADVANCED_OPTIMIZATIONS to be used with minimum cost in final program size. Am I missing something?

This answer was completely rewritten, turns out there's a way to do what user1127813 wants.
You need to provide a property mapping file that maps some names to themselves, using the --property_map_input_file flag. Suppose you have the following original code in test.js:
/** #constructor */
function Fighter() {
this.ID = 42;
this.fullName = 'Generic Jen';
this.hitPoints = 100;
}
Fighter.publishedProperties = ['fullName', 'hitPoints'];
var jen = new Fighter();
var bob = new Fighter();
bob.ID = 54;
bob.fullName = 'Bob the Destructor';
bob.hitPoints = 1337;
for(i = 0; i < Fighter.publishedProperties.length; i++) {
prop = Fighter.publishedProperties[i];
alert(prop + ' = ' + bob[prop]);
}
Compile it like so:
java -jar closure-compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS --js test.js --property_map_output_file testprop.txt --js_output_file test2.js
You will get a new file test2.js (with contents that don't work) and another file testprop.txt that contains:
ID:a
hitPoints:c
fullName:b
Change testprop.txt so it looks like this:
ID:ID
hitPoints:hitPoints
fullName:fullName
Then recompile with testprop.txt as input instead of output:
java -jar closure-compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS --js test.js --property_map_input_file testprop.txt --js_output_file test2.js
Observe the contents of test2.js:
var a=["fullName","hitPoints"],b=new function(){};b.ID=54;b.fullName="Bob the Destructor";b.hitPoints=1337;for(i=0;i<a.length;i++)prop=a[i],alert(prop+" = "+b[prop]);
The desired properties are now accessed with their original name using the dot notation and the program will correctly show popups with the published properties of bob.

The compiler has support for this, but it is awkward, and depends on a "primitive" from the Closure Library called "goog.reflect.object":
/** #nocollapse */
Fighter.publishedProperties = goog.object.transpose(goog.reflect.object(
Fighter, {fullName:1, hitPoints:2}));
This avoid the use of quoted properties. If this is the only thing that you use from the Closure Library everything but the "goog.object.transpose" function will be compiled out (goog.object.transpose isn't special so you are free to use an alternate implementation). This is type safe and can be used with the compiler's type based optimizations (see a discription of that here: http://code.google.com/p/closure-compiler/wiki/ExperimentalTypeBasedPropertyRenaming ).
The key is that goog.reflect.object must be used directly, taking the constructor and an object literal with the keys of the properties you need to preserve.
The other thing that you will want to be aware of this that in ADVANCED mode, if Fighter.publishedProperties is defined in global scope, it will be removed from the constructor due to namespace collapsing. #nocollapse prevents this. An alternative would be to use a helper method to add the property:
function addPublishedProperties(obj, value) {
obj.publishedProperties = goog.object.transpose(value);
}
Ok, I've covered a lot of ground here so be sure to let me know if you would like clarification.

Related

How do I define keywords in Javascript?

I try something like this:
var varr = var;
varr x = 10;
It doesn't work, for obvious reasons, but you get the idea. How do I define keywords in Javascript, like how I can in C:
#define var int
var x = 10;
The above code wouldn't work, but is there a way to do something similar in Javascript? Not that I would absolutely need to, but just wondering.
var is a reserved token by Javascript and thus cannot be used incorrectly, or as part of variable names.
When JavaScript parses our code, behind the scenes it’s converting everything into appropriate characters, then the engine attempts to execute our statements in order and as var is a reserved token it will throw Uncaught SyntaxError: Unexpected token 'var'
JavaScript doesn't allow you to use the reserved keyword as the identifier's value, What you're gonna do is a pretty clear mistake here. you defined variable and assign as value unsupported datatypes which js don't know, Learn more
var <variable-name> = <reserved-keyword>
expected value:
var <variable-name> = <value>
javascript support all datatypes which you use in C, Int, Float, String, Obj...
Example of:
var x; // declare empty variable
x = 1;
var y = "String";
var z = [];
var foo = {};
The reason why this is possible in C is because #define allows you to declare macros that are replaced in the source code before compilation. Javascript doesn't have a concept of macros so it's not a part of the language however there are tools in JS that let you add this kind of compilation step even though it's not a part of JS itself.
Babel is probably the most popular way to do this and https://github.com/kentcdodds/babel-plugin-macros is pretty useful although I'm not sure if you can use it to redefine parts of the language.
You can instead use something like https://github.com/sweet-js/sweet-core to do what you want which lets you add a pre-processor step to replace macros however like I said, JS doesn't support macros so this is a step you have to execute to generate valid Javascript.
syntax varr = function (ctx) {
return #`var`;
};
varr test = 10;
$ sjs test.sweet
var test = 10;
It's also important to mention that in C this is something that's built into the language so IDEs understand how to deal with macros, but if you're using an external tool you're not going to have a fun time using macros that redefine keywords, especially when it comes to things like syntax highlighting. This is something I'd definitely discourage, but it is technically possible if you're willing to step outside the bounds of just Javascript.

How to "take variables out of an object" in javascript

I'm looking for something that will import the contents of an object to the global scope:
var y = {}
y.x = 5
//do some magic here
console.log(x); //5
I want to do this is so I can make an easy to use module with memorable function names without having to worry about things accidentally getting overridden by other modules.
Consider this example:
funModule = {};
funModule.washClothes = function(clothes){...}
funModule.walkDog = function(dogName){...}
//etc
funModule.UNITED_STATES_DEFICIT = ...;
Here I've created a module that has some useful functions and constants (implementations and values were replaced with "...").
I don't want my users to have to type out the module name every time they call function or use a constant. That would result with really messy code:
funModule.walkDog(funModule.UNITED_STATES_DEFICIT);
I could try it again by defining everything globally:
washClothes = function(clothes){...}
walkDog = function(dogName){...}
//etc
UNITED_STATES_DEFICIT = ...;
but if a different module has also defined the commonly named function washClothes we've got trouble. (in my actual case the commonly named function is run)
Removed from technical context, here is the problem I'm faced with:
Firstly I want to use simple and memorable names to make the module easy to learn and fun to use.
Secondly I don't want the easy names to make the module impossible to use with others. Especially as it grows, a lot of common names will be used. It would be great if the users could decide whether or not import the names directly.
Thirdly I realized as I'm typing this that what I'm describing is something that definitely already exists, in python. See http://effbot.org/zone/import-confusion.htm for more detail.
tl;dr How can python-like imports be done with javascript?
EDIT:
It seems there is not a universal way to do this.
Using Window won't work in all environments (but will work in any common browser).
Apparently ES6 Modules are not available to web browsers directly.
This question is different from this one because its not about Node.js. I was looking for a universal way to do it, but that doesn't seem possible, so I'll limit it to web browsers, (namely chrome, firefox, safari, opera, and maybe ie)
EDIT:
This general article about Scope could be useful for anyone with a similar question as mine: https://toddmotto.com/everything-you-wanted-to-know-about-javascript-scope/
Object.prototype.makeglobal=function(){
for(key in this){
if(window[key]){//replace window if youre not in a browser
//already exist, error handling
console.error(key+' already exist in window');
}else{
window[key]=this[key];
}}};
Use like this:
funModule.makeglobal();
//now you can
washClothes();
But this is bad as it pollutes the global object.
2.Your user should create his own namespace:
function(){
this.washClothes();
//more of his content
}.call(funModule);
3.You could also add a loader:
funModule.load=function(func){
console.log(func);
console.log(this);
func.call(this,this);
};
Now you can do:
funModule.load(function(fun){
this.washClothes();
fun.washClothes();
});
4.If youre concerned about readability you may use function chaining (?):
funModule.washClothes=function(){
//your code
return this;
}
now you can do:
funModule.washClothes("tshirts").washClothes("trousers").washClothes();
ES6 Modules are what you want.
If you will define your object as es6 module you could do this (using the names in your example):
import { washClothes } from "fun-module";
and then washClothes will be globally available on the file that imported it, just like you want.
Read about it here.
If you really want a magic solution like in the comment in your post and don't want to use ES6 and you run in the browser you can put it on the window object:
window.x = 5
In JavaScript, at least in a browser, global variables are properties of the window object: that is, window.x and x (where x is global) reference the same value. So, in theory, you could use Object.assign() to copy your object's properties to the window object making them global variables. This is roughly equivalent to globals().update(myobj.__dict__) in Python.
But just as import * is usually a bad idea in Python, so too this sounds like a bad idea, except even worse because window has a lot of other properties that you probably don't want to clobber.
After some additional research I found a way, without polluting the global namespace, to allow users to directly access module contents.
This solution allows the user to:
Write code that directly references the module's functions/properties
Define precedence if there are multiple modules written in this same style
Still access the module's functions/properties by module name*
*This feature comes with a catch
Here's the code
Module
funModule = {};
//This stuff is the arbitrary contents of the module:
funModule.washClothes = function(clothes){...}
funModule.walkDog = function(dogName){...}
//etc
funModule.UNITED_STATES_DEFICIT = ...;
//etc
//This part is necessary:
funModule.run(userApp)
{
for(key in this){
eval(key + " = " + this[key] + ";");
}
userApp();
}
The only way (that I could find) to dynamically define functions both in funModule.run's scope and in funModule is to use Eval. Using call, apply, or bind to manipulate scope would still require use of the this keyword and the whole point of this unusual style is to make client code as simple and non-repetitive as possible.
Client Code 1
function myApp()
{
washClothes(UNITED_STATES_DEFICIT);
}
funModule.run(myApp);
Here in the client code it is possible to directly access everything except for funModule.run. So the global namespace is kept clean but the user's code does not need unnecessary repetition.
Client Code 2
function myApp()
{
washClothes(UNITED_STATES_DEFICIT);
}
funModule.run( otherModule.run.bind({},myApp) ); //otherModule has precedence here
Assume otherModule is a different module that features the same run function. funModule will load its contents then call its first argument. The first argument will load otherModule's contents, overriding anything from funModule with the same name.
Client Code 3
function myApp()
{
//directly access stuff from funModule
walkDog()
var big = UNITED_STATES_DEFICIT * 3.14;
//explicitly access stuff from specific modules
clothes = new otherModule.Clothes();
funModule.washClothes(otherModule.washClothes(clothes));
}
funModule.run(myApp)
This is the feature that makes use of eval necessary. The user can opt out of ambiguity of direct access. They can still access properties/methods by naming the module they come from.
But Why?
Some StackOverflow users were understandably concerned about the unusual set of constraints in the question, so I figured I would answer the following question:
Why don't you use a short alias for your module.
I tried to answer that question in this article, which pulls from this question and answer.

Is it possible to import variables in JavaScript (node.js)?

I have variables in app.js:
var G = {};
module.exports = G;
var DATA = G.DATA = 'DATA';
var F1 = G.F1 = function(val)
{
return val;
};
In this manner, I can export variables under the object G, and at the same time, can access the variable directly writing DATA without G. prefix.
So far so good.
Now, I want to run a test for app.js in test.js:
var G = require('./app.js');
console.log(G.DATA); // -> DATA
This works, but I also want to access the variable directly writing DATA without G. prefix like console.log(DATA); // -> DATA
Surely, I could do like
var DATA = G.DATA; for every variables(property) export&required module G object, but obviously it's a tedious process to add every variable to the test file manually to correspond the G objects.
Is there any way to do this automatically?
So far, I'm pessmistic since
JS function encloses var in the own scope, so in theory there's no way to have a helper function to var for every object property.
Thanks.
PS. I would like to avoid any eval or VM of node solution. I have tried them in past, and too much problems.
I could assign a local variables for every property export&required module G object, but obviously it's a tedious process to add every variable to the test file manually to correspond the G objects.
No, that's how it is supposed to work. You - and only you - are in charge of what local variables exist in your module scope. No changes in the "export variables" of an included module should break your code.
Accessing properties on the imported module (with a self-chosen name) is the way to go. This is quite equivalent to Python's import app or import app as g.
If you want some particular properties as local variables, you will usually choose them manually, as in Python's from app import DATA, F1. In JS, you will need a multiple var statement like the one you've shown in your question. However, there is a syntax feature called destructuring assignment which will make this more fluid. You can use this in JavaScript 1.7+ (Gecko), CoffeeScript, or EcmaScript 6:
var {DATA, F1} = require("app.js");
Is there any way to do this automatically?
Yes and No. You should not do this, but you can - just like Python's frowned-upon from app import *. To cite what they say, which is equally true for JavaScript:
[It] introduces an unknown set of names into the interpreter, possibly
hiding some things you have already defined.
Note that in general the practice of importing * from a module or
package is frowned upon, since it often causes poorly readable code.
However, it is okay to use it to save typing in interactive sessions.
In JavaScript, you can[1] use the with-statement:
with (require("app.js")) {
…
}
[1]: Not in ES5.1 strict mode, though - which is recommended for optimisation

Closure compiler, Backbone and meta programming

I am trying to use Backbone.js and Closure Compiler in advanced mode. I wrote a convenient function that creates getters/setter for my Backbone.Models using Backbone.Model.defaults, it looks like this:
some.defaultProperties = function(ctor) {
if (!ctor.prototype.defaults)
return;
var defattr = function(name) {
return {
get: function() {
return this.get(name);
},
set: function(val) {
var diff = {};
diff[name] = val;
return this.set(diff);
}
};
};
var props = {};
for (var attr in ctor.prototype.defaults) {
if (ctor.prototype.defaults.hasOwnProperty(attr))
props[attr] = defattr(attr);
}
Object.defineProperties(ctor.prototype, props);
};
Equivalent in CoffeeScript here http://srackham.wordpress.com/2011/10/16/getters-and-setters-for-backbone-model-attributes/
Now back to Closure Compiler in advanced mode. It doesn't seem to like it because I'm accessing those using normal property access syntax, ie. model.color instead of model.get('color'), that's the point. But Closure is mangling those, and therefore I get undefined instead of my value. Any workaround for this? (Except rewriting everything to use get('attrname'))?
UPDATE And of course, how would this work with Backbone.Model.hasChanged and other methods that take a string literal for attribute name.
You are defining your properties using quoted syntax:
props[attr]
But your problem is occurring when you try to access them via dotted syntax:
model.color
In ADVANCED_OPTIMAZATIONS, a cardinal rule is that you must reference a property consistently. See https://developers.google.com/closure/compiler/docs/api-tutorial3#propnames
It sounds like the easiest answer may be for you to use quoted syntax for these properties:
model['color']
However, you'll lose all renaming and dead code elimination for such properties.
Any properties you create dynamically are "external" in advanced mode and you have three choices: (1) use quoted access (as Chad suggests) or (2) create externs or (3) use Simple mode and give up property rename and global dead code removal.

Obfuscate javascript properties?

I've recently tested UglifyJS and YUI Compressor and noticed something odd.
Both minifiers don't seem to change the names of object properties, only the names of variables and functions.
for instance if I have the following code:
var objName = {first:2, second:4};
alert(objName.first + " " + objName.second);
the names first and second remain unchanged in the minified version.
Why is that?
Since in javascript a new scope is created in a function, you can scope your code in an immediately invoked function.
// scoped
(function() {
var objName = {first:2, second:4};
alert(objName.first + " " + objName.second);
})();
Then using Google's Closure Compiler, if you turn on the "Advanced" optimization it will see that the properties are only used locally, and will obfuscate them.
// result
var a={a:2,b:4};alert(a.a+" "+a.b);
It's because it doesn't know where the object is going to be used. It could be used externally by other code and you wouldn't want your other code to have to change whenever you obfuscate it.
Edit So basically, it's like that to prevent obfuscation from breaking external/internal references to properties that may not be possible to figure out while obfuscating.
Since there are no well defined scoping rules around objects in JavaScript it's impossible to obfuscate the names in a way that is guaranteed to be correct.
For example, if you had the following function:
function f() {
return { first: 'foo', second: 'bar' };
}
In order to obfuscate the property names you would have to nail down all the places that f is called from. Since functions are first-class in JavaScript they can be assigned and passed around in arbitrary ways making it impossible to pin down where f is referenced without actually running the program.
Additionally, JavaScript doesn't have any way for you to specify intent around what's public API and what isn't. Even if the minimizer could reliably determine where the function is called from in the code you give it, there would be no way for it to make the same changes to code that it hasn't seen.
I guess that's because the minifiers would break the object properties. Consider this:
function getProp(ob,name) {
return ob[name];
}
var objName = {first: 2, second: 4};
var prop = getProp(objName, "second");
There's no way for the minifier to know the string literal "second" being an object property. The minified code could look like this then:
function a(b,c){return b[c]}var d={p1:2,p2:4};var e=a(d,"second")
Broken now.
The latest release of uglify (today) has object property mangling, see v2.4.19. It also supports reserved files for excluding both object properties and variables that you don't want mangled. Check it out.
The only public tool so far to obfuscate property and function names (afaik) is the Closure Compiler's Advanced mode. There are a lot of limitations and restrictions, but the end result is generally worth it.
As a passing note: the Dojo Toolkit is compatible (with some minor modifications) with the Closure Compiler in Advanced mode -- arguably the only large-scale public JavaScript library that can be fully obfuscated. So if you are looking at obfuscation to protect your IP, you should look into using Dojo for the task.
http://dojo-toolkit.33424.n3.nabble.com/file/n2636749/Using_the_Dojo_Toolkit_with_the_Closure_Compiler.pdf?by-user=t
Stephen
What about doing something like:
// scoped
(function() {
var objName = {first:2, second:4};
var vA = 'first';
var vB = 'second';
alert(objName[vA] + " " + objName[vB]);
})();
Once objName.first and/or objName.second are referenced enough times, this technique will start to save characters. I can't think of any reason that wouldn't work, but I can't find any minifiers that do it.

Categories