My application takes a very long time to build for production using ng build --prod
Sometimes it even fails with
FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
Is there something I can do to reduce the build time?
There are some things that can be done to reduce the build time.
The build command is executed by node where a single process has a maximum memory limit of 1.76 GB on 64bit machines. It can be increased by adding the --max-old-space-size
argument to the build command
Since this argument must be passed to the node process itself, the command must be run directly with node. An example allocation 4096 MB (4GB) of RAM to the process would be:
node --max-old-space-size=4096 ./node_modules/@angular/cli/bin/ng build
Increasing the memory limit will also prevent the "heap out of memory" error.
There does appear to be a limit to how much memory the process uses. A project of mine had it's build time significantly reduced by a memory increase to 12GB - but increasing it to 32GB gave no further improvement.
Referencing external stylesheets from node_modules using relative paths has a negative performance impact on the build process and should be avoided.
The build process uses Webpack's sass-loader
, which supports a syntax where the location of node_modules is referenced with the tilde ~
.
Using the tilde instead of the relative path greatly reduces build time. So instead of importing external css stylesheets with
import "../../../../../node_modules/x/whatever.css"
use
import "~node_modules/x/whatever.css"
By default the production build uses the configuration from your angular.json
file. The default values are
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true
}
Do not divert from the production build defaults unless you have a very good reason.
These are a big part of keeping the build time low (espescially disabling sourceMap and enabling buildOptimizer).
The Angular CLI teamb continuously improves the speed of the build process.
Notibly the upgrade in build performance from version 6 to 7 is substantial, so keeping the @angular/cli
library up to date is always a good idea.
To have a fast building application you need to be very careful with which libraries you import.
Many popular libraries such as jQuery, lodash and moment are very large in size and not properly optimized for the Webpack building process.
Look for libraries that supports Webpack's Tree-Shaking to allow the build process to only bundle the parts of the library that is actually used in your application.
Also, don't fall into the trap of adding an entire utility library (such as lodash) if you only need to use a single function from it (like _get()
).
Compressing assets (often images) is largely a trivial task (just google "compress images online"), and it can increase the performance of the build process and the application itself.
Since Javascript is a single-threaded the benefits of having multiple CPU cores won't speed up the build process.
In fact, if you monitor your CPU during the build you will see a single core is under 100% load almost during the entire process.
If you are regulary building your application with production flag as part of your continuous integration setup, you may consider using a machine equipped with high single-threaded performance (for benchmarks, see cpubenchmark.net)