JavaScript Transformation - JSConf 2015

JavaScript Transformation - JSConf 2015

9b7cbca4917f83679696b0924d0ed09d?s=128

sebmck

May 31, 2015
Tweet

Transcript

  1. JavaScript transformation

  2. Sebastian McKenzie @sebmck Web Content Optimisation @ CloudFlare

  3. JavaScript transformation

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

  5. History

  6. None
  7. None
  8. None
  9. None
  10. None
  11. None
  12. How?

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

    };
  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
  15. AST Variable Declaration Program Variable Declarator Identifier Function Expression Block

    Statement Return Statement Identifier
  16. Transformer Manipulates AST Parser Turns code into an AST Generator

    Turns AST back into code
  17. Parser Transformer Generator

  18. Function Declaration Block Statement Return Statement Program Variable Declaration Variable

    Declarator Identifier Function Expression Block Statement Return Statement Identifier Traversal Visitor
  19. Replacement [x, y] = calculateCoordinates();

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

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

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

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

    = _ref[1], _ref));
  24. Removal left + right; Right Left Binary Expression

  25. Removal left +; Left Binary Expression

  26. Removal left; Left

  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 • …
  28. • Transpilation (ie. ES2015 to ES5) • Application optimisation •

    Browser compatibility • ??? ✨
  29. None
  30. None
  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
  32. None
  33. None
  34. ES2015 Arrow Functions var multiply = (num) => num *

    num;
  35. ES2015 Arrow Functions • Implicit return for expression bodies •

    “Inherits” arguments and this binding • Cannot new it • No prototype
  36. Implicit return for expression bodies var multiple = (num) =>

    num * num; // turns into var multiply = function (num) { return num * num; };
  37. ES2015 Arrow Functions • Implicit return for expression bodies •

    “Inherits” arguments and this binding • Cannot new it • No prototype ✓
  38. arguments and this var bob = { name: “Bob” friends:

    [“Amy”], printFriends() { this.friends.forEach(f => console.log(this.name + " knows " + f) ); } };
  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); }); } };
  40. ES2015 Arrow Functions • Implicit return for expression bodies •

    “Inherits” arguments and this binding • Cannot new it • No prototype ✓ ✓
  41. no new var foo = () => {}; new foo;

    // should be illegal!
  42. no new function _construct(obj) { if (obj.name === “_arrow”) throw

    new Error(“nope”); return new obj; } var foo = function _arrow() {}; _construct(foo);
  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);
  44. None
  45. • Implicit return for expression bodies • “Inherits” arguments and

    this binding • Cannot new it • No prototype ✗ ES2015 Arrow Functions ✓ ✓
  46. no prototype var foo = () => {}; foo.prototype; //

    should be undefined!
  47. no prototype function _getPrototype(obj) { if (obj._arrow) { return undefined;

    } else { return obj.prototype; } } var foo = function () {}; foo._arrow = true; _getPrototype(foo);
  48. no prototype var bar = “prototype”; var foo = ()

    => {}; foo[bar];
  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);
  50. None
  51. None
  52. Do not use transpilers as a basis to learn new

    language features
  53. None
  54. Compile-time vs Runtime function square(num) { return num * num;

    } square(2); square(age);
  55. None
  56. JSX var foo = <div> <span className=“foobar”>{text}</span> </div>;

  57. JSX Constant Elements function render() { return <div className="foo" />;

    }
  58. JSX Constant Elements var foo = <div className="foo" />; function

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

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

    var foo = <Foo>{text}</Foo>; return function render() { return foo; }; }
  61. None
  62. Precompiling tagged templates import hbs from “htmlbars-inline-precompile"; var a =

    hbs`<a href={{url}}></a>`;
  63. import hbs from “htmlbars-inline-precompile"; var a = Ember.HTMLBars.template(function() { /*

    crazy HTMLBars template function stuff */ }); Precompiling tagged templates
  64. • Shouldn’t rely on preprocessing for functionality • YOU can

    make assumptions about your code • JS engine can’t be more lenient
  65. None
  66. None
  67. Named function expressions var f = function g() {}; typeof

    g === “function”; // true f === g; // false https://kangax.github.io/nfe/#jscript-bugs
  68. What’s the solution?

  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!
  70. Result var f = function g() {}; // becomes var

    f = (function () { function g() {} return g; })();
  71. Emojification Emojification

  72. ES2015 • Unicode code point escapes • var \u{1F605} =

    “whatever"; • Emojis
  73. None
  74. None
  75. None
  76. How? $ npm install babel babel-plugin-emojification $ babel --plugins emojification

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

  78. None