Matthew de Nobrega
Matthew de Nobrega in Technology
December 12, 2015

Angular2 with Webpack — tips and tricks

 

Angular2 is yet to hit beta, but Google has deployed the first reasonable-scale Angular2 application and after some big refactors the core apis now look fairly stable (this was written when alpha-52 had just been published). So we’re getting to the point where Angular2 is a viable option for new builds.

Any reasonably complex client-side application is going to have many dependencies — Typescript/JavaScript files, libraries, style sheets, images, and HTML. Webpack (which is very popular in React circles and is gaining traction in the Angular space) is an excellent choice for managing these dependencies. I see the key advantages as:

  1. The ability to include style sheets, images and html files as well as script files as dependencies — so specifying an app root means Webpack will automatically package all of the app’s assets
  2. Smart chunking of shared dependencies for multiple apps, so common dependencies are served from a common file
  3. Smart code splitting to package assets that are loaded on demand
  4. A development server that does watching and live reloading
  5. A clean yet flexible — if not perfectly documented — configuration mechanism

After using Webpack with Angular2 for about a month I’ve worked out a few tips and tricks which make working with the pair easier.

The AngularClass starter

AngularClass have an excellent starter project (which is also available on npm). It is regularly updated, appropriately minimal while still being useful, and handles many of the pain points (setting up Typescript and getting Karma working in particular).

Css pre-processing

The starter uses inline styles and templates — which is fine for a start but too limited for large applications. Webpack has loaders for SASS and LESS which are easy to configure. The best way to include the output in your app is to require the text output inline in your components (rather than linking to a file):

@Component({
    selector: ‘component’
})
@View({
    styles: [require(‘!raw!sass!.component.scss’)],
    template: require(‘./component.html’)
})
export class Component { }

Doing this means you can leverage Angular2’s View Encapsulation functionality (which I see as a big win for complex apps) while still having your styles pre-processed in separate files (with the associated tooling benefits). Incidentally you can require your html in the same way.

Web Workers

One of Angular2’s most exiting features is its off-the-shelf support for web workers. This is one aspect of a bigger picture where Angular2 is designed to run in different contexts — mobile apps being the other obvious one — and thus doesn’t have any dependencies on browser-specific features. Web worker apps have some code running on the UI thread to handle interaction with the DOM, the main application running in the worker, and communication between them happening over a message buss.

Setting all of this up is fairly simple (I have a slightly out-of-date example for of the AngularClass seed here), but unfortunately Webpack’s development server is not set up to do live reloading in a worker. There are a couple of open PR’s to fix this, but in the meantime if you require web worker support you need to make the following change manually to line 4 of the index.js file of your development server:

var scriptElements = (typeof document !== ‘undefined’) ? document.getElementsByTagName(‘script’) : [];

Multiple applications

The project I’m working on has three Angular2 applications, served off different namespaces in the same domain — all using HTML5 history API routes. Currently the Webpack development server doesn’t support this (again there is an outstanding PR), and you need to run a simple Express proxy in front of the server for this to work.

“use strict”;
var express = require(‘express’);
var proxy = require(‘proxy-middleware’);
var url = require(‘url’);
var app = express();
app.use(‘/__build__’,     proxy(url.parse(‘http://localhost:3000/__build__')));
app.use(‘/lib’, proxy(url.parse(‘http://localhost:3000/lib')));
app.get(‘/app1*’, function(req, res) {
    res.sendFile(__dirname + ‘/src/public/app1/index.html’);
});
//Etc for other apps
app.listen(8081);

Further reading

There’s a rapidly growing pool of resources for Angular2, and the Google team have been very good at communicating the thinking behind the decisions that went in to the new framework. Viktor Savkin has an excellent blog, as does Pascal Precht at Thoughtram. There were also some great presentations at the recent Angular Connect conference.

 

0
Matthew de Nobrega
Matthew de Nobrega
Product Owner & Front-end Lead at Lobster Ink