Skip to content

Files

Latest commit

 

History

History
 
 

rails

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 

Gulp Starter on Rails

Using gulp-starter with Rails (instead of the built in asset pipeline) is actually pretty easy. This directory contains the extra pieces you'll need to get going.

Overview

Firstly, note that we're going to leave the existing asset pipeline in place. Many gems rely on it (e.g, Active Admin), and it's a good idea to keep it around. That said, it's important to keep it separated. We won't be mixing gulp-generated assets with rails generated ones.

Source files should be in a src directory in the root of the project, not in app/assets. You'll also no longer be using the built in Rails asset helpers like javascript_include_tag and the like. Instead, you'll use a set of gulp_asset_helpers with regular markup.

app/helpers/gulp_asset_helper.rb

In production (npm run production), filenames get hashed so you can cache them forever. When the file or any of it's referenced assets changes, the hash changes. This works just like the Rails asset pipeline, and we have similar helpers to ensure that the correct filenames are referenced in production:

gulp_asset_path('image/asset.jpg') # -> /image/logo-n39o4orb81.png
gulp_js_path('app.js')             # -> /javascripts/app-f43e9abc11.js
gulp_css_path('app.css')           # -> /stylesheets/app-d29e4cdb76.css
gulp_image_path('logo.png')        # -> /images/logo-n39o4orb81.png

So instead of this:

<%= image_tag 'logo.png', alt: 'logo' %>

You would do this:

<img src="<%= gulp_image_path('logo.png') %>" alt="logo">
Sprite helper

There's also a <%= sprite('id') %> helper included for use with the svgSpriteTask task. It looks like:

def sprite(id, classes = "", viewBox = "0 0 24 24")
  "<svg class='sprite -#{id} #{classes}' aria-hidden='true' preserveAspectRatio viewBox='#{viewBox}'><use xlink:href='#{gulp_image_path('sprites.svg')}##{id}' /></use></svg>".html_safe
end

Modify as needed.

config/initializers/gulp.rb

The asset path helpers check for the existence a rev-manifest.json file, generated by the gulp rev tasks. It may look something like this:

{
  "javascripts/app.js":  "app-f43e9abc11.js",
  "stylesheets/app.css":  "app-d29e4cdb76.css"
}

And so on. This initializer file reads and caches the object in production. In development, the file is constantly checked for and read. The asset helpers read this and find strings matching the key, and replace them with their hashed value.

What about my gem assets and Sprockets manifest files?

For things like Active Admin that rely on the asset pipeline (Sprockets), continue usin g Sprockets manifest files (application.js, application.css, etc.) and //=include your gem asset dependencies there. You'll also use the existing Rails helpers to include these files on the page.

<%= javascript_include_tag 'application' %>

In some cases, this means you may have two JS files on your page. One containing only your gem-installed assets, and one for your bundles compiled with Webpack. I try to avoid using gem assets where possible though, and usually just have my webpack bundle on the page.

You may be thinking, "couldn't you still bundle them together, either by including Gulp complied files in the sprockets manifest, or vice versa?" The answer is, yes, technically, but we've been down that road, and it's not a good one to travel. Trust me on this—it's better to keep them separate.

Deploying

Heroku

Heroku makes deploying SUPER easy, but there are a couple of things you'll need to do to get this running.

Since we're using Ruby (to run Rails) AND Node (to compile our assets with Gulp) in our setup, we need both running on our server. Heroku will automatically detect ONE of these at a time based on the presence of a Gemfile or package.json, but to get both running simultaneously, we need to specifiy heroku-buildback-multi as your buildpack. This enables us to specify multiple custom buildpacks in a .buildpacks file.

https://github.com/heroku/heroku-buildpack-nodejs.git
https://github.com/orlando/heroku-buildpack-ruby.git

(see: vigetlabs/gulp-rails-pipeline#6 (comment))

Add the following postinstall script to your scripts property in package.json:

  "postinstall": "npm run production"

OR set up a different way to tell Heroku to run this task when deploying (this is not the only way).

Now, when we deploy to Heroku, first npm install will run, then our postinstall script specified in package.json, and then bundle install will run.

Take note of the following:

  #production.rb line 25
  config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present?

Heroku requires config.serve_static_files to be enabled, so be sure to either add RAILS_SERVE_STATIC_FILES as a config var in your Heroku settings, or manually set this to true in your production.rb file.

A note on devDependencies

You'll either need to make sure all dependencies accessed during the production gulp task are included in dependencies rather than devDependencies or do the following:

Npm reads configuration from any environment variables beginning with NPM_CONFIG. We set production=true by default to install dependencies only. If you would like to install additional devDependencies, you can disable this behavior:

$ heroku config:set NPM_CONFIG_PRODUCTION=false

https://devcenter.heroku.com/articles/nodejs-support#customizing-the-build-process

Capistrano

All we need to do is add a task to run npm install before we compile the assets.

The example below shows an example of using nvm (node version manager) to use the specified node version for your application.

# ./config/deploy.rb

before "deploy:assets:precompile", "deploy:npm_install"

namespace :deploy do
  desc "Run npm install"
  task :npm_install do
    invoke_command "bash -c '. /home/deploy/.nvm/nvm.sh && cd #{release_path} && npm install'"
  end
end

Blog Post (some methods are outdated, but gives some additional reasoning): viget.com/extend/gulp-rails-asset-pipeline