Rails 4 + gulp + webpack + browsersync on Cloud9

I wanted super flawless experience for web app development so I chose:

  1. Rails 4 for fast back-end developing
  2. Webpack for compiling Coffeescript files with modules support and also for ability to dynamically load necessary javascript in runtime
  3. Gulp for LESS compiling (also with @import resolving), SVG icons sprites, CSS autoprefixing, source maps, minifying etc.
  4. Browsersync for page live reload on js or css changes while developing
  5. Also I’m using Cloud9 browser online IDE for developing my pet project. In fact Cloud9 is not only online IDE, but it’s complete VPS for all developer’s need. It’s very useful when you work on multiple computers and when you want to code in travel.

No time for reading? Try it with this  https://github.com/DimitryDushkin/rails-gulp-webpack-browsersync.

You can find a lot of rails’ project stubs with gulp, webpack etc., but there is no examples of browsersync integration with Rails and Cloud9.

It’s quite untrivial to make cloud9 work with browsersync, because Cloud9 accepts connections only on 80 port and also uses own proxy for verifying access rights to hosted web app.

First of all lets start rails server via “rails s -b 0.0.0.0“.

That’s what happens on running “gulp watch” command in my workflow:

  1. Browsersync starts its own http server on 8080 port.
    1. Cloud9 expects your server to run on 8080 port. Cloud9 uses it’s own proxy server which works on 80 port, it accepts all connections, making some authorization magic and then forward request to 8080 port, that’s why you need to configurate your web server on 8080.
    2. Browsersync can work as proxy server to include it’s javascript file in HTML that Rails responding. So we configurate Browsersync to be proxy server to 3000 port.
  2. Gulp watches for changes in LESS files and compiles it
  3. Gulp watch for changes in coffeescript files and runs webpack to compile them
  4. Browsersync watches for changes in compiled CSS and JS and reloads browser (or reloads just stylesheets)

This scheme with Cloud9 + browsersync + rails seems quite complicated so I made a little image of this solution:

Cloud9 + Browsersync + Rails 4

 

gulpfile.js looks like this:

/* jshint node: true */
var path = require('path'),

    gulp = require('gulp'),
    gulpif = require('gulp-if'),
    prefix = require('gulp-autoprefixer'),
    concat = require('gulp-concat'),
    minifyCSS = require('gulp-minify-css'),
    sourcemaps = require('gulp-sourcemaps'),
    util = require('gulp-util'),
    less = require('gulp-less'),
    svgstore = require('gulp-svgstore'),
    rename = require('gulp-rename'),

    broSync = require('browser-sync').create(),

    webpack = require('gulp-webpack'),
    webpackConfig = require('./webpack.config.js'),

    paths = {
        src: path.resolve(__dirname, './blocks'),
        dest: path.resolve(__dirname, '../back/app/assets')
    },

    production = util.env.stage === 'production' ? true : false;

gulp.task('js', function() {
    return gulp.src(paths.src + '/**/*.coffee')
        .pipe(webpack(webpackConfig))
        .pipe(gulp.dest(paths.dest + '/javascripts/'));
});

gulp.task('css', function() {

    return gulp
        .src([
            // starting point for all @imports
            paths.src + '/page/page.less'
        ])
        .pipe(sourcemaps.init())
        .pipe(less({
            // @include paths
            paths: [path.join(__dirname), 'node_modules']
        }))
        .pipe(concat('app.css'))

        // CSS autoprefixer
        .pipe(prefix([
            '> 7%',
            'Opera > 7%',
            'Safari > 7%',
            'Firefox > 7%',
            'Explorer > 7%',
            'Chrome > 7%'
        ], {
            cascade: true
        }))

        // minify for production
        .pipe(gulpif(production, minifyCSS()))

        // add sourcemaps for developing
        .pipe(gulpif(!production, sourcemaps.write()))
        .pipe(gulp.dest(paths.dest + '/stylesheets/'))

        // for changing CSS without page refresh
        .pipe(broSync.reload({ stream: true}));

});

// SVG icons for inlining in HTML
gulp.task('icons', function() {

    return gulp.src(paths.src + '/icons/*.svg')
        .pipe(rename({prefix: 'icon-'}))
        .pipe(svgstore({
            inlineSvg: true
        }))
        .pipe(rename('_icons.erb'))
        .pipe(gulp.dest(paths.dest + '/../views/layouts'));

});

gulp.task('watch', ['js', 'css', 'icons'], function() {

    broSync.init({
        proxy: '0.0.0.0:3000',   // rails server
        port: 8080               // cloud9 proxied port to 80
    });

    gulp.watch(paths.src + '/**/*.less', ['css']);

    gulp
        .watch(paths.src + '/**/*.coffee', ['js'])
        .on('change', broSync.reload);

    gulp
        .watch(paths.src + '/icons/*.svg', ['icons'])
        .on('change', broSync.reload);

});

gulp.task('default', ['css', 'icons', 'js']);

Project stub with all solutions available at https://github.com/DimitryDushkin/rails-gulp-webpack-browsersync.

This post and project were very helpful. Thanks to the author!