ECMAScript tools

composable modules and transpiler infrastructure


Yusuke Suzuki (a.k.a Constellation)

self introduction

GitHub screenshot

background

ECMAScript everywhere

ECMAScript is now widely used

And ECMAScript tools are also developed widely

ECMAScript tools

Problem - Transpiler

Problem - SourceMap

Problem - SourceMap

SourceMap problem

To solve it

Transpiler must also do minify task...


As the result, current complex ECMAScript tools become all-in-one because of lack of composability

composable modules

Why aren't they composable?

Because they use raw script text as IR


passing raw text

IR

We suggest using Mozilla JS AST as IR

Parser API AST

AST example

var i = 42;
{
    "type": "Program",
    "body": [
        {
            "type": "VariableDeclaration",
            "declarations": [
                {
                    "type": "VariableDeclarator",
                    "id": {
                        "type": "Identifier",
                        "name": "i"
                    },
                    "init": {
                        "type": "Literal",
                        "value": 42
                    }
                }
            ],
            "kind": "var"
        }
    ]
}

AST as IR

By using AST as IR, we can pass rich information

And we can develop modules using AST as IR and compose them

modules

Introduction

We'll introduce mainly 3 modules

Esprima

ECMAScript parsing infrastructure for multipurpose analysis : link

Esprima page

Esprima

Esprima provides complete ECMAScript parser (including strict-mode syntax check)

Parser demo

Esprima tree

Esprima

InputJavaScript code
OutputMozilla JavaScript AST
Esprima use

Escodegen

ECMAScript code generator : link

Escodegen page

Escodegen

Escodegen provides ECMAScript code generator

code generator demo


principle:

// structurally equal
parse(generate(parse(code))) === parse(code)

Escodegen do not mangle names and do other things

This keeps module simple and composable

Escodegen

InputMozilla JavaScript AST
OutputJavaScript
Esprima use

Esmangle

ECMAScript mangler / minifier / optimizer : link

Esmangle page

Esmangle

Esmangle doesn't parse / generate code. It's only responsible to optimizing AST

function upperBound(array, func) {
    var diff, len, i, current;

    len = array.length;
    i = 0;

    while (len) {
        diff = len >>> 1;
        current = i + diff;
        if (func(array[current])) {
            len = diff;
        } else {
            i = current + 1;
            len -= diff + 1;
        }
    }
    return i;
}
function upperBound(e,f){var b,a,c,d;a=e.length,c=0;while(a)b=a>>>1,d=c+b,f(e[d])?a=b:(c=d+1,a-=b+1);return c}

Esmangle

Esmangle consists of many small pass functions. We apply them to AST iteratively to resolve fixed point of AST like compiler.

InputMozilla JavaScript AST
OutputMozilla JavaScript AST
Esmangle use

Because it uses AST as IR, modules can preserve original line/column information

And other tools

For example...


And we can develop other small (or large) modules using AST as IR

combine them to large tools

Modules are composable

Because they use standarized IR - Mozilla JS AST

We can use them and combine them into large tools


These modules become transpiler infrastructure!

Example 1 : Esmangle minifier

Esmangle minifier

It can produce SourceMap to original code

Esmangle minifier

Example 2 : CoffeeScriptRedux

new CoffeeScript compiler - well-modularized compiler

CoffeeScriptRedux compiler uses Escodegen as its backend

CoffeeScriptRedux

Example 3 : sweet.js

Sweet.js brings hygienic macros from languages like Scheme and Rust to JavaScript

sweet.js also uses Escodegen as its backend

sweet.js sweet.js preview

Example 4 : istanbul

istanbul is coverage tool using Esprima & Escodegen

istanbul

istanbul screen shot

istanbul preview

Other examples

And...

If we develop modules using AST as IR, we can apply them to all transpiling languages that produce AST

For example...

conclusion

Conclusion

Any Questions?