Starter repository for React on Rails. Fork it!
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
images
src
static
tasks
.editorconfig
.gitignore
README.md
config.js
gulpfile.js
package.json

README.md

React on Rails Starter Kit

Plug and play Starter Kit for the Ultimate React Framework.

Usage

  1. Clone/fork
  2. npm install
  3. Hack the code
  4. npm start
  5. gulp watch
  6. Visit http://localhost:8080/

Important note: Don't npm install react or anything similar. react-rails includes its own version of React, and you should use it. require('react-rails').React if needed, but React just doesn't work well if multiple instances are in the same package.

Release notes/news

  • 30/9/2014: Should be ready for use, but expect some bugs, still very early release. Feel free to post and issue.

Whats included?

This starter kit contains:

  • An opinionated, simple and efficient file structure (see below)

  • Preconfigured assets pipelines and build tools, including:

    • linting (jshint with esnext and globals:Promise)

    • Serveral bread-and-butter libs/polyfills, including:

      • lodash (fast _ API implementation),
      • bluebird (fast Promise API implementation),
      • R.scope (fast bind for context-only function binding),
      • cors for express,
      • co (generators-based coroutines).
    • ES6/7/JSX to ES5 transpiling of many features:

      • Promises (bluebird),
      • jsx transforms (react-tools),
      • es6 generators (using regenerator),
      • all the features supported by esnext:
        • arrow functions,
        • classes,
        • comprehensions,
        • computed property keys,
        • default params,
        • destructuring,
        • iterators + for-of,
        • object literal concise definitions,
        • object literal shorthand,
        • rest params,
        • spread,
        • template strings.
    • Common JS bundling for the browser (using browserify)

      • all of the above transformations transpiled to ES5,
      • fs.readFileSync and alike static files preloading (using brfs),
    • development/production modes (configurable in src/config.js) to opt-in/out of:

      • js minification (using UglifyJS 2),
      • css minification (using css-min),
      • skip runtime types/invariants checks from React and React on Rails,
      • reduce console verbosity,
      • disable long traces support for setImmediate and Promise.
    • Style processing

      • normalize.css included by default,
      • autoprefixer and css-min (in production mode) on components styles and stylesheets,
      • optionally declare your components' style in their class definition, they get processed and bundled into components.css and served statically. Who needs a CSS preprocessor when you get the full power of JS?
  • A complete starter app source, including:

    • A simple components hierarchy,
    • A navigation router,
    • A memory-based Flux (Store/EventEmitter/Dispatcher) named memory
    • An uplink-based Flux named uplink
    • A static server, serving static/ under the path /
    • A prerendering server,
    • A basic Uplink server implementing Flux over the wire,
    • Preconfigured plugins for React of Rails:
      • R.History, managing navigation,
      • R.Localize, managing i18n,
      • R.Window, managing window events,
      • R.XWindow, managing cross-window events,
      • R.Fullscreen, managing fullscreen state/events,
  • Several scaffolding tools:

    • gulp component --displayName=MyComponent [--tagName=div] to scaffold a component named MyComponent in src/components, and populates its render method with the appropriate JSX element. JSX element tagName defaults to div, but can be anything like "span", "MyOtherComponent", etc. Component name should match /[A-Z][a-zA-Z0-9]*$/, ie. be like MyComponent, not like myComponent or my_Component.
    • gulp import-all-components to update src/componentsClasses to reflect all the components in src/components.
    • npm start that "just works".

What now?

Everything in this repo is configurable.

  • Just want to plug in your components? Head to src/components and consider using gulp component for scaffolding.
  • Want to implement client-side global logic? Head to src/dispatchers/MemoryDispatcher.
  • Want to implement server-side global logic? Head to src/dispatchers/UplinkDispatcher.
  • Want to modify how you HTML contains? Head to src/index.tpl.
  • Want to include more stylesheets, external components or customize which plugins are used? Head to src/App.js.
  • Want to customize your passive REST backend? Head to src/Uplink.js.

File structure

The file structure has been carefully curated to be pleasant to work with. You are free to modify it but many things such as automated tasks and cross-dependencies depends on it.

Project root
+--package.json
|    Package configuration. Make sure to update it by running `npm init`.
|    Core module `assert` is listed as a dependency because oddly browserify requires it.
|
+--config.js
|    Configuration variables. Keys are straightforward, notable keys include
|    `supportedLocales`, `mode` (either `development` or `production`), and render/uplink
|    server hostnames and ports.
|    Don't mind the convoluted trick with process["env"]["NODE_ENV"], its working as intented.
|
+--.gitignore
|    In addition to `node_modules` and the usual, contains `dist` and `tmp`.
|    Consider removing `node_modules` and `dist` if you plan to use git for deployment.
|
+--README.md
|    This file. Overwrite with you own README.md.
|
+--gulpfile.js
|    Contains a series of preconfigured tasks. You can safely add yours.
|    Notable tasks include:
|      - `default`, which builds everything, puts the server executables in `dist` and the
|         bundled client in `static`,
|      - `watch`, which automatically rebuilds everything that changes,
|      - `component`, which bootstraps a new component using eg.
|        `gulp component --displayName="MyComponent"`
+--src
|  |  Single source of truth for the building pipeline. Contains all of your actual source.
|  |  Files in this directory will be transpiled to ES3, but you can safely use `jsx` tags
|  |  (in `.jsx` files), generators (`function*()`), arrow functions, destructuring, etc.
|  |
|  +--components
|  |  |  Directory for the components classes.
|  |  |  You should have exactly one file per component class, with the extension `.jsx`
|  |  |  and the `jsx` pragma `/** @jsx React.DOM */`. This file should export a single
|  |  |  value, which should be the result of `React.createClass`.
|  |  |  Components class names should have their first letter uppercased.
|  |  |  Most components should have `R.Component.Mixin`.
|  |  |  You may easily scaffold new components using
|  |  |  `gulp component --displayName=MyComponent` (see below).
|  |  |
|  |  +--Root.jsx
|  |  |    Default root component, preconfigured to play nicely as an isomorphic router
|  |  |    backed by the `memory` store populated by `R.History.Plugin`.
|  |  |    Routes are read from `/src/routers/NavigationRouter`.
|  |  |    Feel free to modify the routing behaviour, remove it, or move it
|  |  |    into another component.
|  |  |
|  |  +--HistoryLink.jsx
|  |  |    App-level link component preconfigured to play nicely with `R.History.Plugin`,
|  |  |    backed by the `memory` dispatcher.
|  |
|  +--dispatchers
|  |  |  Directory for the dispatchers classes.
|  |  |  You should have exactly one file per dispatcher class. This file should export a
|  |  |  single value, which should be the result of `R.Dispatcher.createDispatcher`.
|  |  |  Each dispatcher class defines how actions are dispatched, and most often trigger
|  |  |  side effects in the current Flux instance, such as updating a store.
|  |  |  A single dispatcher class can be used, but it is recommended to use one dispatcher
|  |  |  class per backend (eg. one for local data, one for server-sent data) to avoid
|  |  |  confusion.
|  |  |  Most dispatchers will simply be instances of a `R.Dispatcher.createDispatcher`
|  |  |  constructor, but since Dispatcher is just an API contract, you might want to
|  |  |  implement your own.
|  |  |
|  |  +--MemoryDispatcher.js
|  |  |  Default memory dispatcher. Add your actions listeners here.
|  |  |
|  |  +--UplinkDispatcher.js
|  |  |  Default uplink dispatcher. Add your actions listeners here.
|  |  |  Note that an uplink dispatcher usually won't actually do much on its own; most
|  |  |  times it will only check input and forward appropriate messages to the underlying
|  |  |  `Uplink` instance.
|  |
|  +--eventEmitters
|  |  |  Directory for the event emitters classes.
|  |  |  You should have exactly one file per event emitter class. This file should export
|  |  |  a single value, which should be the result of `R.EventEmitter.createEventEmitter`.
|  |  |  Most event emitters will use presets from `R.EventEmitter`, but since EventEmitter
|  |  |  is just an API contract, you might want to implement your own.
|  |  |
|  |  +--MemoryEventEmitter.js
|  |  |  Cached value of calling `R.EventEmitter.createMemoryEventEmitter`.
|  |  |  Represents a local event emitter residing in memory. It exposes an `emit` method
|  |  |  which a Dispatcher (usually a MemoryDispatcher) may invoke.
|  |  |
|  |  +--UplinkEventEmitter.js
|  |  |  Cache value of calling `R.EventEmitter.createUplinkEventEmitter`.
|  |  |  Represents a remote event emitter residing in an uplink server. It is
|  |  |  subscribe-only and a Dispatcher may not emit directly, only pass actions to an
|  |  |  uplink server that will then emit.
|  |
|  +--routers
|  |  |  Directory for the routers classes.
|  |  |  You should have exactly one file per router class. This file should export a
|  |  |  single value, which should be derived from `R.Router`.
|  |  |  Most routers will simply derive `R.Router` by prototypal inheritance and
|  |  |  adding some routes, but since Router is just and API contract, you might want
|  |  |  to implement your own.
|  |  |  Remember that in `R`, routers are just URL-patterns-friendly generalized regular
|  |  |  expressions, and are passive objects waiting for you to call `match` on them.
|  |  |
|  |  +--NavigationRouter.js
|  |  |  An demo navigation router, feel free to edit it.
|  |  |  Note that `/src/components/Root` relies on its behaviour, update it accordingly.
|  |
|  +--stores
|  |  |  Directory for the stores classes.
|  |  |  You should have exactly one file per store class. This file should export a
|  |  |  single  value, which should be the result of `R.Store.createStore`.
|  |  |  Most event emitters will use presets from `R.Store`, but since Store is just an
|  |  |  API contract, you might want to implement your own.
|  |  |
|  |  +--MemoryStore.js
|  |  |  Cached value of calling `R.Store.createMemoryStore`.
|  |  |  Represents a local store residing in memory. It exposes a `set` method which a
|  |  |  Dispatcher (usually a MemoryDispatcher) may invoke.
|  |  |
|  |  +--UplinkStore.js
|  |  |  Cached value of calling `R.Store.createUplinkStore`.
|  |  |  Represents the local reflection of a store residing in an Uplink server. This
|  |  |  reflection is automatically updated whenever the Uplink server is updated.
|  |
|  +--App.js
|  |  Main `R.App` class.
|  |  You may want to modify the main HTML file template, do more stuff at template vars
|  |  bootstrapping time, load more stylesheets, etc.
|  |  Default configuration include general purpose plugins (Window, History, Localize,
|  |  Fullscreen, XWindow), which you may remove if you don't want them, as well as
|  |  `normalize.css`.
|  |  If you want to add your CSS framework of choice (such as Twitter Bootstrap or Pure),
|  |  just drop your stylesheet there.
|  |  Don't forget to copy the stylesheet in `static` at build time (see
|  |  `gulpfile.js`).
|  |  If you need more scripts to be loaded on the client (eg. Facebook SDK), you can also
|  |  add them, but note that they won't be available in node, so make sure no isomorphic
|  |  code depends on them.
|  |
|  +--client.js
|  |  Client entry point. Simply mounts the class on the client. You most likey won't modify
|  |  anything here.
|  |
|  +--Flux.js
|  |  Main `R.Flux` class.
|  |  Here is setup the context in which each app instance will run (either on the client or
|  |  on the server).
|  |  You may want to add more initalization, but beware not to create leaks, such as
|  |  timeouts or intervals.
|  |  This file is typically where your define your remote connections (such as uplink or
|  |  REST client), stores, event emitters and dispatchers.
|  |  The default configuration includes:
|  |    - one uplink client
|  |    - one memory-backed store (`memory`)
|  |    - one uplink-backed store (`uplink`)
|  |    - one memory-backed event emitter (`memory`)
|  |    - one uplink-backed event emitter (`uplink`)
|  |    - one dispatcher intented to handle purely local actions (`memory`)
|  |    - one dispatcher intented to handle local-remote actions (`uplink`)
|  |
|  +--index.tpl
|  |  Main HTML template file. You probably won't need to modify it, since the default
|  |  template is production-ready, assuming `/App` is correctly configured.
|  |
|  +--render-server.js
|  |  Render/static server entry point. Starts a new `express` server and mounts a
|  |  `static` middleware to serve `/static` as `/`.
|  |  Feel free to replace `express` by something else or add more middleware (caching, etc).
|  |
|  +--server.js
|  |  Simple process manager whose sole job is to start both `/render-server` and
|  |  `/uplink-server` as child processes.
|  |  In addition, server.js watches for changes in `dist` and restarts its children
|  |  whenever its contents changes. Ideal in combination with `gulp watch`.
|  |
|  +--uplink-server.js
|  |  Uplink server entry point. Starts a new `express` server and mounts the uplink server.
|  |
|  +--Uplink.js
|  |  Main `R.Uplink` class. Simple `Uplink` client configured to work well.
|  |
|  +--UplinkServer.js
|  |  Main `R.UplinkServer` class. Resembles closely an all-in-one dispatcher.
|  |  Here you can modify what happens when a new session is created, or a session is
|  |  destroyed (either leaves or expires).
|  |  Stores and event emitterw need to be explicitly whitelisted (router-like patterns
|  |  are accepted).
|  |  Actions handlers are passed to their handler generators.
|  |  You may want to use locks to avoid race conditions (see `R.Lock`).
|
+--dist
|  Don't put anything here. Its intented to be populated and cleaned by automated tasks.
|
+--static
|  All files in this directory will be publicly accessible.
|  This is were the browserified client build is put, as `client.js`.
|  You can put here custom CSS stylesheets, external JS deps, images, favicon.ico, etc.
|  By default, should contain "normalize.css", copied from the npm package `normalize.css`
|  for automatic update.
|
+--tasks
|  |  Quality of life tasks to ease your development/deployment experience.
|  |
|  +--createAllComponentsStylesheets.js
|  |  Extracts all the styles declared inside components source files, process them, and
|  |  bundles them into the appropriate .css files in `static/`. For example, if a components'
|  |  `statics.getStylesheetRules` returned { components: ..., main: ... }, then the rules
|  |  will respectively get dumped into `static/components.css` and `static/main.css`.
|  |
|  +--createComponent.js
|  |  Pass a component name as `--displayName="ComponentName"`.
|  |  Creates a new file into `/src/components` in a new `.jsx` file, containing a predefined
|  |  template.
|  |
|  +--createComponent.tpl
|  |  Template injected into new components files. Feel free to modify it, for example if you
|  |  want to include more or less libs.