I spent some time figuring out how to load Bootstrap styles from node_modules in a Webpack build, so here’s how I finally got it to work. The demo project used here is available on GitHub with a step-by-step walkthrough of the changes.

Project setup

Let’s assume we start out with a project like this:

myProject/
  node_modules/bootstrap/dist/css/bootstrap.css

  src/
    js/
      main.js
    styles/
      main.scss
    index.html

  package.json
  webpack.config.js

src/index.html:

<!DOCTYPE HTML>
<html lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <title> Greeting of the world </title>
</head>
<body>
  <h1> Hello, World! </h1>
  <button class="btn btn-success">
    <span class="glyphicon glyphicon-off"></span>
    I'm a button
  </button>

  <script type="application/javascript" src="bundle.js"></script>
</body>
</html>

src/js/main.js:

console.log('Hello, World!');

src/styles/main.scss:

body {
  background-color: "#101010";
  color: "#606060";
}

package.json (relevant parts):

{
  "devDependencies": {
    "jshint": "^2.8.0",
    "jshint-loader": "^0.8.3",
    "webpack": "^1.12.2",
    "webpack-dev-server": "^1.12.1"
  },
  "dependencies": {
    "bootstrap": "^3.3.5"
  }
}

webpack.config.js:

'use strict';

var path = require('path');
var webpack = require('webpack');

var SRC_DIR = path.resolve(__dirname, 'src');
var BUILD_DIR = path.resolve(__dirname, 'build');

module.exports = {
  context: SRC_DIR,

  entry: {
    app: './js/main.js',
  },
  output: {
    path: BUILD_DIR,
    filename: 'bundle.js',
  },

  resolve: {
    root: SRC_DIR,
  },

  module: {
    loaders: [
      {
        test: /\.js$/,
        loader: 'jshint',
        exclude: /node_modules|bower_components|lib/,
      },
    ],
  },
};

Getting to work

Alright, first of all let’s build the project and take a look.

$ npm install
$ ./node_modules/.bin/webpack-dev-server --content-base src/

You should see the “Hello, World!” message on the page and in the console, and an unstyled button. So far so good.

Let’s add some styles! We’ll do this by loading our styles as a module in main.js:

'use strict';
require('styles/main');

console.log("Hello, World!");

For this to work, we’ll need to add some loaders to our Webpack configuration. First, we install the loaders and their peer dependencies:

$ npm install --save-dev style-loader css-loader sass-loader node-sass

Then we add these loaders to our Webpack configuration, and also tell the resolver to look for files with the .scss extension:

module.exports = {
  // ...
  resolve: {
    // ...
    extensions: ['', '.min.js', '.js', '.json', '.scss'],
  },
  module: {
    loaders: [
      // ...
      {
        test: /\.css$/,
        loaders: ['style', 'css'],
      },
      {
        test: /\.scss$/,
        loaders: ['style', 'css', 'sass'],
      },
    ],
  },

We restart webpack-dev-server and see that our styles from main.scss have been loaded!

Now let’s load those Bootstrap styles to make your button pretty. This is the part that took me some time to figure out. We’ll do that is by adding an @import rule to main.scss. The ~ in the import path tells the Webpack loader to look for the bootstrap module in node_modules instead of trying to resolve it as a relative path:

@import "~bootstrap/dist/css/bootstrap.css";

However, building our project now greets us with a bunch of errors:

ERROR in ../~/css-loader!../~/sass-loader!./styles/main.scss
Module not found: Error: Cannot resolve 'file' or 'directory' ../fonts/glyphicons-halflings-regular.eot in ./src/styles
 @ ../~/css-loader!../~/sass-loader!./styles/main.scss 6:4386-4438 6:4461-4513

ERROR in ../~/css-loader!../~/sass-loader!./styles/main.scss
Module not found: Error: Cannot resolve 'file' or 'directory' ../fonts/glyphicons-halflings-regular.woff2 in ./src/styles
 @ ../~/css-loader!../~/sass-loader!./styles/main.scss 6:4565-4619

ERROR in ../~/css-loader!../~/sass-loader!./styles/main.scss
Module not found: Error: Cannot resolve 'file' or 'directory' ../fonts/glyphicons-halflings-regular.woff in ./src/styles
 @ ../~/css-loader!../~/sass-loader!./styles/main.scss 6:4652-4705

ERROR in ../~/css-loader!../~/sass-loader!./styles/main.scss
Module not found: Error: Cannot resolve 'file' or 'directory' ../fonts/glyphicons-halflings-regular.ttf in ./src/styles
 @ ../~/css-loader!../~/sass-loader!./styles/main.scss 6:4737-4789

ERROR in ../~/css-loader!../~/sass-loader!./styles/main.scss
Module not found: Error: Cannot resolve 'file' or 'directory' ../fonts/glyphicons-halflings-regular.svg in ./src/styles
 @ ../~/css-loader!../~/sass-loader!./styles/main.scss 6:4825-4877

This is because bootstrap.css references font files using url('<foo>'), and Webpack tries to resolve and inline those files into the CSS bundle. The solution is, again, to add more loaders. The one we need in this case is url-loader:

$ npm install --save-dev url-loader file-loader

Let’s add it to the Webpack configuration:

module.exports = {
  // ...
  module: {
    loaders: [
    // ...
      {
        test: /\.(woff|woff2|ttf|svg|eot)/,
        loader: 'url?limit=100000',
      },
    ]
  }
}

After restarting the webpack-dev-server we see that the Bootstrap styles and fonts are now loaded successfully!