Getting Angular and Webpack Working

June 20, 2017

Getting Angular and Webpack Working Together in the Fair Offer Project

As part of scoping the fair offer project, I decided to use angular and webpack.

Webpack logo on white background

To recap, webpack is a module bundler that generates static assets and splits the application into multiple chunks to load those chunks on demand.

Experiencing Frustration and a Solution

At first, I found it a bit hard to get working. In fact, I remember plugging away at it for an hour or two (I’m writing this months later, so I can’t recall exactly) one evening after work and remember what a pain it was to get it working with bootstrap.

Fortunately, I came across this post by the ody brothers. I still ran into a couple of issues, but it helped me get going in the right direction.

Here are the steps I followed to get the webpack module compiling.

Step 1 – Add to bower.json and package.json

In bower.json I added the following:

"angular-bootstrap": "~1.2.4",
"bootstrap": "~3.3.6"

In package.json I added these files:

"file-loader": "*"
url-loader": "^0.5.6"

Step 2 – Add to app.js and webpack.config.js

In app.js, I added the following line:

require('bower/bootstrap');

In webpack.config.js, I added the following…

  • Add file loader to module.exports
module:
  loaders: [
    {
      test: /\.css$/, loader: 'style-loader!css-loader'
    },
    {
      test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: "file"
    },
    {
      test: /\.(woff|woff2)$/, loader:"url?prefix=font/&limit=5000"
    },
    {
      test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/octet-stream"
    },
    {
      test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=image/svg+xml"
     }
],
  • Add to resolve
resolve: {
    alias: {
        bower: bowerRoot,
        'jquery': jqueryPath

    },
// some more code
}

Step 3 – Resolve the jQuery error

Of course when I tried to run gulp serve, I got a ‘jQuery is not defined’ type issue.

ERROR in ./bower_components/bootstrap/js/alert.js
Module not found: Error: Cannot resolve 'file' or 'directory' /home/bruce/Documents/bitbucket_code/fair_offer_calculator/jquery/dist/jquery in /home/bruce/Documents/bitbucket_code/fair_offer_calculator/bower_components/bootstrap/js
 @ ./bower_components/bootstrap/js/alert.js 1:0-17

Oops, looks like alert.js in bootstrap can’t work without loading jQuery.

I trolled through this post, this one, and finally this one to fix the error.

plugins: [
// omitted some code here for brevity
  new webpack.ProvidePlugin({
      'angular': 'exports?window.angular!bower/angular',
      '$': "jquery",
      'jQuery': "jquery"
  }),
],

Step 4 – Get the CSS Working

The next issue was how to get bootstrap css to show up. To do that I had to update 2 dependencies in my package.json file, url_loader and file_loader. Then after a bit of Googling, this is the final webpack.config.js file I came up with.

You can see I played around with the path to bootstrap via the bootStrap path variable before commenting it out.

var path              = require('path');
var webpack           = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');

var appRoot           = path.join(__dirname, '/src');
var bowerRoot         = path.join(__dirname, '/bower_components');
//var bootstrapPath     = path.join(__dirname, '/bower_components/bootstrap/less/bootstrap');
var jqueryPath        = path.join(__dirname, '/bower_components/jquery/dist/jquery.min');

module.exports = {
    cache: true,
    debug: true,
    singleRun: true,

    // The entry point
    entry: [
        path.join(appRoot, '/app/app.js')
    ],

    output: {
        path: path.join(__dirname, './static'),
        publicPath: './',
        filename: '[hash].bundle.js',
        chunkFilename: '[chunkhash].js'
    },


    module: {
        loaders: [
            {
                test: /\.less$/, loader: 'style!css!less'
            },
            {
                // require raw html for partials
                test: /\.html$/, loader: 'ng-cache'
            },
            {
                test: /\.json$/, loader: 'json'
            },
            {
              test: /\.css$/, loader: 'style-loader!css-loader'
            },
            {
              test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "url-loader?limit=10000&minetype=application/font-woff"
            },
            {
              test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "file-loader"
            },
//            {
//              test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: "file"
//            },
//            {
//              test: /\.(woff|woff2)$/, loader:"url?prefix=font/&limit=5000"
//            },
            {
              test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/octet-stream"
            },
            {
              test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=image/svg+xml"
            }
        ],

        // don't parse some dependencies to speed up build.
        noParse: [
            path.join(bowerRoot, '/angular-ui-router'),
            path.join(bowerRoot, '/angular-mocks'),
            path.join(bowerRoot, '/angular'),
            path.join(bowerRoot, '/less')
        ],
    },

    resolve: {
        alias: {
            bower: bowerRoot,
            'jquery': jqueryPath

        },

        extensions: [
            '',
            '.js',
            '.less',
            '.css'
        ],

        root: [appRoot]
//        moduleDirectories: [bootstrapPath]
    },


    plugins: [
        // bower.json resolving
        new webpack.ResolverPlugin([
            new webpack.ResolverPlugin.DirectoryDescriptionFilePlugin('bower.json', ['main'])
        ], ['normal', 'loader']),

        // disable dynamic requires
        new webpack.ContextReplacementPlugin(/.*$/, /a^/),

        new webpack.ProvidePlugin({
            'angular': 'exports?window.angular!bower/angular',
            '$': "jquery",
            'jQuery': "jquery"
        }),

        new HtmlWebpackPlugin({
            template: __dirname + '/src/index.html'
        }),

    ],

};

Summary

Hopefully this post gave you a better idea on how to troubleshoot your issues with the baseline repository I used to get going with Webpack, Angular, and Gulp.


Profile picture

Written by Bruce Park who lives and works in the USA building useful things. He is sometimes around on Twitter.