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

Isomorphic JS, Server-side Rendering, React & Rockefeller

Isomorphic JS, Server-side Rendering, React & Rockefeller

Matthew Dapena-Tretter

March 03, 2015
Tweet

More Decks by Matthew Dapena-Tretter

Other Decks in Technology

Transcript

  1. ISOMORPHIC JS, SERVER-SIDE RENDERING, REACT & ROCKEFELLER

  2. • Matthew Dapena-Tretter • matthewwithanm • JavaScript → AS3 →


    Python → JavaScript
  3. • Hirshorn Zuckerman
 Design Group • Offices in Rockville, Baltimore

    and NY • ~170 employees
 (and growing!) • We ❤ React and ReactDC
  4. • Launched in October of 2014 • One of the

    first isomorphic React SPAs in production • Our (the?) second • 100s of React components • 7 committers
  5. ISOMORPHIC?

  6. “ISOMORPHIC” • Runs on the server and in the browser

    • DRY! • Saves times • Prevents bugs • One language everywhere is good for building a team that can jump around
  7. ISOMORPHIC WHAT? • Routing • Data access • Templating?

  8. BENEFITS OF SSR • Easily read by computers • SEO

    • Speed/UX • User doesn’t need to wait for app to
 download and initialize • Progressive enhancement makes site
 resilient to JS errors
  9. DIFFERENT APPROACHES • Serve rendered HTML → Hydrate → Repeat

    • Serve rendered HTML → Hydrate → SPA
  10. JS

  11. hzdg.com JS

  12. hzdg.com JS <html> <head> <title>Welcome | HZDG</title> <meta name=“description” content

    <meta name=“keywords” content=“a </head> <body> <div class=“container”> <div>
  13. hzdg.com JS <html> <head> <title>Welcome | HZDG</title> <meta name=“description” content

    <meta name=“keywords” content=“a </head> <body> <div class=“container”> <div>
  14. hzdg.com JS JS <html> <head> <title>Welcome | HZDG</title> <meta name=“description”

    content <meta name=“keywords” content=“a </head> <body> <div class=“container”> <div>
  15. hzdg.com JS hzdg.com/contact <html> <head> <title>Contact | HZDG <meta name=“description”

    <meta name=“keywords” </head> <body> JS <html> <head> <title>Welcome | HZDG</title> <meta name=“description” content <meta name=“keywords” content=“a </head> <body> <div class=“container”> <div>
  16. hzdg.com JS hzdg.com/contact <html> <head> <title>Contact | HZDG <meta name=“description”

    <meta name=“keywords” </head> <body> JS <html> <head> <title>Welcome | HZDG</title> <meta name=“description” content <meta name=“keywords” content=“a </head> <body> <div class=“container”> <div>
  17. <html> <head> <title>Welcome | HZDG</title> <meta name=“description” content <meta name=“keywords”

    content=“a </head> <body> <div class=“container”> <div> hzdg.com g JS
  18. <html> <head> <title>Welcome | HZDG</title> <meta name=“description” content <meta name=“keywords”

    content=“a </head> <body> <div class=“container”> <div> hzdg.com hzdg.com/contact <html> <head> <title>Contact | HZDG</title> <meta name=“description” content <meta name=“keywords” content=“a </head> <body> <div class=“container”> <div> g JS
  19. WHAT DOES THIS HAVE TO DO WITH REACT? • React

    makes it possible • Not a goal of React, just falls out of good functional design • Ember “FastBoot” announced Dec 22
  20. SSR: THE THEORY function myApp(url):DOM

  21. SSR: THE THEORY • One app (function!) generates entire document

    • On server: React.renderToString • In browser: React.render
  22. SSR HURDLES: <HEAD> • Not all browsers are cool with

    you using innerHTML in head • Different APIs for titles on server and browser • One solution: server-only logic for wrapping UI (and adding head) • Our solution: react-frozenhead
  23. SSR HURDLES: ROUTING

  24. ROUTING SOLUTIONS: REACT-ROUTER-COMPONENT • Features • Declare routes in JSX

    • Colocate data requirements with any component via getInitialStateAsync lifecycle method • But… • Fibers? • “React Async is an anti-pattern” • Made server-side integration tricky
  25. ROUTING SOLUTIONS: REACT-ROUTER • Features • Declare routes in JSX

    • Based on Ember’s router • But… • No SSR solution in sight—certainly not by our launch date • Looked to be repeating the same mistakes as
 react-router-component
  26. ROUTING SOLUTIONS: MONOROUTER • Features • Based on express-style routing

    • Designed from the ground up to work with SSR • Generate entire document (including <head>) • But… • Very conservative design • No colocation of data requirements and UI code
  27. UPDATE! REACT-ROUTER • New API announced November 22 • Takes

    into account input of Andrey Popp (RRC author) • Colocate data requirements with Handler/Controller components (via convention; e.g. static fetchData) • But… • Lots needs to be done outside of router (data fetching, <head>, …) • …maybe that’s a good thing! • Too late for us…this time
  28. SSR HURDLES: ISOMORPHIC JS • Getting your app to run

    in two environments (isomorphic js) • Getting your app to create the same document in both environments
  29. SSR HURDLES: ISOMORPHIC CODE

  30. OUR APPROACH: TWO WEBPACK BUILDS { target: 'node', externals: (

    fs.readdirSync(path.resolve('node_modules')) .map((dir) => new RegExp(`^${ dir }(?:$|\/)`)) ), // ... } { target: 'web', // ... }
  31. NODE LIBRARIES • Lots of modules on npm work in

    the browser • browserify pioneered “browser”
 field in package.son • Watch out for: • Packages that access node platform libraries (mostly I/O stuff) • File size!
  32. BROWSER LIBRARIES • $.uhoh • Don’t do browser stuff until

    componentDidMount • Watch out for memory leaks on the server • Use webpack’s null-loader to avoid running browser code on the server
  33. DATA ACCESS • Goodbye ORM! • HTTP allthethings.jpg

  34. SSR HURDLES: DETERMINISM

  35. CHECKSUM INVALID?? • Markup generated on server must match DOM

    generated in browser • Usually, you’re rendering components with different props • Global state/Flux stores different?
  36. SOURCES OF IMPURITY • Randomness • Temporal values • “3

    hours ago” • Date.now() • Stateful external resources (API) • Non-deterministic native APIs • Object iteration • JSON.stringify() • Engine differences
  37. None
  38. • Circle approximated with two Bézier curves • Drawn using

    math (as a function of radius, handle length, stroke width, etc.) for easy tweaking • Animating is just a matter of changing the control points over time
  39. FLOATING POINT MATH! • Who cares about 0.1 + 0.2?!

    • 7 / 3 • 2.333333333333334 • 2.3333333333333335
  40. DEALING WITH NON-DETERMINISM • Be on the lookout and avoid!

    (toFixed(), etc) • Move code to componentDidMount • only called on client so this is where you can start messing with state with abandon • but nothing you do will be in the initial response (sorry, Google) • so you don’t do much in it • “Fossils”
  41. REHYDRATION & FOSSILS • All state used to generate your

    component tree must be the same on the server and in the browser • Most common solution is to serialize state as JSON “fossils” which are used to reconstruct data on the client • Disclaimer: “fossils” is a term we made up
  42. None
  43. <html> <head>...</head> <body> <div id="app">...</div> <script id="fossils">...</script> </body> </html>

  44. THE FUTURE?

  45. None
  46. ? • Generating the view from the initial request is

    limiting • Very little data sent by browsers (viewport size, supported APIs, etc.) and it can’t be inferred from UAs • Maybe we could load bootstrapper and get server-rendered view with an XHR? • Back in hot water with Google (for now).
 Use <noscript>? • Is it worth the effort and drawbacks? • Debugging story is still awful (facebook/react#2686) • Google will get there…eventually
  47. THE PRESENT! • The most sane way to develop web

    apps so far • Components FTW! • No SEO sacrifices • Site feels snappy • Single-language code base • No ugly hacks for Google (like traditional SPAs) • Got a reusable API out of it
  48. HZDG.COM MATTHEWWITHANM MATTHEW DAPENA-TRETTER M@TTHEWWITHANM.COM HZDG