{"id":15634188,"url":"https://github.com/kirill-konshin/create-react-server","last_synced_at":"2025-08-21T01:32:10.157Z","repository":{"id":57343854,"uuid":"83188750","full_name":"kirill-konshin/create-react-server","owner":"kirill-konshin","description":"Server \u0026 middleware for React + Router + Redux with Server Side Rendering","archived":false,"fork":false,"pushed_at":"2018-02-27T21:40:53.000Z","size":136,"stargazers_count":142,"open_issues_count":2,"forks_count":19,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-07-29T05:02:05.035Z","etag":null,"topics":["react","react-redux","react-router","redux","server-rendering","webpack"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kirill-konshin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-02-26T06:40:06.000Z","updated_at":"2023-12-03T15:46:48.000Z","dependencies_parsed_at":"2022-09-12T06:30:33.452Z","dependency_job_id":null,"html_url":"https://github.com/kirill-konshin/create-react-server","commit_stats":null,"previous_names":["kirill-konshin/react-router-redux-middleware"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/kirill-konshin/create-react-server","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kirill-konshin%2Fcreate-react-server","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kirill-konshin%2Fcreate-react-server/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kirill-konshin%2Fcreate-react-server/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kirill-konshin%2Fcreate-react-server/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kirill-konshin","download_url":"https://codeload.github.com/kirill-konshin/create-react-server/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kirill-konshin%2Fcreate-react-server/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270943039,"owners_count":24672378,"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-18T02:00:08.743Z","response_time":89,"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":["react","react-redux","react-router","redux","server-rendering","webpack"],"created_at":"2024-10-03T10:52:09.978Z","updated_at":"2025-08-21T01:32:09.839Z","avatar_url":"https://github.com/kirill-konshin.png","language":"JavaScript","readme":"Create React Server\n===================\n\nConfig-free server side rendering for React applications based on React Router. Compatible with Redux apps and\nWebpack Dev Middleware for simple and painless development and production usage. Comes as [CLI script](#cli-mode),\n[standalone server](#custom-server), and [middleware](#middleware).\n\n*This package is formerly known as `react-router-redux-middleware` (which is now deprecated).*\n\n- [Installation](#installation)\n- [Examples](#examples)\n- [Async Routes](#async-routes)\n- [Preconditions](#preconditions)\n- [CLI mode](#cli-mode) — simple integration with Create React App (aka React Scripts)\n- [Config](#config)\n- [Template Function](#template-function)\n- [Custom server](#custom-server)\n- [Use with Webpack Dev Middleware](#middleware) useful for \n- [Use with React Helmet](#use-with-react-helmet)\n- [Asynchronous require](#asynchronous-require)\n- [Handling props updates](#handling-props-updates)\n\n## Installation\n\n```bash\nnpm install create-react-server babel-preset-react-app babel-preset-es2015 --save-dev\n```\n\nYou don't have to install `babel-preset-react-app` if you use Create React App, it will be pre-installed already.\n\n## Examples\n\n- With Create React App: [examples/create-react-app](https://github.com/kirill-konshin/create-react-server/tree/master/examples/create-react-app)\n- With Webpack Blocks (custom webpack config, server, dev middleware): [examples/webpack-blocks](https://github.com/kirill-konshin/create-react-server/tree/master/examples/webpack-blocks)\n\nIn order to use examples you should clone the repository and do `npm install` inside the repo and then separate\n`npm install` in example dir.\n\n```bash\ngit clone https://github.com/kirill-konshin/create-react-server.git\ncd create-react-server\nnpm install\ncd examples/[any-example]\nnpm install\nnpm run redeploy # launch in production mode\n```\n\n## Async Routes\n\n**!!!ATTENTION!!! Due to changes in React Router 4 async routes are no longer supported by this package!**\n\nOfficial RR4 documentation says the following: \n\n\u003e 1. You need synchronous module resolution on the server so you can get those bundles in the initial render.    \n\u003e 2. You need to load all the bundles in the client that were involved in the server render before rendering so that\n\u003e the client render is the same as the server render. (The trickiest part, I think its possible but this is where\n\u003e I gave up.)   \n\u003e 3. You need asynchronous resolution for the rest of the client app’s life.\n\n[Code Splitting \u0026 Server Rendering](https://reacttraining.com/react-router/web/guides/code-splitting/code-splitting-server-rendering)\n\nSo not at this moment at least, stay tuned, we will try to add this in future releases! Especially if React Fiber (16)\nwill take care of some async component lifecycle.\n\n## Preconditions\n\n### Add `.babelrc` file or `babel` section of `package.json`\n\n```json\n{\n    \"presets\": [\n      \"es2015\",\n      \"react-app\"\n    ]\n}\n```\n\n### Page (e.g. leaf router node)\n\nServer rendering procedure takes `getInitialProps` static property and performs everything defined in it both on server\nand later on client (if needed). Anything that was returned from `getInitialProps` becomes the initial set of props\nwhen component will be rendered on server.\n\nOn client these props will be available with some delay, so you may use custom property `initialLoading` which will be\n`true` while `getInitialProps` function is resolving.\n\nIf an error occurs inside `getInitialProps` it will be available via `initialError` property. This property is populated\nfrom the server as well (as a string, no trace, you may capture this also in `template` function).\n\nComponent also receives a wrapped version of `getInitialProps` in its `props`, so that it can be called when needed,\nfor example when `componentWillReceiveProps` on React Router route change to load new data, but be careful and don't\ncause infinite loops or race conditions.\n\nIf you use `withWrapper` you *must* wrap each leaf page, otherwise if you open unwrapped page in browser and then\nnavigate to wrapped no `getInitialProps` will be called because wrapped will assume that it's first run.\n\n```js\n// src/Page.js\n\nimport React, {Component} from \"react\";\nimport {connect} from \"react-redux\"; // this is optional\nimport {withWrapper} from \"create-react-server/wrapper\";\n\nexport class App extends Component {\n\n    static async getInitialProps({location: {pathname, query}, params, store}) {\n        await store.dispatch(barAction()); // this is optional\n        return {custom: 'custom'};\n    };\n\n    render() {\n        const {foo, bar, custom, initialError} = this.props;\n        if (initialError) return \u003cpre\u003eInitial Error: {initialError.stack}\u003c/pre\u003e;\n        return (\n            \u003cdiv\u003eFoo {foo}, Bar {bar}, Custom {custom}\u003c/div\u003e\n        );\n    }\n\n}\n\nApp = connect(state =\u003e state)(App); // this is optional\nexport default withWrapper(App); // here we connect to WrapperProvider\n```\n\nComponent which will be used as 404 stub should have `notFound` static property:\n\n```js\n// src/NotFound.js\n\nimport React, {Component} from \"react\";\n\nexport default class NotFound extends Component {\n    static notFound = true;\n    render() {\n        return (\n            \u003cdiv\u003e404 Not Found\u003c/div\u003e\n        );\n    }\n\n}\n```\n\n### Main App\n\nYou have to make a `createApp` function that should return an app with React Router routes.\n\n```js\n// src/app.js\n\nimport React from \"react\";\nimport {Route, IndexRoute} from \"react-router\";\nimport NotFound from './NotFound';\nimport Page from './Page';\nimport IndexPage from './IndexPage';\n\nexport default ({state, props, req, res}) =\u003e {\n\n    if (!state \u0026\u0026 !!req) { // this means function is called on server\n        state = {\n            'foo': req.url + ':' + Date.now()\n        };\n    }\n\n    return (\n        \u003cProvider store={createStore(state)}\u003e\n            \u003cWrapperProvider initialProps={props}\u003e\n                \u003cSwitch\u003e\n                    \u003cRoute exact path=\"/\" component={IndexPage}/\u003e\n                    \u003cRoute path=\"/page\" component={Page}/\u003e\n                    \u003cRoute component={NotFound}/\u003e\n                \u003c/Switch\u003e\n            \u003c/WrapperProvider\u003e\n        \u003c/Provider\u003e\n    );\n\n};\n```\n\nIf you don't use Redux then `Provider` is not needed.\n\nParameters that function receives are (all parameters may be `null` depending on where the function is launched, you may\nhave custom logic specifically for server or client based on what paratements are available):\n\n- `state` \u0026mdash; initial Redux state received from server (if any)\n- `props` \u0026mdash; initial props received from server (if any)\n- `req` \u0026mdash; NodeJS Request (if any)\n- `res` \u0026mdash; NodeJS Response (if any)\n\n### Redux (optional)\n\nIf your app is using Redux, then you will have to make a `createStore` function, that should take initial state as an\nargument and return a new `Store`:\n\n```js\n// src/store.js\n\nimport {createStore} from \"redux\";\n\nfunction reducer(state, action) { return state; }\n\nexport default function (initialState, {req, res}) {\n    if (req) { // it means it's launched from server in CLI mode\n        initialState = {foo: res.url}; // so we can pre-populate something\n    }\n    return createStore(\n        reducer,\n        initialState\n    );\n}\n```\n\n### Main App Entry Point\n\nYou have to create a root app component, which normally consists only of `BrowserRouter` or `HashRouter` and a call to\n`createApp`.\n\n```js\n// src/index.js\n\nimport React from \"react\";\nimport {render} from \"react-dom\";\nimport {BrowserRouter} from \"react-router-dom\";\nimport createApp from \"./app\";\n\nconst Root = () =\u003e (\n    \u003cBrowserRouter\u003e\n        {createApp({\n            state: window.__INITIAL_STATE__, // you can skip this if you don't use Redux\n            props: window.__INITIAL__PROPS__\n        })}\n    \u003c/BrowserRouter\u003e\n);\n\nrender((\u003cRoot/\u003e), document.getElementById('root'));\n```\n\n## CLI Mode\n \nFirst of all prepare your application according to steps in [preconditions](#preconditions).\n\nIt is convenient to put console command into `scripts` section of `package.json`:\n\n```json\n{\n    \"build\": \"react-scripts build\",\n    \"server\": \"create-react-server --app path-to/src/app.js [options]\"\n}\n```\n\nAll specified JS files must export functions as `default export` or as `module.exports`. It assumes that\n`--app path-to-app.js` as path to file which exports a `createApp` and so on.\n\nAvailable options:\n\n- `--app` or `-r` path to JS file with `createApp` function\n- `--template` or `-t` path to JS file with `template` function\n- `--outputPath` or `-o` as path to your `build` (e.g. your static files)\n- `--templatePath` or `-i` path to your `index.html`\n- `--debug` or `-d` if you want to get more information of requests handling \u0026 stack traces of errors\n- `--port` or `-p` to bind to something other than `3000`, port will also be automatically taken from `process.env.PORT`\n\n\nYou may also run with `NODE_ENV=development` to get more info:\n\n```bash\nNODE_ENV=development create-react-server [your options]\n```\n\nThen run from console:\n\n```bash\nnpm run build\nnpm run server\n```\n\nNow if you open `http://localhost:3000` you will see a page rendered on the server.\n\n## Config\n\nMiddleware accepts following options:\n\n- `options.outputPath` **required** path with static files, usually equals to Webpack's `output.path`\n- `options.app({props, state, req, res})` **required** function must return an app that uses React Router \n- `options.template` *optional*, main [template function](#template-function), performs injection of rendered HTML to\n    the template, default = replaces `\u003cdiv id=\"root\"\u003e\u003c/div\u003e` with `\u003cdiv id=\"root\"\u003e%HTML%\u003c/div\u003e`\n    completely failed to render\n- `options.templatePath` *optional* path to `index.html`, default = `%outputPath%/index.html`\n- `options.debug` *optional* emits to console some extra information about request handling, default = `false`\n- `options.initialStateKey` *optional* key in `window` object that will be used to pass initial props, \n    default = `__INITIAL_PROPS__`\n- `options.initialPropsKey` *optional* key in `window` object that will be used to pass initial state, \ndefault = `__INITIAL_STATE__` \n\nServer accepts following options in addition to the ones accepted by middleware:\n\n- `options.skipExtensions` *optional* array of strings that represent most commonly imported non-JS extensions that has\n    to be skipped during server build, default = `['css', 'jpg', 'gif', ...]` \n- `options.port` *optional* port to listen, default = `3000`\n- `options.listen` *optional* Express's listen function\n\n## Template Function\n\nTemplate function performs injection of rendered HTML to the template. This function will also be called if React App\nfailed to render (e.g. in case of server error).\n\nFunction accepts `config` as parameter with the following always available properties:\n\n- `config.error` error object if function is called as error handler, equals `null` otherwise\n- `config.req` instance of NodeJS Request\n- `config.res` instance of NodeJS Response\n- `config.template` contents of `index.html` or any other file defined in `templatePath` option\n\nIf function is called in a **normal** way, e.g. NOT as error handler, the following properties will also be provided,\nsome of them still *may* be available in error handler mode, depending on which stage the error has happened:\n\n- `config.component` matched component (your leaf page)\n- `config.html` result of React rendering\n- `config.initialProps` result of `getInitialProps` (resolved result of Promise if it was returned)\n- `config.store` instance of Redux Store\n\nMost common cases when this function is called as error handler are:\n\n- You forgot to configure React Router's fallback route, e.g. `\u003cRoute path=\"*\" component={...}/\u003e`\n- React Router has returned an error\n\nIf you don't output any error information then the client will be rendered as if nothing happened.\n\nBy default this function replaces `\u003cdiv id=\"root\"\u003e\u003c/div\u003e` (exactly as written). If there is an error — it's HTML is\ninjected right before `div#root`.\n\nIf anything will be thrown from this function, then default error handler will take over. You should avoid this by\nplacing `try {} catch {}` around your code, in this case default handler wiil not be called.\n\n## Custom server\n\nFirst of all prepare your application according to steps in [preconditions](#preconditions).\n\nIn these example we will use `express` server and `babel-cli`:\n\n```bash\nnpm install express babel-cli --save-dev\n```\n\nModify `scripts` section of `package.json`:\n\n```json\n{\n    \"build\": \"react-scripts build \u0026\u0026 npm run build-server\",\n    \"build-server\": \"NODE_ENV=production babel --source-maps --out-dir build-lib src\",\n    \"server\": \"node ./build-lib/server.js\"\n}\n```\n\nIt makes client side build using Create React App (React Scripts) and server side build using Babel, which takes\neverything from `src` and puts the outcome to `build-lib`. You may add this directory to `.gitignore`.\n\n```js\n// src/server.js\n\nimport path from \"path\";\nimport {createExpressServer} from \"create-react-server\";\nimport app from \"./app\";\n\ncreateExpressServer({\n    port: process.env.PORT || 3000,\n    app: app,\n    template: ({template, html, req}) =\u003e (\n        template.replace(\n            `\u003cdiv id=\"root\"\u003e\u003c/div\u003e`,\n            `\u003cdiv id=\"root\"\u003e${html}\u003c/div\u003e`)),\n    outputPath: path.join(process.cwd(), 'build')\n});\n```\n\nCheck out the ready-to-use example in [examples/create-react-app](https://github.com/kirill-konshin/create-react-server/tree/master/examples/create-react-app)\nfolder.\n\nIn this mode your `createStore` function will on server will receive second config argument: `{req, res}` with request\nand response respectively. In other modes you can control what is passed where.\n\n## Middleware\n\nThere are two middleware modes: for Webpack Dev Server and for Express server.\n\nIf you have access to `webpack.config.js` then you may run the Webpack Dev Server along with server side rendering,\nthis example covers both.\n\nIn order to do that we need to install `webpack-dev-server` (in addition to packages from \n[preconditions step](#preconditions)), you may skip this if you have already installed it. In these example we will use\n`express` server and `babel-cli` to make server side builds:\n\n```bash\nnpm install express babel-cli babel-preset-react-app webpack-dev-server html-webpack-plugin --save-dev\n```\n\n*Note: you don't have to install `babel-preset-react-app` if you use Create React App or you already have preset.\n\n### Modify `scripts` section of `package.json`\n\nIn this example we run server by Babel Node, in this case server will be transformed in runtime (which is not\nrecommended for production). You also can build the server like in [custom server](#custom-server) section.\n\n```json\n{\n    \"server-dev\": \"NODE_ENV=development babel-node ./src/server.js\",\n    \"server-runtime\": \"NODE_ENV=production babel-node ./src/server.js\"\n}\n```\n\n### Webpack Config\n\nMain entry file `index.html` should be a part of webpack build, e.g. emitted to you output path. It could be a\nreal file or generated by `HtmlWebpackPlugin`, but it has to be known by Webpack.\n\nMake sure your `webpack.config.js` has all the following:\n\n```js\n// webpack.config.js\n\nvar HtmlWebpackPlugin = require('html-webpack-plugin');\nmodule.exports = {\n//...\n    \"output\": {\n        path: process.cwd() + '/build', // mandatory\n        publicPath: '/',\n    },\n    \"plugins\": [new HtmlWebpackPlugin({\n        filename: 'index.html',\n        favicon: './src/favicon.ico', // this is optional\n        template: './src/index.html'\n    })],\n    devServer: {\n        port: process.env.PORT || 3000,\n        contentBase: './src',\n    }\n//...\n}\n```\n\n### Server\n\n```js\n// src/server.js\n\nimport path from \"path\";\nimport Express from \"express\";\nimport webpack from \"webpack\";\nimport Server from \"webpack-dev-server\";\nimport app from \"./app\"; // same file as in client side\nimport config from \"../webpack.config\";\nimport {createExpressMiddleware, createWebpackMiddleware, skipRequireExtensions} from \"create-react-server\";\n\nskipRequireExtensions(); // this may be omitted but then you need to manually teach Node to ignore non-js files\n\nconst port = process.env.PORT || 3000;\n\nconst options = {\n    app: app,\n    template: ({template, html}) =\u003e (template.replace(\n        // !!!!! MUST MATCH THE INDEX.HTML\n        `\u003cdiv id=\"root\"\u003e\u003c/div\u003e`,\n        `\u003cdiv id=\"root\"\u003e${html}\u003c/div\u003e`\n    )),\n    templatePath: path.join(config.output.path, 'index.html'),\n    outputPath: config.output.path\n};\n\nif (process.env.NODE_ENV !== 'production') {\n\n    const compiler = webpack(config);\n\n    config.devServer.setup = function(app) {\n        app.use(createWebpackMiddleware(compiler, config)(options));\n    };\n\n    new Server(compiler, config.devServer).listen(port, '0.0.0.0', listen);\n\n} else {\n\n    const app = Express();\n\n    app.use(createExpressMiddleware(options));\n    app.use(Express.static(config.output.path));\n\n    app.listen(port, listen);\n\n}\n\nfunction listen(err) {\n    if (err) throw err;\n    console.log('Listening %s', port);\n}\n```\n\nCheck out the ready-to-use example in [examples/webpack-blocks](https://github.com/kirill-konshin/create-react-server/tree/master/examples/webpack-blocks)\nfolder.\n\n## Use with React Helmet\n\nTake a look at React Helmet's [readme note about server side rendering](https://github.com/nfl/react-helmet#server-usage).\nIn a few words you have to add `renderStatic()` call to your implementation of `template` option:\n\n```js\nimport Helmet from \"react-helmet\";\n\nconst template = ({template, html, req}) =\u003e {\n\n    const head = Helmet.renderStatic();\n\n    return template\n        .replace(\n            `\u003cdiv id=\"root\"\u003e\u003c/div\u003e`,\n            `\u003cdiv id=\"root\"\u003e${html}\u003c/div\u003e`\n        )\n        .replace(\n            /\u003ctitle\u003e.*?\u003c\\/title\u003e/g,\n            head.title.toString()\n        )\n        .replace(\n            /\u003chtml\u003e/g,\n            '\u003chtml ' + head.htmlAttributes.toString() + '\u003e'\n        );\n\n};\n```\n\n## Asynchronous Require\n\nIf you use `require.ensure` in your app, you will have to install `babel-plugin-transform-ensure-ignore`.\n\n```bash\nnpm install babel-plugin-transform-ensure-ignore --save-dev\n```\n\nAnd add it to `.babelrc` file or `babel` section of `package.json`:\n\n```json\n{\n    \"presets\": [\n      \"es2015\",\n      \"react-app\"\n    ],\n    \"plugins\": [\n      \"transform-ensure-ignore\"\n    ]\n}\n```\n\nIf you use dynamic `import()` function, then you will need more plugins `babel-plugin-dynamic-import-webpack`, it should\nbe used together with `babel-plugin-transform-ensure-ignore`. Make sure it is used only on server, and Webpack (client\nbuild) will not pick it up. On client plugin `babel-plugin-syntax-dynamic-import` should be used.\n\n## Handling props updates\n\nYour component may receive props from React Router without unmounting/mounting, for example `query` or `param` has\nchanged.\n\nIn this case you can create a `componentWillReceiveProps` lifecycle hook and call `this.props.getInitialProps()` from\nit to force static `getInitialProps` method to be called again:\n\n```js\nexport class Page extends React.Component {\n\n    static async getInitialProps({params}) {\n        var res = await fetch(`/pages?slug=${params.slug}`);\n        return await res.json();\n    }\n\n    componentWillReceiveProps(newProps) {\n        if (this.props.params.slug !== newProps.params.slug) this.props.getInitialProps();\n    }\n\n    render() {\n        // your stuff here\n    }\n\n}\n\nexport default withWrapper(Page);\n```","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkirill-konshin%2Fcreate-react-server","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkirill-konshin%2Fcreate-react-server","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkirill-konshin%2Fcreate-react-server/lists"}