Awesome
React on Rails Starter Kit
Plug and play Starter Kit for the Ultimate React Framework.
Usage
- Clone/fork
npm install
- Hack the code
npm start
gulp watch
- 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
withesnext
andglobals:Promise
) -
Serveral bread-and-butter libs/polyfills, including:
lodash
(fast_
API implementation),bluebird
(fastPromise
API implementation),R.scope
(fastbind
for context-only function binding),cors
forexpress
,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.
- Promises (
-
Common JS bundling for the browser (using
browserify
)- all of the above transformations transpiled to ES5,
fs.readFileSync
and alike static files preloading (usingbrfs
),
-
development
/production
modes (configurable insrc/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
andPromise
.
- js minification (using
-
Style processing
normalize.css
included by default,autoprefixer
andcss-min
(inproduction
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 namedMyComponent
insrc/components
, and populates itsrender
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 updatesrc/componentsClasses
to reflect all the components insrc/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 usinggulp 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 <head> 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.