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

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. • Hirshorn Zuckerman
 Design Group • Offices in Rockville, Baltimore

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

    first isomorphic React SPAs in production • Our (the?) second • 100s of React components • 7 committers
  3. “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
  4. 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
  5. DIFFERENT APPROACHES • Serve rendered HTML → Hydrate → Repeat

    • Serve rendered HTML → Hydrate → SPA
  6. JS

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

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

    <meta name=“keywords” content=“a </head> <body> <div class=“container”> <div>
  9. 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>
  10. 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>
  11. 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>
  12. <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
  13. <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
  14. 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
  15. SSR: THE THEORY • One app (function!) generates entire document

    • On server: React.renderToString • In browser: React.render
  16. 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
  17. 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
  18. 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
  19. 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
  20. 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
  21. 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
  22. OUR APPROACH: TWO WEBPACK BUILDS { target: 'node', externals: (

    fs.readdirSync(path.resolve('node_modules')) .map((dir) => new RegExp(`^${ dir }(?:$|\/)`)) ), // ... } { target: 'web', // ... }
  23. 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!
  24. 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
  25. 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?
  26. 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
  27. • 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
  28. FLOATING POINT MATH! • Who cares about 0.1 + 0.2?!

    • 7 / 3 • 2.333333333333334 • 2.3333333333333335
  29. 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”
  30. 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
  31. ? • 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
  32. 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