{"id":19922721,"url":"https://github.com/igorprado/isomorphic-react-app","last_synced_at":"2025-05-03T07:30:52.958Z","repository":{"id":68242898,"uuid":"43920987","full_name":"igorprado/isomorphic-react-app","owner":"igorprado","description":"An isomorphic React app using isomorphic-flux-boilerplate","archived":false,"fork":false,"pushed_at":"2015-10-11T19:30:25.000Z","size":744,"stargazers_count":8,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-07T13:05:30.529Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://isomorphic-react-app.herokuapp.com/","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/igorprado.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":"2015-10-08T23:06:17.000Z","updated_at":"2022-05-30T02:17:24.000Z","dependencies_parsed_at":"2023-03-11T03:16:25.847Z","dependency_job_id":null,"html_url":"https://github.com/igorprado/isomorphic-react-app","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igorprado%2Fisomorphic-react-app","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igorprado%2Fisomorphic-react-app/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igorprado%2Fisomorphic-react-app/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igorprado%2Fisomorphic-react-app/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/igorprado","download_url":"https://codeload.github.com/igorprado/isomorphic-react-app/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252156785,"owners_count":21703350,"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","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":[],"created_at":"2024-11-12T22:11:58.176Z","updated_at":"2025-05-03T07:30:52.173Z","avatar_url":"https://github.com/igorprado.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/iam4x/isomorphic-flux-boilerplate.svg?branch=new-alt-resolver)](https://travis-ci.org/iam4x/isomorphic-flux-boilerplate)\n[![Coverage Status](https://coveralls.io/repos/iam4x/isomorphic-flux-boilerplate/badge.svg?branch=master\u0026service=github)](https://coveralls.io/github/iam4x/isomorphic-flux-boilerplate?branch=master)\n[![Dependency Status](https://david-dm.org/iam4x/isomorphic-flux-boilerplate.svg)](https://david-dm.org/iam4x/isomorphic-flux-boilerplate)\n[![devDependency Status](https://david-dm.org/iam4x/isomorphic-flux-boilerplate/dev-status.svg)](https://david-dm.org/iam4x/isomorphic-flux-boilerplate#info=devDependencies)\n[![NPM Version](http://img.shields.io/npm/v/isomorphic-flux-boilerplate.svg?style=flat)](https://www.npmjs.com/package/isomorphic-flux-boilerplate)\n\n# ES6 Isomorphic Flux/ReactJS Boilerplate\n\n\u003e A wonderfull boilerplate for **Flux/ReactJS** [isomorphic](http://nerds.airbnb.com/isomorphic-javascript-future-web-apps/) applications, running on **Koa**.\n\n**Demo:** http://isomorphic.iam4x.fr\n\n## Libraries Included\n\n* [react](https://facebook.github.io/react/)\n* [react-router](https://github.com/rackt/react-router)\n* [react-intl](https://github.com/yahoo/react-intl)\n* [react-redbox](https://github.com/KeywordBrain/redbox-react)\n* [alt](https://github.com/goatslacker/alt)\n* [iso](https://github.com/goatslacker/iso)\n* [koa](http://koajs.com/)\n* [webpack](http://webpack.github.io/)\n* [webpack-hot-middleware](https://github.com/glenjamin/webpack-hot-middleware)\n* [webpack-dev-middleware](https://github.com/webpack/webpack-dev-middleware)\n* [babeljs](https://babeljs.io/)\n* [cssnext](http://cssnext.io/)\n\n## TL;DR\n\nUse with `nodejs^4.x`, clone the repo, `npm install` and `npm run dev`.\n\nLearn React ([react-prime-draft](https://github.com/mikechau/react-primer-draft)), learn Flux and Alt ([alt guide](http://alt.js.org/guide/)).\n\nWrap you async actions into promises, send them to `altResolver` with `altResolver.resolve(xxx)` for async server side rendering (see [app/actions/users.js:31](https://github.com/iam4x/isomorphic-flux-boilerplate/blob/master/app/actions/users.js#L31)).\n\nBuild for production with `npm run build`, don't forget to run the tests before `npm test`.\n\n## Concepts\n\n**Koa** will be our server for the server side rendering, we use **alt** for our Flux architecture and **react-router** for routing in our app.\n\nWith **iso** as helper we can populate **alt** flux stores before the first rendering and have a complete async isomorphic React application.\n\nRun this boilerplate, you will see the server is fetching some fake users and will populate the `UserStore` with this data. **Koa** will render the first markup, serve the JavaScript and then it will entirely run on the client.\n\n## Flux\n\nWe use [alt](http://alt.js.org) instance as [Flux](http://facebook.github.io/react/blog/2014/05/06/flux.html) implementation.\n\nWe need to use instances for isomorphic applications, to have a unique store/actions per requests on the server.\n\nOn the client, Flux is initialized in `app/main.js` and sent to our first React Component via props (`this.props.flux`). Everytime you want to uses stores or actions in a component you need to give it access through props.\n\nOn the server, it's similar but Flux is initialized in `server/router.jsx`. The instance is sent to `alt-resolver` for rendering components with the correct props.\n\nLearn more about [alt instances](http://alt.js.org/docs/altInstances) in the alt documentation.\n\n## Internationalization (i18n)\n\nWe use [react-intl](https://github.com/yahoo/react-intl) for internationalization, it uses browser implementation of [Intl](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl). For older browser and for node, we load the polyfill.\n\n* Support localized strings (see [data/en.js](https://github.com/iam4x/isomorphic-flux-boilerplate/blob/master/app%2Fdata%2Fen.js))\n* Support localized dates, times and currencies.\n\nLang files and Intl polyfill are compiled into webpack chunks, for lazy-loading depending the locale of the user.\n\nIf user changes locale, it is saved into a cookie `_lang` and used by the server to know the locale of rendering. If there's no `_lang` cookie, server will rely on `Accept-Language` request header. Server will set `\u003chtml lang='x'\u003e` on rendering.\n\nThank's to [gpbl/react-locale-hot-switch](https://github.com/gpbl/react-locale-hot-switch) for the implementation example!\n\nIn order to use `FormattedRelative` you have to pass `{...this.props}` to component:\n\n```\n\u003cFormattedRelative\n  {...this.props}\n  value={Date.now() - (1000 * 60 * 60 * 24)} /\u003e\n```\n\n## Localized routes\n\nWe have an utility to generate severals routes for the same component (see `app/utils/localized-routes.js`).\n\nUse the same logic as localized string, declare the localized routes into `app/routes.js` and into your `data/{lang}` file.\n\n## Async data-fetching\n\nAlt-resolver is the magic thing about the boilerplate, it will be our tool for resolving promises (data-fetching) before server side rendering.\n\nWrap data-fetching requests from actions into promises and send them to `altResolver` like:\n\n```\nfetch() {\n  const promise = (resolve) =\u003e {\n    request\n      .get('http://example.com/api/users')\n      .end((response) =\u003e {\n        // fire new action to send data to store\n        this.actions.fetchSuccess(response.body);\n        return resolve();\n      });\n  };\n  // Send the `promise` to altResolver\n  this.alt.resolve(promise);\n}\n```\n\nCall the fetch action from component in the `componentWillMount` method:\n\n```\nstatic propTypes: {\n  flux: React.PropTypes.object.isRequired\n}\n\ncomponentWillMount() {\n  const usersActions = this.props.flux.getActions('users');\n  return usersActions.fetch();\n}\n```\n\nOn browser side, the rendering won't be stopped and will resolve the promise instantly.\n\nOn server side, `altResolver.render` will fire a first render to collect all the promises needed for a complete rendering. It will then resolve them, and try to re-render the application for a complete markup.\n\nOpen `app/actions/users.js`, `app/utils/alt-resolver.js`, `app/stores/users.js` for more information about data-fetching.\n\n## How to `require()` images on server side\n\nOn client with webpack, you can directly `require()` images for your images DOM element like:\n\n```\n\u003cimg src={require('images/logo.png')} /\u003e\n```\n\nWebpack will load them through the `url-loader` and if it's too big it will sent through `file-loader` for minification/compilation. The results is an image with a new filename for cache busting.\n\nBut on node, `require()` an image will just throw an exception. There's an util for loading image on server side to achieve this:\n\n```\nimport imageResolver from 'utils/image-resolver'\n\nlet image;\n// On browser just require() the image as usual\nif (process.env.BROWSER) {\n  image = require('images/logo.png');\n}\nelse {\n  image = imageResolver('images/logo.png');\n}\n\n...\nrender () {\n  return (\n    \u003cimg src={image} /\u003e\n  );\n}\n...\n```\n\nThe utils/image-resolver with match the original image name with the compiled one.\n\nVoilà! You can `require()` images on server side too.\n\n## Installation / How-to\n\nIt's super easy to do with [nvm](https://github.com/creationix/nvm):\n\n* `$ nvm install stable`\n* `$ nvm use stable`\n* `$ nvm alias default stable`\n\nAfter that, you will just need to clone the repo and install dependancies:\n\n* `$ git clone -o upstream https://github.com/iam4x/isomorphic-flux-boilerplate.git app`\n* `$ cd app \u0026\u0026 npm install`\n\n(Don't forget to add your remote origin: `$ git remote origin git@github.com:xxx/xxx.git`)\n\n### Run the project in development:\n\n* `$ npm run dev`\n\nOpen your browser to `http://localhost:3002` and you will see the magic happens! Try to disable JavaScript in your browser, you will still be able to navigate between pages of the application. Enjoy the power of isomorphic applications!\n\n(Note: ports 3000-3002 are needed, you can change this with `$ PORT=3050 npm run dev` it will run on 3050-3052)\n\n### Run tests\n\n* `$ npm test` will run the tests once\n* `$ npm run dev-test` will watch for changes and run the tests on change\n\n### Build project:\n\nJust run `$ npm run build`, it will produce these tasks:\n\n* Run tests from `test/spec/**/*.jsx`\n* Concat \u0026 minify styles to `/dist/app-[hash].css`\n* Concat \u0026 minify scripts to `/dist/js/app-[hash].js`\n\n### Update the boilerplate\n\nYou can fetch the upstream branch and merge it into your master:\n\n* `$ git checkout master`\n* `$ git fetch upstream`\n* `$ git merge upstream/master`\n* `$ npm install`\n\n### Run in production\n\nBuild the project first:\n\n* `$ npm run build`\n\nThen start the koa server:\n\n* `$ NODE_ENV=production node server/index.js`\n\nYou can also use `processes.json` to run the application with [PM2 Monitor](https://github.com/Unitech/pm2) on your production server (customize it for your use):\n\n* `$ pm2 start processes.json`\n\n### (OSX) Run into docker for development\n\nYou can build and dev with the boilerplate through docker container, it runs with dinghy.\n\n* Install [dinghy](https://github.com/codekitchen/dinghy) (it has support for NFS sharing which is required for changes detection and it's fast!)\n* `$ docker-compose up \u0026\u0026 open http://webapp.docker`\n\n### Learn more\n\n* [Official ReactJS website](http://facebook.github.io/react/)\n* [Official ReactJS wiki](https://github.com/facebook/react/wiki)\n* [Official Flux website](http://facebook.github.io/flux/)\n* [ReactJS Conf 2015 links](https://gist.github.com/yannickcr/148110d3ca658ad96c2b)\n* [Learn ES6](https://babeljs.io/docs/learn-es6/)\n* [ES6 Features](https://github.com/lukehoban/es6features#readme)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Figorprado%2Fisomorphic-react-app","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Figorprado%2Fisomorphic-react-app","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Figorprado%2Fisomorphic-react-app/lists"}