JavaScript Transformation - React Europe 2015

9b7cbca4917f83679696b0924d0ed09d?s=47 sebmck
July 06, 2015

JavaScript Transformation - React Europe 2015

9b7cbca4917f83679696b0924d0ed09d?s=128

sebmck

July 06, 2015
Tweet

Transcript

  1. Sebastian McKenzie @sebmck

  2. JAVASCRIPT TRANSFORMATION

  3. None
  4. None
  5. None
  6. None
  7. None
  8. None
  9. WHAT IS CODE TRANSFORMATION?

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

  11. HOW DOES IT WORK?

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

    code
  13. AST Abstract Syntax Tree

  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" } }] }] } }] }] } Data structure
  15. Identifier Graph Variable Declaration Program Variable Declarator Identifier Function Expression

    Block Statement Return Statement Identifier
  16. List • Program • VariableDeclaration • VariableDeclarator • Identifier •

    FunctionExpression • Identifier • BlockStatement • ReturnStatement • Identifier
  17. Parser Turns code into an AST Transformer Manipulates AST Generator

    Turns AST back into code Parser Turns code into an AST Transformer and Generator Traverses AST and manipulates it via strings jstransform Parser Turns code into an AST
  18. Lexical Analysis Turn code into a stream of tokens Syntactic

    Analysis Turn tokens into a tree Parser Turns code into an AST
  19. Turn your code into tokens LEXICAL ANALYSIS

  20. foo = 1 + “bar”; What is a token?

  21. foo = 1 + “bar”; What is a token? Identifier

    Punctuator Number String 1. Identifier<foo> 2. Punctuator<=> 3. Number<1> 4. Punctuator<+> 5. String<bar> 6. Puncutator<;>
  22. SYNTACTIC ANALYSIS Turn the tokens into a tree

  23. class Foo extends Bar {} Syntactic analysis

  24. class Foo extends Bar {} pp.parseClassDeclaration = function () {

    let node = this.startNode(); this.expect(tt._class); node.id = this.parseIdentifier(); if (this.type === tt._extends) { this.next(); node.superClass = this.parseExprSubscripts(); }; node.body = this.parseClassBody(); return this.finishNode(node, "ClassDeclaration"); }; Identifier Punctuator Keyword 1. Keyword<class> 2. Identifier<Foo> 3. Keyword<extends> 4. Identifier<Bar> 5. Punctuator<{> 6. Punctuator<}> Syntactic analysis
  25. pp.parseClassDeclaration = function () { let node = this.startNode(); this.expect(tt._class);

    node.id = this.parseIdentifier(); if (this.type === tt._extends) { this.next(); node.superClass = this.parseExprSubscripts(); }; node.body = this.parseClassBody(); return this.finishNode(node, "ClassDeclaration"); }; 1. Keyword<class> 2. Identifier<Foo> 3. Keyword<extends> 4. Identifier<Bar> 5. Punctuator<{> 6. Punctuator<}> Syntactic analysis
  26. pp.parseClassDeclaration = function () { let node = this.startNode(); this.expect(tt._class);

    node.id = this.parseIdentifier(); if (this.type === tt._extends) { this.next(); node.superClass = this.parseExprSubscripts(); }; node.body = this.parseClassBody(); return this.finishNode(node, "ClassDeclaration"); }; 1. Keyword<class> 2. Identifier<Foo> 3. Keyword<extends> 4. Identifier<Bar> 5. Punctuator<{> 6. Punctuator<}> Syntactic analysis
  27. pp.parseClassDeclaration = function () { let node = this.startNode(); this.expect(tt._class);

    node.id = this.parseIdentifier(); if (this.type === tt._extends) { this.next(); node.superClass = this.parseExprSubscripts(); }; node.body = this.parseClassBody(); return this.finishNode(node, "ClassDeclaration"); }; 1. Keyword<class> 2. Identifier<Foo> 3. Keyword<extends> 4. Identifier<Bar> 5. Punctuator<{> 6. Punctuator<}> Syntactic analysis
  28. pp.parseClassDeclaration = function () { let node = this.startNode(); this.expect(tt._class);

    node.id = this.parseIdentifier(); if (this.type === tt._extends) { this.next(); node.superClass = this.parseExprSubscripts(); }; node.body = this.parseClassBody(); return this.finishNode(node, "ClassDeclaration"); }; 1. Keyword<class> 2. Identifier<Foo> 3. Keyword<extends> 4. Identifier<Bar> 5. Punctuator<{> 6. Punctuator<}> Syntactic analysis
  29. pp.parseClassDeclaration = function () { let node = this.startNode(); this.expect(tt._class);

    node.id = this.parseIdentifier(); if (this.type === tt._extends) { this.next(); node.superClass = this.parseExprSubscripts(); }; node.body = this.parseClassBody(); return this.finishNode(node, "ClassDeclaration"); }; 1. Keyword<class> 2. Identifier<Foo> 3. Keyword<extends> 4. Identifier<Bar> 5. Punctuator<{> 6. Punctuator<}> Syntactic analysis
  30. pp.parseClassDeclaration = function () { let node = this.startNode(); this.expect(tt._class);

    node.id = this.parseIdentifier(); if (this.type === tt._extends) { this.next(); node.superClass = this.parseExprSubscripts(); }; node.body = this.parseClassBody(); return this.finishNode(node, "ClassDeclaration"); }; 1. Keyword<class> 2. Identifier<Foo> 3. Keyword<extends> 4. Identifier<Bar> 5. Punctuator<{> 6. Punctuator<}> Syntactic analysis
  31. pp.parseClassDeclaration = function () { let node = this.startNode(); this.expect(tt._class);

    node.id = this.parseIdentifier(); if (this.type === tt._extends) { this.next(); node.superClass = this.parseExprSubscripts(); }; node.body = this.parseClassBody(); return this.finishNode(node, "ClassDeclaration"); }; 1. Keyword<class> 2. Identifier<Foo> 3. Keyword<extends> 4. Identifier<Bar> 5. Punctuator<{> 6. Punctuator<}> Syntactic analysis
  32. pp.parseClassDeclaration = function () { let node = this.startNode(); this.expect(tt._class);

    node.id = this.parseIdentifier(); if (this.type === tt._extends) { this.next(); node.superClass = this.parseExprSubscripts(); }; node.body = this.parseClassBody(); return this.finishNode(node, "ClassDeclaration"); }; 1. Keyword<class> 2. Identifier<Foo> 3. Keyword<extends> 4. Identifier<Bar> 5. Punctuator<{> 6. Punctuator<}> Syntactic analysis
  33. { type: "ClassDeclaration", start: 0, end: 23, id: { type:

    “Identifier", start: 6, end: 9, name: “Foo" }, superClass: { type: “Identifier", end: 21, start: 18, name: “Bar" }, body: { type: “ClassBody", start: 21, end: 23, body: [] } } Syntactic analysis
  34. Identifier Class Declaration Identifier Class Body Syntactic analysis

  35. Transformer Manipulates AST Traversal Visit the tree Static Analysis Infer

    what nodes represent
  36. TRAVERSAL Walking the tree

  37. Visitor • Controls traversal state • Interface for visiting, replacing

    and removing nodes • Consolidates visiting logic
  38. Traversal Visitor Variable Declaration Program Variable Declarator Identifier Function Expression

    Block Statement Return Statement Identifier
  39. STATIC ANALYSIS Infer what your code does by how it

    looks
  40. var foo = bar + “”; Type inference Variable Declaration

    Program Variable Declarator Identifier Binary Expression Literal Identifier
  41. Transpilation var [x, y] = [1, 2]; var _ref =

    [1, 2]; var x = _ref[0]; var y = _ref[1];
  42. Transpilation var [x, y] = [1, 2]; var x =

    1; var y = 2;
  43. PATHS Bidirectional reactive AST abstraction

  44. Identifier Function Expression Block Statement Return Statement Identifier Unidirectional tree

    Variable Declaration Program Variable Declarator Identifier Identifier
  45. Path Path Path Path Variable Declaration Program Variable Declarator Function

    Expression Identifier
  46. Identifier Variable Declaration Program Variable Declarator Identifier Function Expression Block

    Statement Return Statement Identifier argument body[0] Root declarations [0] id init body body[0] id Bidirectional tree
  47. Path • Abstraction for dealing with node relationships • Constant,

    same-instance always • Reactive to tree changes - propagates updates
  48. CONTEXTLESS REPLACEMENT Transforming broken code

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

  50. Path-based replacement var _ref = calculateCoordinates(); x = _ref[0]; y

    = _ref[1];
  51. Path-based replacement doSomething([x, y] = calculateCoordinates());

  52. Path-based replacement doSomething(var _ref = calculateCoordinates()); x = _ref[0]; y

    = _ref[1];);
  53. Path-based replacement var _ref; doSomething((_ref = calculateCoordinates(), x = _ref[0],

    y = _ref[1], _ref));
  54. Style Inference Retain input style in output Code Generation Turn

    the tree into code Generator Turns AST back into code
  55. Transformer Manipulates AST Generator Turns AST back into code Parser

    Turns code into an AST Lexical Analysis Turn code into tokens Syntactic Analysis Turn tokens into a tree Traversal Visit the tree Static Analysis Infer what nodes represent Code Generation Turn the tree into code Style Inference Retain input style in output
  56. HOW’S THIS USEFUL?

  57. JSX OPTIMISATION

  58. CONSTANT ELEMENTS A React element is conceptually equivalent if all

    it’s values are the same.
  59. Constant value types function render() { return <div className=“header” />;

    } render() === render();
  60. var _ref = React.createElement("div", { className: “foo" }); function render()

    { return _ref; } React 0.14 Constant hoisting function render() { return React.createElement("div", { className: “foo" }); } React <= 0.13
  61. INLINE ELEMENTS Building elements ahead of time

  62. Inline elements <div className=“foo”> {bar} <Bar key=“baz” /> </div>

  63. Inline elements ({ type: "div", props: { className: "foo", children:

    [ bar, { type: Baz, props: {}, key: "baz", ref: null } ] }, key: null, ref: null })
  64. SYNTAX EXTENSIONS

  65. DISCLAIMER ES7 DOES NOT MEAN WHAT YOU THINK IT DOES

  66. class Counter extends React.Component { static propTypes = { initialCount:

    React.PropTypes.number }; static defaultProps = { initialCount: 0 }; state = { count: this.props.initialCount }; } Class properties
  67. function autobind(target, key, descriptor) { return { get: function ()

    { return descriptor.value.bind(this); } }; } class Person { @autobind getFullName() { return `${this.firstName} ${this.lastName}`; } } Decorators
  68. class Counter extends React.Component { tick() { this.setState({ count: this.state.count

    + 1 }); } render() { return <div onClick={::this.tick}> Clicks: {this.state.count} </div>; } } Bind syntax
  69. THE FUTURE • Dead code elimination/minification • Constant folding/static evaluation

    • Static analysis/linting
  70. None
  71. Thank you!