If you want Bootstrap with Sprockets and ImportMaps, you will pin your JS dependencies — in our case Bootstrap and Popper — in any one of these 3 ways:
(1) Via a CDN,
(2) from the vendor folder of a Gem, or
(3) from your own
How to Get Rails 7 Bootstrap from Sprockets and Sassc-Rails by Pinning with Importmap
Note that sass-rails is now no longer enabled in the Rails 7 default installation, but it is in your Gemfile as a commented-out gem. (So you will need to uncomment and bundle install to use it, which are in the steps below.)
Remember “Sprockets” is another name for “asset pipeline.” For a detailed history of the Rails gem defaults check out my blog post about Hampton Lintorn-Catlin’s petition for Rails to adopt a Node-based Sass compiler. The rejection of this petition signaled that Rails 7 was switching to the C-based compiler in the sassc-rails gem.
That means that because sassc-rails is commented out in the default Gemfile, sprockets-rails was made part of the default Gemfile. Before Rails 7, both sass-rails and sprockets-rails (by being a dependency on sass-rails) were part of what got loaded in the default Gemflie, even though sprockets-rails wasn’t actually in the default Gemfile.
In Rails, this confusion was not helped by the fact that having both the Asset Pipeline (Sprockets) and Webpacker enabled you to pick and choose and many developers new to the eco-system got lost in the choice overload.
Now, with Rails 7, the Rails core team has officially ejected Node (webpacker) for three primary reasons:
• ImportMap, a feature where we can load ES modules dynamically at runtime, is natively available in Chrome and Firefox and works with a shim with the other modern browsers.
• Internet Explorer (IE) is finally dead
• HTTP2, which is now widely available on all modern browsers too, doesn’t have the ‘each network request’ cost associated with HTTP1 that the traditional web had.
However, keep in mind that this was at the price of having a development & deployment experience for things like Typescript, NPM/Yarn-managed JS dependencies, and a React-friendly setup. For those things, you’ll want either JSBundling or Shakapacker. To help you choose, see this post.
• Get Rails 7 working with Bootstrap via ImportMap-Rails
• Stimulus + Turbo
In this tutorial, we will use the standard rails new command which comes bundled with everything listed (except Bootstrap). I will also go over step-by-step how to confirm that each component is working.
For a faster quick setup guide that excludes verifying each component, see this post.
Let’s start by making a new app.
rails new MyGreatApp
By using none of the flags when creating a new Rails 7 app, you will be creating a Rails app with Sprockets, Imoprtmaps, Stimulus, and Turbo (sprockets-rails, importmap-rails, stimulus-rails, turbo-rails).
1. Hello sassc-rails Gem
Start by uncommenting the scssc-rails gem which is commented out by default in the Gemfile:
2. Turn on Inline Source maps (so we can debug Rails 7 Bootstrap)
in config/environments/development.rb add this line:
config.sass.inline_source_maps = true
Also, the sassc-rails gem README advises this note as well:
Delete this file:
Now make a new empty file called
application.scss in the same folder
4. Import Rails 7 Bootstrap into your Application
Add to Gemfile, add
gem 'bootstrap', '~> 5.1.3'
In this case we are using the old Bootstrap gem for its CSS only as a bridge between the old Sprockets world and Bundling world. In this example, our JS will be served through Importmap’s new paradigm.
Also, in the application.scss file we created in Step 3, add this:
.scss to Asset Precompilation (because it’s needed by Rails 7 Bootstrap)
Go to config/initializers/assets.rb
We want to uncomment and change this line:
Rails.application.config.assets.precompile += %w( application.scss )
Notice that we do not have to make any changes to our application.html.erb, which by default looks as below. This is handy and happens because the
stylessheet_link_tag just references the
stylesheet file without the extension type, which means it picks up the SCSS instead of the CSS file when we switched it from one to the other.
No changes here.
6. Dummy Controller & Route
Create the articles controller with:
rails generate controller Articles
Add an empty def index to it:
class ArticlesController < ApplicationController def index end end
in config/routes.rb, uncomment this line:
And finally, create a Hello World file at app/views/articles/index.erb
Now, load your website in your browser and click “View Source”
Notice here that Sprockets has applied a thumbprint to this specific build. When we change anything in our CSS, Sprockets will recompile the application file and give it a new thumbprint.
7. Now add Something for Rails 7 Bootstrap
If we look in our browser, our existing layout looks like so:
The shrewd eye might notice that Bootstrap is in fact applied, but we would hardly notice since all our app does is say “Hello World”‘
So let’s add a Bootstrap navbar:
<nav class="navbar navbar-expand-lg navbar-light bg-light"> <div class="container-fluid"> <a class="navbar-brand" href="#">Navbar</a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarSupportedContent"> <ul class="navbar-nav me-auto mb-2 mb-lg-0"> <li class="nav-item"> <a class="nav-link active" aria-current="page" href="#">Home</a> </li> <li class="nav-item"> <a class="nav-link" href="#">Link</a> </li> <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false"> Dropdown </a> <ul class="dropdown-menu" aria-labelledby="navbarDropdown"> <li><a class="dropdown-item" href="#">Action</a></li> <li><a class="dropdown-item" href="#">Another action</a></li> <li><hr class="dropdown-divider"></li> <li><a class="dropdown-item" href="#">Something else here</a></li> </ul> </li> <li class="nav-item"> <a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a> </li> </ul> <form class="d-flex"> <input class="form-control me-2" type="search" placeholder="Search" aria-label="Search"> <button class="btn btn-outline-success" type="submit">Search</button> </form> </div> </div> </nav>
Ok now let’s take a look:
Our app now has what looks like a Bootstrap Navbar, but if you examine it closely, you’ll notice it is not working.
8. Choose to either use your JS via CDN or as vendor file
We’re going to pin this file using ImportMap. This small little piece of magic needs to be done under the hood to make ES Modules work, and fortunately, the Rails core team has done most of the hard work for you.
What you need to do is pin the name
popper (or anything else in the future) to those “named” imports. A shim allows for the browser to automatically import those dependencies whenever it encounters an ES Module that needs them.
Option #1: Use Via a CDN
Pin Bootstrap and Popper:
./bin/importmap pin firstname.lastname@example.org
./bin/importmap pin @email@example.com
Go to config/importmap.rb and look at the lines that got added:
pin "bootstrap", to: "https://ga.jspm.io/npm:firstname.lastname@example.org/dist/js/bootstrap.esm.js" pin "@popperjs/core", to: "https://ga.jspm.io/npm:@email@example.com/lib/index.js"
Add Bootstrap to the Application
Because Bootstrap requires Popper, we just need to Import bootstrap once in the application.js file to make it available via the importmap.
Now start the Rails server.
The Boostrapy interactions work!
Also, because this is built-in to the Navbar we built, if you shrink your browser window a bit you’ll see the hamburger nav for mobile:
Option #2: Use Bootstrap & Popper Bundled from the Gem
What we did above is called loading the from a CDN. That means we tell the browser to load the JS dependencies (Bootstrap, and Popper) directly from the sky. Optionally, we can pack up the JS into our application from the compiled source in the bootstrap gem.
However, to do that we need to tell Sprockets to load it.
Add bootstrap.min.js popper.js
Rails.application.config.assets.precompile += %w( application.scss bootstrap.min.js popper.js )
In config/importmap.rb add
pin "popper", to: 'popper.js', preload: true pin "bootstrap", to: 'bootstrap.min.js', preload: true
import "popper" import "bootstrap"
GO TO https://getbootstrap.com/ and click Download
Now do the same for Popper which you can do at https://popper.js.org/
Rails.application.config.assets.precompile += %w( application.scss bootstrap.min.js popper.min.js )
In config/importmap.rb add
pin "popper", to: 'popper.min.js', preload: true pin "bootstrap", to: 'bootstrap.min.js', preload: true
import "popper" import "bootstrap"
Note that in Rails 7, there is now another file called
application.js also, inside of the Stimulus controllers, which you should not confuse with this