@mdo

Using Bootstrap in Hugo with npm

Up until the latest redesign of the Bootstrap documentation, our blog and Icons sites were including Bootstrap’s compiled CSS and JavaScript via CDN. This worked great overall and gave, but I found myself needing and wanting more granular control over the final production assets. In particular, I wanted the source Sass files, but just the compiled JS for now. Despite using Hugo for years now in Bootstrap’s docs, I’m a complete Hugo newbie, so I had no idea how to actually include Bootstrap with npm in a Hugo project. So I set out to fix that.

The solution I used is straightforward, but I didn’t see many clear and concise answers on it outside some forum threads: use the Hugo mounts system. So, after you create your package.json and npm i bootstrap, you setup your Hugo config to pull from the node_modules directory.

Here’s how it looks in our config.yml for the blog.

module:
  mounts:
    - source:           node_modules/bootstrap/scss
      target:           assets/scss/bootstrap
    - source:           node_modules/bootstrap/dist/js/bootstrap.min.js
      target:           assets/js/bootstrap.min.js

Now we can import Bootstrap’s styles with @import "bootstrap/{filename}"; as we’ve mounted Bootstrap’s source scss directory as part of our regular assets directory in Hugo. Here’s how the start of our stylesheet looks in the blog repo:

// src/assets/scss/style.scss

@import "bootstrap/functions";
@import "bootstrap/variables";
@import "bootstrap/maps";
@import "bootstrap/mixins";
@import "bootstrap/utilities";
@import "bootstrap/root";
@import "bootstrap/reboot";
@import "bootstrap/type";
@import "bootstrap/images";
@import "bootstrap/containers";
@import "bootstrap/grid";
@import "bootstrap/tables";
// @import "bootstrap/forms";
@import "bootstrap/buttons";
@import "bootstrap/transitions";
@import "bootstrap/dropdown";
// @import "bootstrap/button-group";
//
// ...and the rest of the Bootstrap imports

From here, you can use the Sass functions, maps, mixins, mixins, and any component you need. Read the Bootstrap Sass docs for more info. Importing the compiled CSS looks something like this:

{% raw %}{{- $style := resources.Get "scss/style.scss" }}{% endraw %}
<link href="{% raw %}{{ $style.Permalink | relURL }}{% endraw %}" rel="stylesheet">

On the JavaScript side, things are simpler since we’re just importing Bootstrap’s compiled and bundled JS file.

{% raw %}{{ $bootstrapJs := resources.Get "/js/bootstrap.min.js" }}{% endraw %}
<script src="{% raw %}{{ $bootstrapJs.Permalink | relURL }}{% endraw %}"></script>

I decided I only really wanted the source Sass files and the compiled JavaScript for now. This way my dependencies and build steps would stay quite simple. To build your own JS bundle, you’d need your own bundler or an ESM shim like es-module-shim. Skipping that saved time and energy in keeping shipping the latest design updates.

Lastly, there’s also the official Hugo module for Bootstrap’s SCSS and JS if you need it. I wanted to know how everything was working, so I went with the solution shown here instead of the module, but you should be good to go with either.