Nonlinear Performance Magnification

    create-render-4r

    3.1.2 • Public • Published

    Universal render for React+ Build Status

    Express.js middleware to render a 4r app server-side:

    Diagram: Universal Web Apps & create-render-4r

    Features

    Example Universal Web App

    Demonstrates using this renderer in a working universal app.

    Install

    Add the module to package.json:

    npm install create-render-4r --save
     
    # Save peer dependencies for production (otherwise they're only dev dependencies): 
    npm install radium@0.15.x react@0.14.x react-document-meta@2.x react-dom@0.14.x react-redux@4.x react-router@1.x redux@3.x --save

    Upgrading

    Breaking changes are indicated by major versions. See UPGRADING

    Usage

    Basic usage in an Express server.js:

    var express = require('express');
    var createRender4r = require('create-render-4r');
     
    var app = express();
     
    // These are unique to your own app.
    var routes = require('./my-routes');
    var loadStore = require('./my-load-store');
    var layoutHtml = require('./my-layout-html');
     
    // Create the render middleware.
    var render4r = createRender4r({
      routes:       routes,
      loadStore:    loadStore,
      layoutHtml:   layoutHtml
    });
     
    // Add the render for all requests.
    app.use(render4r);
     
    var PORT = process.env.PORT || 3000;
    app.listen(PORT, function () {
      console.log('Server listening on', PORT);
    });

    Example server.js

    API

    createRender4r()

    This function is used to generate the Express.js middleware.

    It accepts a single argument, an object:

    createRender4r({ routes, loadStore, layoutHtml, decorateResponse })

    routes

    (Required) The <Router/> component

    loadStore

    (Required) A function taking initial state, returning the Redux store; created with Redux createStore

    var Redux = require('redux');
    var createStore = Redux.createStore;
    var combineReducers = Redux.combineReducers;
     
    var reducers = './my-reducers';
     
    function loadStore(initialState) {
      return createStore(combineReducers(reducers), initialState);
    }

    layoutHtml

    (Required) An HTML template function; this sample uses ES2015 module & template string syntx:

    function layoutHtml(componentHTML, cleanInitialState, documentMeta) {
      return `
        <!DOCTYPE html>
        <html>
          <head>
            ${documentMeta}
     
            <script type="application/javascript">
              window.__INITIAL_STATE__ = ${cleanInitialState};
            </script>
          </head>
          <body>
            <div id="react-view">${componentHTML}</div>
     
            <script type="application/javascript" src="/bundle.js"></script>
          </body>
        </html>
      `;
    }

    decorateResponse

    (Optional) A side-effect function to update the response based on state:

    function decorateResponse(res, state) {
      /*
      Example: set 404 response status when the item couldn't be fetched,
        while the app still renders a nice Not Found message in the UI.
      */
      var errText = state.item.get('error');
      if (errText && /^404/.exec(errText)) {
        res.status(404)
      }
    }

    Example createRender4r()

    Server-side async data loading

    Per-component data loading for the current route.

    fetchData()

    Define this static (class) method on React components to enable Promise-based server-side fetching. You'll need to use a universal library like isomorphic-fetch within redux-thunk async action creators so they will work equivalently on the server-side & in web browsers.

    fetchData(dispatch, props)

    • dispatch (required) the Redux store's dispatcher
    • props (required) the component's props

    Must return a Promise to await completetion of the fetch. (This is what Redux thunk does.)

    static fetchData(dispatch, props) {
      return dispatch(ItemActions.getItem(props.params.id));
    }

    Example fetchData()

    sagasToRun()

    Define this static (class) method on React components to enable Generator-based server-side fetching via Redux sagas.

    sagasToRun(dispatch, props)

    • dispatch (required) the Redux store's dispatcher
    • props (required) the component's props

    Must return an array of arrays of arguments for middleware.run.

    static sagasToRun(dispatch, props) {
      return [
        [fetchThingsSaga],
        [verifyAuthSaga, { userId: props.params.authUserId }]
      ];
    }

    Additionally, the Redux store returned by loadStore() must expose the Saga middleware as store.sagaMiddleware:

    // …
    import createSagaMiddleware       from 'redux-saga';
    // …
     
    export default function loadStore(...createStoreRestParams) {
      const sagaMiddleware            = createSagaMiddleware(...sagas);
      // …
      // This accessor must be added for Saga middleware to be used server-side:
      store.sagaMiddleware            = sagaMiddleware;
      return store;
    }

    Absolute URLs

    Frequently, app code will need its absolute URL, canonical hostname & protocol to render links or make API requests.

    This module includes a sourceRequest reducer to handle this state. It is captured on the server for each request as the Redux store is initialized.

    Example state.sourceRequest.host values:

    • localhost:3000
    • example.com
    • api.example.com:8443
    • velvet-glacier-1234.herokuapp.com

    Example state.sourceRequest.protocol values:

    • https
    • http

    To use these values in an app:

    1. Add this module's reducers to your store:
    import { combineReducers } from 'redux'
    import { reducers as cr4rReducers } from 'create-render-4r'
     
    const rootReducer = combineReducers(
      Object.assign(
        cr4rReducers,
        // …& the app's reducers
      )
    )

    Example reducers/index.js

    1. Then access it in the Redux state:
    // `store` is the Redux store
    const state = store.getState();
    const proto = state.sourceRequest.protocol;
    const host = state.sourceRequest.host;

    Example actions/counter.js

    Keywords

    none

    Install

    npm i create-render-4r

    DownloadsWeekly Downloads

    2

    Version

    3.1.2

    License

    MIT

    Last publish

    Collaborators

    • avatar