save and reuse obfuscation mappings

Apr 9, 2012 at 5:05 AM


Is it possible to create a sort of dictionary after each run so that subsequent runs only transform newly introduced functions/variables and keep the same names for known functions/variables?

Thank you

Apr 13, 2012 at 5:53 PM

If you look at the output of the -a option on your script, you will see that for every scope I know the original names and the minified names for all the local variables and functions within. I'm thinking that what you're asking for would be a command-line switch to generate a file that programmatically itemizes all the nested scopes and their locals with their renamed names, and then a way to feed that file back into the app so that when a match is found (variable named X in scope Y), the previously minified name is used rather than just generating a new one. That might work; I'll have to think through and make sure that all possible changes to the original file (new variables, moved variables, etc) won't cause problems.

Apr 24, 2012 at 1:22 PM
Edited Apr 24, 2012 at 1:22 PM

Can you please explain why scopes matter? All the obfuscators I've used in the past always changed variables to the same obfuscated name throughout the application. Why is scope important?

Anyway, it would be really great if the library supported this. Imagine an obfuscated application that allows 3rd party plugins - the plugins would stop working if after every obfuscation the host program has entirely different function/variable names. The reusable dictionary allows so much flexibility in more complex scenarios.

Apr 24, 2012 at 4:51 PM

I completely disagree with your interpretation, and urge you to read more about JavaScript scopes, what they mean, how they work, etc. It's a critical part of understanding the language. And I'm not being snide or anything; I mean that in an earnest, respectful way. Seriously, it's really important, because you're not getting what minification does and how 3rd-party scripts interact with host scripts.

First off, a private scope is just that: PRIVATE. There is no way a 3rd-party plugin has access to anything in a private scope (more on that assertion later), so it doesn't matter one bit what the variables and functions inside it are renamed to. That is really a fundamental part of JavaScript -- you have to understand that before you can understand how minification works. So no: a "host" can minify its private variables and functions all they want, even renaming them on every page view for all any other script cares about. You're totally wrong on that assertion.

Secondly, that scenario you gave is exactly why AjaxMin doesn't rename global variable/functions or object property/method names. THOSE are the parts that can be shared across modules -- and AjaxMin doesn't touch those. Well, that's not entirely true; a developer CAN touch those, but not in an automated manner. If you create a static XML file, you can rename global variable/function and property/method names using the -rename switch, but as you mention, if the developer chooses to do so, it is extremely important that he doesn't change that XML mapping willy-nilly because who knows who else might be referencing something you rename.

Now, let's go back to my first assertion: actually there is a way to access private variables and functions via 3rd-party script in JavaScript: if you embed an eval-statement way down in your scope tree, load some third-party code into a string and execute it with that statement, the code you execute will have access to all the private variables and functions in that scope and all parent scopes. I consider that really bad coding that should be avoided for SO many reasons (not least of all Security), but if the developer chooses to do that, they should use the -evals switch of AjaxMin. The default value is "ignore," which means AjaxMin ignores eval-statements, so unless you are eval-ing JSON data (or any other code that has no dependency whatsoever on your host code), don't use evals. Seriously, there are usually plenty of better, more secure ways to code JavaScript than evals. But if you must use evals, you have to decide whether the code you execute will access private variables/functions only within the scope in which the eval-statement resides (in which case use "immediate" for the switch value), or the code is wide open and can access anything in the entire scope stack (in which case use "safeall"). Using those flags means AjaxMin won't automatically rename any variables in those scope(s), precisely because the third-party script being executed by the eval-statement might access them, and it can't be expected to know what name they happen to be minified to this time. But again, if one is using eval-statements, I say (and this is my personal opinion) they are doing it wrong.

With-statements are the other kink in the minification story, but don't use with-statements. In fact, if you mark your script as "strict" (and I strongly irge everyone to do so), using a with-statement will throw an error. It's just bad and should be avoided at all costs. But if you insist on using one, AjaxMin won't rename any variables referenced within the with-statement, nor any parent-scope variables of the same name. Every time I see a with-statement in someone's JavaScript code, I cry just like that Native American from the littering PSAs of my youth.

If you want to read up on scopes and closures and private variables/functions, I would suggest first going to He has great tutorials on JavaScript, how it works, and what all these things I've been talking about mean. From there, a Bing search for "JavaScript closures" will give you a wealth of documentation. In a nutshell:

  • Every function is its own "scope." Variables and functions defined within that scope are accessable only to that scope and any child scopes.
  • Functions can contain functions, thereby creating a scope tree. A child scope has access to its variables and functions, plus all variables and functions in all parent scopes. This creates the "closure" aspect of JavaScript which is incredibly useful if you understand how it all works.
  • Everyone has access to the "global scope."
  • Whenever a variable name is encountered, the current scope is first checked to see if there is something with that name defined within it. If so, that value is referenced; if not, the parent scope is checked recursively up the chain.
  • The global scope in a browser is essentially the window object. All global variables and functions you define are created as properties on the window object - even ones you didn't mean to define.
  • In browsers other than IE, the catch-block of a try-catch statement defines the error variable as the only private variable in the scope of the catch-block. For IE, there is no separate catch-scope and the error variable is defined within the parent scope.
  • In browsers other than IE, the name of a named function expression is only defined within the function expression (and any child scopes). In IE, the name of the function expression is also available to its parent scope.
  • The with-statement evaluates the expression within it's parentheses, then places the results as an object onto the scope stack. So any variables/functions referenced inside the statement will first see if there is a property on the scoped object with that name; if so, it will use it, otherwise it will continue up the scope chain to resolve the name.

I've greatly simplified things here. If you really want to get into the soup-to-nuts details, get a hold of a copy of the ECMA-262 specification and read up on it. There are actually two types of "environments": delcarative and object. And every scope has two pointers: the lexical environment and the variable environment. The lexical environment is used to dereference names (variables and functions), and the variable environment is used to define names. For function scopes, both pointers point to the same declarative environment. For with-statements, the lexical environment points to an object environment created from the results of the expression, and is a child to the variable environment. For catch-blocks, the lexical environment points to a declarative environment with just the error variable defined within it, which is a child of the variable environment. The pointers for the global scope are also the same, but they both point to an object environment created from the window object, and doesn't have a parent environment.

Again, it's a HUGE topic, so take some time to read up on it. People who say JavaScript is some sort of toy language don't understand scopes and the power they bring to the table. JavaScript is an actual object-oriented language that satisfies the three criteria of OOP: polymorphism, encapsulation, and inheritance. Scopes are the key to encapsulation (prototype is the key to inheritance, and JavaScript goes to the extreme for polymorphism).

Hope that helps!

Apr 24, 2012 at 9:58 PM

I meant what's the importance of scopes for minification, why not use the same obfuscated name if you already encountered it in the past?

Basically why a dictionary like the one I'm talking about needs to have anything beyond elemWidth=a1, elemHeight=a2.


I've used obfuscators (programs, not embeddable - which is what I'm looking for now) before and I always obfuscated 99% of the code, having "public" functions with full names is just too easy. Maybe it's the difference in terminology - minification vs. obfuscation. (I also asked in a different thread recently on how to force renaming of all the functions, even the public ones)


Apr 24, 2012 at 10:41 PM

Basically names aren't minified, fields are. The same name might point to completely different fields in different scopes, so it really doesn't matter what the original name is. To optimize the length of the resulting code, I [in general] minify the most-often-referenced fields in a scope first, so a field referenced twenty times might have fewer characters representing it in the resulting references than a field referenced only twice; unused fields don't skew the results; and therefore less code is generated. There are other considerations: the entropy of the code greatly affects the gzipped results, so for instance I rename function arguments first before I rename declared variables and functions, regardless of reference count. But for the most part the number of references a field has influences when it gets renamed, which determines what the final name ends up being. Google closure compiler even goes a step further: they will actually combine references to the same field if they determine that those different references don't overlap (I love that feature)!

Apr 24, 2012 at 10:45 PM

Oh, and for the second part of your question, AjaxMin is not an obfuscator. Sure, minification makes it really hard to read and debug, but that is not the purpose of the tool. The sole purpose is to reduce the number of bytes downloaded to the client, thereby increasing the performance of a web page, while allowing developers to write easy-to-read and maintain source files. Obfuscation is merely a sometimes-good/sometimes-bad side-effect.

Apr 24, 2012 at 11:49 PM

I'll be truly sad to fall back to running java based command-line obfuscators from .Net (*shudder*), especially after I got really excited after finding this library, as it's the only .Net minifier that looked close to what I'm looking for.

Thank you

Apr 25, 2012 at 12:02 AM

I still don't see why you can't use AjaxMin as it currently stands. There is no renaming issue as you described. Huge sites have been using this tool for years -- sites that integrate a lot of third-party scripts from Facebook, Twitter, and many, many other partners. Is this naming file really the only thing holding you up? And if so, I still don't understand why it's an issue.

Apr 25, 2012 at 1:42 PM

I have 3 requirements:

  1. Obfuscate static files, including "public" things - basically everything besides javascript reserved names, but it needs to be configurable (i.e. allow to preserve specific names I specify)

  2. Obfuscate dynamic responses, based on the result of the static obfuscations
      For example, if `variableA` was encountered when obfuscating the statics, the same obfuscated name will be used in obfuscation of the dynamic response

  3. Use additional list of "constants" - like I asked here


What we know now - 1st isn't completely supported, what you've said about scopes and how the library handles naming, makes me think that the 2nd item is also pretty hard to accomplish.


Apr 25, 2012 at 3:52 PM

1. supported. See the "-rename NFILE" syntax. You create an XML file with your name mappings and pass that file to AjaxMin. It will rename your publics those specific names every time.

2. supported, given the above. The only thing that matters are the public renamings, and those are supported as per #1. I still maintain it doesn't matter what privates are renamed. If you really need your private variables and functions consistently renamed, AjaxMin just doesn't support that at this time.

3. I still plan on doing this because it was a very good idea. Just haven't had the time yet.

Apr 27, 2012 at 5:22 PM
Edited Apr 27, 2012 at 5:26 PM

The problem here is that the XML has to be created (and populated) manually. It makes the process awkward, slow and prone to error.

The two features I was talking about can actually make the XML approach useful and fun:

1) renaming of public things switch
2) dictionary output (same XML format as input)

Manipulating an existing file is so much easier than typing out an XML and manually looking for public function names. You run ajaxmin once to get an XML "analysis" dictionary (that includes the obfuscated names), then you play with the dictionary, moving things between "obfuscate" and "keep", and run ajaxmin again

To me, it sounds like a great feature that not only makes the XML approach a lot more useful, but also makes the minification process itself help with development - suppose that the minification is part of the build and QA tells you that in their environment, firebug complains about some a12 or p93 variable. Wouldn't it be nice to be able to know what these are, just by peeking at the minification dictionary?

regading #3 - the approach I've used with obfuscators before - I had a constants.js file that had a bunch of these lines:


VAR1 = 15;

In development, I'd call the script file, after obfuscation, I didn't have to, because all VAR1 turned into 15. Would be nice if this kind of approach was somehow supported - cause it's REALLY useful :)