{"id":13802125,"url":"https://github.com/gabrielbull/react-router-server","last_synced_at":"2025-08-31T19:43:41.676Z","repository":{"id":2754924,"uuid":"3752629","full_name":"gabrielbull/react-router-server","owner":"gabrielbull","description":"Server Side Rendering library for React Router v4.","archived":false,"fork":false,"pushed_at":"2018-02-22T15:32:38.000Z","size":117,"stargazers_count":434,"open_issues_count":7,"forks_count":17,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-06-25T11:00:53.652Z","etag":null,"topics":["code-splitting","react","react-component","react-router","reactjs","server","server-side-rendering","ssr","webpack","webpack2"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gabrielbull.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-03-18T03:41:56.000Z","updated_at":"2024-09-05T15:40:03.000Z","dependencies_parsed_at":"2022-08-06T12:31:16.797Z","dependency_job_id":null,"html_url":"https://github.com/gabrielbull/react-router-server","commit_stats":null,"previous_names":[],"tags_count":31,"template":false,"template_full_name":null,"purl":"pkg:github/gabrielbull/react-router-server","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gabrielbull%2Freact-router-server","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gabrielbull%2Freact-router-server/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gabrielbull%2Freact-router-server/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gabrielbull%2Freact-router-server/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gabrielbull","download_url":"https://codeload.github.com/gabrielbull/react-router-server/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gabrielbull%2Freact-router-server/sbom","scorecard":{"id":416482,"data":{"date":"2025-08-11","repo":{"name":"github.com/gabrielbull/react-router-server","commit":"75949010a61a8178473985171e27586fab0d1d19"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.3,"checks":[{"name":"Code-Review","score":2,"reason":"Found 7/24 approved changesets -- score normalized to 2","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 13 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-19T00:00:10.851Z","repository_id":2754924,"created_at":"2025-08-19T00:00:10.851Z","updated_at":"2025-08-19T00:00:10.851Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273032930,"owners_count":25034067,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-31T02:00:09.071Z","response_time":79,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["code-splitting","react","react-component","react-router","reactjs","server","server-side-rendering","ssr","webpack","webpack2"],"created_at":"2024-08-04T00:01:36.664Z","updated_at":"2025-08-31T19:43:41.601Z","avatar_url":"https://github.com/gabrielbull.png","language":"JavaScript","funding_links":[],"categories":["📦 Legacy \u0026 Inactive Projects"],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\u003cimg width=\"460\"src=\"https://rawgit.com/gabrielbull/react-router-server/master/react-router-server.svg\" alt=\"React Router Server\"\u003e\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://travis-ci.org/gabrielbull/react-router-server\"\u003e\u003cimg src=\"https://img.shields.io/travis/gabrielbull/react-router-server.svg?style=flat-square\" alt=\"Build Status\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://codeclimate.com/github/gabrielbull/react-router-server\"\u003e\u003cimg src=\"https://img.shields.io/codeclimate/github/gabrielbull/react-router-server.svg?style=flat-square\" alt=\"Code Climate\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.org/package/react-router-server\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/react-router-server.svg?style=flat-square\" alt=\"npm version\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://gitter.im/gabrielbull/react-router-server?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\"\u003e\u003cimg src=\"https://img.shields.io/gitter/room/gabrielbull/react-router-server.svg?style=flat-square\" alt=\"Gitter\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  Server Side Rendering library for React Router v4.\n\u003c/p\u003e\n\n## Help wanted!\n\nIf anyone is interested in taking over this project please let me know.\n\n## Table Of Content\n\n1. [About](#about)\n2. [Installation](#installation)\n3. [Examples](#examples)\n   - [Example](#complex-example)\n4. [Usage](#usage)\n   - [Server Side Rendering](#server-side-rendering)\n   - [Code Splitting](#code-splitting)\n   - [Fetch State](#fetch-state-usage)\n   - [Usage with Webpack](#webpack-usage)\n   - [Usage with React Router](#react-router-usage)\n   - [Usage with Redux](#redux-usage)\n5. [API](#api)\n   - [extractModules](#extract-modules)\n   - [fetchState](#fetch-state)\n   - [withDone](#with-done)\n   - [Module](#module)\n   - [preload](#preload)\n   - [renderToString](#render-to-string)\n   - [ServerStateProvider](#server-state-provider)\n6. [Contributing](#contributing)\n7. [License](#license)\n\n\u003ca name=\"about\"\u003e\u003c/a\u003e\n## About\n\nThis library allows to fetch states for your components on the server side and mount them on the client side.\n\nIt also allows to do code splitting by providing a component that can be used to load modules splitted by Webpack 2.\n\n\u003ca name=\"installation\"\u003e\u003c/a\u003e\n## Installation\n\n`npm install react-router-server --save`\n\n\u003ca name=\"examples\"\u003e\u003c/a\u003e\n## Examples\n\n\u003ca name=\"complex-example\"\u003e\u003c/a\u003e\n### Example\n\nA working example using Webpack bundle and preloading is \n[provided here](https://github.com/gabrielbull/react-router-server-complex-example). \nTo try for yourself, you can clone it and run it. This will provide a server accessible at \n[http://localhost:3000](http://localhost:3000).\n\n```\ngit clone git@github.com:gabrielbull/react-router-server-complex-example.git\nnpm install\nnpm start\n```\n\n\u003ca name=\"usage\"\u003e\u003c/a\u003e\n## Usage\n\n\u003ca name=\"server-side-rendering\"\u003e\u003c/a\u003e\n### Server Side rendering\n\nTo render an app that has code splitting or state fetching, you need to load the modules and states required by your app\nbefore rendering. `react-dom/server` does not offer a function to do that, but you can use the `renderToString` function \nprovided by this library. This function will return a promise that will return the rendered app once the modules and states are loaded.\n\n```jsx\nimport { renderToString } from 'react-router-server';\nimport App from './path/to/app';\n\nrenderToString(\u003cApp/\u003e)\n  .then(({ html }) =\u003e {\n    // send html to client side\n  });\n```  \n\n\u003ca name=\"code-splitting\"\u003e\u003c/a\u003e\n### Code Splitting\n\nThe code splitting consist of a component that you can use to load modules splitted by Webpack 2. \nIt also allows you to get information on the modules required to render a page so that you can preload \nthe modules before displaying the page on the client side.\n\nTo use code splitting, you will need to import the `Module` component and provide the `System.import` call inside \nthe module property of that component. Then, you need to defined a callback function as the children of the component.\n\n```jsx\nimport { Module } from 'react-router-server';\n\n\u003cModule module={() =\u003e System.import('./Foo')}\u003e\n  {module =\u003e module ? \u003cmodule.default/\u003e : \u003cdiv\u003eLoading...\u003c/div\u003e}\n\u003c/Module\u003e\n```\n\nTo preload the modules on the client side, you can use the `preload` method and pass the modules from the server into that method. \n\nIn the following example, `__INITIAL_MODULES__` would be provided by the server and rendered in the HTML document as a global variable.\n\n```jsx\nimport { preload } from 'react-router-server';\nimport { render } from 'react-dom';\nimport App from './path/to/app';\n\npreload(__INITIAL_MODULES__).then(() =\u003e render(\u003cApp/\u003e, document.getElementById('#my-app')));\n```\n\nYou can get the modules from the `renderToString` function on the server side and extract them from your webpack stats by using the `extractModules` method.\nFor more information on usage with webpack, check the [usage with webpack](#webpack-usage) part of this read me.\n\n```jsx\nimport { renderToString, extractModules } from 'react-router-server';\nimport App from './path/to/app';\nimport stats from './path/to/stats';\n\nrenderToString(\u003cApp/\u003e)\n  .then(({ html, modules }) =\u003e {\n    modules = extractModules(modules, stats);\n    // send html and modules to client side\n  });\n```\n\nTo be able to use `System.import` calls on the server side, you will need to install the [babel-plugin-system-import-transformer](https://github.com/thgreasi/babel-plugin-system-import-transformer) plugin.\n\n\u003ca name=\"fetch-state-usage\"\u003e\u003c/a\u003e\n### Fetch State\n\nOn the server side, you will often need to fetch data before rendering your component and then pass that data to the client side\nso that the components are in sync.\n\nTo fetch data for your components, use the `fetchState` decorator provided by this library. The `fetchState` decorator takes two arguments,\n`mapStateToProps` and `mapActionsToProps`. `mapStateToProps` allows you to map the state to the props of your component while `mapActionsToProps`\nallows you to map the `done` action to the props of your component. \n\n```jsx\nimport * as React from 'react';\nimport { fetchState } from 'react-router-server';\n\n@fetchState(\n  state =\u003e ({ message: state.message }),\n  actions =\u003e ({ done: actions.done })\n)\nclass MyComponent extends React.Component {\n  componentWillMount() {\n    if (!this.props.message) {\n      setTimeout(() =\u003e {\n        this.props.done({ message: 'Hello world!' });\n      }, 10);\n    }\n  }\n\n  render() {\n    return (\n      \u003cdiv\u003e{this.props.message}\u003c/div\u003e\n    );\n  }\n}\n```\n\nTo pass that state from the server to the client, you need to wrap the client app with the `ServerStateProvider` and pass the \nstate from the server into that component's `state` property.\n\nIn the following example, `__INITIAL_STATE__` would be provided by the server and rendered in the HTML document as a global variable.\n\n```jsx\nimport { ServerStateProvider } from 'react-router-server';\nimport App from './path/to/app';\n\n\u003cServerStateProvider state={__INITIAL_STATE__}\u003e\n  \u003cApp/\u003e\n\u003c/ServerStateProvider\u003e\n```\n\nYou can get the state from the `renderToString` function on the server side.\n\n```jsx\nimport { renderToString } from 'react-router-server';\nimport App from './path/to/app';\n\nrenderToString(\u003cApp/\u003e)\n  .then(({ html, state }) =\u003e {\n    // send html and state to client side\n  });\n```\n\n\u003ca name=\"webpack-usage\"\u003e\u003c/a\u003e\n### Usage with Webpack\n\nYou can extract the required modules per requests when running your server to pass them to the client side.\nThis allows you to preload your modules before running the client side app. To do so, you need to get the\n[stats from Webpack](https://github.com/webpack/docs/wiki/node.js-api#stats).\n\nThere are many ways to do this, but we recommend using the [stats-webpack-plugin](https://github.com/unindented/stats-webpack-plugin).\nHere's a code sample that you can add to your webpack config's plugins section. This will create a `stats.json` file that you can use to extract \nthe required modules for your app.\n\n```js\n[\n  new StatsPlugin('stats.json', {\n    chunkModules: true,\n    exclude: [/node_modules/]\n  })\n]\n```\n\nTo extract the modules, you can use the `extractModules` function and pass the modules provided by the `renderToString` as well as the stats\ngenerated by webpack. See the [code splitting usage](#code-splitting) part of this documentation to learn more on code splitting.\n\nTo be able to use `System.import` calls on the server side, you will need to install the [babel-plugin-system-import-transformer](https://github.com/thgreasi/babel-plugin-system-import-transformer) plugin.\n\n\u003ca name=\"react-router-usage\"\u003e\u003c/a\u003e\n### Usage with React Router\n\nTo use with React Router v4, you can pass the `Module` component to the `Route` component of React Router.\n\n```jsx\nimport { Route } from 'react-router';\nimport { Module } from 'react-router-server';\n\n\u003cRoute\n  exact\n  path=\"/\"\n  render={matchProps =\u003e (\n    \u003cModule module={() =\u003e System.import('./Foo')}\u003e\n      {module =\u003e module ? \u003cmodule.default {...matchProps}/\u003e : \u003cdiv\u003eLoading...\u003c/div\u003e}\n    \u003c/Module\u003e\n  )}\n/\u003e\n```\n\n\u003ca name=\"redux-usage\"\u003e\u003c/a\u003e\n### Usage with Redux\n\nIf you are rehydrating state with redux instead of using `ServerStateProvider`, all you need is access to the `done` action so the server can wait for async stuff to complete. In that case, you can use the `withDone` decorator, which is a shorthand for `fetchState(null, ({ done }) =\u003e ({ done }))`.\n\n```jsx\nimport * as React from 'react';\nimport { connect } from 'react-redux';\nimport { withDone } from 'react-router-server';\nimport { setMessage } from './actions';\n\n@withDone\n@connect(state =\u003e state.message, { setMessage })\nclass MyComponent extends React.Component {\n  componentWillMount() {\n    // using async actions\n    const { setMessage, done } = this.props;\n    setMessage('Hello world').then(done, done);\n  }\n\n  render() {\n    return (\n      \u003cdiv\u003e{this.props.message}\u003c/div\u003e\n    );\n  }\n}\n```\n\nFor more details on usage with redux, check [this boilerplate](https://github.com/diegohaz/arc/tree/redux-ssr).\n\n\u003ca name=\"api\"\u003e\u003c/a\u003e\n## API\n\n\u003ca name=\"extract-modules\"\u003e\u003c/a\u003e\n### extractModules\n\n`extractModules(modules, stats)`\n\n__modules__: modules provided by the renderToString method.\n\n__stats__: stats generated by webpack.\n\n\u003ca name=\"fetch-state\"\u003e\u003c/a\u003e\n### fetchState\n\n`fetchState(mapStateToProps, mapActionsToProps)`\n\n__mapStateToProps(state)__: function to map the state provided by the done action\nto props in your component;\n\n__mapActionsToProps(actions)__: function to map the actions\nto props in your component; Currently, only the done action exists and \nis used when you are finished fetching props.\n\n\u003ca name=\"with-done\"\u003e\u003c/a\u003e\n### withDone\n\nShorthand for `fetchState(null, ({ done }) =\u003e ({ done }))`\n\n\u003ca name=\"module\"\u003e\u003c/a\u003e\n### Module \n\nThe Module component allows to do code splitting. The Module component takes these propeties:\n\n__module__: a function that returns a System.import call. E.G. `() =\u003e System.import('./Foo')` \n\n__children__: a function. E.G. `{module =\u003e module ? \u003cmodule.default/\u003e : null}`\n\n\u003ca name=\"preload\"\u003e\u003c/a\u003e\n### preload\n\n`preload(modules)`\n\n__modules__: array of modules passed by the server side to the client side\nfor preloading.\n\n\u003ca name=\"render-to-string\"\u003e\u003c/a\u003e\n### renderToString\n\nAsync version of ReactDOM.renderToString.\n\n`renderToString(element)`\n\n__element__: The element to render\n\nReturns an object ({ html, state, modules }) with:\n\n__html__: the rendered HTML\n\n__state__: the app state provided by fetch state\n\n__modules__: the app modules provided by code splitting\n\n\u003ca name=\"server-state-provider\"\u003e\u003c/a\u003e\n### ServerStateProvider\n\nThe ServerStateProvider component is used for providing the server state \nto the client side. Provided by the `state` prop.\n\n\u003ca name=\"contributing\"\u003e\u003c/a\u003e\n## Contributing\n\nEveryone is welcome to contribute and add more components/documentation whilst following the [contributing guidelines](/CONTRIBUTING.md).\n\n\u003ca name=\"license\"\u003e\u003c/a\u003e\n## License\n\nReact Router Server is licensed under [The MIT License (MIT)](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgabrielbull%2Freact-router-server","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgabrielbull%2Freact-router-server","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgabrielbull%2Freact-router-server/lists"}