Skip to content

Instantly share code, notes, and snippets.

@kenhowardpdx
Created March 11, 2016 06:20
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kenhowardpdx/4f4a44b0fbdc77934bef to your computer and use it in GitHub Desktop.
Save kenhowardpdx/4f4a44b0fbdc77934bef to your computer and use it in GitHub Desktop.
Bundling Angular With webpack

I love building Angular applications. Becuase Angular is so modular you can separate your JavaScript code like your controllers and services into multiple files. But adding all of the script references to my HTML file is painful. If only there were some way to use a module loader similar to how modules work in Node...

WebPack To The Rescue

WebPack is a module loader that works similar to how Node handles modules.

With WebPack you can install Angular using NPM, the Node Package Manager.

NPM ships with Node and has becoming the defacto package manager for front-end JavaScript libraries and frameworks.

In this tutorial you'll update an existing Angular application to use CommonJS modules and bundle it using WebPack.

I won't go into why you should use WebPack, you can read the motivation behind the project and come to your own conclusions.

Here's how the starter project is structured:

project/
  app/
    controllers/
      dashboard.controller.js
    directives/
      yep-nope.directive.js
    services/
      github-status.service.js
    app.js
  js/
    angular.min.js
  index.html

Your Angular application is pretty small right now, but you'll need to update it to use a module loader like WebPack so it's ready for the future. WebPack has a wide variety of use cases and configuration options. You'll be using a very small subset of WebPack's capabilities in this tutorial.

Be Prepared

Before you start you must have Node installed on your machine. You can download Node from nodejs.org. Once Node is installed you'll be able to follow this tutorial.

You'll also need to download the starter project for this tutorial.

Review Application

Go ahead and unzip the application and open index.html in your favorite browser. You should see something like this.

See the Pen Angular WebPack Starter by Ken Howard (@kenhowardpdx) on CodePen.

<script async src="//assets.codepen.io/assets/embed/ei.js"></script>

Let's get started migrating this Angular application for use with WebPack.

Step One: Update index.html

Open the project in your favorite editor.

We'll be bundling our application into two primary files (app.bundle.js and vendor.bundle.js). Bundling is the process of joining multiple files into a single file. In our case we'll be bundling all of our application's code into app.bundle.js. Third party libraries like Angular and other dependencies will be bundled into vendor.bundle.js. This keeps the vendor code separate from our code and makes debugging our application less of a hassle.

Take a look at the index.html file.

<!doctype html>
<html>
    <head>
        <title>Dashboard</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
        
        <script src="js/angular.min.js"></script>
        <script src="app/app.js"></script>
        <script src="app/directives/yep-nope.directive.js"></script>
        <script src="app/services/github-status.service.js"></script>
        <script src="app/controllers/dashboard.controller.js"></script>
        
    </head>
    <body ng-app="dashboard">
        <div class="container">
        <br />
        <div ng-controller="dashboardController as ctrl">
            <div class="alert alert-danger" ng-class="{'alert-danger': !ctrl.github, 'alert-success': ctrl.github}">Is GitHub Up? <yep-nope check="ctrl.github"></yep-nope></div>
        </div>
        </div>
    </body>
</html>

You'll notice there are more than a few JavaScript files referenced. You'll need to replace these references with the bundled files you're about to create. The order you reference these scripts is important because the browser executes them as they are loaded. And because our application depends on Angular, the vendor.bundle.js script needs to load first.

<script src="js/vendor.bundle.js"></script>
<script src="js/app.bundle.js"></script>

Great. Your index file is ready. Next you'll need to configure WebPack to create the bundles.

Step Two: Install Dependencies

The downloaded project included angular.min.js in the js directory. In this step you'll install Angular using NPM so the included Angular library is no longer needed. Delete angular.min.js from the js directory before you continue.

Open a terminal and navigate to the root of your application.

» cd ~/path-to-the-files

Before you install WebPack or any of your third party libraries like Angular you'll need to initialize your project with NPM.

You can do this by simply executing this command in your terminal window:

» npm init -y

The -y flag bypasses the configuration wizard and accepts all of the default configuration options. Omit the -y flag if you'd prefer to use the configuration wizard instead.

Now install your dependencies. At this point our application only needs Angular and WebPack.

» npm install angular webpack --save-dev

If you are familiar with NPM you've probably noticed that we're using the --save-dev flag here instead of the --save flag. It is up to you and your build process on how you install dependencies. I recommend only using --save when a server-side application requires third-party modules at run-time. Otherwise use the --save-dev flag. In the case of this tutorial, Angular and WebPack are part of a build process so you should use the --save-dev flag.

Great. You've got Angular and WebPack installed!

Step Three: Configuring WebPack

WebPack needs to know where your application files live and where you want to store the bundles. To do this it looks for the webpack.config.js file in the root of your project. This file informs WebPack on how you want your application bundles separated and if you have any pre-processing tasks to perform.

Create webpack.config.js in the root of your project.

var webpack = require('webpack');

module.exports = {
    context: __dirname + '/app',
    entry: {
        app: './app.js',
        vendor: ['angular']  
    },
    output: {
        path: __dirname + '/js',
        filename: 'app.bundle.js'
    },
    plugins: [
        new webpack.optimize.CommonsChunkPlugin(/* chunkName= */"vendor", /* filename= */"vendor.bundle.js")
    ]
};

This file needs to export a configuration definition that WebPack can interprit. The key properties here are context, entry, and output.

  • context: This is an absolute path to your application's source files.
  • entry: The main file that bootstraps your Angular application. In our case we passed an object with keys of app and vendor. This generates multiple bundle files.
  • output: An object that configures where the bundle files are saved once generated.

There's also a plugins property. The only plugin we need is built into WebPack. It allows you to split your application's code and your third party code into separate files. You can read more about code splitting here.

Good work so far. You've got WebPack installed and configured. Next you'll edit your Angular application to use CommonJS modules.

Step Four: Require Modules

If WebPack were to bundle your code at this point it would only bundle the app.js file that is referenced in your webpack.config.js files. This is because your app.js file hasn't required any additional files.

To include yep-nope.controller.js, github-status.service.js, and dashboard.controller.js you'll need to require them within your app.js file.

You could simply require these files at the bottom of app.js.

// app.js
...
require('./directives/yep-nope.controller');
require('./services/github-status.service');
require('./controllers/dashboard.controller');

This works well for small applications, but it could get out of hand with larger applications.

Instead of simply requiring these files create a new file called index.js in the controllers folder. This file will act as the entry point for all of your application's controllers.

This file should require Angular and your dashboard.controller.js file.

'use strict';

var angular = require('angular');

angular.module('dashboard').controller('dashboardController', require('./dashboard.controller'));

Be sure to remove the controller definition line from dashboard.controller.js.

Now do the same for the directives directory.

Create the index.js which will act as the entry point for all your application's directives.

This file should require Angular and your yep-nope.directive.js file.

'use strict';

var angular = require('angular');

angular.module('dashboard').directive('yepNope', require('./yep-nope.directive'));

Remove the directive definition line from yep-nope.directive.js.

Next create an index.js file in the services folder. This file will act as the entry point for all of your services.

This file should require Angular and your github-status.service file.

'use strict';

var angular = require('angular');

angular.module('dashboard').service('GithubStatusService', require('./github-status.service'));

Now in github-status.service.js remove the service definition at the bottom of the file and add a module.exports definition and export the GithubStatusService function.

The last line of the file should look like this

module.exports = GithubStatusService;

The final piece of the puzzle is to require these new files in your app.js file

// app.js
...
require('./directives');
require('./services');
require('./controllers');

When your application grows and you need to add new directives, services, and controllers you'll need to create the Angular definitions in directives/index.js, services/index.js, or controllers/index.js before they'll be included in your bundle.

You're Angular application is ready to go. Next you'll configure NPM to bundle your code using WebPack.

Step Five: Configuring Tasks

When you initialized the project with the npm init command at the beginning of this tutorial you might have noticed a file named package.json was in your project's root directory. The package.json is responsible for keeping track of your project's dependencies. It also provides a way of running various tasks via the scripts option. When you create a script Node can execute your project's dependencies. We're going to add a bundle task to bundle our code.

Open package.json in your text editor.

Add a new line below the test script. Call the task "bundle" and have it execute "webpack". The scripts block should look something like this:

"scripts": {
	"test": "echo \"Error: no test specified\" && exit 1",
  "bundle": "webpack"
},

In your terminal execute npm run bundle. The terminal should output something like this

» npm run bundle

> angular-webpack@1.0.0 bundle /Users/ken/Projects/angular-webpack
> webpack

Hash: fa17ee9ecec0b19a73ae
Version: webpack 1.12.12
Time: 550ms
           Asset     Size  Chunks             Chunk Names
   app.bundle.js  1.42 kB       0  [emitted]  app
vendor.bundle.js  1.12 MB       1  [emitted]  vendor
   [0] ./app.js 82 bytes {0} [built]
   [0] multi vendor 28 bytes {1} [built]
   [1] ./services/index.js 145 bytes {0} [built]
   [4] ./services/github-status.service.js 373 bytes {0} [built]
   [5] ./controllers/index.js 147 bytes {0} [built]
   [6] ./controllers/dashboard.controller.js 278 bytes {0} [built]
    + 2 hidden modules

Now run the application in the browser.

» open index.html

You did it! Your Angular application is up and running using WebPack.

ES6 Modules

In this tutorial you've learned how to migrate a simple Angular application for use with WebPack using the standard exports/require CommonJS module pattern. While this works in practice today, more and more application developers are making the leap to ES6 module loading and transpiling their code using tools like Babel and TypeScript.

If you are interested in developing your application using ES6 modules you should take a look at the babel-loader and ts-loader plugins for use with WebPack.

Get Coding

You're ready to start building your own applications using Angular and WebPack. If you have questions or hit any stumbling blocks be sure to leave a comment below. We're all in this together!

You can download the final project files of this tutorial to compare them with your copy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment