Customizing Angular CLI build — an alternative to ng eject (v2)
This and other articles are available for free on my personal blog. Make sure to sign up to get the latest and greatest!
So, your Angular CLI project just went a bit beyond a TODO app and you have to customize your build configuration.
The question is, how?
Angular CLI 1.x ng eject VS Angular CLI builders
In Angular CLI 1.x up to Angular 5 you had theng eject
command for this, which was ejecting the whole underlying webpack configuration and allowing you to modify it as you please.
In Angular CLI 6 this command has been removed and it is not coming back. Instead Angular CLI exposes an API for developers allowing them to hook into the build process by providing their own builders.
With the new Angular CLI you can customize the build process by defining your own builders as well as using any of the builders provided by the community.
Extending underlying Webpack configuration
So let’s go ahead and customize our build by extending the underlying Webpack configuration:
- Install @angular-builders/custom-webpack:
npm i -D @angular-builders/custom-webpack
. - In angular.json change the
@angular-devkit/build-angular:browser
builder to@angular-builders/custom-webpack:browser
:
"architect": {
...
"build": {
"builder": "@angular-builders/custom-webpack:browser"
"options": {
...
}
...
}
- If you build a universal app and would like to modify your server build configuration use
@angular-builders/custom-webpack:server
instead of@angular-builders/custom-webpack:browser
- Add
customWebpackConfig
to the build target options :
"architect": {
...
"build": {
"builder": "@angular-builders/custom-webpack:browser"
"options": {
"customWebpackConfig": {
"path": "./extra-webpack.config.js"
}
...
}
...
}
Check out the full description of customWebpackConfig
object here.
- Create extra-webpack.config.js in the root of your application (or whatever path you specified in angular.json).
- Fill in the extra configuration required (plain Webpack configuration).
- Note that in contrary to
ng eject
this configuration will be merged with the default Angular build configuration so you only have to configure the part you want to change/add.
For example, if you want to add another Webpack loader, your Webpack config will look like this:
module.exports = {
module: {
rules: [
{
test: /\.cool$/,
use: 'cool-loader'
}
]
}
};
- Run
ng build
Advanced webpack configuration
There are use cases when just merging the delta of Webpack config is not enough.
If it’s just a matter of multiple configurations (use one build config for development
and another for staging
etc.) you can keep these configurations in separate files and utilize the configurations
option of build target.
However, sometimes it’s still not enough.
When you have a complicated logic for modifying your build configuration you can export a function from custom-webpack.config.js
rather than exporting an object.
The function receives base Webpack config and the builder options as parameters and returns a modified config. No merge performed.
For example:
const webpack = require('webpack');
const pkg = require('./package.json');
module.exports = (config, options) => {
config.plugins.push(
new webpack.DefinePlugin({
'APP_VERSION': JSON.stringify(pkg.version),
}),
);
return config;
};
Modifying index.html
Since Angular CLI 8 index.html
is not generated as part of Webpack build. This means that you cannot modify index.html
by modifying Webpack config.
Instead you should use indexTransform
option. This option allows you to provide a function that transforms index.html
(either synchronously or not).
So what do you have to do:
- Install @angular-builders/custom-webpack (≥8.1.0 required):
npm i -D @angular-builders/custom-webpack
.
Note that it requires @angular-devkit/build-angular>=0.801.0, install it by running:npm i -D @angular-devkit/build-angular
- Create a file
index-html-transform.js
in the root of your application (or whatever path you specified inangular.json
) - Export from this file transform function like this:
module.exports = async (targetOptions, indexHtmlContent) => {
//your transformation here
return newIndexHtmlContent;
}
Note that it doesn’t have to be async
.
- Modify the builder entry and add
indexTransform
option inangular.json
:
"architect": {
...
"build": {
"builder": "@angular-builders/custom-webpack:browser"
"options": {
"indexTransform": "./index-html-transform.js"
...
}
...
}
- Run
ng build
And what about ng serve?
Just replace @angular-devkit/build-angular:dev-server
inside the serve
target with @angular-builders/custom-webpack:dev-server
.
Now when you run ng serve
the build will use the config you’ve specified in browser
target.
Additional sources
- Check out this example project which uses
customWebpackConfig
as well asindexTransform
. - Another example that leverages the power of custom-webpack builder to build Angular Electron app with Native Node Addons.
What is next
In the next article we will learn how to create your own builder.