How to add Bootstrap to Gatsby

I tried adding Bootstrap 4 to my Gatsby 2.13.50 (CLI: 2.7.14) project today. Based on beginner tutorials I created a layout.js as the base template. It looks like this:

import React from "react"
import Header from '../components/header'
import '../styles/bootstrap-4.3.1-dist/css/bootstrap.css'
import { withPrefix } from "gatsby"

// NOTE 1: ADDING THE JS FILES TO /styles IN /src DID NOT WORK.
// import '../styles/site_js/jquery.js'
// import '../styles/site_js/popper.js'
// import '../styles/site_js/bootstrap.js'

import { Helmet } from "react-helmet"

const Layout = (props) => {
return (
<html lang="en">
<head>
<Helmet>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no" />

<meta name="description" content="Hayat chat SAAS demo site." />
<meta name="author" content="Alex Yang, notathoughtexperiment" />

<title>Hayat Demo</title>
</Helmet>
</head>
<body>
<Header />
<main role="main" className="container">
{props.children}
</main>

// NOTE 2: CALLING JS FROM EXTERNAL SOURCES DID NOT WORK.
{/* <Helmet>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</Helmet> */}

// NOTE 3: THIS WORKED. BUT. SEE BELOW.
<Helmet>
<script src={withPrefix('site_js/jquery.js')} type="text/javascript" />
<script src={withPrefix('site_js/popper.js')} type="text/javascript" />
<script src={withPrefix('site_js/bootstrap.js')} type="text/javascript" />
</Helmet>

</body>
</html>
)
}

export default Layout

Notes 1 and 2 in the code above tell you what did not work. The error was an extremely persistent: "TypeError: Cannot read property 'fn' of undefined".

After reading about it online for a couple of hours (or more) I think it's because bootstrap.js kept loading before jquery.js and popper.js. Sources, including Bootstrap's official site, say that bootstrap.js must load AFTER jquery.js and popper.js.

Most solutions say that we can simply order the code as I've done above. Place jquery.js and popper.js first. And bootstrap.js last. Well, didn't work.

I tried a lot, a lot of different things including the code denoted in Notes 1 and 2.

Finally, I stumbled across this solution. Basically, place your files in /static in the root directory. Then use <script src={withPrefix('site_js/YOUR_REQUIRED_FILE.js')} type="text/javascript" /> to call them.

I've no idea why or how it works. But it does. But, the error still comes up, once every handful of reloads. After skulking around in the shadows of dejection for a while, I came up with a new solution, detailed next.

I know JS files load in the order they are placed. But, just to make extra sure that they really, really, really do that, I decided to override Gatsby's default-html.js so that I could add jquery.js and popper.js to the <head> tag.

I don't know what default-html.js does. I just have a feeling it loads first and acts as some sort of basis for the whole project.

So, following Gatsby's docs on default-html.js, I first ran cp .cache/default-html.js src/html.js.

Now that it's named html.js in /src, I opened it up and added the two JS files to the <head> section:

    import { withPrefix } from "gatsby"

    <head>
    ...
        <script async src={withPrefix('site_js/jquery.js')} type="text/javascript" />
        <script async src={withPrefix('site_js/popper.js')} type="text/javascript" />
    </head>

To make things load just a bit fast, I added async to their <script> tags following this wee article.

Now, it works perfectly.

However, I think the trade-off is, because the JS files load first, it might affect loading time. The files are not big and it's not critical for my project so I think it's ok. Maybe if loading time is more critical in future I might try `npm install bootstrap` or some other solution.

Comments

There are currently no comments

New Comment

required

required (not published)

optional

required