Considerations for jQuery with Rails and Webpack

We have a few options for how we include jQuery and a few considerations:

Considerations

  1. jquery-ujs monkey patches $.ajax to send the CSRF parameters. For more info on this, see: Rails Guides on CSRF. This is the key file that gets inserted: rails.js. This code uses the jQuery.ajaxPrefilter from this line. If this file is not loaded in the Rails application.js, then the CSRF token is not added when when $.ajax (or it’s friends, like $.get) is called. This is part of the jquery-rails gem. Note, there is no separate gem for jquery-ujs. However, there’s a separate github repo, probably so that it can be used by npm, but I’m just guessing.
  2. We under NO CIRCUMSTANCES want to load 2 versions of jQuery. We want the version of jQuery used to be as transparent as possible. Is the reason obvious? Thus, it’s critical that we load jQuery from the gem, then we DO NOT load jquery in the webpack config.
  3. It turns out that there is a npm version of jquery-ujs!

#Options for jQuery Inclusion

A. jQuery loaded from Rails

Having jQuery included before loading the bundle from web, and specify jQuery as an “external”.

1. jquery-rails Gem

Use the jquery-rails gem and be sure to specify what version of jQuery. This is somewhat obtuse, as it requires locking the jQuery version by the gem version. This is specified here.

2. jQuery from a CDN

Use the jquery-rails-cdn gem. If we do that, we need to load it first in the Rails main application layout. This gem will use this version of jQuery:

jQuery version is automatically detected via jquery-rails

B. jquery-ujs and jquery from npm

Let’s load both jquery-ujs and jquery in our webpack configuration. The advantages to doing this:

  1. It’s clear what versions we’re using as they specified just like the other dependencies. This is the way we’re handling all other 3rd party JavaScript, so let’s be consistent.

  2. No chance of accidentally having a different version loaded from both Rails and Webpack.

  3. We simply need to expose jQuery as global so that other JavaScript or CoffeeScript code in the Rails project that’s not using the Webpack config can find jQuery and $. This is documented for Webpack:

  4. We need to expose the jquery-ujs part, through an addition to the entries so this gets loaded by webpack (PENDING EXAMPLE).

  5. You need to use the expose-loader.

npm install expose-loader --save

You can either do this when you require it:

require("expose?$!jquery");

or you can do this in your config:

loaders: [
    { test: /jquery\.js$/, loader: 'expose?$' },
    { test: /jquery\.js$/, loader: 'expose?jQuery' }
]

We will very shortly have this as an example here: Break out jquery from jquery-ujs: How to use webpack complete managed javascript library · Issue #51 · shakacode/react-webpack-rails-tutorial · GitHub.

Questions

  1. How useful is the CDN for jQuery performance wise?

I just posted a question regarding the duplication of the jquery-ujs file in both repos:

We ended up creating our own npm module:

This pull request has the changes:

To summarize:

  1. Remove jquery-rails from your Rails Gemfile.
  2. Add jquery, jquery-ujs to your list of entry points, in your webpack config, like this.
  3. Expose jQuery and $ in your webpack config like this.
  4. Edit your application.js so that your generated/client-bundle from Webpack comes before other libraries that depend on jQuery, such as bootstrap-sprockets, as shown here.
  5. Be sure to run bundle and npm install and npm shrinkwrap, committing the updates to your Gemfile.lock and npm-shrinwrap.json.

BOOM! No more gemified jquery-ujs and jquery, and just one place to track dependency versions of your JavaScript!