Coder Social home page Coder Social logo

dangerdespain / isomorphic-flux-boilerplate Goto Github PK

View Code? Open in Web Editor NEW

This project forked from iam4x/isomorphic-flux-boilerplate

0.0 2.0 0.0 620 KB

ES7 Isomorphic Flux/ReactJS Boilerplate

Home Page: http://isomorphic.iam4x.fr

JavaScript 96.95% CSS 3.05%

isomorphic-flux-boilerplate's Introduction

Circle CI Coverage Status Dependency Status devDependency Status NPM Version

A complete ES7 Isomorphic Universal ReactJS boilerplate with alt as Flux library.

A wonderfull boilerplate for Flux/ReactJS universal applications, running on Koa.

Demo: http://isomorphic.iam4x.fr

Libraries Included

TL;DR

Use with [email protected], 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 context (this.context.flux). Every time you want to uses stores or actions in a component you need to give it access through context.

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.

There's also alt-devtools enabled in development, it's a Chrome Extension that you can find here: https://github.com/goatslacker/alt-devtool

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!

In order to use FormattedRelative you have to require messages && locales from context and pass them as props:

static contextTypes = {
  messages: PropTypes.object.isRequired,
  locales: PropTypes.array.isRequired
}

render() {
  return (
    <FormattedRelative
      { ...this.context }
      value={Date.now() - (1000 * 60 * 60 * 24)} />
  );
}

Localized routes

We have an utility to generate severals routes for the same component (see app/utils/localized-routes.js).

Use the same logic as localized string, declare the localized routes into app/routes.js and into your data/{lang} file.

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.

Alt-resolver expose also an ApiClient for doing the requests to the intern API. It handle for you the cookies on server and URI matching between server and browser.

Wrap data-fetching requests from actions into promises and send them to altResolver like:

show(id) {
  // You need to return a fn in actions
  // to get alt instance as second parameter to access
  // `alt-resolver` and the ApiClient
  return (dispatch, { resolve, request  }) =>
  // We use `alt-resolver` from the boilerplate
  // to indicate the server we need to resolve
  // this data before server side rendering
    resolve(async () => {
      try {
        const response = await request({ url: '/users' });
        this.actions.indexSuccess(response);
      } catch (error) {
        this.actions.indexFail({ error });
      }
    });
}

Call the fetch action from component in the componentWillMount method:

import React, { Component, PropTypes } from 'react';
import connect from 'connect-alt';

// connect-alt is an util to connect store state to component props
// you can read more about it here: http://github.com/iam4x/connect-alt
// it handle store changes for you :)
//
// users -> store name
// collection -> `this.collection` into users store
//
@connect(({ users: { collection } }) => ({ users: collection }))
class Users extends Component {

  static contextTypes: { flux: PropTypes.object.isRequired }
  static propTypes: { users: PropTypes.array.isRequired }

  componentWillMount() {
    const { flux } = this.context
    return flux.getActions('users').fetch();
  }

  render() {
    const { users } = this.props;
    return (<pre>{ JSON.stringify(users, null, 4) }</pre>)
  }
}

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

It's super easy to do with nvm:

  • $ nvm install stable
  • $ nvm use stable
  • $ nvm alias default stable

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 add origin [email protected]:xxx/xxx.git)

Run the project in development:

  • $ npm run dev

Open 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!

(Note: ports 3000-3002 are needed, you can change this with $ PORT=3050 npm run dev it will run on 3050-3052)

Run tests

  • $ npm test will run the tests once
  • $ npm run dev-test 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:

  • $ npm run build

Then start the koa server:

  • $ NODE_ENV=production node server/index.js

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

(OSX) Run into docker for development

You can build and dev with the boilerplate through docker container, it runs with dinghy.

  • Install dinghy (it has support for NFS sharing which is required for changes detection and it's fast!)
  • $ dinghy up
  • $ docker-compose build (don't kill your terminal it take time to install node_modules for dev)
  • $ docker-compose up

Then open http://webapp.docker into your browser. (You can change this URL into docker-compose.yml)

Learn more

isomorphic-flux-boilerplate's People

Contributors

iam4x avatar lancetw avatar jbroadice avatar adamjv90 avatar allenfang avatar aegyed91 avatar joeframbach avatar maxsvargal avatar doodledood avatar nuragic avatar bitdeli-chef avatar quicksnap avatar tabakd avatar sogko avatar heidar avatar jasonlfunk avatar tizmagik avatar jeremymarc avatar iquabius avatar

Watchers

James Cloos avatar Devin Despain 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.