docs(core): incremental builds with Angular and React (#4366)
This commit is contained in:
parent
f271f19d15
commit
7040cf60ba
100
docs/angular/guides/setup-incremental-builds.md
Normal file
100
docs/angular/guides/setup-incremental-builds.md
Normal file
@ -0,0 +1,100 @@
|
||||
# Setup incremental builds for Angular applications
|
||||
|
||||
In this guide we’ll specifically look into which changes need to be made to enable [incremental builds](/angular/guides/ci/incremental-builds) for Angular applications.
|
||||
|
||||
## Use buildable libraries
|
||||
|
||||
To enable incremental builds you need to use buildable libraries.
|
||||
You can generate a new buildable lib with
|
||||
|
||||
```
|
||||
nx g @nrwl/angular:lib mylib --buildable
|
||||
```
|
||||
|
||||
## Adjust the executors/builders
|
||||
|
||||
Nx comes with faster executors allowing for a faster build. Make sure that your libraries use the @nrwl/angular:ng-packagr-lite builder.
|
||||
|
||||
```
|
||||
"mylib": {
|
||||
"projectType": "library",
|
||||
...
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@nrwl/angular:ng-packagr-lite",
|
||||
"options": {...},
|
||||
"configurations": {...}
|
||||
},
|
||||
"lint": {...},
|
||||
"test": {...}
|
||||
},
|
||||
...
|
||||
},
|
||||
```
|
||||
|
||||
Change your Angular app’s executor to @nrwl/angular:webpack-browser and the “serve” executor to @nrwl/web:file-server instead.
|
||||
|
||||
```
|
||||
"app0": {
|
||||
"projectType": "application",
|
||||
...
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@nrwl/angular:webpack-browser",
|
||||
"options": { ... }
|
||||
"configurations": { ... }
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@nrwl/web:file-server",
|
||||
"options": {
|
||||
"buildTarget": "app0:build"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"buildTarget": "app0:build:production"
|
||||
}
|
||||
}
|
||||
},
|
||||
...
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
## Running and serving incremental builds
|
||||
|
||||
To build an app incrementally use the following commands.
|
||||
|
||||
```
|
||||
nx build myapp --with-deps --parallel
|
||||
```
|
||||
|
||||
To serve an app incrementally use this command:
|
||||
|
||||
```
|
||||
nx serve myapp --with-deps --parallel
|
||||
```
|
||||
|
||||
Note: you can obviously specify the `--with-deps` and `--parallel` flags as part of the options property on the executor in your `angular.json` or `workspace.json`.
|
||||
|
||||
```
|
||||
"mylib": {
|
||||
"projectType": "library",
|
||||
...
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@nrwl/angular:ng-packagr-lite",
|
||||
"options": {
|
||||
...,
|
||||
"withDeps": true,
|
||||
"parallel": true
|
||||
},
|
||||
...
|
||||
},
|
||||
},
|
||||
...
|
||||
},
|
||||
```
|
||||
|
||||
## Example repository
|
||||
|
||||
Check out the [nx-incremental-large-repo](https://github.com/nrwl/nx-incremental-large-repo) for a live example.
|
||||
@ -1021,6 +1021,11 @@
|
||||
"name": "Incremental Builds",
|
||||
"id": "incremental-builds",
|
||||
"file": "shared/incremental-builds"
|
||||
},
|
||||
{
|
||||
"name": "Setup incremental builds for Angular applications",
|
||||
"id": "setup-incremental-builds-angular",
|
||||
"file": "angular/guides/setup-incremental-builds"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
BIN
docs/shared/incremental-build-webpack-vs-incremental.png
Normal file
BIN
docs/shared/incremental-build-webpack-vs-incremental.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
@ -1,56 +1,60 @@
|
||||
# Incremental Builds
|
||||
|
||||
Building applications incrementally is one of the main ways to scale your development as your applications getting bigger.
|
||||
|
||||
For instance, say we generate an application and a library, and then import the library from the application:
|
||||
As your applications are getting bigger, one of the main ways to scale your development is to build them in an incremental fashion.
|
||||
Right now, for instance, say we generate an application and a library as follows:
|
||||
|
||||
```bash
|
||||
nx g @nrwl/react:app myapp
|
||||
nx g @nrwl/react:lib mylib
|
||||
```
|
||||
|
||||
In this case `mylib` isn't a buildable library. We can test and lint it independently, but the only way to build it is by building some application using it (in this case `myapp`). For small and medium size applications this provides the best dev experience because WebPack is optimized for this scenario. But as your application keeps growing, the dev experience degrades.
|
||||
...and then import the library from the application. In this case, `mylib` isn't a buildable library. We cannot test and lint it independently, but the only way to build it is by building some application using it (in this case `myapp`). The default setup is to use Webpack, which builds "mylib" and bundles it directly into "myapp".
|
||||
This provides the best dev experience for small and medium-size applications, because Webpack is optimized for this scenario. But as your application keeps growing, the dev experience degrades.
|
||||
|
||||
## Buildable Libraries
|
||||
> The **duration** of the invoked operations should be **proportional** to the **size of the change**
|
||||
|
||||
Now let's create a buildable library instead (you can always make an existing library buildable after the fact).
|
||||
## Publishable and Buildable Libraries
|
||||
|
||||
```bash
|
||||
nx g @nrwl/react:app myapp
|
||||
Nx has **publishable libraries**. As the name suggests, such libraries are meant to be built and published to some package registry s.t. they can be consumed also from outside the Nx workspace. The executor for building a publishable library does more than just building. It makes sure the output is properly compressed and might even produce more bundles s.t. the package can be consumed in a variety of ways (e.g. also produces UMD bundles).
|
||||
|
||||
```
|
||||
nx g @nrwl/react:lib mylib --publishable --importPath=@myorg/mylib
|
||||
```
|
||||
|
||||
On the other hand, the executor of a **buildable library**, performs a subset of the operations compared to the publishable library's executor. That's because buildable libraries are not intended to be published and thus only produce the minimum necessary output for the incremental build scenario to work. For example, no UMD bundles or minification is being done. The main goal of the executor is to perform the build as fast as possible.
|
||||
|
||||
```
|
||||
nx g @nrwl/react:lib mylib --buildable
|
||||
```
|
||||
|
||||
Every buildable library has a build task:
|
||||
Read more about [Publishable and Buildable Nx Libraries here.](https://nx.dev/latest/workspace/structure/buildable-and-publishable-libraries)
|
||||
|
||||
```json
|
||||
{
|
||||
"build": {
|
||||
"builder": "@nrwl/web:package",
|
||||
"options": {
|
||||
"outputPath": "dist/libs/mylib",
|
||||
"tsConfig": "libs/mylib/tsconfig.lib.json",
|
||||
"project": "libs/mylib/package.json",
|
||||
"entryFile": "libs/mylib/src/index.ts",
|
||||
"external": ["react", "react-dom"],
|
||||
"babelConfig": "@nrwl/react/plugins/bundle-babel",
|
||||
"rollupConfig": "@nrwl/react/plugins/bundle-rollup"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
## Nx computation cache and Nx Cloud
|
||||
|
||||
When building the app, we need to first run `nx build mylib` and then `nx build myapp`. As the number of libraries grows, running these commands quickly becomes unworkable. Instead, we can run `nx build myapp --with-deps`.
|
||||
In an incremental build scenario, when building the app, all it's dependencies need to be built first. In our scenario above, that means we need to first run `nx build mylib` and then `nx build myapp`. As the number of libraries grows, running these commands quickly becomes unmanageable. Instead, we can run `nx build myapp --with-deps`.
|
||||
|
||||
Running `nx build myapp --with-deps` is basically the same as running `nx run-many --target=build --projects=myapp --with-deps`. Nx will look at all the dependencies of `myapp`, and will build them in the right order. So if say some `parentlib` depends on `childlib`, `childlib` will be built first. Nx will build whatever it can in parallel.
|
||||
It is costly to rebuild all the buildable libraries from scratch every time you want to serve the app. That's why the Nx computation caching is so important. The caching allows us to only rebuild a small subset of the libraries, which results in much better performance.
|
||||
|
||||
When using buildable libraries, the application doesn't depend on the source code of the library. Instead, it depends on the compiled output. This is what lets you save a lot of time and make your builds fast.
|
||||
If we can share the cache with our teammates, we can get a much better dev experience. For instance, [this repo](https://github.com/nrwl/nx-incremental-large-repo) has a large application, where `nx serve` takes just a few seconds.
|
||||
|
||||
## Incremental Builds and Cache
|
||||

|
||||
|
||||
It's costly to rebuild all the buildable libraries from scratch every time you want to serve the app. That's why the Nx computation caching is so important. The caching allows us to only rebuild a small subset of the libraries, which results in much better performance.
|
||||
The above chart has three different test runs:
|
||||
|
||||
If we can share the cache with our teammates, we can get a much better dev experience. For instance, [this repo](https://github.com/nrwl/nx-incremental-large-repo) has a large application, where `nx serve` takes just a few seconds. Check out [nx.app](https://nx.app) for more information on how to do it.
|
||||
- **Normal build -** which visualizes using the normal Angular webpack setup executing “nx build” (blue), “nx serve” (red) and the time to rebuild/re-serve when a file change happened (yellow)
|
||||
|
||||
## Restrictions
|
||||
- **Incremental build (cold) -** running all the above commands but using the Nx incremental builds but without having any kind of cache. That run takes slightly more than the normal Webpack build, which is expected.
|
||||
|
||||
- Buildable libraries can only depend on other buildable libraries.
|
||||
- **Incremental build (warm) -** running the Nx incremental build having already cached results from a previous run or from some other coworker that executed the build before. In a real world scenario, we expect always some kind of cached results either of the entire workspace or part of it. This is where the teams really get the value and speed improvements.
|
||||
|
||||
## When should I use incremental builds
|
||||
|
||||
We're continously improving the speed of incremental builds. However as of now, incremental builds become really benefitial in **really large repositories**.
|
||||
|
||||
Also, using incremental builds only really makes sense when using the distributed Nx caching with Nx Cloud. Check out [nx.app](https://nx.app) for more information on how to setup distributed caching.
|
||||
|
||||
## Setup an incremental build
|
||||
|
||||
- [Setup an incremental build for an Angular app](/{{framework}}/guides/ci/setup-incremental-builds-angular)
|
||||
- _Setup an incremental build for a React app (soon)_
|
||||
- _Setup an incremental build for a Node app (soon)_
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user