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.
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.