So your Angular 6 project just went a bit beyond TODO app and you have to customize your build configuration.
The question is how?
Angular CLI 1.x ng eject VS Angular CLI 6 builders
In Angular CLI 1.x (Angular 5) you had ng 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 temporarily disabled, and I suspect that it will be deprecated soon due to the new concept called Builders.
With the new Angular CLI you can customize the build process by defining your own builders as well as using one of the builders provided by the community.
Extending underlying webpack configuration
So lets go ahead and customize our build by extending the underlying webpack configuration:
Install @angular-builders/custom-webpack:
npm i -D @angular-builders/custom-webpack
.
Note that it requires version @angular-devkit/build-angular>=0.7.0 so you might need to install it (if not yet installed):
npm i -D @angular-devkit/build-angular
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 it with extra configuration you need (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'
}
]
}
};
And what about ng serve?
If you want to run ng serve
with custom webpack configuration (given you performed all the above steps) you should do the following:
- Install @angular-builders/dev-server
- Replace
@angular-devkit/build-angular:dev-server
inside the serve target with@angular-builders/dev-server:generic
- Run
ng serve
Additional sources
You can check out this electron-angular-native project for the example of Electron Angular application with node addons built with Angular CLI 6.
What is next
In the next article we will learn how to create your own builder.
Top comments (15)
This is amazing to see the hybrid solution actually working.
Thank you very much Evgeny.
At the moment I am have two problems I am trying to resolve.
1) make use of string-replace-webpack-plugin to replace index.html content
I think I have got the configuration right however the loader rule for it just doesnt seem to execute.
I also tried a different plugin webpack-html-string-replace-plugin but it needs usage of HtmlWebpackPlugin which messes up with the ng cli default webpack configuration causing rendering issues.
2) override default builder for protractor such that it is compatible with build and serve architect/targets
Any experience customizing these ?
Loader for string-replace-webpack-plugin
{
//Replace baseUrl with appropriate value as per dev or production mode
test: /index.html$/,
exclude: /node_modules/,
use: [ { loader: StringReplacePlugin.replace({
replacements: [
{
pattern: /@baseUrl/,
replacement: function (match, p1, offset, string) {
// if (isProd)
// return "";
// else if (isDev)
return "/vmi/";
}
}
]
})
}]
}
Hi,
Thank you very much for the kind words.
Regarding 1 - have you added an instance of StringReplacePlugin to plugins array as the documentation suggests? Another possible issue is the order in which the loader is applied. Prepending your loader instead of appending it might work as well. Here is an example of issue that was fixed by simply changing the order.
Regarding 2 - there is no such a builder but it's definitely an option. Please create a feature request on github and I'll look into it.
If the proposed solution for 1 doesn't work, please open an issue on github so that we could continue the investigation.
Regarding 2: they use dev-server target for protractor tests, so using @angular-builders/dev-server should be enough.
Thank you for writing this article. I'm currently working on an app that has multiple elements, so I'm trying to build all the elements into a single file.
Following you steps, I get this error: An unhandled exception occurred: Could not find the implementation for builder @angular-builders/dev-server:generic
Does anyone has any idea why?
I believe you're trying to use it with a newer version of @angular-builders. It's been deprecated, you should be using
@angular-builders/custom-webpack:dev-server
instead. Refer to the documentation.This solution seems not working correctly:
Did you try to customize the webpack.config file adding plugins such as 'webpack-dashboard' or 'webpackmonitor'?
I guess no! right?
---UPDATE---
I didn't read the "serve" part of your topic.
Now everything works perfectly
Is was able to over-ride entry , output, and some plugins using this strategy. But unfortunately didn't find a way to override / stop the generation of vendor chunk by cli and generate it manually using webpack-dll plugin. Any way out ?
Actually stopping vendor chunk generation is pretty easy - just specify
"vendorChunk": false
in yourdev-server
(orbuild
) configuration. Like this:As for DllPlugin, I have never used it so can't help you here.
I'm sure though if you figure that out there are folks that would be interested in that. So keep me posted!
Hi I am using @angular/cli": "~6.1.1", and Followed the steps you specefied, but getting error when trying to build the solution. Build statement used -
ng build --prod --aot --vendor-chunk --common-chunk --delete-output-path --build-optimizer --stats-json
chema validation failed with the following errors:
Data path ".builders['browser']" should have required property 'class'.
Error: Schema validation failed with the following errors:
Data path ".builders['browser']" should have required property 'class'.
at MergeMapSubscriber._registry.compile.pipe.operators_1.concatMap.validatorResult [as project]
I need to modify the uglifyOptions from the UglifyJSPlugin, any idea how to do that?
Sure, please take a look at this comment. Although Angular CLI is not using UglifyJsPlugin directly, not since Webpack 4. I think you need the optimization option in Webpack.
Let me know how it turned out. If it still doesn’t work for you, kindly open an issue on github and let us continue the discussion there.
Hi,
If you see the
node_modules/@angular-devkit/build-angular/src/angular-cli-files/models/webpack-configs/common.js
You can see it requests
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
Then it is configured in the same file a bit further.
I'm using a 3rd party tool that requires setting the uglifyOptions.compress.unused to false.
Since the default is true I have some issues with this library.
My objective is to use extra-webpack.config.js
to modify and add the uglifyOptions compress "unused" to false. Could you give me some guidance on how to get there?
unused:false
}
In your plugins section add
UglifyJSPlugin
withcompress.unused
set tofalse
.If
Angular CLI
uses this plugin, your configuration will take preference and will override thecompress.unused
of the defaultUglifyJSPlugin
.@felipecarrillo100 , here are few insights:
TerserPlugin
instead ofUglifyJsPlugin
.minimizer
array. Plugins merge was implemented forplugins
array but not for the rest. If you'd like this functionality to be added, please open a feature request on github. PR is also welcome.optimization
entry. For this you have to:optimization: replace
inmergeStrategies
object in builder configurationextra-webpack.config.js
. Angular optimization definitions can be found inand in
You can do it easily now with version
7.4.1
. Just export a function in your config file, it will receive the original config and expected to return a modified config. You can do whatever you like with the config that you receive.