├── .editorconfig ├── .gitignore ├── README.md ├── config.js ├── gulpfile.js ├── images └── ReactLogo.svg ├── package.json ├── src ├── App.js ├── Flux.js ├── Uplink.js ├── UplinkServer.js ├── client.js ├── components │ ├── AboutPage.jsx │ ├── CurrentVisitorsCount.jsx │ ├── HistoryLink.jsx │ ├── HomePage.jsx │ ├── NotFoundPage.jsx │ ├── Pages.jsx │ ├── Root.jsx │ └── TotalVisitorsCount.jsx ├── dispatchers │ ├── MemoryDispatcher.js │ └── UplinkDispatcher.js ├── eventEmitters │ ├── MemoryEventEmitter.js │ └── UplinkEventEmitter.js ├── index.tpl ├── render-server.js ├── routers │ └── NavigationRouter.js ├── server.js ├── stores │ ├── MemoryStore.js │ └── UplinkStore.js ├── styles.js └── uplink-server.js ├── static └── ReactLogo.svg └── tasks ├── createComponent.js └── createComponent.tpl /.editorconfig: -------------------------------------------------------------------------------- 1 | root=true 2 | [*] 3 | end_of_line = lf 4 | insert_final_newline = true 5 | indent_style = space 6 | indent_size = 2 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | tmp 4 | *.pid 5 | *.lock 6 | npm-debug.log 7 | static/components.css 8 | static/client.js 9 | static/normalize.css 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | React on Rails Starter Kit 2 | ========================== 3 | 4 | Plug and play Starter Kit for the [Ultimate React Framework](https://github.com/elierotenberg/react-rails). 5 | 6 | Usage 7 | ===== 8 | 0. Clone/fork 9 | 0. `npm install` 10 | 0. Hack the code 11 | 0. `npm start` 12 | 0. `gulp watch` 13 | 0. Visit `http://localhost:8080/` 14 | 15 | Important note: Don't `npm install react` or anything similar. `react-rails` includes its own version of React, 16 | and you should use it. `require('react-rails').React` if needed, but React just doesn't work well if multiple 17 | instances are in the same package. 18 | 19 | 20 | Release notes/news 21 | ================== 22 | - 30/9/2014: Should be ready for use, but expect some bugs, still very early release. 23 | Feel free to post and issue. 24 | 25 | Whats included? 26 | =============== 27 | 28 | This starter kit contains: 29 | 30 | - An opinionated, simple and efficient file structure (see below) 31 | 32 | - Preconfigured assets pipelines and build tools, including: 33 | - linting (`jshint` with `esnext` and `globals:Promise`) 34 | - Serveral bread-and-butter libs/polyfills, including: 35 | - `lodash` (fast `_` API implementation), 36 | - `bluebird` (fast `Promise` API implementation), 37 | - `R.scope` (fast `bind` for context-only function binding), 38 | - `cors` for `express`, 39 | - `co` (generators-based coroutines). 40 | 41 | - ES6/7/JSX to ES5 transpiling of many features: 42 | - Promises (`bluebird`), 43 | - `jsx` transforms (`react-tools`), 44 | - es6 generators (using [`regenerator`](https://github.com/facebook/regenerator)), 45 | - all the features supported by [`esnext`](https://github.com/esnext/esnext): 46 | - arrow functions, 47 | - classes, 48 | - comprehensions, 49 | - computed property keys, 50 | - default params, 51 | - destructuring, 52 | - iterators + for-of, 53 | - object literal concise definitions, 54 | - object literal shorthand, 55 | - rest params, 56 | - spread, 57 | - template strings. 58 | 59 | - Common JS bundling for the browser (using `browserify`) 60 | - all of the above transformations transpiled to ES5, 61 | - `fs.readFileSync` and alike static files preloading (using `brfs`), 62 | 63 | - `development`/`production` modes (configurable in `src/config.js`) to opt-in/out of: 64 | - js minification (using `UglifyJS 2`), 65 | - css minification (using `css-min`), 66 | - skip runtime types/invariants checks from React and React on Rails, 67 | - reduce console verbosity, 68 | - disable long traces support for `setImmediate` and `Promise`. 69 | 70 | - Style processing 71 | - `normalize.css` included by default, 72 | - `autoprefixer` and `css-min` (in `production` mode) on components styles and stylesheets, 73 | - optionally declare your components' style in their class definition, they get processed 74 | and bundled into `components.css` and served statically. Who needs a CSS preprocessor when you 75 | get the full power of JS? 76 | 77 | - A complete starter app source, including: 78 | - A simple components hierarchy, 79 | - A navigation router, 80 | - A memory-based Flux (Store/EventEmitter/Dispatcher) named `memory` 81 | - An uplink-based Flux named `uplink` 82 | - A static server, serving `static/` under the path `/` 83 | - A prerendering server, 84 | - A basic Uplink server implementing Flux over the wire, 85 | - Preconfigured plugins for React of Rails: 86 | - `R.History`, managing navigation, 87 | - `R.Localize`, managing i18n, 88 | - `R.Window`, managing window events, 89 | - `R.XWindow`, managing cross-window events, 90 | - `R.Fullscreen`, managing fullscreen state/events, 91 | 92 | - Several scaffolding tools: 93 | - `gulp component --displayName=MyComponent [--tagName=div]` to scaffold a component 94 | named `MyComponent` in `src/components`, and populates its `render` method with the appropriate JSX element. 95 | JSX element tagName defaults to div, but can be anything like "span", "MyOtherComponent", etc. 96 | Component name should match /[A-Z][a-zA-Z0-9]*$/, ie. be like MyComponent, not like myComponent or my_Component. 97 | - `gulp import-all-components` to update `src/componentsClasses` to reflect all the components in `src/components`. 98 | - `npm start` that "just works". 99 | 100 | 101 | What now? 102 | ========= 103 | 104 | Everything in this repo is configurable. 105 | 106 | - Just want to plug in your components? Head to `src/components` and consider using `gulp component` for scaffolding. 107 | - Want to implement client-side global logic? Head to `src/dispatchers/MemoryDispatcher`. 108 | - Want to implement server-side global logic? Head to `src/dispatchers/UplinkDispatcher`. 109 | - Want to modify how you HTML
contains? Head to `src/index.tpl`. 110 | - Want to include more stylesheets, external components or customize which plugins are used? Head to `src/App.js`. 111 | - Want to customize your passive REST backend? Head to `src/Uplink.js`. 112 | 113 | File structure 114 | ============== 115 | 116 | The file structure has been carefully curated to be pleasant to work with. 117 | You are free to modify it but many things such as automated tasks and cross-dependencies depends on it. 118 | 119 | ``` 120 | Project root 121 | +--package.json 122 | | Package configuration. Make sure to update it by running `npm init`. 123 | | Core module `assert` is listed as a dependency because oddly browserify requires it. 124 | | 125 | +--config.js 126 | | Configuration variables. Keys are straightforward, notable keys include 127 | | `supportedLocales`, `mode` (either `development` or `production`), and render/uplink 128 | | server hostnames and ports. 129 | | Don't mind the convoluted trick with process["env"]["NODE_ENV"], its working as intented. 130 | | 131 | +--.gitignore 132 | | In addition to `node_modules` and the usual, contains `dist` and `tmp`. 133 | | Consider removing `node_modules` and `dist` if you plan to use git for deployment. 134 | | 135 | +--README.md 136 | | This file. Overwrite with you own README.md. 137 | | 138 | +--gulpfile.js 139 | | Contains a series of preconfigured tasks. You can safely add yours. 140 | | Notable tasks include: 141 | | - `default`, which builds everything, puts the server executables in `dist` and the 142 | | bundled client in `static`, 143 | | - `watch`, which automatically rebuilds everything that changes, 144 | | - `component`, which bootstraps a new component using eg. 145 | | `gulp component --displayName="MyComponent"` 146 | +--src 147 | | | Single source of truth for the building pipeline. Contains all of your actual source. 148 | | | Files in this directory will be transpiled to ES3, but you can safely use `jsx` tags 149 | | | (in `.jsx` files), generators (`function*()`), arrow functions, destructuring, etc. 150 | | | 151 | | +--components 152 | | | | Directory for the components classes. 153 | | | | You should have exactly one file per component class, with the extension `.jsx` 154 | | | | and the `jsx` pragma `/** @jsx React.DOM */`. This file should export a single 155 | | | | value, which should be the result of `React.createClass`. 156 | | | | Components class names should have their first letter uppercased. 157 | | | | Most components should have `R.Component.Mixin`. 158 | | | | You may easily scaffold new components using 159 | | | | `gulp component --displayName=MyComponent` (see below). 160 | | | | 161 | | | +--Root.jsx 162 | | | | Default root component, preconfigured to play nicely as an isomorphic router 163 | | | | backed by the `memory` store populated by `R.History.Plugin`. 164 | | | | Routes are read from `/src/routers/NavigationRouter`. 165 | | | | Feel free to modify the routing behaviour, remove it, or move it 166 | | | | into another component. 167 | | | | 168 | | | +--HistoryLink.jsx 169 | | | | App-level link component preconfigured to play nicely with `R.History.Plugin`, 170 | | | | backed by the `memory` dispatcher. 171 | | | 172 | | +--dispatchers 173 | | | | Directory for the dispatchers classes. 174 | | | | You should have exactly one file per dispatcher class. This file should export a 175 | | | | single value, which should be the result of `R.Dispatcher.createDispatcher`. 176 | | | | Each dispatcher class defines how actions are dispatched, and most often trigger 177 | | | | side effects in the current Flux instance, such as updating a store. 178 | | | | A single dispatcher class can be used, but it is recommended to use one dispatcher 179 | | | | class per backend (eg. one for local data, one for server-sent data) to avoid 180 | | | | confusion. 181 | | | | Most dispatchers will simply be instances of a `R.Dispatcher.createDispatcher` 182 | | | | constructor, but since Dispatcher is just an API contract, you might want to 183 | | | | implement your own. 184 | | | | 185 | | | +--MemoryDispatcher.js 186 | | | | Default memory dispatcher. Add your actions listeners here. 187 | | | | 188 | | | +--UplinkDispatcher.js 189 | | | | Default uplink dispatcher. Add your actions listeners here. 190 | | | | Note that an uplink dispatcher usually won't actually do much on its own; most 191 | | | | times it will only check input and forward appropriate messages to the underlying 192 | | | | `Uplink` instance. 193 | | | 194 | | +--eventEmitters 195 | | | | Directory for the event emitters classes. 196 | | | | You should have exactly one file per event emitter class. This file should export 197 | | | | a single value, which should be the result of `R.EventEmitter.createEventEmitter`. 198 | | | | Most event emitters will use presets from `R.EventEmitter`, but since EventEmitter 199 | | | | is just an API contract, you might want to implement your own. 200 | | | | 201 | | | +--MemoryEventEmitter.js 202 | | | | Cached value of calling `R.EventEmitter.createMemoryEventEmitter`. 203 | | | | Represents a local event emitter residing in memory. It exposes an `emit` method 204 | | | | which a Dispatcher (usually a MemoryDispatcher) may invoke. 205 | | | | 206 | | | +--UplinkEventEmitter.js 207 | | | | Cache value of calling `R.EventEmitter.createUplinkEventEmitter`. 208 | | | | Represents a remote event emitter residing in an uplink server. It is 209 | | | | subscribe-only and a Dispatcher may not emit directly, only pass actions to an 210 | | | | uplink server that will then emit. 211 | | | 212 | | +--routers 213 | | | | Directory for the routers classes. 214 | | | | You should have exactly one file per router class. This file should export a 215 | | | | single value, which should be derived from `R.Router`. 216 | | | | Most routers will simply derive `R.Router` by prototypal inheritance and 217 | | | | adding some routes, but since Router is just and API contract, you might want 218 | | | | to implement your own. 219 | | | | Remember that in `R`, routers are just URL-patterns-friendly generalized regular 220 | | | | expressions, and are passive objects waiting for you to call `match` on them. 221 | | | | 222 | | | +--NavigationRouter.js 223 | | | | An demo navigation router, feel free to edit it. 224 | | | | Note that `/src/components/Root` relies on its behaviour, update it accordingly. 225 | | | 226 | | +--stores 227 | | | | Directory for the stores classes. 228 | | | | You should have exactly one file per store class. This file should export a 229 | | | | single value, which should be the result of `R.Store.createStore`. 230 | | | | Most event emitters will use presets from `R.Store`, but since Store is just an 231 | | | | API contract, you might want to implement your own. 232 | | | | 233 | | | +--MemoryStore.js 234 | | | | Cached value of calling `R.Store.createMemoryStore`. 235 | | | | Represents a local store residing in memory. It exposes a `set` method which a 236 | | | | Dispatcher (usually a MemoryDispatcher) may invoke. 237 | | | | 238 | | | +--UplinkStore.js 239 | | | | Cached value of calling `R.Store.createUplinkStore`. 240 | | | | Represents the local reflection of a store residing in an Uplink server. This 241 | | | | reflection is automatically updated whenever the Uplink server is updated. 242 | | | 243 | | +--App.js 244 | | | Main `R.App` class. 245 | | | You may want to modify the main HTML file template, do more stuff at template vars 246 | | | bootstrapping time, load more stylesheets, etc. 247 | | | Default configuration include general purpose plugins (Window, History, Localize, 248 | | | Fullscreen, XWindow), which you may remove if you don't want them, as well as 249 | | | `normalize.css`. 250 | | | If you want to add your CSS framework of choice (such as Twitter Bootstrap or Pure), 251 | | | just drop your stylesheet there. 252 | | | Don't forget to copy the stylesheet in `static` at build time (see 253 | | | `gulpfile.js`). 254 | | | If you need more scripts to be loaded on the client (eg. Facebook SDK), you can also 255 | | | add them, but note that they won't be available in node, so make sure no isomorphic 256 | | | code depends on them. 257 | | | 258 | | +--client.js 259 | | | Client entry point. Simply mounts the class on the client. You most likey won't modify 260 | | | anything here. 261 | | | 262 | | +--Flux.js 263 | | | Main `R.Flux` class. 264 | | | Here is setup the context in which each app instance will run (either on the client or 265 | | | on the server). 266 | | | You may want to add more initalization, but beware not to create leaks, such as 267 | | | timeouts or intervals. 268 | | | This file is typically where your define your remote connections (such as uplink or 269 | | | REST client), stores, event emitters and dispatchers. 270 | | | The default configuration includes: 271 | | | - one uplink client 272 | | | - one memory-backed store (`memory`) 273 | | | - one uplink-backed store (`uplink`) 274 | | | - one memory-backed event emitter (`memory`) 275 | | | - one uplink-backed event emitter (`uplink`) 276 | | | - one dispatcher intented to handle purely local actions (`memory`) 277 | | | - one dispatcher intented to handle local-remote actions (`uplink`) 278 | | | 279 | | +--index.tpl 280 | | | Main HTML template file. You probably won't need to modify it, since the default 281 | | | template is production-ready, assuming `/App` is correctly configured. 282 | | | 283 | | +--render-server.js 284 | | | Render/static server entry point. Starts a new `express` server and mounts a 285 | | | `static` middleware to serve `/static` as `/`. 286 | | | Feel free to replace `express` by something else or add more middleware (caching, etc). 287 | | | 288 | | +--server.js 289 | | | Simple process manager whose sole job is to start both `/render-server` and 290 | | | `/uplink-server` as child processes. 291 | | | In addition, server.js watches for changes in `dist` and restarts its children 292 | | | whenever its contents changes. Ideal in combination with `gulp watch`. 293 | | | 294 | | +--uplink-server.js 295 | | | Uplink server entry point. Starts a new `express` server and mounts the uplink server. 296 | | | 297 | | +--Uplink.js 298 | | | Main `R.Uplink` class. Simple `Uplink` client configured to work well. 299 | | | 300 | | +--UplinkServer.js 301 | | | Main `R.UplinkServer` class. Resembles closely an all-in-one dispatcher. 302 | | | Here you can modify what happens when a new session is created, or a session is 303 | | | destroyed (either leaves or expires). 304 | | | Stores and event emitterw need to be explicitly whitelisted (router-like patterns 305 | | | are accepted). 306 | | | Actions handlers are passed to their handler generators. 307 | | | You may want to use locks to avoid race conditions (see `R.Lock`). 308 | | 309 | +--dist 310 | | Don't put anything here. Its intented to be populated and cleaned by automated tasks. 311 | | 312 | +--static 313 | | All files in this directory will be publicly accessible. 314 | | This is were the browserified client build is put, as `client.js`. 315 | | You can put here custom CSS stylesheets, external JS deps, images, favicon.ico, etc. 316 | | By default, should contain "normalize.css", copied from the npm package `normalize.css` 317 | | for automatic update. 318 | | 319 | +--tasks 320 | | | Quality of life tasks to ease your development/deployment experience. 321 | | | 322 | | +--createAllComponentsStylesheets.js 323 | | | Extracts all the styles declared inside components source files, process them, and 324 | | | bundles them into the appropriate .css files in `static/`. For example, if a components' 325 | | | `statics.getStylesheetRules` returned { components: ..., main: ... }, then the rules 326 | | | will respectively get dumped into `static/components.css` and `static/main.css`. 327 | | | 328 | | +--createComponent.js 329 | | | Pass a component name as `--displayName="ComponentName"`. 330 | | | Creates a new file into `/src/components` in a new `.jsx` file, containing a predefined 331 | | | template. 332 | | | 333 | | +--createComponent.tpl 334 | | | Template injected into new components files. Feel free to modify it, for example if you 335 | | | want to include more or less libs. 336 | ``` 337 | -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | var mode = 'development'; 2 | 3 | try { 4 | // Convoluted way to avoid browserify (with envify) to throw 5 | // errors at us. You shouldn't modify this. 6 | process['env']['NODE_ENV'] = mode; 7 | } 8 | catch(err) {} 9 | 10 | var config = { 11 | install: { 12 | mode: mode, 13 | }, 14 | supportedLocales: ['en-US', 'fr-FR'], 15 | renderServer: { 16 | hostname: 'localhost', 17 | port: 8080, 18 | }, 19 | uplinkServer: { 20 | hostname: 'localhost', 21 | port: 8000, 22 | prefix: '/uplink/', 23 | }, 24 | }; 25 | 26 | module.exports = config; 27 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | require('6to5/polyfill'); 2 | var _ = require('lodash-next'); 3 | var browserify = require('browserify'); 4 | var buffer = require('vinyl-buffer'); 5 | var del = require('del'); 6 | var envify = require('envify/custom'); 7 | var es6to5 = require('gulp-6to5'); 8 | var gulp = require('gulp'); 9 | var gutil = require('gulp-util'); 10 | var imagemin = require('gulp-imagemin'); 11 | var insert = require('gulp-insert'); 12 | var jshint = require('gulp-jshint'); 13 | var merge = require('merge-stream'); 14 | var plumber = require('gulp-plumber'); 15 | var postcss = require('gulp-postcss'); 16 | var Promise = require('bluebird'); 17 | var R = require('react-rails'); 18 | var react = require('gulp-react'); 19 | var rename = require('gulp-rename'); 20 | var source = require('vinyl-source-stream'); 21 | var sourcemaps = require('gulp-sourcemaps'); 22 | var stylish = require('jshint-stylish'); 23 | var uglify = require('gulp-uglify'); 24 | 25 | var createComponent = require('./tasks/createComponent'); 26 | 27 | var config = require('./config'); 28 | 29 | var dev = config.install.mode !== 'production'; 30 | var prod = !dev; 31 | var style = require('gulp-react-rails-style')(R, dev ? [R.Style.Processors.autoprefixer] : [R.Style.Processors.autoprefixer, R.Style.Processors.min]); 32 | 33 | var statics = [ 34 | 'node_modules/normalize.css/normalize.css', 35 | ]; 36 | 37 | var jshintOptions = { 38 | globals: { 39 | Promise: true, 40 | }, 41 | esnext: true, 42 | sub: true, 43 | }; 44 | 45 | var bustConfig = function bustConfig() { 46 | var module = require.resolve('./config'); 47 | if(require.cache[module]) { 48 | delete require.cache[module]; 49 | require('./config'); 50 | }; 51 | return Promise.resolve(void 0); 52 | }; 53 | 54 | var browserifyClient = function browserifyClient() { 55 | var b = browserify({ 56 | fullPaths: false, 57 | entries: ['./dist/client.js'], 58 | debug: dev, 59 | ignoreMissing: ['promise'], 60 | }); 61 | 62 | var NODE_ENV = prod ? 'production': 'development'; 63 | 64 | b.transform('brfs'); 65 | b.transform(envify({ 66 | NODE_ENV: NODE_ENV, 67 | })); 68 | 69 | return b.bundle() 70 | .pipe(plumber()) 71 | .pipe(source('client.js')) 72 | .pipe(buffer()) 73 | .pipe(prod ? uglify() : gutil.noop()) 74 | .pipe(gulp.dest('./static')); 75 | }; 76 | 77 | var lintJS = function lintJS() { 78 | return gulp.src('src/**/*.js') 79 | .pipe(plumber()) 80 | .pipe(jshint(jshintOptions)) 81 | .pipe(jshint.reporter(stylish)); 82 | }; 83 | 84 | var lintJSX = function lintJSX() { 85 | return gulp.src('src/**/*.jsx') 86 | .pipe(plumber()) 87 | .pipe(react()) 88 | .pipe(jshint(jshintOptions)) 89 | .pipe(jshint.reporter(stylish)); 90 | }; 91 | 92 | var lint = function lint() { 93 | return merge(lintJS(), lintJSX()); 94 | }; 95 | 96 | var compileSources = function compileSources() { 97 | return gulp.src(['src/**/*.js', 'src/**/*.jsx']) 98 | .pipe(plumber()) 99 | .pipe(sourcemaps.init()) 100 | .pipe(react()) 101 | .pipe(insert.prepend('require(\'6to5/polyfill\');\nconst Promise = require(\'bluebird\');\n')) 102 | .pipe(rename({ 103 | extname: '.js', 104 | })) 105 | .pipe(es6to5({ })) 106 | .pipe(sourcemaps.write()) 107 | .pipe(gulp.dest('dist')); 108 | }; 109 | 110 | var copyTemplates = function copyTemplates() { 111 | return gulp.src('src/**/*.tpl') 112 | .pipe(plumber()) 113 | .pipe(gulp.dest('dist')); 114 | }; 115 | 116 | var copyStatics = function copyStatics() { 117 | return gulp.src(statics) 118 | .pipe(plumber()) 119 | .pipe(gulp.dest('static')); 120 | }; 121 | 122 | var compileStyles = function compileStyles() { 123 | return gulp.src('dist/components/*.js') 124 | .pipe(plumber()) 125 | .pipe(style(__dirname + '/dist/styles')) 126 | .pipe(postcss([])) 127 | .pipe(gulp.dest('static')) 128 | }; 129 | 130 | var promisify = function promisify(stream, name) { 131 | return new Promise(function(resolve, reject) { 132 | gutil.log('Starting ' + name + '...'); 133 | stream 134 | .on('error', reject) 135 | .on('end', function() { 136 | gutil.log('Finished ' + name + '.'); 137 | }) 138 | .on('end', resolve); 139 | }); 140 | }; 141 | 142 | gulp.task('build', function(done) { 143 | promisify(lint(), 'lint') 144 | .then(function() { 145 | return bustConfig(); 146 | }) 147 | .then(function() { 148 | return Promise.all([ 149 | promisify(compileSources(), 'compileSources'), 150 | promisify(copyTemplates(), 'copyTemplates'), 151 | promisify(copyStatics(), 'copyStatics'), 152 | ]); 153 | }) 154 | .then(function() { 155 | return Promise.all([ 156 | promisify(compileStyles(), 'compileStyles'), 157 | promisify(browserifyClient(), 'browserifyClient'), 158 | ]); 159 | }) 160 | .then(function() { 161 | done(null); 162 | }) 163 | .catch(function(err) { 164 | gutil.log('Build error', err); 165 | done(null); 166 | }); 167 | }); 168 | 169 | gulp.task('clean', function() { 170 | del(['dist']); 171 | }); 172 | 173 | gulp.task('watch', function() { 174 | gulp.watch(['src/**/*', 'config.js'], ['build']); 175 | gulp.watch('images/**/*', ['imagemin']); 176 | }); 177 | 178 | gulp.task('component', function() { 179 | createComponent(gutil.env.displayName, gutil.env.tagName); 180 | }); 181 | 182 | gulp.task('imagemin', function() { 183 | gulp.src(['images/*.{png,jpg,gif,svg}']) 184 | .pipe(plumber()) 185 | .pipe(imagemin()) 186 | .pipe(gulp.dest('static')); 187 | }); 188 | 189 | gulp.task('default', ['build', 'imagemin']); 190 | -------------------------------------------------------------------------------- /images/ReactLogo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-rails-starterkit", 3 | "version": "0.3.0", 4 | "description": "React on Rails starter kit", 5 | "scripts": { 6 | "start": "node dist/server.js", 7 | "install": "gulp" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git://github.com/elierotenberg/react-rails-starterkit.git" 12 | }, 13 | "keywords": [ 14 | "react", 15 | "react-rails", 16 | "starterkit" 17 | ], 18 | "author": "Elie Rotenberg