Upgrade to Pro — share decks privately, control downloads, hide ads and more …

HTMLBars, how do I even?

22bb3e56828870ee9a0dd93aeadbe04a?s=47 Godfrey Chan
November 03, 2015

HTMLBars, how do I even?

Three Handlebars templates walk into one of the newly-opened HTMLBars on the block. After having a few drinks, they each put down a $100 bill.

The renderer said to them, “sorry, no change” and left the DOM untouched.

22bb3e56828870ee9a0dd93aeadbe04a?s=128

Godfrey Chan

November 03, 2015
Tweet

Transcript

  1. Godfrey Chan @chancancode Yehuda Katz @wycats

  2. None
  3. None
  4. HTMLBars, how do I even? Freedom Freedom ! !

  5. Three Handlebars templates walk into one of the newly-opened HTMLBars

    on the block. After having a few drinks, they each put down a $100 bill.
  6. The renderer said to them, “sorry, no change” and left

    the DOM untouched.
  7. HTML

  8. None
  9. DHTML

  10. Dynamic HTML

  11. DOM APIs

  12. var list = document.getElementById("todos"); for (var i = 0; i

    < todoItems.length; i++) { var item = todoItems[i]; var row = document.createElement("li"); var content = document.createTextNode(item.title); if (item.completed) { var del = document.createElement("del"); del.appendChild(content); row.appendChild(del); } else { row.appendChild(content); } list.appendChild(row); }
  13. What happened to the HTML in the DHTML?

  14. var list = document.getElementById("todos"); var html = ""; for (var

    i = 0; i < todoItems.length; i++) { var item = todoItems[i]; html += "<li>"; if (item.completed) { html += "<del>" + item.title + "</del>"; } else { html += item.title; } html += "</li>"; } list.innerHTML = html;
  15. var completedItem = "<li><del>{{title}}</del></li>"; var incompleteItem = "<li>{{title}}</li>"; var list

    = document.getElementById("todos"); var html = ""; for (var i = 0; i < todoItems.length; i++) { var item = todoItems[i]; var template = item.completed ? completedItem : incompleteItem; html += template.replace("{{title}}", item.title); } list.innerHTML = html;
  16. Data + HTML

  17. Data + HTML

  18. Templates

  19. None
  20. } mustasche

  21. Logicless Templates

  22. <ul> {{#items}} {{#completed}} <li><del>{{name}}</del></li> {{/completed}} {{^completed}} <li>{{name}}</li> {{/completed}} {{/items}} </ul>

  23. None
  24. Logicless Templates Semantic

  25. <ul> {{#each items as |item|}} {{#if item.completed}} <li><del>{{item.title}}</del></li> {{else}} <li>{{item.title}}</li>

    {{/if}} {{/each}} </ul>
  26. Extensibility

  27. Pre-compilation

  28. function(todoItems) { var html = ""; html += "<ul>"; for

    (var i = 0; i < todoItems.length; i++) { var item = todoItems[i]; html += "<li>"; if (item.completed) { html += "<del>" + item.title + "</del>"; } else { html += item.title; } html += "</li>"; } html += "</ul>"; return html; } <ul> {{#each items as |item|}} {{#if item.completed}} <li><del>{{item.title}}</del></li> {{else}} <li>{{item.title}}</li> {{/if}} {{/each}} </ul> Compiler todos.hbs todos.js
  29. None
  30. None
  31. Ember ❤ HTML+CSS

  32. Problem

  33. {{#if item.completed}} <li><del>{{item.title}}</del></li> {{else}} <li>{{item.title}}</li> {{/if}} { "completed": false, "title":

    "Finish HTMLBars Talk " } + <li>Finish HTMLBars Talk </li>
  34. {{#if item.completed}} <li><del>{{item.title}}</del></li> {{else}} <li>{{item.title}}</li> {{/if}} { "completed": true, "title":

    "Finish HTMLBars Talk " } + <li>Finish HTMLBars Talk </li>
  35. {{#if item.completed}} <li><del>{{item.title}}</del></li> {{else}} <li>{{item.title}}</li> {{/if}} { "completed": true, "title":

    "Finish HTMLBars Talk " } + <li><del>Finish HTMLBars Talk </del></li>
  36. How?

  37. <script id="metamorph-173-start" type="text/x-placeholder"></script> <li><del> <script id="metamorph-174-start" type="text/x-placeholder"></script> Finish HTMLBars Talk

    <script id="metamorph-174-end" type="text/x-placeholder"></script> </del></li> <script id="metamorph-173-end" type="text/x-placeholder"></script> {{#if item.completed}} <li><del>{{item.title}}</del></li> {{else}} <li>{{item.title}}</li> {{/if}}
  38. None
  39. <button {{bind-attr class="isActive"}}> <button class="{{isActive}}"> <button class="is-active" data-bindattr-147="147">

  40. None
  41. None
  42. HTMLBars

  43. function(todoItems) { var list = document.createElement("ul"); for (var i =

    0; i < todoItems.length; i++) { var item = todoItems[i]; var row = document.createElement("li"); var content = document.createTextNode(item.title); if (item.completed) { var del = document.createElement("del"); del.appendChild(content); row.appendChild(del); } else { row.appendChild(content); } list.appendChild(row); } return list; } <ul> {{#each items as |item|}} {{#if item.completed}} <li><del>{{item.title}}</del></li> {{else}} <li>{{item.title}}</li> {{/if}} {{/each}} </ul> Compiler todos.hbs todos.js
  44. AST Template Opcodes JavaScript Program HTML Tokens

  45. Metamorph Tags

  46. {{bind-attr}}

  47. XSS Protection

  48. AST Transformations

  49. Real HTML Parser

  50. SVG!

  51. Demo

  52. <svg width="{{width}}" height="{{height}}"> <rect x="0" y="0" width="{{width}}" height="{{height}}" fill="#1B1B1B" />

    {{#each points as |point|}} <circle cx="{{point.x}}" cy="{{point.y}}" r="{{point.size}}" stroke-width="1" stroke="lightblue" stroke-opacity="{{point.opacity}}" fill-opacity="0" /> {{/each}} </svg>
  53. Better Foundation

  54. None
  55. None
  56. Programming Model

  57. var TodoList = React.createClass({ render() { var items = [];

    this.props.todoItems.forEach(function (item) { if (item.completed) { items.push(<li><del>{ item.title }</del></li>); } else { items.push(<li>{ item.title }</li>); } }); return <ul>{ items }</ul>; } });
  58. Always Be Re-rendering™

  59. Diffing

  60. Virtual DOM

  61. O(n3) ?!

  62. Heuristics

  63. O(n)

  64. Incremental DOM

  65. function render(data) { elementOpen('ul'); todoItems.forEach(function (item) { elementOpen('li'); if (item.completed)

    { elementOpen('del'); } text(item.title); if (item.completed) { elementClose('del'); } elementClose('li'); }); elementClose('ul'); }
  66. Compilation Target

  67. “ASM.dom”

  68. Incremental Diffing

  69. None
  70. Programming Model

  71. Write-only Algorithm

  72. <h1>{{post.title}}</h1> <h3 class="post-author"> <i class="fa fa-user"></i> Written by {{post.author}} </h3>

    <h3 class="post-date"> <i class="fa fa-calendar"></i> Published {{relative-time post.published_at}} </h3> <hr> <div class="post-body"> {{post.body}} </div>
  73. <div> <div> <div> <div> <div> <div> <div> <div> <div> <div>

    {{post.title}} </div> </div> </div> </div> </div> </div> </div> </div> </div> </div>
  74. <div> <div> <div> <div> <div> <div> <div> <div> <div> <div>

    Oh hai! </div> </div> </div> </div> </div> </div> </div> </div> </div> </div>
  75. Virtual DOOM?

  76. Semantic Templates

  77. Compiler

  78. Render Nodes

  79. <h1>{{post.title}}</h1> <h3 class="post-author"> <i class="fa fa-user"></i> Written by {{post.author}} </h3>

    <h3 class="post-date"> <i class="fa fa-calendar"></i> Published {{relative-time post.published_at}} </h3> <hr> <div class="post-body"> {{post.body}} </div> [ { node: [TextNode], statement: "{{post.title}}", lastValue: "Rails is omakase" }, { node: [TextNode], statement: "{{relative-time post.published_at}}", lastValue: "3 days ago" }, { node: [TextNode], statement: "{{post.body}}", lastValue: "There are lots of à la carte software..." } ]
  80. [ { node: [TextNode], statement: "{{post.title}}", lastValue: "Rails is omakase"

    } ] <div> <div> <div> <div> <div> <div> <div> <div> <div> <div> {{post.title}} </div> </div> </div> </div> </div> </div> </div> </div> </div> </div>
  81. [ // Nothing to diff! ] <div> <div> <div> <div>

    <div> <div> <div> <div> <div> <div> Oh hai! </div> </div> </div> </div> </div> </div> </div> </div> </div> </div>
  82. O(n*)

  83. O(n*) * n = Number of {{curlies}}, not DOM nodes

  84. None
  85. None
  86. Glimmer 2

  87. Runtime Optimizations

  88. Better Integration with Ember

  89. References

  90. <h1>{{post.title}}</h1> <h3 class="post-author"> <i class="fa fa-user"></i> Written by {{post.author}} </h3>

    <h3 class="post-date"> <i class="fa fa-calendar"></i> Published {{relative-time post.published_at}} </h3> <hr> <div class="post-body"> {{post.body}} </div> [ { node: [TextNode], statement: "{{post.title}}", lastValue: "Rails is omakase" }, { node: [TextNode], statement: "{{relative-time post.published_at}}", lastValue: "3 days ago" }, { node: [TextNode], statement: "{{post.body}}", lastValue: "There are lots of à la carte software..." } ]
  91. <h1>{{post.title}}</h1> <h3 class="post-author"> <i class="fa fa-user"></i> Written by {{post.author}} </h3>

    <h3 class="post-date"> <i class="fa fa-calendar"></i> Published {{relative-time post.published_at}} </h3> <hr> <div class="post-body"> {{post.body}} </div> [ { node: [TextNode], reference: { value(): …, isDirty(): … }, lastValue: "Rails is omakase" }, { node: [TextNode], reference: { value(): …, isDirty(): … }, lastValue: "3 days ago" }, { node: [TextNode], reference: { value(): …, isDirty(): … }, lastValue: "There are lots of à la carte software..." } ]
  92. Components

  93. None
  94. One More Thing™

  95. TypeScript

  96. Godfrey Chan @chancancode Yehuda Katz @wycats