2

I am using Google's closure compiler optimization (simple optimization) to reduce the size of some of my JS script files. Whilst this works well I have run into issues with eval statements in some of my functions where replacement of local variables by the compiler wrecks havoc. I could try to recode the offending functions to beat the compiler but that is liable to be painful - and in the long term dangerous since the tricks I use today may well not work tomorrow.

It would be nicer if I could simply mark the bits of code I want the compiler to leave untouched. At present I am contemplating taking all functions that use evals, putting them in a separate file and tagging that file oat the end of the compiler output. However, before I do that I thought it worth asking here - is there a way to tell the compiler to skip optimizations on certain functions. e.g.

//  @compilation_level SIMPLE_OPTIMIZATIONS
function test(one,two)
{

}

function testTwo(alpha,beta)
{

}

// @Closure:Skip

function evalFunc(one,two)
{
 //eval code here
}

//@Closure:EndSkip

The end result - the code between the Skip, EndSkip sections passes through the compiler without any changes.

I have looked through the documentation but have not found anything that might do just this.

halfer
  • 19,824
  • 17
  • 99
  • 186
DroidOS
  • 8,530
  • 16
  • 99
  • 171
  • possible duplicate of [Partially skip sections with Google Closure Compiler](http://stackoverflow.com/questions/10449195/partially-skip-sections-with-google-closure-compiler) – Chad Killingsworth Jul 09 '14 at 15:07
  • For reference: I asked that question on github, too: https://github.com/google/closure-compiler/issues/1282 – BlaM Dec 04 '15 at 10:44

3 Answers3

1

There are a few hints about this problem in the documentation. The proposed skipping feature probably wouldn't solve anything in most cases for the same reason compiling eval usually fails.

If you aren't accessing any variables outside of the scope of evalFunc though, you could try refactoring all local variables to properties using bracket notation and putting all property names in quotes, so they won't be renamed.

For example,

function evalFunc(one) {
    this['foo'] = one;
    eval('alert(foo);');
}
evalFunc.call({}, 1);

will roughly compile to

function(a) {
    this.foo = a; 
    eval("alert(foo);");
};
a.call({}, 1);

keeping the eval working. It works both on simple and advanced mode.

kapex
  • 28,903
  • 6
  • 107
  • 121
  • The compiler should complain about dangerous use of the `this` keyword for your example. Better to use `window` or be explicit to the object. – Chad Killingsworth Jul 09 '14 at 11:46
  • This solution seems like a really bad idea. You basically are putting all the values into global scope and potentially overwriting global values. – John Jul 10 '14 at 00:22
  • You are right, I've added some explicit function context. – kapex Jul 10 '14 at 01:24
1

Thank you, @kapep. As I often think (when I don't think it out aloud), what a great little forum this is! For the benefit of anyone else seeking to do similar things - the original problem I needed to handle was along the lines of

function evalFunc(leNom)
{
 var str,obj = {'age':18};
 obj.name = leNom;
 str = 'var out = obj.name + " is " + obj.age + " years old"';
 eval(str);
 alert(out);
}

Run that through Closure's simple optimizations and you get

  function evalFunc(a){eval('var out = obj.name + " is " + obj.age + " years old"');
  alert(out)};

which falls flat on its face.

change this to

function evalFunc(leNom)
{
 var str;
 this['obj'] = {'age':18};
 this['obj'].name = leNom;
 str = 'var out = obj.name + " is " + obj.age + " years old"';
 eval(str);
 alert(out);
}

and Closure comes back with

function evalFunc(a){this.obj={age:18};this.obj.name=a;
eval('var out = obj.name + " is " + 
obj.age + " years old"');alert(out)};

which works perfectly!

*------------------ A footnote after some testing. If, like I, you cannot avoid evals in your JS and want to compress or otherwise obfuscate your code be warned that the road ahead is strewn with pitfalls. A careless edit is all that is required to break your code. Microsoft's AJAX minifier offers more control over code containing evals so it is perhaps a better solution. However, by far the safest thing to do is to simply take all functions containing evals OUT, place them in a separate file and tag that to the compressed output. In any well written code functions with evals should be relatively infrequent. That along with gzip compression ensures good bandwidth usage whilst at the same time circumventing the nightmares of rogue evals that go wrong after compression.

DroidOS
  • 8,530
  • 16
  • 99
  • 171
  • Seeing that the compiler doesn't touch strings at all, maybe you can put this to your advantage by creating the whole function from a string. – Robert Jul 09 '14 at 09:55
0

You can use the function constructor if the code isn't too complex:

new Function("a", "b" "return eval('a + b')");

John
  • 5,443
  • 15
  • 21