Install Bootstrap 4 on a Rails 6 App with Webpacker

I know many existing tutorials explain how to install Bootstrap 4 on a Rails 6 application with Webpacker (like the GoRails example). However, I wanted to create this tutorial to highlight a few gotchas, as well as highlight why and how I made some of my choices.

  1. rails new rails-bootstrap
  2. yarn add bootstrap jquery popper.js
  3. Add jQuery and Popper.js plugins. These are required by Bootstrap.

    This step was always so cryptic to me. I would just blindly copy and paste what I saw on other tutorials, but I wanted to know how people knew to even do this.

    I found this example in the Webpacker docs, so decided to use it knowing it was in the official documentation.

    // config/webpack/environment.js
    const { environment } = require("@rails/webpacker");
    const webpack = require("webpack");
    
    environment.plugins.prepend(
      "Provide",
      new webpack.ProvidePlugin({
        $: "jquery",
        jQuery: "jquery",
        jquery: "jquery",
        "window.jQuery": "jquery",
        Popper: ["popper.js", "default"],
      })
    );
    
    module.exports = environment;
    

    Another big problem I ran into was how to correctly import Bootstrap’s styles.

    I initially created app/javascript/packs/application.scss and imported the styles in that file. However, that seemed to break my build in a way that made it so app/javascript/packs/application.js never compiled.

    Next, I renamed app/assets/stylesheets/application.css to app/assets/stylesheets/application.scss, and imported the styles into that file. That worked, but it meant that the Asset Pipeline was responsible for my styles. This isn’t necessarily a bad thing, but I wanted Webpacker to be responsible for all of my front-end code.

    Also, by using a .scss file, you can easily override Bootstrap’s default variales

  4. mkdir app/javascript/
  5. touch app/javascript/stylesheets/application.scss
  6. Import Bootstrap Styles

    // app/javascript/stylesheets/application.scss
    @import "~bootstrap/scss/bootstrap";
    
  7. Import Bootstrap, load styles, and optionally load Tooltips and Popovers everywhere.

    // app/javascript/packs/application.js
    
    require("bootstrap");
    import "../stylesheets/application";
    document.addEventListener("turbolinks:load", function () {
      $(function () {
        $('[data-toggle="tooltip"]').tooltip();
        $('[data-toggle="popover"]').popover();
      });
    });
    

    Webpacker emits css files only if extract_css is set to true in webpacker.yml otherwise stylesheet_pack_tag returns nil.

    When I was running through these steps, I found it strange that I didn’t need to add a stylesheet_pack_tag as I had seen in other tutorials. I realized that this is because I was in development.

    If you change extract_css: false to extract_css: true under the default: block in config/webpacker.yml and then restart your server, you’ll notice that the styles no longer load.

  8. To fix this, simply add the stylesheet_pack_tag and restart the server. After ensuring the styles haves loaded set extract_css: true back to extract_css: false under the default: block in config/webpacker.yml. You might need to run rails webpacker:clobber after making that change.

    <%# app/views/layouts/application.html.erb %>
    
    <!DOCTYPE html>
    <html>
      <head>
        <title>RailsBootstrap4Integration</title>
        <%= csrf_meta_tags %>
        <%= csp_meta_tag %>
    
        <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
        <%# ℹ️ Add stylesheet_pack_tag %>
        <%= stylesheet_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
        <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
      </head>
    
      <body>
        <div class="container">
          <%= yield %>
        </div>
      </body>
    </html>
    
    
  9. Finally, add the responsive meta tag

    <%# app/views/layouts/application.html.erb %>
    
    <!DOCTYPE html>
    <html>
      <head>
        <title>RailsBootstrap4Integration</title>
        <%= csrf_meta_tags %>
        <%= csp_meta_tag %>
        <%# ℹ️ Add a responsive meta tag %>
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    
        <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
        <%= stylesheet_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
        <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
      </head>
    
      <body>
        <div class="container">
          <%= yield %>
        </div>
      </body>
    </html>