generator-alan-react-rails-webpack v0.4.9
generator-alan-react-rails-webpack
Yeoman generator
Getting Started
To install generator-alan-react-rails-webpack
from npm, run:
$ npm install -g generator-alan-react-rails-webpack
Up and Running
Create Ruby on Rails project with normal rails
command, but skip gem bundling:
$ rails new app-name --skip-bundle
Then, initiate the generator:
$ cd app-name
$ yo rails-react-webpack
Answer 'Yes' to all 'Overwrite' actions. Then, update 'config/database.yml' if you use different database than 'sqlite3'.
Dependencies
- Bower via
npm install -g bower
Application template
Javascript modules
All javascript modules are placed in app/frontend/javascripts
folder, which will be compiled into app/assets/javascript/build
folder. In addition, app/assets/javascript/build
is appended to .gitignore
(Webpack built bundles will be ignored and rebuilt every deployment).
Control your application assets via webpack or sprockets.
However, for javascript files, prefer webpack
over sprockets
for the reason that those will run through loaders before getting
serve at the browser.
package.json
Manage built tools and application dependencies
Webpack
config.json
: loads additional configurations intojavascript-build.js
viaconfig = require('./config.json');
{ "webpack": { "path": "./app/frontend/javascripts/", "test": "./__tests__/**/*-test.js", "build": "./app/assets/javascripts/build" } }
default.config.js
: the basic webpack settings for both development and production environment. You can have any available webpack settings here. For example, config externals, loaders, and so on.module.exports = { context: path.join(__dirname, '../', '../'), entry: { main: './app/frontend/javascripts/main' }, ... externals: {}, ... module: { loaders: [{ test: /.js$/, //exclude: /node_modules(?!.*(\/js-csp))/, // ignore node_modules except node_modules/js-csp exclude: /node_modules/, loader: 'babel-loader?experimental&optional=runtime' }] }, };
development.config.js
: contains development config for webpack. For advance usage, Hot Module Replacement(#Hot Module Replacement), and Code splitting(#Code splitting).module.exports = _.merge(defaultConfig, { cache: true, debug: true, outputPathinfo: true, devtool: 'source-map', plugins: [ new webpack.DefinePlugin({ 'process.env.NODE_ENV': '"development"', '__DEV__': true }) ] ...
production.config.js
: contains production config for webpack. For advance usage, Code splitting(#Code splitting).module.exports = _.merge(defaultConfig, { devtool: false, output: { path: './public/assets', publicPath: '/assets/', filename: '[name]-[chunkhash].bundle.js', chunkFilename: '[id]-[chunkhash].bundle.js' }, plugins: [ new webpack.DefinePlugin({ 'process.env.NODE_ENV': '"production"', '__DEV__': false }), new ChunkManifestPlugin({ filename: 'webpack-common-manifest.json', manfiestVariable: 'webpackBundleManifest' }), new webpack.optimize.UglifyJsPlugin() ]
javascript-build.js
: defines javascript built tasks.var _ = require('lodash'), config = require('./config.json'), del = require('del'), gulp = require('gulp'), ...; gulp.task('javascript:clean', function () { ... }); gulp.task('javascript:dev', function () { ... }); gulp.task('javascript:build', function () { ... });
Code splitting
Refer to webpack code spliting for detail implementations.
Bundles are created by require
or require.ensure
will be automatically loaded. Additionally, all the settings in
devlopment.config.js
and production.config.js
for optimizing common chunk
have been added to config files.
new webpack.optimize.CommonsChunkPlugin('common', 'common.bundle.js'), // development.config.js
new webpack.optimize.CommonsChunkPlugin('common', 'common-[chunkhash].bundle.js'), // production.config.js
Uncomment those and add this tag <%= webpack_bundle_tag 'common' %>
before your main bundle in your layout:
<%= webpack_bundle_tag 'common' %>
<%= webpack_bundle_tag 'main' %>
Hot Module Replacement
Refer to HMR for detail implementations, only for development.config.js
.
Uncomment all HMR
config in development.config.js
.
entry: {
main: [
'webpack-dev-server/client?http://localhost:8080/assets/'
]
}, // Hot Module Replacement
output: {
publicPath: 'http://localhost:8080/assets/build/'
}, // Hot Module Replacement
devServer: {
contentBase: path.join(__dirname, './../../'),
hot: true,
inline: true
}, // Hot Module Replacement
...
module: {
loaders: [{
test: /.js$/,
//exclude: /node_modules(?!.*(\/js-csp))/, // ignore node_modules except node_modules/js-csp
exclude: /node_modules/,
loader: 'react-hot'
}]
}, // Hot Module Replacement
plugins: [
new webpack.HotModuleReplacementPlugin(), new webpack.NoErrorsPlugin(), // Hot Module Replacement
...
]
And app/helpers/application_helper.rb
"http://localhost:8080/assets/build/#{bundle}.bundle.js" # Hot module replacement
# "assets/build/#{bundle}.bundle"
This config will concat to every entry with specify in this development.config.js
. The result will be like:
entry: {
main: [
'webpack-dev-server/client?http://localhost:8080/assets/',
'webpack/hot/dev-server',
'./app/frontend/javascripts/main'
]
}, // Hot Module Replacement
Then start coding(#Start developing)
Current transformation applied
Available gulp task
$ gulp javascript:clean # remove the build folder placed at 'app/assets/javascripts/build'
$ gulp javascript:dev # watch over changes for multiple js bundle
$ gulp javascript:build # should use this for testing only, please read Assets compile
Start developing
Run these commands, and start coding
$ gulp javascript:dev
$ rails server
For Hot Module Replacement, update config/webpack/development.config.js
and run these command instead:
$ npm run webpack-dev
$ rails server
Assets compile
$ rake assets:precompile RAILS_ENV=production
Heroku deploy
Configure Heroku to use ddollar's multi-buildpack
:
$ heroku config:add BUILDPACK_URL=https://github.com/ddollar/heroku-buildpack-multi.git
Add the heroku-nodejs buildpack
and heroku-ruby buildpack
to .buildpacks:
$ cat .buildpacks
https://github.com/heroku/heroku-buildpack-nodejs
https://github.com/heroku/heroku-buildpack-ruby
Options
Name: mongoid (for mongodb)
add --skip-active-record
option to your rails new app --skip-active-record
command before selecting this option.
Task
Live reload
For using livereload utility, firstly, install guard. Then, use rack-livereload or install LiveReload Safari/Chrome extension
$ bundle exec guard # to run the guard server and enjoy coding
Testing
Test files are placed in the same folder with component.
▾ home/
home-test.js
home.js*
Use iojs instead of node to run mocha test (See more here). And update mocha config
if you need to in package.json
npm test # unit test
npm run test-converage # generate test coverage using istanbul
Structure
application/
|- app/
| |- apis/
| | |- v1/
| | | |- base.rb
| | | |- person_api.rb
| | |- base.rb
| |- assets/
| | |- images/
| | |- javascripts/
| | | |- build/
| | | | |- page-module.bundle.js
| | | |- application.js
| | |- stylesheets/
| | | |- application.css
| |- frontend/
| | |- javascripts/
| | | |- <page-module-dependencies>/
| | | |- <page-module>.js
| |- controllers/
| |- helpers/
| |- mailers/
| |- models/
| |- views/
| | |- application/
| | | |- index.html # default template for the application
| | |- layouts/
| | | |- application.html.erb
|- bin/
|- config/
| |- initializers/
| | |- *.rb
| | |- webpack.rb # webpack manifest config
| |- webpack/
| | |- config.json
| | |- default.config.js
| | |- development.config.js
| | |- javascript-build.js
| | |- production.config.js
| |- initializers/
| | |- bower_rails.rb # bower rails config
|- db/
|- lib/
| |- assets/
| |- tasks/
| | |- webpack.rake # built task
|- log/
|- public/
|- test/
|- vendor/
| |- assets/
| | |- bower_components/
| | | |- third libararies/
|- | |- bower.json
|- Bowerfile # bower package dependencies
|- config.ru
|- gulpfile.js
|- package.json
|- config.ru
|- Gemfile
|- Gemfile.lock
|- Guardfile # Guard file for livereload
|- Rakefile
|- README.rdoc
Changelog
0.3 -> 0.4: Add babel-plugin-typecheck, fixed redundant event listeners from
dev-server
and only-dev-server
, and update code to es6
Acknowledgement
Thanks Dave Clark for this wonderful post
Example project
Running example
Contribution
All contributions are welcomed.