mobious framework
base on isomorphic-flux-boilerplate
ES6 Isomorphic Flux/ReactJS Boilerplate
A wonderfull boilerplate for Flux/ReactJS isomorphic applications, running on Koa.
Demo: http://isomorphic.iam4x.fr
Libraries Included
TL;DR
Use with iojs^1.8.0
or nodejs^0.12.0
, clone the repo, npm install
and npm run dev
.
Learn React (react-prime-draft), learn Flux and Alt (alt guide).
Wrap you async actions into promises, send them to altResolver
with altResolver.resolve(xxx)
for async server side rendering (see app/actions/users.js:31).
Build for production with npm run build
, don't forget to run the tests before npm test
.
Concepts
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.
With iso as helper we can populate alt flux stores before the first rendering and have a complete async isomorphic React application.
Run 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.
Flux
We use alt instance as Flux implementation.
We need to use instances for isomorphic applications, to have a unique store/actions per requests on the server.
On 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.
On 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.
Learn more about alt instances in the alt documentation.
Internationalization (i18n)
We use react-intl for internationalization, it uses browser implementation of Intl. For older browser and for node, we load the polyfill.
- Support localized strings (see data/en.js)
- Support localized dates, times and currencies.
Lang files and Intl polyfill are compiled into webpack chunks, for lazy-loading depending the locale of the user.
If 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 <html lang='x'>
on rendering.
Thank's to gpbl/react-locale-hot-switch for the implementation example!
Async data-fetching
Alt-resolver is the magic thing about the boilerplate, it will be our tool for resolving promises (data-fetching) before server side rendering.
Wrap data-fetching requests from actions into promises and send them to altResolver
like:
fetch() {
const promise = (resolve) => {
request
.get('http://example.com/api/users')
.end((response) => {
// fire new action to send data to store
this.actions.fetchSuccess(response.body);
return resolve();
});
};
// Send the `promise` to altResolver
this.alt.resolve(promise);
}
Call the fetch action from component in the componentWillMount
method:
propTypes: {
flux: React.PropTypes.object.isRequired
},
componentWillMount() {
const usersActions = this.props.flux.getActions('users');
return usersActions.fetch();
}
On browser side, the rendering won't be stopped and will resolve the promise instantly.
On 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.
Open app/actions/users.js
, app/utils/alt-resolver.js
, app/stores/users.js
for more information about data-fetching.
How to require()
images on server side
On client with webpack, you can directly require()
images for your images DOM element like:
<img src={require('images/logo.png')} />
Webpack 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.
But on node, require()
an image will just throw an exception. There's an util for loading image on server side to achieve this:
import imageResolver from 'utils/image-resolver'
let image;
// On browser just require() the image as usual
if (process.env.BROWSER) {
image = require('images/logo.png');
}
else {
image = imageResolver('images/logo.png');
}
...
render () {
return (
<img src={image} />
);
}
...
The utils/image-resolver with match the original image name with the compiled one.
Voilà! You can require()
images on server side too.
Installation / How-to
I recommend to use io.js to take advantages of ES6
without --harmony
flag on NodeJS
.
It's super easy to do with nvm:
$ nvm install iojs
$ nvm use iojs
$ nvm alias default iojs
(to make node
default to iojs
)
But it works well with nodejs^0.12.0
as well :)
After that, you will just need to clone the repo and install dependancies:
$ git clone -o upstream https://github.com/iam4x/isomorphic-flux-boilerplate.git app
$ cd app && npm install
(Don't forget to add your remote origin: $ git remote origin git@github.com:xxx/xxx.git
)
Run the project in development:
Open your browser to http://localhost:8080
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!
Run tests
$ npm test
will run the tests once$ ./node_modules/.bin/karma start
will watch for changes and run the tests on change
Build project:
Just run $ npm run build
, it will produce these tasks:
- Run tests from
test/spec/**/*.jsx
- Concat & minify styles to
/dist/app-[hash].css
- Concat & minify scripts to
/dist/js/app-[hash].js
Update the boilerplate
You can fetch the upstream branch and merge it into your master:
$ git checkout master
$ git fetch upstream
$ git merge upstream/master
$ npm install
Run in production
Build the project first:
Then start the koa server:
$ NODE_ENV=production node server/index.js
(iojs)$ NODE_ENV=production node --harmony server/index.js
(nodejs 0.12.x)
You can also use processes.json
to run the application with PM2 Monitor on your production server (customize it for your use):
$ pm2 start processes.json
Learn more
Common errors
Error: `libsass` bindings not found. Try reinstalling `node-sass`
- Be sure you are running with iojs > 1.7.0 (check node version
node -v
) - Delete node_modules
mv node_modules /tmp
(mv
is much faster than rm -rf
) - Clear npm cache
npm cache clear
- Build
node-sass
for your system $ npm install node-sass
- Re-install modules
npm install
This is an issue with node-sass
it is reported almost everywhere on the internet.
Windows 7:
On windows for building node-sass
before running the commands you need:
Windows 8:
There's an issue with node-sass #870 open.