Rails with Webpacker and Blueprintjs

published 19.1.2021

frontendbackendprototypingquick tip
cssjavascriptreactrailsblueprint.js

Blueprint.js is a UI toolkit by Palantir that I decided to try on my next project. I've been using Bootstrap, Material, Ant Design and custom in-house design systems in the past. I'd like to see how would Blueprint turn out compared to my favorite Ant Design.

Setup rails with webpacker

I've created a new rails project using:

rails new woot-app --webpack=react

Next, I updated webpacker to the current latest version in Gemfile:

-gem 'webpacker', '~> 5.0'
+gem 'webpacker', '6.0.0.beta.2'

Now I had to install the updated webpacker, and generate the base controller and route. Since this was a fresh project, I just allowed webpacker to override any existing files.

bundle install
bundle exec rails webpacker:install
bundle exec rails g controller Home index
# content of the following file is duplicated in package.json, and prevents webpack from running
rm .browserslistrc

Finally, I configured the layout to use React snippet provided by rails out of the box. I used the chunks version for code splitting/caching in app/views/layouts/application.html.erb:

<%= javascript_packs_with_chunks_tag 'hello_react' %>

Add blueprint.js into the mix

Install Blueprint npm package:

yarn add @blueprintjs/core

Now update the app/javascript/packs/hello_react.js to show some Blueprintjs component:

import { Button } from "@blueprintjs/core";

const Hello = props => (
  <div>
    Hello {props.name}!
    <Button intent="success" text="button content" onClick={console.log} />
  </div>
)

// ...

When I run the app now (bundle exec rails s and ./bin/webpack-dev-server), it won't work. At the time of writing, there is an issue in blueprintjs related to undefined process object. The solution suggested on github, is to use DefinePlugin to mock the object in browser. This involves a couple of changes in webpack config, to extend the default configuration.

Blueprint's "process undefined" error

Create a new file at config/webpack/blueprint.js

const webpack = require('webpack');

module.exports = {
  plugins: [
    new webpack.DefinePlugin({
      'process.env': '{}',
    }),
  ],
};

And use it in config/webpack/base.js

const { merge } = require('webpack-merge');
const { webpackConfig } = require('@rails/webpacker');
const blueprintjsConfig = require('./blueprint');
 
module.exports = merge(webpackConfig, blueprintjsConfig);

After restarting the webpack dev server, you should see the button rendered. However, it's missing a proper style.

Adding the style

We need to import css from blueprintjs npm package, as described in the docs. First, install webpack loaders for proper css handling:

yarn add css-loader css-minimizer-webpack-plugin mini-css-extract-plugin

Next, create app/javascript/packs/hello_react.css file:

@import "~normalize.css";
@import "~@blueprintjs/core/lib/css/blueprint.css";
@import "~@blueprintjs/icons/lib/css/blueprint-icons.css";

At last, add it to the app/views/layouts/application.html.erb

<%= stylesheet_packs_with_chunks_tag 'hello_react' %>

Now, restart the webpack dev server and you should see the button styled properly.