Migrate Sprockets to Webpacker with React-rails

Ruby on Rails recently launched support for compiling static assets, such as JavaScript, using Webpack. Among other things, Webpack is more powerful at JS compilation when compared to the previous Rails default of Sprockets. Integration with Rails is provided by the Webpacker gem. Several features that I was interested in leveraging were tree shaking and support for the NPM package repository. With Sprockets, common JS libraries such as ReactJS had to be imported using Gems such as react-rails or classnames-rails. This added friction to adding new dependencies and upgrading to new versions of dependencies.

A couple of my projects used react-rails to render React components on the server-side using the legacy Sprockets system. This worked well, but I wanted to migrate to Webpacker to easily upgrade to the newest versions of React and React Bootstrap (previously I imported this using the reactbootstrap-rails, but this stopped being maintained with the launch of Webpacker.) However, migrating React components to support Webpack required changes to every single file adding ES6-style imports, file moves/renames, and scoping changes. This would have been too large to do all at once. What if there was a way to slowly migrate the JS code from Sprockets to Webpack, making components in either side available to the other side?

Here outlines a guide on how to migrate an existing Sprockets-based Rails application to start using Webpacker. After this, we’ll have 2 different

Enable Webpacker and add React

Note: The Webpacker gem includes more detailed instructions.

Add Webpacker gem to Gemfile:
gem 'webpacker'
This must be loaded in development, production, and during asset compilation.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
rails webpacker:install
rails webpacker:install:react
rails generate react:install```

## Load React through Webpack

Now that React has been installed and is available in the node\_modules folder, we need to load it in the Webpack JS context and make it available on the client-side to Sprockets. We can attach it to window.React, etc. to share it with other components.

app/javascript/packs/application.js:
```javascript
import React from 'react';
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'

global.React = React;
global.ReactDOM = ReactDOM;
global.PropTypes = PropTypes;

Don’t forget to remove any references to React in your Sprockets JS manifest in app/assets/javascript/application.js.

Now you can migrate scripts from the app/assets/javascript/* to app/javascripts/*.

Expose Webpack to Asset Pipeline

Once you start moving code to the Webpack location, you’ll probably see that code in Asset Pipeline that references a component in Webpack won’t work. This is because Webpack doesn’t export components to the global scope (window.) There’s an easy to get this to work, you can add the following to app/javascript/packs/application.js

1
2
3
4
5
6
7
8
// For all components
const componentRequireContext = require.context("..", true);

for (const component of componentRequireContext.keys()) {
  if (!f.endsWith('.js')) {
    window[f.substring(2)] = componentRequireContext(f).default;
  }
}

This will take all of the JavaScript files that are defined in Webpack and export them to the window. The name of the JavaScript file will be used as the component name, so make sure the name matches the default export in that file. Also, this will prevent Webpack from being able to do any tree shaking, so make sure to remove this once all code is migrated or tweak the path in require.context("..", true) to specify a folder that you want to export.

Copyright - All Rights Reserved

Comments

Comments are currently unavailable while I move to this new blog platform. To give feedback, send an email to adam [at] this website url.