BinaryWebPark

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, urlloader_ and fileloader_. 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.