Skip to content

Instantly share code, notes, and snippets.

@greypants
Last active August 29, 2015 14:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save greypants/3590465cc1e9ad23d1c6 to your computer and use it in GitHub Desktop.
Save greypants/3590465cc1e9ad23d1c6 to your computer and use it in GitHub Desktop.
Decisions: The Asset Pipeline

Decisions: The Asset Pipeline

The initial choice to abandon the Rails asset pipeline, was due to the difficulty of achieving the following goals within the rails ecosystem:

Browserify compatibility.

Browserify is one of the best things to happen to front-end JS development in the last few years. Here are a few of the benefits:

  • Modular node-style code (CommonJS) in the browser. This improves organization, maintainablity, and dependency management considerably.

  • Powerful file transforms

  • Access to NPM modules make grabbing, managing, and using modules super convenient. This is where JS developers publish (not rubygems).

     # download to node_modules and save as dependency in package.json
     npm install someLibrary --save
     # Profit.
     $ = require 'someLibrary'

Fast on the fly compile times.

Using Gulp to process files is noticeably faster than any alternatives thanks to node streams.

By harnessing the power of node's streams you get fast builds that don't write intermediary files to disk. - gulpjs.com

During build out, we're re processing files and reloading the browser every time we save. Thats thousands of times. Faster compiles means less time wasted waiting.

BrowserSync w/stylesheet injection updates (vs full page refreshes).

BrowserSync live reloads as many browsers as you have pointed to your local site simultaneously, across devices. Automatic hard refreshes work with Rails, but live stylesheet updates without a full page refresh don't, due to the way the asset pipeline works. BrowserSync relies on watching a css file change - but in development, Rails doesn't regenerate files until a server asks for it.

Flexibility to use current, up-to-date toolsets.

The Asset Pipeline is dated. Clearly, we've had trouble integrating it with modern front end toolsets. Rails itself, along with many gems are out of sync with current versions of the tools they're trying to port, and other tools are just missing or incompatible. By having assets independently managed, we'd had hoped to break free from any one framework's opinions, allowing us to use the same tools and process across projects.

Our Problem

While we were able to create near feature parity with the Rails asset pipeline, using Gulp tasks, many third party gems still assume the default pipeline is being used. This means we can't totally abandon it. Rails still needs to process these dependencies

Additionally, nearly all of the benefits of a home-rolled asset pipeline are only seen by the front-end team. For Rails devs and dev ops, it adds complexity, without much benefit for them. With that in mind, and the fact that most of the majority of front-end work will be complete as we hand this off, here are the re-priorized goals:

  1. Simplicity and Maintainability
  • Browserify compatibility
  • Fast on the fly compiling

Below are some options to address these goals. Each one has trade offs in different areas. We're open to whatever solution you think will serve you best moving forward, and will make any necessary adjustments as soon as possible.

Option 1: Rails Asset Pipeline for everything except browserify

The main global.coffee file would still be compiled with Browserify either with Gulp, or the command line. The standard asset pipeline would handle everything, else, and the compiled browserify bundle would simply be pulled into an application.js file using sprockets, along with any other javascript you want to require (third party or otherwise).

The workflow would look like this:

  1. Compile global.coffee with browserify (with a gulp task or the command line) to app/assets/javascripts/bundles/global.js
  • In app/assets/javascripts/application.js.coffee, pull in the bundle like you would any other javascript asset:
#= require 'ahoy'
#= require 'updates/someNewThing.coffee'
#= require 'bundles/global.js'

Pipeline does its thing, and you include applicaiton.js in your layout like normal.

Pros

  • Lets rails do as much as possible, and only uses browserify (with gulp or the command line) to compile one file.
  • All the browserify benefits are available, but optional moving forward.
  • Rails handles assets like normal, and just pulls in your compiled browserify bundle with a regular sprockets //=require in application.js
  • The browserify workflow is optional. New JS could be pulled in however you want.
  • Compiled code is checked in, so no need to compile or npm install on deploy
  • Can still keep gulp around for browserify compiling, or non-asset tools like watching, live reloading or compressing images
  • No compiled code checked in

Cons

  • Still have to run gulp locally when working with bundled javascript
  • Checked in compiled code causes needless rebase conflicts. This can be avoided with some git configuration. Alternatively, you could .gitignore bundles and compile them on deploy, similar to what we're doing now.

Option 2: Asset Pipeline + browserify-rails gem

Remove most if not all Gulp tasks, and get Browserify functionality through the browserify-rails gem. This still uses a package.json for configuration and js dependencies.

Pros:

  • Use Browserify and Sprockets interchangeably
  • Asset pipeline otherwise works like normal
  • Reduces complexity: gulp is out of the picture (except maybe for some standalone tasks like image compression)
  • CommonJS requires can be used
  • Still get NPM for managing front end dependencies

Cons:

  • Slower compiling (maybe ~10x) because there's no way to use it with watchify (cacheing, watching, verison of browserify)
  • Still some extra overhead.

Option 3: Rails Asset Pipeline does 100% (un-browserify js)

Remove Gulp AND Browserify, let Rails do what it's always done. This would require refactoring javascript out of modules and into a namespace on the window, and using sprockets requires to concatenate.

Pros:

  • Least complexity, no additional tech to learn, configure or maintain

Cons

  • Dated (arguably less maintainable) JavaScript style
  • Limited toolset
  • Slower compiling
@rymohr
Copy link

rymohr commented Oct 3, 2014

Ever thought about using webpack? I'm in a similar spot and it's the only promising solution I've seen: https://medium.com/brigade-engineering/setting-up-webpack-with-rails-c62aea149679

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment