The Angular CLI handles a great deal of the heavy lifting for us. In particular, its build process is highly advanced and ships with numerous optimizations by default.
Yet, there are times when we want to tweak this default behavior to meet specific needs in our projects. In the past, one could eject from the CLI using ng eject. However, once ejected, the CLI could no longer be used for building, which is a key reason this feature has been unsupported since CLI 6.
This article presents a solution that may even offer advantages over ejecting. The accompanying example project is available in my GitHub repository.
The role of ngx-build-plus
To make extending the CLI's build pipeline straightforward, I've developed ngx-build-plus. It extends the default webpack-based builder and thus replicates the CLI's standard behavior. Additionally, it enables two key features:
- Providing a partial webpack configuration that gets merged with the CLI's own config.
- Supplying a plain JavaScript file (called a plugin) that can dynamically alter the existing webpack configuration.
Furthermore, it adds an --single-bundle flag for ng build, which—as the name suggests—bundles the application's code into a single file. This is particularly handy for Web Components or custom elements built with Angular Elements.
Setting up ngx-build-plus
For projects using Angular with CLI 7, installation is as simple as running ng add:
ng add ngx-build-plus
When your CLI workspace contains multiple projects, use the --project switch to target the right one:
ng add ngx-build-plus --project getting-started
Next, you can define a custom partial webpack config. I've placed mine in the project root as webpack.extra.js:
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.BannerPlugin('----- Manfred was here -----')
]
}
For clarity, this example merely employs the BannerPlugin, which inserts a comment at the top of every generated bundle.
To incorporate this partial config into your build, invoke ng build with the --extra-webpack-config option supplied by ngx-build-plus:
ng build --extra-webpack-config webpack.extra.js
Again, if you have multiple projects in the workspace, specify which one to build:
ng build --extra-webpack-config webpack.extra.js --project getting-started
Upon completion, the added comment will appear in the opening lines of the output bundles:

To streamline this process, it's wise to wrap the command in an npm script.
Crafting a plugin
At times, a simple custom webpack config isn't sufficient. When you need to tweak specific parts of the default configuration, ng-build-plus lets you write a plugin.
Essentially, a plugin is just a JavaScript file that exports an object containing three methods:
exports.default = {
pre: function() {
},
config: function(cfg) {
var time = new Date().getTime();
var pattern = 'getting-started.[name].' + time + '.js';
cfg.output.filename = pattern;
return cfg;
},
post: function() {
}
}
In the example, this file resides in the project root and is named plugin.js.
As you'd expect, the pre method runs at the start of the build chain, while post is invoked at the end. The config method is called after pre and receives the CLI's default webpack config, giving you the opportunity to alter it.
In this minimal illustration, config simply changes the bundle names.
When running ng build, you can reference your plugin:
ng build --plugin ~plugin.js
The leading ~ tells ngx-build-plus that you're referring to a local file. Without it, the tool assumes the given name corresponds to an installed npm package.
After the build, you'll observe the new bundle names:

As before, wrapping this command in an npm script is recommended.
A more advanced plugin example is my side project ngx-build-modern. It generates two sets of bundles: one ES5-based for legacy browsers (like IE) and another ES2015-based for modern ones. The latter is more streamlined and omits many polyfills. It also produces an index.html that picks the appropriate bundle set for the user's browser.
