Git Product home page Git Product logo

react-router-server's Introduction

React Router Server

Build Status Code Climate Dependency Status peerDependency Status devDependency Status npm downloads npm version Gitter

Server Side Rendering library for React Router v4. Allows to do code-splitting using webpack and to fetch data. Renders the page on the server side and resolves all issues with mounting on the client side.

Table Of Content

  1. Installation
  2. Example
  3. Usage
  4. API
  5. Webpack Bundle Support
  6. Contributing
  7. License

Installation

npm install react-router-server --save

Example

A working example is provided in the example directory of this project. To try for yourself, you can clone this project and run npm start. This will provide a server accessible at http://localhost:3000.

Usage

Loading code splitted module

To load a module splitted by webpack use the importModule method and the Match component provided by this library.

import { Match, importModule } from 'react-router-server';

<Match
  exactly
  pattern="/test"
  render={matchProps => importModule('moduleName', './module', () => System.import("./module"))
    .then(module => {
      const Component = module.default;
      return <Component/>;
    })
  }
/>

Loading props on the server side

To load props for your components to render on the server side, use the fetchState decorator.

@fetchState(
  state => ({
    isLoaded: state.user ? true : false,
    user: state.user
  }),
  actions => ({
    done: actions.done
  })
)
class MyComponent extends Component {
  componentWillMount() {
    if (!this.props.isLoaded) {
      loadAsyncUser()
        .then(user => this.props.done({ user }));
    }
  }
  
  render() {
    ...
  }
}

Server Side

You need to use the renderToString provided by this library:

import renderToString from 'react-router-server';
import { ServerRouter, createServerRenderContext } from 'react-router'

const context = createServerRenderContext();

renderToString(
    <ServerRouter
      location={'/current/path/' /* provide the request url */}
      context={context}
    >
      <App/>
    </ServerRouter>
).then(html => console.log(html)); // send html

An initial state and modules to preload will be passed through the context. You will need to pass these to your HTML template to preload the modules and pass the initialState to the client side.

import stats from './stats.json';

const initialState = context.getInitialState();
const modules = context.getModules(stats);

You will need to get the webpack stats to extract the modules from webpack. To do this, you can use the stats-webpack-plugin and add this line to your webpack config plugins.

  plugins: [
    new StatsPlugin('stats.json')
  ]

Client Side

Preload the modules in your HTML file if you are using code-splitting. Pass the initial state and modules to your app.

<link rel="preload" href="/path/to/module" as="script">

<script>
  window.__INITIAL_STATE__ = ...;
  window.__INITIAL_MODULES__ = ...;
</script>

Preload the modules in your JS before rendering the app.

import React from 'react';
import { BrowserRouter } from 'react-router';
import { render } from 'react-dom';
import { preloadModules, ServerStateProvider } from 'react-router-server';

preloadModules(__INITIAL_MODULES__).then(() => {
  render((
    <ServerStateProvider state={__INITIAL_STATE__}>
      <BrowserRouter>
        <App/>
      </BrowserRouter>
    </ServerStateProvider>
  ), document.getElementById('main'));
});

API

fetchState

fetchState(mapStateToProps, mapActionsToProps)

mapStateToProps(state): function to map the state provided by the done action to props in your component;

mapActionsToProps(actions): function to map the actions to props in your component; Currently, only the done action exists and is used when you are finished fetching props.

importModule

importModule(name, path, systemImport)

name: Unique name of your module.

path: Path to your module relative to the current file. Same as the path in the systemImport param.

systemImport: A function returning a promise with your System.import("./path/to/your/module") call.

importWebpackBundle

importModule(appSystemImport, moduleSystemImport)

systemImport: A function returning a promise with your System.import("./path/to/your/app.bundle") call.

moduleSystemImport: A function returning a promise with your System.import("./path/to/your/0.module.bundle") call. E.G. (path) => System.import('./' + path)

Match

The Match component is the same as the react-router Match component but can be used for async render methods.

preloadModules

preloadModules(modules)

modules: array of modules passed by the server side to the client side for preloading.

renderToString

Async version of ReactDOM.renderToString.

renderToString(element, context)

element: The element to render

context: The server context.

ServerStateProvider

The ServerStateProvider component is used for providing the server state to the client side. Provided by the state prop.

Webpack Bundle Support

Server Side Rendering (SSR) is nice, but your app is probably complicated and uses Webpack loaders to load CSS or other types of files. Traditionally, this has always been complicated for SSR because those Webpack loaders are not supported by NodeJS.

To work around this limitation, you can import your Webpack bundle directly into your React Router Server application and do SSR on the bundle instead of importing the unbundled files.

To do this, you will need to create a bundle for the server app and a bundle for the client app, you will need the Webpack stats on both of them to cross reference the modules, as they won't be the same for the server and the client.

React Router Server provides a importWebpackBundle method to import the bundle in your server.

Here's a simple example of how this works:

import { ServerRouter, createServerRenderContext } from 'react-router';
import { renderToString, importWebpackBundle } from 'react-router-server';
import serverStats from './stats/server.json';
import clientStats from './stats/client.json';

importWebpackBundle(
  () => System.import('./app'), // path to your your server bundle
  (path) => System.import(`./${path}`) // callback for module imports inside your app
)
  then(({ default: App }) => {
    const context = createServerRenderContext();
    renderToString(
        <ServerRouter
          location={'/current/path/' /* provide the request url */}
          context={context}
        >
          <App/>
        </ServerRouter>
    )
      .then(html => {
        const result = context.getResult();
        const initialState = context.getInitialState();
        const modules = context.getModules(serverStats, clientStats); // you need to provide stats for the server bundle and the client bundle
        
        // send data to client, with the initial state and preloading the modules
      })
  });

To use System.import in your server script, take a look at the babel-plugin-system-import-transformer Babel plugin.

Contributing

Everyone is welcome to contribute and add more components/documentation whilst following the contributing guidelines.

License

React Router Server is licensed under The MIT License (MIT).

react-router-server's People

Contributors

gabrielbull avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.