react-with-mustaches · require("./grammar.js") .parse("hello, world!")...
TRANSCRIPT
![Page 1: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/1.jpg)
![Page 2: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/2.jpg)
{
![Page 3: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/3.jpg)
👋
![Page 4: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/4.jpg)
not to scale
Anton 2007
@zemlanin
![Page 5: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/5.jpg)
not to scale
Anton 20192007
@zemlanin
Wix
![Page 6: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/6.jpg)
not to scale
Anton 20192015 2007
@zemlanin
Wix{{
![Page 7: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/7.jpg)
<body> <header> <ul data-nav> <li> … </li> <li> … </li> <li> … </li> </ul> </header> <content> <ul data-products> <li> … </li> <li> … </li> <li> … </li> </ul> </content> <footer> … </footer> </body>
![Page 8: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/8.jpg)
<body> <header> <ul data-nav> <li> … </li> <li> … </li> <li> … </li> </ul> </header> <content> <ul data-products> <li> … </li> <li> … </li> <li> … </li> </ul> </content> <footer> … </footer> </body>
![Page 9: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/9.jpg)
def render_navigation(): return ( "<div data-nav>" + render("navigation.tmpl") + "</div>" )
import Nav from "navigation.tmpl"
function hydrateNavigation() { for (let n of document.querySelectorAll("[data-nav]")) { ReactDOM.hydrate(<Nav />, n) } }
![Page 10: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/10.jpg)
def render_navigation(): return ( "<div data-nav>" + render("navigation.tmpl") + "</div>" )
import Nav from "navigation.tmpl"
function hydrateNavigation() { for (let n of document.querySelectorAll("[data-nav]")) { ReactDOM.hydrate(<Nav />, n) } }
"navigation.tmpl"
"navigation.tmpl"
![Page 11: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/11.jpg)
<body> <header> <ul data-nav> <li> … </li> <li> … </li> <li> … </li> </ul> </header> <content> <ul data-products> <li> … </li> <li> … </li> <li> … </li> </ul> </content> <footer> … </footer> </body>
![Page 12: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/12.jpg)
![Page 14: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/14.jpg)
![Page 15: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/15.jpg)
.button { border: none }
.button.red { background-color: red }
import styles from "./styles.css" // => { button: "0bad", red: "c0de" }
![Page 16: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/16.jpg)
<a href={{ href }}>{{ label }}</a>
var React = require("react") module.exports = function (props) { return React.createElement( "a", { href: props.href }, props.label ) }
{{
![Page 18: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/18.jpg)
1. parsing 2. code generation
![Page 19: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/19.jpg)
parsing
<a href={{href}}> {{label}} </a>
![Page 20: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/20.jpg)
<b>hello, <i>world</i>!</b>
<b>hello, <i>world</i>!</b>
<b> hello, <i>world</i>! </b>
<i>world</i>hello, !
![Page 21: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/21.jpg)
regex
![Page 22: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/22.jpg)
🚫
regex
![Page 24: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/24.jpg)
custom lexer + parser
![Page 25: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/25.jpg)
custom lexer + parser
![Page 26: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/26.jpg)
Parsing Expression Grammar
grammar bitsy
node <- tag / text_node tag <- i_tag / b_tag i_tag <- "<i>" node* "</i>" b_tag <- "<b>" node* "</b>" text_node <- [^<>]+
![Page 27: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/27.jpg)
ANTLR
![Page 28: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/28.jpg)
ANTLR
PEGjs
Canopy
![Page 30: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/30.jpg)
grammar Schwartzman
root <- node* %strip_whitespaces
![Page 31: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/31.jpg)
grammar Schwartzman
root <- node* %strip_whitespaces
node <- dom_node / mustache_node / text_node
![Page 32: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/32.jpg)
grammar Schwartzman
root <- node* %strip_whitespaces
node <- dom_node / mustache_node / text_node
dom_node <- (open_tag node* close_tag) %validate
![Page 33: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/33.jpg)
grammar Schwartzman
root <- node* %strip_whitespaces
node <- dom_node / mustache_node / text_node
dom_node <- (open_tag node* close_tag) %validate
open_tag <- "<" tag_name space attrs space? ">"
![Page 34: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/34.jpg)
SyntaxError: Line 1: expected [^<>], "<i>", "<b>", [^<>], "</i>" <b>beaver <i>platypus</b> duck</i> ^
require("./grammar.js") .parse("<b>beaver <i>platypus</b> duck</i>")
![Page 35: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/35.jpg)
require("./grammar.js") .parse("<b>hello, <i>world</i>!</b>")
TreeNode { text: '<b>hello, <i>world</i>!</b>', offset: 0, elements: [ TreeNode { text: '<b>', offset: 0, elements: [] }, TreeNode { text: 'hello, <i>world</i>!', offset: 3, elements: [ TreeNode { text: 'hello, ', offset: 3, elements: [Array] }, TreeNode { text: '<i>world</i>', offset: 10, elements: [Array] }, TreeNode { text: '!', offset: 22, elements: [Array] } ] }, TreeNode { text: '</b>', offset: 23, elements: [] } ] }
![Page 36: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/36.jpg)
Антону надо перевести дыхание Держите пёсиков
![Page 37: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/37.jpg)
code generationvar React = require("react")
module.exports = function (props) { return React.createElement( "a", { href: props.href }, props.label ) }
![Page 38: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/38.jpg)
function loader(content) { const tree = parse(content) const { code } = compile(tree)
return `var h = require("react").createElement
module.exports = function (props) { return ${code} }
if ( typeof process !== "undefined" && process.env && process.env.NODE_ENV === "test" ) { /* … */ }` }
![Page 39: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/39.jpg)
return `var h = require("react").createElement
module.exports = function (props) { return ${code} }
if ( typeof process !== "undefined" && process.env && process.env.NODE_ENV === "test" ) { /* … */ }` }
const tree = parse(content) const { code } = compile(tree)
function loader(content) {
![Page 40: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/40.jpg)
return `var h = require("react").createElement
module.exports = function (props) { return ${code} }
if ( typeof process !== "undefined" && process.env && process.env.NODE_ENV === "test" ) { /* … */ }` }
const tree = parse(content) const { code } = compile(tree)
function loader(content) {
![Page 41: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/41.jpg)
function compile(node) { const { tag_name, attrs, elements } = node
const children = compileChildren(elements) const compiledAttrs = compileAttrs(attrs)
return { code: `h("${tag_name}", ${compiledAttrs}, ${children})`, // … } }
![Page 42: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/42.jpg)
<div> {{ mark }} </div>
React.createElement( "div", null, props.mark )
![Page 43: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/43.jpg)
<div> {{& mark }} </div>
React.createElement("div", { dangerouslySetInnerHTML: { __html: props.mark } })
![Page 44: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/44.jpg)
<div> <i>{{ john }}:</i> oh, hi {{& mark }} </div>
ehh…
![Page 45: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/45.jpg)
escape by hand?<div> <i>{{ john }}:</i> oh, hi {{& mark }} </div>
![Page 46: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/46.jpg)
escape by hand?<div> <i>{{ john }}:</i> oh, hi {{& mark }} </div>
![Page 47: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/47.jpg)
escape by hand? restrict {{& }}
<div> <i>{{ john }}:</i> oh, hi {{& mark }} </div>
![Page 48: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/48.jpg)
if ( children.length === 1 && children[0].escaped ) { // add some `danger` } else if ( children.some(c => c.escaped) ) { throw new OneChildPolicy() }
escape by hand? restrict {{& }}
![Page 49: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/49.jpg)
{{^ invert }} body {{/ invert }}
{{# section }} body {{/ section }}
![Page 50: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/50.jpg)
<b>{{^ great }}Not terrible{{/ great }}</b>
![Page 51: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/51.jpg)
<b>{{^ great }}Not terrible{{/ great }}</b>
React.createElement( "b", null, (!props.great || !props.great.length) ? "Not terrible" : null )
{ great: false } { great: [] }
![Page 52: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/52.jpg)
<div>{{# user }}{{ name }}{{/ user }}</div>
![Page 53: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/53.jpg)
<div>{{# user }}{{ name }}{{/ user }}</div>
React.createElement( "div", null, props.user ? props.name : null )
{ user: true, name: "Anatoly Dyatlov" }
{{# if }}
![Page 54: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/54.jpg)
<div>{{# user }}{{ name }}{{/ user }}</div>
React.createElement( "div", null, props.user ? props.user.name : null )
{ user: { name: "Anatoly Dyatlov" } }
{{# scope }}
![Page 55: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/55.jpg)
// schwartzman/index.js
return `function scopeSearch(scopes, name) { var path = name.split(".")
for (var i = 0; i < scopes.length; i++) { // … for (var n = 0; n < path.length; n++) { // … } }
return null }`
![Page 56: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/56.jpg)
<div>{{# user }}{{ name }}{{/ user }}</div>
React.createElement( "div", null, ...props.user.map(u => u.name) )
{ user: [ { name: "Anatoly" }, {name: "Dyatlov"} ] }
{{# for_each }}
![Page 57: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/57.jpg)
<div>{{# user }}{{ name }}{{/ user }}</div>
React.createElement( "div", null, ✨ f(props.user, props, ["user"]) ✨ // => createElement("b", null, "Anatoly Dyatlov") )
{ user: () => (text, cb) => `<b>${cb(text)}</b>`, name: "Anatoly Dyatlov" }
{{# lambda }}
![Page 58: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/58.jpg)
// schwartzman/index.js
return `function section(/* … */) { var obj = scopeSearch(/* `scope` section */)
if (obj) { if (isArray(obj)) { // `for_each` section } else if (isFunction(obj)) { // `lambda` section } else { // `if` section } } }`
![Page 59: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/59.jpg)
// `if` section } } }`
} else if (isFunction(obj)) { // `lambda` section } else {
// schwartzman/index.js
return `function section(/* … */) { var obj = scopeSearch(/* `scope` section */)
if (obj) { if (isArray(obj)) { // `for_each` section
![Page 60: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/60.jpg)
// schwartzman/index.js
return `function render(/* … */) { var lowLevel = require("schwartzman").lowLevel var parsed = lowLevel.parse(/* … */) // … return eval(lowLevel.compile(parsed)) }`
![Page 61: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/61.jpg)
eval
// schwartzman/index.js
return `function render(/* … */) { var lowLevel = require("schwartzman").lowLevel var parsed = lowLevel.parse(/* … */) // … return eval(lowLevel.compile(parsed)) }`
![Page 62: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/62.jpg)
eval
// schwartzman/index.js
return `function render(/* … */) { var lowLevel = require("schwartzman").lowLevel var parsed = lowLevel.parse(/* … */) // … return eval(lowLevel.compile(parsed)) }`
:feels
-good:
![Page 63: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/63.jpg)
{{#users u}} {{ u.name }} {{/users}}
![Page 64: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/64.jpg)
{{#users u}} {{ u.name }} {{/users}}
🚫
![Page 65: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/65.jpg)
![Page 66: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/66.jpg)
![Page 67: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/67.jpg)
Features-- UX++
![Page 69: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/69.jpg)
![Page 70: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/70.jpg)
var h = require("react").createElement
var lowLevel = require("schwartzman").lowLevel
![Page 71: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/71.jpg)
var h = require("react").createElement
var lowLevel = require("schwartzman").lowLevel
var parseQuery = require("loader-utils").parseQuery
![Page 72: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/72.jpg)
module.exports = function (content) { … }
if ( typeof process != "undefined" && process.env && process.env.NODE_ENV === "test" ) { … }
var h = ("react").createElement
var lowLevel = ("schwartzman").lowLevel
var parseQuery = ("loader-utils").parseQuery
require
require
require
![Page 73: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/73.jpg)
window.module = {} window.process = { env: { NODE_ENV: "test" } }
window.require = function (name) { if (name === "loader-utils") { return { parseQuery() { return {} } } }
if (name === "react") { return /* … */ }
if (name === "schwartzman") { return /* … */ } }
![Page 74: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/74.jpg)
<script src="https://unpkg.com/react@16/umd/react.production.min.js"> </script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom-server.browser.production.min.js"> </script>
<script src="https://unpkg.com/schwartzman"></script>
![Page 75: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/75.jpg)
![Page 76: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/76.jpg)
![Page 77: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/77.jpg)
TWO YEARS LATER…
![Page 78: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/78.jpg)
<div style="color: red;">hello world</div> ^ ^
<!-- vs -->
<div style="color:red">hello world</div> ^ ^
![Page 79: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/79.jpg)
react@15 => react@16
me: users:
:(:)
![Page 80: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/80.jpg)
react@15 => (react@15 | react@16)
react@15 => react@16
me: users:
:)
![Page 81: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/81.jpg)
react@15 => (react@15 | react@16)
react@15 => react@16
me: users:
:)❌
![Page 82: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/82.jpg)
// test/rendering.test.js
const rendered = semver.gte(React.version, "16.0.0") ? `<div style="color:red">red</div>` : `<div style="color:red;">red</div>`
assert.equal( rendered, ReactDOMServer.renderToStaticMarkup( React.createElement(tmpl, {}) ) )
![Page 83: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/83.jpg)
// package.json
"peerDependencies": { "react": "^0.14.3 || ^15.6.1 || ^16.0.0" }
![Page 84: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/84.jpg)
# .travis.yml
env: - REACT_VER=* - REACT_VER=0.14.3 - REACT_VER=15.6.1 - REACT_VER=16.0.0
![Page 85: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/85.jpg)
# .travis.yml
env: - REACT_VER=* - REACT_VER=0.14.3 - REACT_VER=15.6.1 - REACT_VER=16.0.0
install: - npm ci - npm i --no-save "react@$REACT_VER" "react-dom@$REACT_VER"
![Page 86: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/86.jpg)
![Page 87: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/87.jpg)
not to scale
20192018 2015
schwartzman
![Page 88: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/88.jpg)
not to scale
20192015
experience
schwartzman
2018
![Page 89: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/89.jpg)
![Page 90: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/90.jpg)
![Page 91: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/91.jpg)
![Page 92: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/92.jpg)
window.module = {}
window.require = function (name) { if (name === "loader-utils") { return { parseQuery() { return {} } } }
if (name === "react") { return /* … */ }
if (name === "schwartzman") { return /* … */ } }
![Page 94: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/94.jpg)
// test/rendering.test.js
const rendered = semver.gte(React.version, "16.0.0") ? `<div style="color:red">red</div>` : `<div style="color:red;">red</div>`
assert.equal( rendered, ReactDOMServer.renderToStaticMarkup( React.createElement(tmpl, {}) ) )
![Page 95: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/95.jpg)
![Page 96: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/96.jpg)
) thank you
![Page 97: react-with-mustaches · require("./grammar.js") .parse("hello, world!") TreeNode { text: 'hello, world!',](https://reader033.vdocuments.site/reader033/viewer/2022053014/5f114d1e5be5d333544ad34a/html5/thumbnails/97.jpg)
)
anton.click/rm
questions?
@zemlanin