I'm using Google's Closure Compiler to reduce the size of my Java Script code. Unfortunately the Closure Compiler does also change ALL function names in the Advanced mode without an easy option to change that.
I do need to exclude functions that are defined as properties (e.g. car.bla = function() ) completely. This includes the ones that I use and that are not defined at all in the local code, and the ones that I define myself.
I know that there is externs and exports (although I don't fully understand them) but I do not want to have to keep maintaining any extra files beside my code.
I would also be find to exclude any functions (also non-property functions).
After googling for a few hours I've still not found an options for that.
There are a few answers here;
Use #export to label a property as "used by external sources", such as an Angular binding.
Create an externs. These are used when you have code that is compiled separately from your code, but they need to interact. Have a look at how simple Angular's externs are.
Reduce your compilation level to WHITESPACE_ONLY
Depending on your setup, you may be able to pass --property_renaming=ALL_UNQUOTED and use foo['bar'] to access foo.bar
Depending on your setup, you may be able to Pass --property_renaming=OFF
Related
The Google Closure Compiler is a powerful compiler and minifier for JS, which gives a lot of optimization options such as renaming variables, removing dead codes, collapsing variable declarations, rewriting control flow structures and etc.
What I want is to separately apply one or some of these optimizations on an input JS program. For example, I may want to rename variables with short names, but not to remove dead codes. How can I achieve this kind of detailed compilation pass control? Does the source code of CC expose specific interfaces to do this customization, or I should write my own pass(If so, how am I supposed to start?).
The command line features do offer several options for controlling the compilation, but are insufficient to fit what I want above. Since the source code is kinda complicated and few detailed design documentation can be found, I am truly stuck here. Any insights would be appreciated, thanks :)
Take a look at DefaultPassConfig. That class lists all the passes that are run during the compilation, based on what options are set in the CompilerOptions. Some of the CompilerOptions can be controlled from the command line, but we generally try to keep the compiler relatively simple and easy to use, and not ask users to make decisions about a bunch of different compiler flags. Plus, there are some passes that actually increase the code size, but they do it in such a way that it makes it easier for some later pass to decrease it afterwards.
Of course if you're just experimenting with the compiler or trying to understand how it works, you can turn on and off whichever passes you want, either by adding new flags, or just modifying DefaultPassConfig directly.
It took me a while but I finally figured out what the purpose of symbols in ECMAScript 6 is: avoiding name collision when attaching properties to shared objects - HTML elements e.g. (In case you're stuck on the same question, I recommend this article.)
But then I stumbled upon Symbol.for(). Apparently ECMAScript 6 will maintain a global symbol registry which you can query with this function by providing the symbol description. Come again? If I use symbols to avoid name collisions, why would I want code other than my own to use them? (*) And how would I avoid name collisions in that global registry? Sharing of symbols seems to completely subvert the concept and a global registry doubly so.
(*) Yes, I know symbols aren't truly private, but that's besides the point.
If you don't want your symbols to be available in GlobalSymbolRegistry, just don't use Symbol.for.
Only use it if you want to allow other codes to use your symbol.
In the following example, I create a symbol to store data in DOM elements. And I may want every other code (e.g. internal raw uncompiled handlers) to read that data. So I make the symbol globally available.
var sym = Symbol.for('storeDataInDOM');
document.querySelector('button')[sym] = 'Hello, world!';
<button onclick="alert(this[Symbol.for('storeDataInDOM')])">Click me</button>
It's like creating global variables: should be avoided in general, but has its advantages. But with symbols instead of strings.
If I use symbols to avoid name collisions, why would I want code other than my own to use them?
That's not the only use case of symbols. The two most important other ones are:
they don't collide with string-keyed properties
they are not enumerated by the usual mechanics
Sharing of symbols seems to completely subvert the concept and a global registry doubly so.
Not necessarily. Right from that article you read: "The registry is useful when multiple web pages, or multiple modules within the same web page, need to share a symbol." The best example for these are the intrinsic symbols - they guarantee interoperability across realms, that's why the global symbol registry is more global than your global scope.
For example you might have a library that is loaded in a web page, an iframe and a web worker. If you share data between those environments (realms), all of the three instances of your library would want to use the same symbol.
There also is a real need interoperability between different libraries, which might not even know about each other. Good examples are transducers, algebraic structures or promises. Would ES6 already be in use, all of these would have agreed on common names in the global symbol registry, instead of relying on strings like these or the then method.
Another good example would be custom hooks defined by your engine, e.g. a Symbol.inspect = Symbol.for("inspect") that you can use to define custom stringification behavior to be used by console.log. Admittedly, that symbol does not necessarily need to be made available through the global symbol registry, it could as well be put on that specific library object (e.g. console.inspect = Symbole("console.inspect")).
And how would I avoid name collisions in that global registry?
Just like you previously did with properties, or global module objects: by using very long, very descriptive names - or by good faith. Also there are some naming conventions.
I invented the most useful feature of Symbol.for() call. If there is using symbols in your code sometimes it is difficult to use conditional breakpoints while debugging. For example, you need to catch if the variable equals the value which is of symbol type and this value binded in the different module. The first difficult way is to use this value as a constant and export it from that module. In this case, the condition of the breakpoint will look:
catchedVariable === exportedSymbolConst
But the easiest way is to temporarily change the code inside the module adding .for to Symbol. Then you can write the condition:
catchedVariable === Symbol.for('string_key')
After the successful debugging you will be changing the code back just removing .for part.
I have tried to minimize my javascript files using YUI compressor, but to no end, I cannot get the names of functions inside objects to minimize. I have tried to minimize function names in the global scope, but have come to understand this is not possible. Is there any way to minimize javascript code in a way that renames the function names also? Perhaps by encapsulating them in an object somehow? Other than obfuscating, which I have read has quality implications, I cannot think of any other way to protect client side code. Thank You.
Closure-compiler does this when you use ADVANCED_OPTIMIZATIONS. Be warned however, that it does it to everything unless you take specific steps to prevent this. Converting a large code base to be compatible with ADVANCED_OPTIMIZATIONS can be daunting.
See Which Compilation Level is Right for Me?
If you are writing a library that others will consume, there are even more considerations.
So closure compiler is great but exporting functions and defining externs seems to be too much manual work. Is there a way to tell the compiler that it should not remove any functions and should not rename any undefined functions?
I have 2 major reasons behind this:
If a function or property is not defined in the scope of the javascript document, then it's probably defined in an external file. Therefore, I wouldn't like these to be renamed.
If the function is defined in a given scope but isn't being called within the same scope, then it's probably being called in some external code. Therefore, I would like to keep this function in the file without renaming it.
This way, we could simply compile javascript files without worrying about external libraries and exporting functions that are called from html pages.
It very much sounds like you should run the compiler with the optimization level of SIMPLE_OPTIMIZATIONS. Don't be fooled by the name, as it still fully compiles your code. The main difference is that SIMPLE_OPTIMIZATION will not rename or eliminate dead code in the global scope. This means the requirements of externs and exports are no longer present.
To avoid this, I run the closure compiler on a complete script that is the concatenation of all the scripts of my application. So this is a two-step process :
1 - concatenate all
2 - run the closure compiler
Additionally, you may want (as I often do, due to problems with jquery before v1.8) to run the compiler with compilationLevel="simple".
Concatenation is very important as in general the slowness isn't related to the total size but mainly to the number of requests.
EDIT : of course you have to automate all this. I can provide you an ant task definition if you use ant.
I have 3000+ lines of javascript that I need to get into a sensible/maintainable structure. I have chosen to use requireJS as it has been recommend to me by a few people. I have a bunch of variables that are used throughout the application and need to be available everywhere. I also have a bunch of functions that need to be available everywhere. Apart from these two dependencies most of the code can be divided off into their own modules.
I am having trouble understanding how to manage my main variables so that if one module of code makes changes to the variables the rest of the JS modules will see that change. I think I need to see a few examples that demonstrate how requireJS is intended to work on a larger scale that the examples in the documentation.
If anyone is an experienced requireJS user I would love the hear your tips!
The whole point of RequireJS is to avoid the need for these global variables and global functions.
Can't you wrap those globals into a module, then depend on it in your other modules?
For example, a RequireJS modularized Dojo may be something like:
dojo/cache module
dojo/string module (requires dojo/cache)
dojo/date module (requires dojo/string)
dojo/cookie module (requires dojo/string)
:
:
dojo module (requires everything above, make them all into sub-objects, say, e.g. dojo.cache, dojo.string, dojo.date etc.)
user module #1 (requires dojo)
user module #2 (maybe only requiring dojo/string)
RequireJS gives you better options for encapsulating modules, but it doesn't change Javascript itself at all. As a transition strategy, you can still define your globals inside the function block. Depending on the module that contains these definitions will ensure that it has run before the dependent modules.
Next step would be to assign those methods to an object other than window, and then use that object through the variable received from RequireJS module dependency.
Hopefully by the time you've done this, you might have some insight into a cleaner solution. I refactored (and still am) a single-file project into several files, including optional plug-ins, although I did most of it before adding RequireJS to the mix.
See the RequireJS documentation:
Defining a module
Definition Functions with Dependencies
If the module has dependencies, the first argument should be an array of dependency names, and the second argument should be a definition function. ... The dependencies will be passed to the definition function as function arguments
define(["./cart", "./inventory"], function(cart, inventory) {
// ...
return { ... };
}
);
So I think you can define() your main module like all other modules and make the submodules depend on that main module. Then the module object is passed as an argument to the definition function of a submodule. You don't have to use global variables.
If you want to share information between modules, attach the information to the module object, and have the other modules rely on that module, and check its property.
If you have existing code, you can assign to window.x to provide a global x while you are cleaning it up.