Webpack

Webpack is great when it works. When it breaks, the whole team fixes the build.

Bradley Brown, Cohort 10

What is Webpack?

Webpack is a JavaScript bundler and task runner. Webpack will gather all code in your program and pack it up ready-to-use format for the end user's web browser. It can also automate the running of tasks such as minifying code (i.e., compressing code into an efficient format that executes faster). Webpack is also flexible in handling different formats and tasks using its plugin system.

What Webpack Does

When using webpack with an Angular project, webpack performs the following steps:

  1. Find the code listed at the entry point
  2. For each component in the entry point object:
    1. Compile the component from TypeScript to JavaScript
    2. Add the compiled ouput to the application
    3. Map out the dependencies of this component
    4. Recursively repeat the compilation and mapping of the dependencies until all files have been compiled and mapped
  3. Compress (minify) the completed application
  4. Generate <link> and <script> tags and inject them into the <head> tag

Notice this process stacks code up as it encounters it. All the code it sees will be compiled and mapped, including and especially external code such as Angular and Bootstrap. It also uses an algorithm called tree shaking to find and delete duplicate code caused by unintentionally including internal and external components more than once.

TL; DR

This process incrementally builds and optimizes your project for you. Webpack compresses dependencies for you. It creates a version that loads fast and is browser compatible.

Configuring Webpack

Important Configuration Concepts

Webpack uses a very modular, plugin-enhanced configuration system. The configuration, divided into two major files, comes down the following important components:

  1. entry point: an object that tells webpack where to start; this is important because this will mark what files webpack will kick off the process with
  2. loader: a plugin or webpack core component that handles different file types and formats (e.g., CSS, HTML, TypeScript, …)
  3. plugin: a third party extension that extends webpack's core functionality
  4. output: rules webpack will follow when writing optimized files to the server for end user deployment

The order of the configuration components roughly corresponds to the order webpack processes them. Webpack starts at each entry point, uses the appropriate loader (and plugin if applicable), runs the rest of the plugins, and writes to the output.

Directory Structure

project-root

webpack

helpers.js

index.html

webpack.common.js

webpack.live.js

helpers.js

helpers.js is directly taken from the Angular documentation. Simply stated, it provides an extra function to resolve the root of the project in a universal, unambigious way to prevent pathing problems.

index.html

index.html is a minimalistic HTML template to give webpack a place to insert the generated code into. This file is purposely kept plain as front end components will be added in the main Angular application.

webpack.common.js

webpack.common.js is the core of the webpack configuration and the basis for most configuration components. The first major component is the entry point:

entry: {
	'polyfills': helpers.root('app') + '/polyfills.ts',
	'vendor': helpers.root('app') + '/vendor.ts',
	'app': helpers.root('app') + '/app.ts',
	'css': helpers.root('app') + '/app.css'
}

The order of the entry points matters. Webpack will process them in the order in which they appear in the object:

  1. polyfills: prerequisites for Angular itself
  2. vendor: Angular, Bootstrap, FontAwesome, and any other project-specific dependencies
  3. app: your Angular application
  4. CSS sheet: your CSS sheet for the application

The next major component are the loaders, which tell webpack how to handle different formats. The loaders are mostly boilerplate, and largely taken from the Angular documentation. Modification should only be necessary to handle a new file type not in the example.

The last major component are the plugins, which we will use to tell webpack how to assemble everything it found.

plugins: [
	new webpack.optimize.CommonsChunkPlugin({
		name: ['app', 'vendor', 'polyfills']
	}),

	new HtmlWebpackPlugin({
		inject: 'head',
		filename: helpers.root('public_html') + '/index.html',
		template: helpers.root('webpack') + '/index.html'
	})
]

Of particular interest is the HtmlWebpackPlugin. The purpose of the plugin is to steer webpack in its template generation and tell it where to read and write templates. It is configured with the following parameters:

  • inject: which tag to inject into, in this case, the <head> tag
  • filename: the destination of where to write the final packed up file
  • template: the minimal HTML template to use when writing the template

This plugin is very important because it serves as the hub for filesystem operations and tells webpack where to start and end the HTML generation process.

webpack.live.js

The last major configuration component we encounter is the output section, which tells webpack how to deploy to the server.

output: {
	path: helpers.root('public_html/dist'),
	publicPath: 'dist',
	filename: '[name].[hash].js',
	chunkFilename: '[id].[hash].chunk.js'
}

Output is configured by the following variables:

  • path: directory to write webpack's output files to
  • publicPath: prefix for <link> and <script> tags
  • filename: template file name to generate, hash is recommended to counteract cache poisoning
  • chunkFilename: template file name to generate for chunks loaded on demand instead of by default

The final part of the the webpack.common.js file finalizes the process with the plugins that will compress and minify the code and write it to the output directories. The final live deployment is ready-to-use and cross browser for the end user's browser. This is the final step in using webpack to pack up and deploy an Angular project.