Starting a new Rails 6 project with Bootstrap 4 and Fontawesome 5

Background

So a few things have changed with the release of Rails 6, like Webpacker now being the default Javascript compiler. While Sprockets (Rails 5 default) and Webpacker can be used side-by-side, I'll be using Webpacker exclusively for Bootstrap and JavaScript. I won't be adding Bootstrap from a gem, but rather add custom Javascript and CSS via Webpacker.

First up, you'll need to change how you think about bundling assets in Rails 6.

To quote Ross Ross Kaffenberger:

Webpack and Sprockets are fundementally different. They are set up in very different ways. They have different strategies for bundling JavaScript code together… Webpack tries to push you to use smaller bundles, not big ones. It wants you to not use global code (maybe not even jQuery at all). — Ross Kaffenberger

Some Webpack resources (optional reading)

My setup

At the time of writing my setup was:

  • MacOS 10.15.2
  • Ruby 2.6.3
  • Rails 6.0.2.1
  • yarn 1.21.1

Start a new project

1
$ rails new rails6-boots-fontaw

Wait until the project is finished setting up and then:

1
$ cd rails6-boots-fontaw

Getting things ready

Open your project in your favourite code editor and note the following file: app/javascript/packs/application.js

Webpack will use this file as the entry point for all assets to be bundled. Thus, if you want to add custom assets, like Bootstrap, you'll have to use this file in some way or another to tell Webpacker to include it in your project.

Let that sink in for a moment. The app/javascript/packs folder is your entry point to your javascript/css/font assets. Each file in this folder will represent a pack to be compiled into a file in your public folder.

Ideally, a pack should merely be an index, pointing to other files that will be combined together to form said pack (aka bundle).

This bundle will be called by app/views/layouts/application.html.erb as seen below:

1
2
3
4
    ...
    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
    ...

You'll also note that our style sheet is still being called in the old way (the asset pipeline) with the link_tag. With webpacker you can also call your CSS assets via the pack_tag, which is exactly what we'll do now.

By the way, you can use Sprockets (old asset pipeline) and Webpack together if you really want to, though I'd recomment just biting the bullet and moving over to Webpack completely, especially since you are creating a new project.

Create a CSS pack

  1. Still in application.html.erb change stylesheet_link_tag to stylesheet_pack_tag

  2. But wait, we still need to create the stylesheet pack… Let's do that in Terminal

    1
    2
    3
    
    $ mkdir app/javascript/css
    $ touch app/javascript/css/main.scss
    $ touch app/javascript/css/custom.scss
    
  3. Remember how I mentioned earlier that app/javascript/packs/application.js is the entry point for all webpacker assets? Let's add our custom CSS pack to application.js, by pointing to the main.scss file relative to the application.js file.

    Add the following to the bottom of app/javascript/packs/application.js

    1
    
    import '../css/main.scss'
    

Now, you may be asking why on earth I created two scss files. Well, the point is to have a main file that points to other css files and libraries. It should become more clear later in the tutorial.

Test your custom CSS pack

To ensure that our custom CSS is actually working, we'll create a basic page and add some CSS styles to it.

  1. Add the following code to the newly created main.scss file:

    1
    
    @import 'custom.scss';
    
  2. Add the following code to the newly created custom.scss file:

    1
    2
    3
    
    h1 {
        color: red;
    }
    
  3. Generate a page to view to test the page by generating a controller-view pair from the terminal:

    1
    
    $ rails generate controller home index
    
  4. Add a route to config/routes.rb:

    1
    2
    3
    
    Rails.application.routes.draw do
        root to: 'home#index'
    end
    
  5. Test that the <h1> tag displays text in red by starting a rails server and navigating to localhost from your browser:

    1
    
    $ rails server
    

If the heading was red, you are clear to move on to the next step. If not, something went wrong… Good luck!

Add Bootstrap 4 to Rails

  1. Now we're ready to install bootstrap and its dependencies, jquery and popper, from our Terminal:

    1
    
    $ yarn add bootstrap jquery popper.js
    

    Open package.json to ensure that all three are now listed therein.

  2. Import bootstrap into the main.scss file, which should now read:

    1
    2
    
    @import 'custom.scss';
    @import '~bootstrap/scss/bootstrap.scss';
    
  3. Add some Bootstrap specific styles to your view app/views/home/index.html.erb, which should now read:

    1
    2
    3
    4
    
    <h1>Home#index</h1>
    <p>Find me in app/views/home/index.html.erb</p>
    
    <button class="btn btn-primary">Hide</button>
    
  4. Test that the Bootstrap styling is applied to your view by starting a Rails server and visually confirming that all is in order:

    1
    
    $ rails server
    

At this point, you should see the typical blue Bootstrap button and your text should have the Bootstrap styling as well.

Getting jQuery to work in Rails

If you were to add some javascript to your page that calls a jquery function, it would fail as Javascript wouldn't understand the $ called when utilising jQuery. This is because Webpack doesn't add anything to the global scope by default. We thus need to add $ to the global scope.

To do this, we add the jQuery aliases to config/webpack/environment.js, as shown below:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
const { environment } = require('@rails/webpacker');

const webpack = require('webpack');

environment.plugins.append("Provide", new webpack.ProvidePlugin({
  $: 'jquery',
  jQuery: 'jquery',
  Popper: ['popper.js', 'default']
}));

environment.config.set('resolve.alias', {jquery: 'jquery/src/jquery'});

module.exports = environment;

To ensure that there are no issues, add the code below to app/views/home/index.html.erb:

1
2
3
4
5
6
7
<script>
$(document).ready(function(){
  $("button").click(function(){
    $(this).hide();
  });
});
</script>

Now stop your rails server with CTRL+C and reload your rails server:

1
$ rails server

At this point, the Hide button should disappear once clicked.

Add Fontawesome 5 to Rails

  1. Get the latest FontAwesome library with yarn

    1
    
    $ yarn add @fortawesome/fontawesome-free
    
  2. Import the library into you JS pack - app/javascript/packs/application.js

    1
    
    import "@fortawesome/fontawesome-free/js/all";
    
  3. Import the library into your CSS pack - app/javascript/css/main.scss

    1
    
    @import '@fortawesome/fontawesome-free';
    
  4. Add a FontAwesome icon to your view to ensure that all is well - app/views/home/index.html.erb:

    1
    
    <p><i class="far fa-smile-beam fa-3x"></i></p>
    

Lastly, restart your rails server and ensure that you can see the icon.

Final notes

Loading the entire Bootstrap library is not the most performant thing in the world. It's fine for testing and MVP setup, but ideally, you should only import what you're using. There are a few tutorials on the net explaining how to do that, which should be easier to understand after following the instructions above.

Keep this in mind when you go down the Webpack rabbit-hole, and stay curious. Webpack has some awesome functionality, like asynchronous loaders.

Thanks for reading.