RReverser's

Ingvar Stepanyan

JavaScript developer, speaker and reverse engineer. D2D programmer. Sometimes human.


Using Mozilla AST with UglifyJS

Hi there.

I'm continuing my work on tools for manipulating SpiderMonkey AST - as creating new as well as improving existing ones.

This time it was UglifyJS.

It's great JavaScript minifier, but what always bothered me (and other developers) was incompatibility of it's internal AST representation and Mozilla format, and so impossibility of combining it with other tools without dirty and slow hacks like:

  1. Transform Mozilla AST to UglifyJS AST (thanks Mihail, we already got method for this).
  2. Compress, mangle etc. it with UglifyJS API.
  3. Generate code and source map with UglifyJS API.
  4. Parse generated code with either esprima or acorn.
  5. Translate generated source map onto existing AST with sourcemap-to-ast helper.

(I had to use this hackchain for aster-uglify)

So I've decided to add back-conversion from UglifyJS to SpiderMonkey AST format, and it's already landed in UglifyJS!

Now you can use UglifyJS as any other intermediate tool for transforming JavaScript ASTs using it's native API.

Example:

// Parsing
var ast = acorn.parse(code, {  
  locations: true,
  ranges: true
});

// Any AST pre-transformations here
ast = preTransform(ast);

// Conversion
var uAST = UglifyJS.AST_Node.from_mozilla_ast(ast);

// Compression
var compressor = UglifyJS.Compressor(options);  
uAST.figure_out_scope();  
uAST = uAST.transform(compressor);

// Mangling (optional)
uAST.figure_out_scope();  
uAST.compute_char_frequency();  
uAST.mangle_names();

// Back-conversion
ast = uAST.to_mozilla_ast();

// Any AST post-transformations here
ast = postTransform(ast);

// Generating output code and source map
var output = escodegen.generate(ast, {  
  sourceMapWithCode: true,
  sourceMap: true
});

// Done!

UPDATE

In Twitter, I was asked about speed of such conversion, so decided to show timings for above example executed against jQuery v1.11.1 development source without pre-/post-transformations:

Parsing:             175ms   (5%)  
Conversion:          148ms   (4%)  
Compression:         2155ms  (56%)  
Mangling:            502ms   (13%)  
Back-conversion:     48ms    (1%)  
Generating output:   829ms   (21%)  

Or, in grouped view:

I/O             1004ms  (26%)  
Conversions     196ms   (5%)  
Compressions    2657ms  (69%)  

So, as you can see, speed of conversions has negligible performance impact.

comments powered by Disqus