Title Text

ISOMORPHIC APPS:

(JUST) THE GOOD PARTS

@marianodvazquez

github.com/nanovazquez

Isomorphic

Isomorphic JavaScript apps are that run the same code in the client and the server

Isomorphic

Introducción

isomorphic, universal, server-side rendering, client-side rendering

Isomorphic

You heard it here first — within a few years, it will be rare to see an advanced web app that isn’t running some JavaScript on the server.

Isomorphic JavaScript: The Future of Web Apps (2013)

 

Universal

Universal

Is a term used to emphasize the fact that a particular piece of JavaScript code is able to run in multiple environments

Universal

Using Universal JavaScript means the rendering logic is simply passed down to the client.

Making Netflix.com faster (2015)

 

BUT

Isomorphic also is the functional aspect of seamlessly switching between client and server side rendering

without losing state

Full client-side rendering

Full server-side rendering

Full server-side rendering

Exercise 0: Client-side app using React + Redux

Scenario:

  1. Full client-side app, no SSR

  2. PerceivedLoading time at initial render

  3. No SEO support

Exercise 1: Server side rendering with React

Challenge:

  1. Remove (perceived) loading time at initial render

  2. SEO support

  3. What about the data?

What about Redux?

To send the data down to the client, we need to:

  • create a fresh, new Redux store instance on every request;

  • optionally dispatch some actions;

  • pull the state out of store;

  • and then pass the state along to the client.

 

On the client side, a new Redux store will be created and initialized with the state provided from the server.

 

Redux's only job on the server side is to provide the initial state of our app.

What about Redux?

import path from 'path'
import Express from 'express'
import React from 'react'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import counterApp from './reducers'
import App from './containers/App'

const app = Express()
const port = 3000

// This is fired every time the server side receives a request
app.use(handleRender)

// We are going to fill these out in the sections to follow
function handleRender(req, res) { /* ... */ }
function renderFullPage(html, preloadedState) { /* ... */ }

app.listen(port)

What about Redux?

import { renderToString } from 'react-dom/server'

function handleRender(req, res) {
  // Create a new Redux store instance
  const store = createStore(counterApp)

  // Render the component to a string
  const html = renderToString(
    <Provider store={store}>
      <App />
    </Provider>
  )

  // Grab the initial state from our Redux store
  const preloadedState = store.getState()

  // Send the rendered page back to the client
  res.send(renderFullPage(html, preloadedState))
}

What about Redux?

function renderFullPage(html, preloadedState) {
  return `
    <!doctype html>
    <html>
      <head>
        <title>Redux Universal Example</title>
      </head>
      <body>
        <div id="root">${html}</div>
        <script>
          window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState)}
        </script>
        <script src="/static/bundle.js"></script>
      </body>
    </html>
    `
}

What about Redux?

import React from 'react'
import { render } from 'react-dom'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import App from './containers/App'
import counterApp from './reducers'

// Grab the state from a global injected into server-generated HTML
const preloadedState = window.__PRELOADED_STATE__

// Create Redux store with initial state
const store = createStore(counterApp, preloadedState)

render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)

Since we have the same initial state for our (client) Redux store the result will be the same real DOM.

Exercise 2: SEO

Challenge:

  1. Be a crawler: compare SEO between 2 apps: a SSR and an SPA

  2. How can you measure it?

  3. Is it useful for you?

Exercise 2: SEO

Fetch as Google!

Exercise 3: initial rendering time & bundles

Challenge:

  1. Improve initial rendering time by using bundles

  2. Identify tradeoffs

async, defer, attributes

more info here 

Bonus track: next.js

For free:

  • Server-side rendering and indexing of each ./pages
  • That means automatic code splitting :)
  • Lifecycle hooks for initial data population
  • Error handling
  • and other stuff (static folder, error handling, bundling, etc)

 

A minimalistic framework for universal server-rendered React applications

Made with Slides.com