Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Bootstrap Sass & resolve-url-loader

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $12.00

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

Right now, we're loading Bootstrap's CSS. That's cool... but, there's a library called bootstrap-sass... which is a Sass version of all that Bootstrap CSS. That's even cooler... because if we used that instead, we could control and tweak Bootstrap itself, by just overriding some Sass variables.

Tip

Bootstrap 4 uses Sass natively. You can either require the CSS files or the Sass files from the main package (from the sass/ directory).

Installing bootstrap-sass

Let's do it! First, use yarn to remove the old package:

yarn remove bootstrap

Then, add the new package:

yarn add bootstrap-sass --dev

This package is just like the previous one... except it has Sass files instead of CSS. It does still contain the Bootstrap JavaScript. So to keep loading that, just change the require to bootstrap-sass:

... lines 1 - 3
require('bootstrap-sass');
... lines 5 - 15

Next, for the CSS require, we need to find the new path. Look inside node_modules/ for bootstrap-sass. Ok! It has an assets/stylesheets/_bootstrap.scss file! This is the key: it imports every piece of bootstrap.

Ok! Back in our file, require bootstrap-sass/assets/stylesheets/_bootstrap.scss:

... lines 1 - 3
require('bootstrap-sass');
... lines 5 - 7
require('bootstrap-sass/assets/stylesheets/_bootstrap.scss');
... lines 9 - 15

Check out the terminal that's running Webpack. It had a ton of errors... but now it's happy again! Try out the site. Nice!

Importing Sass instead of Require

Up until now, to load CSS or Sass, we've required it from JavaScript. But, you can also use @import from inside CSS. Close the node_modules/ directory and open our main.scss. At the very top, add @import. Then, copy the path to the bootstrap Sass file, remove it:

... lines 1 - 7
require('bootstrap-sass/assets/stylesheets/_bootstrap.scss');
... lines 9 - 15

And add it to the @import line:

@import '~bootstrap-sass/assets/stylesheets/_bootstrap.scss';
... lines 2 - 80

Webpack parses these @import lines... so this is effectively identical to what we had before. Except... it doesn't work! Even PhpStorm is super angry! When you use require inside a JS file, Webpack knows to look for bootstrap-sass inside the node_modules/ directory. But when you use a CSS @import, that path is relative to this file.

No worries! To hint to Webpack that you want to treat this path like a module path, prefix it with ~:

@import '~bootstrap-sass/assets/stylesheets/_bootstrap.scss';
... lines 2 - 80

Let's do this for Font Awesome too: copy its path, remove the require line:

... lines 1 - 8
require('font-awesome/css/font-awesome.css');
... lines 10 - 15

And add @import ~, then the path:

... line 1
@import '~font-awesome/css/font-awesome.css';
... lines 3 - 80

Path Problems in Sass

In theory... this should work just like before. Right? Right? Try it!

Oh no! It looks terrible! Find your terminal. Interesting:

Can't resolve fonts/bootstrap/glyphicons-halflings-regular.svg

... and then it references our main.scss file. Huh. This is really odd.

What's really curious is that the file is actually referenced from deep inside bootstrap: we require _bootstrap.scss, it imports another _glyphicons.scss and it references the font files. Well, it uses some variables, but this code references that file.

And this worked a moment ago... so why would it break? All we did was change the way that we were require these files.

So... this is a little confusing. Without going into too much detail, when you @import a Sass file from another Sass file in a different directory, any paths wrapped in url() get totally messed up: Webpack, well really, css-loader, looks for those paths relative to the first Sass file. In other words, it looks for the font files relative to main.scss, not _glyphicons.scss

The resolve-url-loader

The most important thing is to fix this nonsense. How? With another loader. Find your terminal and run

yarn add resolve-url-loader@2 --dev

Tip

Latest resolve-url-loader has a few breaking changes. Stay on version 2 to keep things working.

Tip

An alternative way to fix this is to override the $icon-font-path variable and point it at the fonts/ directory inside bootstrap-sass.

This loader exists only to solve this problem. Once it's installed, find webpack.config.js and, right before sass-loader, add resolve-url-loader:

... lines 1 - 4
module.exports = {
... lines 6 - 15
module: {
rules: [
... lines 18 - 34
{
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
'resolve-url-loader',
... line 41
]
},
... lines 44 - 65
]
},
... lines 68 - 78
};

But, for this to work, on sass-loader, add ?sourceMap:

... lines 1 - 4
module.exports = {
... lines 6 - 15
module: {
rules: [
... lines 18 - 34
{
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
'resolve-url-loader',
'sass-loader?sourceMap',
]
},
... lines 44 - 65
]
},
... lines 68 - 78
};

We're going to talk more about source maps in a few minutes. But internally, the resolve-url-loader needs them so it can do its job.

I know. It's a little crazy. But! If we go back and restart Webpack...

./node_modules/.bin/webpack --watch

It works! And the page comes back to life!

Hey! We've got Bootstrap via Sass! Now, let's tweak some stuff!

Leave a comment!

11
Login or Register to join the conversation

If anyone else still encounters error while importing bootstrap-sass from main scss even after adding resolve-url-loader, add this before you import _bootstrap.scss:

$bootstrap-sass-asset-helper: true;

Found the solution here: https://github.com/webpack-...

2 Reply

Hey Igor,

Thank you for this hint!

Cheers!

Reply
Geoffrey M. Avatar
Geoffrey M. Avatar Geoffrey M. | posted 4 years ago

Hello !
I wonder if it's up to date...
The url-resolver didn't fixed the path error. I had to add $icon-font-path: '~bootstrap-sass/assets/fonts/bootstrap/';
Otherwise it wasn't working and i kept having the error:
"Module not found: Error: Can't resolve '../../node_modules/bootstrap-sass/assets/stylesheets/fonts/bootstrap/glyphicons-halflings-regular.woff2'"

1 Reply

having the same issue :/ should i update to webpack 4 instead of using 3 and downgrading everything? Ohwell, seems like your fix does it to

Reply

Don't forget the trailing slash, without it the path is messed up:


Module not found: Error: Can't resolve 'bootstrap-sass/assets/fonts/bootstrapglyphicons-halflings-regular.eot'
                                                                             ^
1 Reply

Hey Ivan,

Good tip, thanks for sharing it with others!

Cheers!

Reply
Max A. Avatar

I had troable with path resolition
Module not found: Error: Can't resolve '../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/font-path("bootstrap/glyphicons-halflings-regular.woff2"'

This helped me.

https://github.com/webpack-...

Reply
Default user avatar
Default user avatar James Pike | posted 5 years ago

Bootstrap-sass installs Bootstrap 3.3.7 not Bootstrap 4

Reply

Hey James,

Yes, exactly. As we said in a tip: Bootstrap 4 uses Sass natively.

Cheers!

Reply
Default user avatar
Default user avatar James Pike | Victor | posted 5 years ago

Thanks Victor, yeah must of skipped over it, unreal.

Reply

No problem ;)

Cheers!

Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

This tutorial explains the concepts of an old version of Webpack using an old version of Symfony. The most important concepts are still the same, but you should expect significant differences in new versions.

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": "^7.2.0",
        "symfony/symfony": "3.3.*", // v3.3.16
        "twig/twig": "2.10.*", // v2.10.0
        "doctrine/orm": "^2.5", // v2.7.0
        "doctrine/doctrine-bundle": "^1.6", // 1.10.3
        "doctrine/doctrine-cache-bundle": "^1.2", // 1.3.5
        "symfony/swiftmailer-bundle": "^2.3", // v2.6.3
        "symfony/monolog-bundle": "^2.8", // v2.12.1
        "symfony/polyfill-apcu": "^1.0", // v1.4.0
        "sensio/distribution-bundle": "^5.0", // v5.0.22
        "sensio/framework-extra-bundle": "^3.0.2", // v3.0.26
        "incenteev/composer-parameter-handler": "^2.0", // v2.1.2
        "friendsofsymfony/user-bundle": "^2.0", // v2.1.2
        "doctrine/doctrine-fixtures-bundle": "~2.3", // v2.4.1
        "doctrine/doctrine-migrations-bundle": "^1.2", // v1.3.2
        "composer/package-versions-deprecated": "^1.11", // 1.11.99
        "friendsofsymfony/jsrouting-bundle": "^1.6" // 1.6.0
    },
    "require-dev": {
        "sensio/generator-bundle": "^3.0", // v3.1.6
        "symfony/phpunit-bridge": "^3.0" // v3.3.5
    }
}

What JavaScript libraries does this tutorial use?

// package.json
{
    "dependencies": [],
    "devDependencies": {
        "babel-core": "^6.25.0", // 6.25.0
        "babel-loader": "^7.1.1", // 7.1.1
        "babel-plugin-syntax-dynamic-import": "^6.18.0", // 6.18.0
        "babel-preset-env": "^1.6.0", // 1.6.0
        "bootstrap-sass": "^3.3.7", // 3.3.7
        "clean-webpack-plugin": "^0.1.16", // 0.1.16
        "copy-webpack-plugin": "^4.0.1", // 4.0.1
        "core-js": "^2.4.1", // 2.4.1
        "css-loader": "^0.28.4", // 0.28.4
        "extract-text-webpack-plugin": "^3.0.0", // 3.0.0
        "file-loader": "^0.11.2", // 0.11.2
        "font-awesome": "^4.7.0", // 4.7.0
        "jquery": "^3.2.1", // 3.2.1
        "lodash": "^4.17.4", // 4.17.4
        "node-sass": "^4.5.3", // 4.5.3
        "resolve-url-loader": "^2.1.0", // 2.1.0
        "sass-loader": "^6.0.6", // 6.0.6
        "style-loader": "^0.18.2", // 0.18.2
        "sweetalert2": "^6.6.6", // 6.6.6
        "webpack": "^3.4.1", // 3.4.1
        "webpack-chunk-hash": "^0.4.0", // 0.4.0
        "webpack-dev-server": "^2.6.1", // 2.6.1
        "webpack-manifest-plugin": "^1.2.1" // 1.2.1
    }
}
userVoice