$30 off During Our Annual Pro Sale. View Details »

JavaScript Transformation - JSConf 2015

JavaScript Transformation - JSConf 2015

sebmck

May 31, 2015
Tweet

More Decks by sebmck

Other Decks in Programming

Transcript

  1. JavaScript transformation

    View Slide

  2. Sebastian McKenzie
    @sebmck
    Web Content Optimisation @ CloudFlare

    View Slide

  3. JavaScript transformation

    View Slide

  4. JavaScript transformation
    myOldWeirdJavaScript(“whatever”);
    myNewTransformedJavaScript(“yay!”);

    View Slide

  5. History

    View Slide

  6. View Slide

  7. View Slide

  8. View Slide

  9. View Slide

  10. View Slide

  11. View Slide

  12. How?

    View Slide

  13. Source code
    var foo = function foo() {
    return bar;
    };

    View Slide

  14. {
    type: "Program",
    body: [{
    type: "VariableDeclaration"
    kind: "var",
    declarations: [{
    type: "VariableDeclarator",
    id: { type: "Identifier", name: "foo" },
    init: {
    type: “FunctionExpression",
    id: { type: “Identifier”, name: “foo” },
    params: [],
    body: [{
    type: "BlockStatement",
    body: [{
    type: "ReturnStatement",
    argument: { type: "Identifier", name: "bar" }
    }]
    }]
    }
    }]
    }]
    }
    AST

    View Slide

  15. AST
    Variable
    Declaration
    Program
    Variable
    Declarator
    Identifier
    Function
    Expression
    Block
    Statement
    Return
    Statement
    Identifier

    View Slide

  16. Transformer
    Manipulates AST
    Parser
    Turns code into an AST
    Generator
    Turns AST back into code

    View Slide

  17. Parser
    Transformer
    Generator

    View Slide

  18. Function
    Declaration
    Block
    Statement
    Return
    Statement
    Program
    Variable
    Declaration
    Variable
    Declarator
    Identifier
    Function
    Expression
    Block
    Statement
    Return
    Statement
    Identifier
    Traversal
    Visitor

    View Slide

  19. Replacement
    [x, y] = calculateCoordinates();

    View Slide

  20. Replacement
    var _ref = calculateCoordinates();
    x = _ref[0];
    y = _ref[1];

    View Slide

  21. Replacement
    doSomething([x, y] = calculateCoordinates());

    View Slide

  22. Replacement
    doSomething(var _ref = calculateCoordinates());
    x = _ref[0];
    y = _ref[1];);

    View Slide

  23. Replacement
    var _ref;
    doSomething((_ref = calculateCoordinates(), x =
    _ref[0], y = _ref[1], _ref));

    View Slide

  24. Removal
    left + right;
    Right
    Left
    Binary
    Expression

    View Slide

  25. Removal
    left +;
    Left
    Binary
    Expression

    View Slide

  26. Removal
    left; Left

    View Slide

  27. Uses
    • Transpilation
    • Application optimisation
    • Browser compatibility
    • Minification
    • Obfuscation
    • Hot reloading
    • Code coverage
    • Language experimentation
    • Conditional compilation
    • Dynamic polyfill inclusion
    • Module mocking
    • Code linting
    • Execution tracing
    • Intellisense
    • Profiling
    • Refactoring
    • Dependency analysis
    • Instrumentation
    • Module bundling
    • …

    View Slide

  28. • Transpilation (ie. ES2015 to ES5)
    • Application optimisation
    • Browser compatibility
    • ??? ✨

    View Slide

  29. View Slide

  30. View Slide

  31. • Additional standard lib methods
    • Arrow functions
    • Block scoping
    • Classes
    • Collections
    • Computed properties
    • Constants
    • Destructuring
    • Default and rest parameters
    • Generators
    • Iterators and for…of
    • Modules
    • Promises
    • Property method and value
    shorthand
    • Proxies
    • Spread
    • Sticky and unicode regexes
    • Symbols
    • Subclassable built-ins
    • Template literals
    • Better unicode support
    • Binary and octal literals
    • Reflect API
    • Tail calls

    View Slide

  32. View Slide

  33. View Slide

  34. ES2015 Arrow Functions
    var multiply = (num) => num * num;

    View Slide

  35. ES2015 Arrow Functions
    • Implicit return for expression bodies
    • “Inherits” arguments and this binding
    • Cannot new it
    • No prototype

    View Slide

  36. Implicit return for
    expression bodies
    var multiple = (num) => num * num;
    // turns into
    var multiply = function (num) {
    return num * num;
    };

    View Slide

  37. ES2015 Arrow Functions
    • Implicit return for expression bodies
    • “Inherits” arguments and this binding
    • Cannot new it
    • No prototype

    View Slide

  38. arguments and this
    var bob = {
    name: “Bob”
    friends: [“Amy”],
    printFriends() {
    this.friends.forEach(f =>
    console.log(this.name + " knows " + f)
    );
    }
    };

    View Slide

  39. arguments and this
    var bob = {
    name: “Bob”,
    friends: [“Amy”],
    printFriends() {
    var _this = this;
    this.friends.forEach(function (f) {
    return console.log(_this.name + " knows " + f);
    });
    }
    };

    View Slide

  40. ES2015 Arrow Functions
    • Implicit return for expression bodies
    • “Inherits” arguments and this binding
    • Cannot new it
    • No prototype


    View Slide

  41. no new
    var foo = () => {};
    new foo; // should be illegal!

    View Slide

  42. no new
    function _construct(obj) {
    if (obj.name === “_arrow”)
    throw new Error(“nope”);
    return new obj;
    }
    var foo = function _arrow() {};
    _construct(foo);

    View Slide

  43. no new
    function _construct(obj) {
    if (obj._arrow === “_arrow”)
    throw new Error(“nope”);
    return new obj;
    }
    var foo = function () {};
    foo._arrow = true;
    _construct(foo);

    View Slide

  44. View Slide

  45. • Implicit return for expression bodies
    • “Inherits” arguments and this binding
    • Cannot new it
    • No prototype

    ES2015 Arrow Functions


    View Slide

  46. no prototype
    var foo = () => {};
    foo.prototype; // should be undefined!

    View Slide

  47. no prototype
    function _getPrototype(obj) {
    if (obj._arrow) {
    return undefined;
    } else {
    return obj.prototype;
    }
    }
    var foo = function () {};
    foo._arrow = true;
    _getPrototype(foo);

    View Slide

  48. no prototype
    var bar = “prototype”;
    var foo = () => {};
    foo[bar];

    View Slide

  49. no prototype
    function get(obj, key) {
    if (key === “prototype”) {
    return obj._arrow ? undefined : obj.prototype;
    } else {
    return obj[key];
    }
    }
    var bar = “prototype”;
    var foo = () => {};
    get(foo, bar);

    View Slide

  50. View Slide

  51. View Slide

  52. Do not use transpilers as a basis to learn
    new language features

    View Slide

  53. View Slide

  54. Compile-time vs Runtime
    function square(num) {
    return num * num;
    }
    square(2);
    square(age);

    View Slide

  55. View Slide

  56. JSX
    var foo =
    {text}
    ;

    View Slide

  57. JSX Constant Elements
    function render() {
    return ;
    }

    View Slide

  58. JSX Constant Elements
    var foo = ;
    function render() {
    return foo;
    }

    View Slide

  59. JSX Constant Elements
    var Foo = require(“Foo”);
    function createComponent(text) {
    return function render() {
    return {text};
    };
    }

    View Slide

  60. JSX Constant Elements
    var Foo = require(“Foo”);
    function createComponent(text) {
    var foo = {text};
    return function render() {
    return foo;
    };
    }

    View Slide

  61. View Slide

  62. Precompiling tagged templates
    import hbs from “htmlbars-inline-precompile";
    var a = hbs``;

    View Slide

  63. import hbs from “htmlbars-inline-precompile";
    var a = Ember.HTMLBars.template(function() {
    /* crazy HTMLBars template function stuff */
    });
    Precompiling tagged templates

    View Slide

  64. • Shouldn’t rely on preprocessing for functionality
    • YOU can make assumptions about your code
    • JS engine can’t be more lenient

    View Slide

  65. View Slide

  66. View Slide

  67. Named function expressions
    var f = function g() {};
    typeof g === “function”; // true
    f === g; // false
    https://kangax.github.io/nfe/#jscript-bugs

    View Slide

  68. What’s the solution?

    View Slide

  69. export function FunctionExpression(node, print) {
    if (!node.id) return;
    return t.callExpression(
    t.functionExpression(null, [], t.blockStatement([
    t.toStatement(node),
    t.returnStatement(node.id)
    ])),
    []
    );
    }
    Automate it!

    View Slide

  70. Result
    var f = function g() {};
    // becomes
    var f = (function () {
    function g() {}
    return g;
    })();

    View Slide

  71. Emojification
    Emojification

    View Slide

  72. ES2015
    • Unicode code point escapes
    • var \u{1F605} = “whatever";
    • Emojis

    View Slide

  73. View Slide

  74. View Slide

  75. View Slide

  76. How?
    $ npm install babel babel-plugin-emojification
    $ babel --plugins emojification script.js

    View Slide

  77. myOldWeirdJavaScript(“whatever”);
    myNewTransformedJavaScript(“yay!”);

    View Slide

  78. View Slide