angular / angular-cli

CLI tool for Angular
https://cli.angular.io
MIT License
26.77k stars 11.97k forks source link

Buildtime increased by 50% in v12 #20792

Closed kemsky closed 3 years ago

kemsky commented 3 years ago

🐞 Bug report

Command (mark with an x)

Description

This is v11.2.13:

$ ng build --prod
√ Browser application bundle generation complete.
√ Copying assets complete.
√ Index html generation complete.

Initial Chunk Files                   | Names         |      Size
main.1bbe17e891e0e81a6bae.js          | main          |   3.20 MB
scripts.5b3322e07a3cdcf6af69.js       | scripts       |   1.48 MB
styles.19406af932cc90ae2667.css       | styles        | 152.44 kB
polyfills-es5.2cb7395a5fd592fe7443.js | polyfills-es5 |  85.88 kB
runtime.23c71f07ba7ec5c3766a.js       | runtime       |   1.51 kB

                                      | Initial Total |   4.92 MB

Build at: 2021-05-14T11:00:10.476Z - Hash: 034e3176df64cbc0b60a - Time: 88357ms

Verbose log (logging itself causes slowdown, unfortunately...): angular11.txt

Angular CLI: 11.2.13
Node: 14.17.0
OS: win32 x64

Angular: 11.2.13
... animations, cli, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router
Ivy Workspace: Yes

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1102.13
@angular-devkit/build-angular   0.1102.13
@angular-devkit/core            11.2.13
@angular-devkit/schematics      11.2.13
@angular/cdk                    11.2.12
@angular/material               11.2.12
@schematics/angular             11.2.13
@schematics/update              0.1102.13
rxjs                            6.6.7
typescript                      4.1.5

This is v12 with yarn.lock and node_modules removed and reinstalled:

$ ng build --configuration production
Warning: Support was requested for IE 11 in the project's browserslist configuration. IE 11 support is deprecated since Angular v12.
For more information, see https://angular.io/guide/browser-support
√ Browser application bundle generation complete.
√ Copying assets complete.
√ Index html generation complete.

Initial Chunk Files                   | Names         |      Size
main.25755cb56d908f1ffa0c.js          | main          |   3.19 MB
scripts.5b3322e07a3cdcf6af69.js       | scripts       |   1.48 MB
styles.51baf6c2a9fbe6837aa1.css       | styles        | 154.28 kB
polyfills-es5.b787b17c5e8d81a4b18e.js | polyfills-es5 |  90.75 kB
runtime.bf3db8034d6e10a74a56.js       | runtime       |   1.20 kB

                                      | Initial Total |   4.92 MB

Build at: 2021-05-14T11:18:16.175Z - Hash: 8806f0a3a3b1271495e0 - Time: 157125ms

Verbose log (logging itself causes slowdown, unfortunately...): angular12.txt

Angular CLI: 12.0.0
Node: 14.17.0
Package Manager: yarn 1.22.5
OS: win32 x64

Angular: 12.0.0
... animations, cdk, cli, common, compiler, compiler-cli, core
... forms, language-service, material, platform-browser
... platform-browser-dynamic, router

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1200.0
@angular-devkit/build-angular   12.0.0
@angular-devkit/core            12.0.0
@angular-devkit/schematics      12.0.0
@schematics/angular             12.0.0
rxjs                            6.6.7
typescript                      4.2.4

We have a single small *.scss file (overriding some material colors) and it was updated by migration. The application has only one module. I tried removing scss and css from angular.json, but it is still slower than v11.

On average it is 50% slower.

-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
TypeScript                    1011          10391           2652          54543
HTML                           311            629              7           7832
CSS                             66            344             30           2109
Sass                             1             15             14             63
JavaScript                       1              9              3             55
JSON                             1              0              0              3
-------------------------------------------------------------------------------
SUM:                          1391          11388           2706          64605
-------------------------------------------------------------------------------

Recorded profile using node 12:

https://link.nithins.me/s2Uca0Ti

jcompagner commented 3 years ago

It's this commit a fix (or possible could have positive impact) for this case? https://github.com/angular/angular-cli/commit/f90a8324b46bd96e87a7b889a74aab432a391015

But what does it exactly mean that node modules just be immutable? Because angular will change it on the first build (ngcc compile) but will that be a problem ? Because this will be done already before webpack really starts to do it's thing right?

alan-agius4 commented 3 years ago

Version 12.1.0 has been released which contains several performance improvements. We also introduced an experimental file system cache which should improve the second/warm build quite a lot. You can opt-in using the NG_PERSISTENT_BUILD_CACHE=1 environment variable.

Please update using ng update @angular/cli @angular/core.

If the issue persist please report back providing one of the following;

simeyla commented 3 years ago

@alan-agius4 I'm seeing reductions from 40 > 30 seconds for my build with this change.

Given that this is experimental I'm assuming once in a while we might need to clear the cache. Do you have any thoughts on how stable this feature is at this time?

For anyone curious, the cache is stored in node_modules\.cache\angular-webpack

Also for anybody on Windows this is the correct way to set environmental variables in Powershell.

$env:NG_PERSISTENT_BUILD_CACHE=1
ng serve
zwjohn commented 3 years ago

I am not seeing much improvement after upgraded to 12.1.0 comparing to 12.0.5. It's still slow if you compare to V11. However, hasn't crashed with OOM yet, will keep monitoring. I am using cross env to set environment variable "cross-env NG_PERSISTENT_BUILD_CACHE=1 ng serve"

alan-agius4 commented 3 years ago

@zwjohn, if it’s still noticeable slower compared to v11, please provide one of the below as otherwise we’ll be unable to look into your issue.

zwjohn commented 3 years ago

@alan-agius4 For starter, here is a component that I removed a space from the ts file, it took 15-16 seconds to recompile for the first change while running ng serve, and around 10-11 seconds after first time. Note that all tests were just to remove a space from ts file. It was less than 5 seconds in V11. The reproduction for OOM is pretty hard to do, since there is no specific trigger I noticed, it happened a few times while making changes to the project during local development , it just crashed, however, it was with 12.05, not yet crashed for 12.1. I will continue to monitor.

My problem is with ng serve , the slow recompilation of ng serve is impacting development speed. node v14.17.0 npm v6.14.13

Lazy Chunk Files | Names | Size ****_module_ts.js | - | 132.76 kB

60 unchanged chunks

Build at: 2021-06-26T02:07:18.541Z - Hash: f27b25b4ae1c532eca8b - Time: 15864ms

√ Compiled successfully.

Build and Serve configuration in angular.json, I will monitor about OOM crash.

                           "build": {
                           "builder": "@angular-devkit/build-angular:browser",
                           "options": {
                               "aot": true,
                               "outputPath": "dist",
                               "index": "src/index.html",
                               "main": "src/main.ts",
                               "polyfills": "src/polyfills.ts",
                               "tsConfig": "tsconfig.app.json",

                               "assets": [
                                   "src/assets/favicon/favicon.ico",
                                   "src/assets/favicon/favicon-16x16.png",
                                   "src/assets/favicon/favicon-32x32.png",
                                   "src/assets/favicon/favicon.ico",
                                   "src/assets",
                                   {
                                       "glob": "_redirects",
                                       "input": "src",
                                       "output": "/"
                                   },
                                   "src/manifest.webmanifest"
                               ],
                               "styles": [
                                   "src/styles.scss",
                                   "node_modules/@ctrl/ngx-emoji-mart/picker.css"
                              ],
                               "scripts": [],
                               "allowedCommonJsDependencies": [
                                   "lodash",
                                   "@swimlane/dragula",
                                   "chart.js",
                                   "angular-calendar",
                                   "calendar-utils/date-adapters/date-fns",
                                   "contra/emitter",
                                   "crossvent",
                                   "dom-plane",
                                   "dom-set",
                                   "@mattlewis92/dom-autoscroller",
                                   "dragula"
                               ]
                           },
                           "configurations": {
                               "production": {
                                   "budgets": [
                                       {
                                           "type": "initial",
                                           "maximumWarning": "5mb",
                                           "maximumError": "8mb"
                                       },
                                       {
                                           "type": "anyComponentStyle",
                                           "maximumWarning": "150kb",
                                           "maximumError": "200kb"
                                       }
                                   ],
                                   "fileReplacements": [
                                       {
                                           "replace": "src/environments/environment.ts",
                                           "with": "src/environments/environment.prod.ts"
                                       }
                                   ],
                                   "outputHashing": "all",
                                   "serviceWorker": true,
                                   "ngswConfigPath": "ngsw-config.json",
                                   "optimization": true,
                                   "sourceMap": false,
                                   "extractCss": true,
                                   "namedChunks": false,
                                   "extractLicenses": true,
                                   "vendorChunk": false,
                                   "buildOptimizer": true
                               },

                               "development": {
                                   "buildOptimizer": false,
                                   "optimization": false,
                                   "vendorChunk": true,
                                   "extractLicenses": false,
                                   "sourceMap": true,
                                   "namedChunks": true
                               }
                           },
                           "defaultConfiguration": "production"
            },
           "serve": {
                "builder": "@angular-devkit/build-angular:dev-server",
                "options": {
                    "browserTarget": "build"
                },
                "configurations": {
                    "production": {
                        "browserTarget": "build:production"
                    },
                    "development": {
                        "browserTarget": "build:development"
                    }
                },
                "defaultConfiguration": "development"
            },

package.json Angular related libs

"dependencies": { "@angular-eslint/schematics": "12.1.0", "@angular-material-components/datetime-picker": "6.0.3", "@angular-material-components/moment-adapter": "6.0.0", "@angular/animations": "12.1.0", "@angular/cdk": "12.1.0", "@angular/common": "12.1.0", "@angular/compiler": "12.1.0", "@angular/core": "12.1.0", "@angular/flex-layout": "12.0.0-beta.34", "@angular/forms": "12.1.0", "@angular/material": "12.1.0", "@angular/material-moment-adapter": "12.1.0", "@angular/platform-browser": "12.1.0", "@angular/platform-browser-dynamic": "12.1.0", "@angular/router": "12.1.0", "@angular/service-worker": "12.1.0", }

"devDependencies": { "@angular-devkit/build-angular": "12.1.0", "@angular/cli": "12.1.0", "@angular/compiler-cli": "12.1.0", "@angular/language-service": "12.1.0", "@angularclass/hmr": "3.0.0", "@types/dompurify": "2.2.2", "@types/jasmine": "3.7.7", "@types/jquery": "^3.5.5", "@types/lodash": "4.14.170", "@types/node": "15.12.2", "@types/prismjs": "1.16.5", "codelyzer": "6.0.2", "cross-env": "7.0.3", "jasmine-core": "3.7.1", "jasmine-spec-reporter": "7.0.0", "karma": "6.3.4", "karma-chrome-launcher": "3.1.0", "karma-jasmine": "4.0.1", "karma-jasmine-html-reporter": "1.6.0", "protractor": "7.0.0", "replace-in-file": "6.2.0", "ts-node": "10.0.0", "tslint": "6.1.3", "typescript": "4.2.4", "webpack-bundle-analyzer": "4.4.2" }

I tried to generate CPU profile by using NG_BUILD_PROFILING=1 and kept getting errors, and it builds fine without setting this environment variable

Option "extractCss" is deprecated: Deprecated since version 11.0. No longer required to disable CSS extraction for HMR.

alan-agius4 commented 3 years ago

To generate a build profile you can you use the below.

node -β€”cpu-proof node_module/@angular/cli/lib/init.js serve

If are are comparing rebuild times, try to do something meaningful such as changing a string value adding a console.log or something that effects the final bundle, adding only a space in a file will indeed be slower in v12.

Also, the first rebuild will always be slower than later rebuilds.

Side note: it appears that you are experiencing a different issue from the original reported were it was related to increase in non incremental build times. Therefore, I do suggest to open an new issue to for your problem and provide all the necessary info and keep this issue focused on the original reported problem.

Yohandah commented 3 years ago

@alan-agius4 Still can't build in prod mode on my project ... JS heap out of memory, works in v11. How can I help you ? This is a private project for a company I'm working for, I am unable to share it with you unfortunately.

profile I have sent them by email to alan.agius4@gmail.com

angular.json the build for plex3 works, for production-plex3, it doesn't

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "defaultProject": "app",
  "newProjectRoot": "projects",
  "projects": {
    "app": {
      "root": "",
      "sourceRoot": "src",
      "projectType": "application",
      "prefix": "app",
      "schematics": {},
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "preserveSymlinks": true,
            "outputPath": "www",
            "index": "src/index.html",
            "main": "src/main.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "tsconfig.app.json",
            "assets": [
              {
                "glob": "**/*",
                "input": "src/assets",
                "output": "assets"
              },
              {
                "glob": "**/*.svg",
                "input": "node_modules/ionicons/dist/ionicons/svg",
                "output": "./svg"
              },
              {
                "glob": "**/*",
                "input": "src/app/home/assets",
                "output": "assets"
              },
              {
                "glob": "**/*",
                "input": "src/app/synoptique/assets",
                "output": "assets"
              },
              {
                "glob": "**/*",
                "input": "src/app/teleprogrammation/assets",
                "output": "assets"
              },
              {
                "glob": "**/*",
                "input": "src/app/grapheur/assets",
                "output": "assets"
              },
              {
                "glob": "**/*",
                "input": "src/app/cde/assets",
                "output": "assets"
              },
              "src/manifest.webmanifest"
            ],
            "styles": ["src/styles/styles.global.scss"],
            "aot": false,
            "vendorChunk": true,
            "extractLicenses": false,
            "buildOptimizer": false,
            "sourceMap": true,
            "optimization": false,
            "namedChunks": true
          },
          "configurations": {
            "plex3": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.development.ts"
                }
              ]
            },
            "ic-plex3": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.ic.ts"
                }
              ]
            },
            "production-plex3": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.production.ts"
                }
              ],
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "namedChunks": false,
              "aot": true,
              "extractLicenses": true,
              "buildOptimizer": true,
              "budgets": [
                {
                  "type": "initial",
                  "maximumWarning": "2mb",
                  "maximumError": "5mb"
                },
                {
                  "type": "anyComponentStyle",
                  "maximumWarning": "6kb"
                }
              ],
              "serviceWorker": true,
              "ngswConfigPath": "ngsw-config.json"
            },
            "ci": {
              "progress": false
            }
          },
          "defaultConfiguration": ""
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "browserTarget": "app:build"
          },
          "configurations": {
            "production-plex3": {
              "browserTarget": "app:build:production-plex3"
            },
            "plex3": {
              "browserTarget": "app:build:plex3"
            },
            "ci": {
              "progress": false
            }
          }
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browserTarget": "app:build"
          }
        },
        "lint": {
          "builder": "@angular-eslint/builder:lint",
          "options": {
            "lintFilePatterns": ["src/**/*.ts", "src/**/*.html"]
          }
        },
        "ionic-cordova-build": {
          "builder": "@ionic/angular-toolkit:cordova-build",
          "options": {
            "browserTarget": "app:build"
          },
          "configurations": {
            "production": {
              "browserTarget": "app:build:production"
            }
          }
        },
        "ionic-cordova-serve": {
          "builder": "@ionic/angular-toolkit:cordova-serve",
          "options": {
            "cordovaBuildTarget": "app:ionic-cordova-build",
            "devServerTarget": "app:serve"
          },
          "configurations": {
            "production": {
              "cordovaBuildTarget": "app:ionic-cordova-build:production",
              "devServerTarget": "app:serve:production"
            }
          }
        }
      }
    }
  },
  "cli": {
    "defaultCollection": "@ionic/angular-toolkit",
    "analytics": false
  },
  "schematics": {
    "@ionic/angular-toolkit:component": {
      "prefix": "app",
      "styleext": "scss",
      "lintFix": true
    },
    "@ionic/angular-toolkit:page": {
      "styleext": "scss"
    },
    "@schematics/angular:directive": {
      "prefix": "app"
    }
  }
}
terencehonles commented 3 years ago

Version 12.1.0 has been released which contains several performance improvements. We also introduced an experimental file system cache which should improve the second/warm build quite a lot. You can opt-in using the NG_PERSISTENT_BUILD_CACHE=1 environment variable.

Please update using ng update @angular/cli @angular/core.

If the issue persist please report back providing one of the following;

  • CPU profile, memory snapshots and angular.json configuration
  • Reproduction (Even shared privately).

I'm seeing a regression(?) with 12.1 and I'm not sure if I should open that separately or if it might be related to this. With 12.0 I was able to build whatever V8 decided was appropriate for a machine with 4GB of RAM, but with 12.1 I had to bump --max_old_space_size up to 3GB. It's possible we were almost at that line and an unrelated package update is what actually pushed us over the limit.

I have the CI running with NG_BUILD_CACHE=1 already (hopefully that makes sense). Is there something that NG_PERSISTENT_BUILD_CACHE=1 would provide over the other option?

I can try profiling, but I'll have to see when I'd have time to do that since bumping the memory is the bandaid I have time for right now :sweat_smile:

alan-agius4 commented 3 years ago

That being said, this issue is about build times and not memory, hence if you are experiencing memory issues please file a new issue providing all the necessary profiles and/or a reproduction.

alan-agius4 commented 3 years ago

@Yohandah, let's please keep this issue on build times. If you are experiencing memory issues please file a new issue and attach the memory heap profiles for v11 and v12.

Thanks.

Yohandah commented 3 years ago

@alan-agius4 you closed the issue concerning build crashes and said it was now tracked here ........ ?

alan-agius4 commented 3 years ago

@Yohandah, are you referring to version 9 issue (https://github.com/angular/angular-cli/issues/16860#issuecomment-852031823)? I stated that this issue (https://github.com/angular/angular-cli/issues/20792) is for build-time performance.

Yohandah commented 3 years ago

@alan-agius4 Well could you reopen #16860 then ? the title says "& out of memory errors", and my issue is a memory error; or should I open a new issue ?

alan-agius4 commented 3 years ago

@alan-agius4 Well could you reopen #16860 then ? the title says "& out of memory errors", and my issue is a memory error; or should I open a new issue ?

Most of the context in #16860 is no longer relevant in version 12, since that was dedicated to version 9. Hence please open a new issue with profiles from v11 and v12. Thanks.

jcompagner commented 3 years ago

also for us using NG_PERSISTENT_BUILD_CACHE is a lot faster

production build goes from 80+ seconds to 20+ seconds

and also none production builds do gain like 28 seconds to 20 seconds.

so using that flag the production build are quite close to the none (debug) builds..

MadeleineCodes commented 3 years ago

Unfortunately, we do not see much improvement with NG_PERSISTENT_BUILD_CACHE, I tried with and without but compared to 11.0.2 it's still much slower. I could live with production or even development build to be slower, but the much slower watch really hurts during development... :/

command 11.0.2 12.1.0 12.1.0 with NG_PERSISTENT_BUILD_CACHE 1st 12.1.0 with NG_PERSISTENT_BUILD_CACHE 2nd
develop build ~83s ~98s ~100s ~106s
production build ~180s ~270s ~240s ~225s
watch ~92s 140s + 48s* 106s + 43s* -
recompile (main bundle**) ~13s ~22s ~21s -

* initial watch always immediately triggers a recompile for whatever reason ** main bundle has about 6-7mb in watch mode

angular.json:

{
  "version": 1,
  "projects": {
    "app": {
      "projectType": "application",
      "schematics": {
        "@nrwl/angular:component": {
          "style": "less",
          "changeDetection": "OnPush"
        }
      },
      "root": "apps/app",
      "sourceRoot": "apps/app/src",
      "prefix": "app",
      "architect": {
        "build": {
          "builder": "@angular-builders/custom-webpack:browser",
          "options": {
            "customWebpackConfig": {
              "path": "apps/app/extra-webpack.config.js",
              "mergeStrategies": {
                "optimization.minimizer": "replace",
                "externals": "replace"
              }
            },
            "outputPath": "dist/apps/app",
            "index": "apps/app/src/index.html",
            "main": "apps/app/src/main.ts",
            "polyfills": "apps/app/src/polyfills.ts",
            "tsConfig": "apps/app/tsconfig.app.json",
            "preserveSymlinks": true,
            "aot": true,
            "allowedCommonJsDependencies": [
              "jstimezonedetect",
              "css-element-queries",
              "fastdom",
              "dragula",
              "contra/emitter",
              "crossvent",
              "dom-autoscroller",
              "dom-plane",
              "dom-set",
              "pdfjs-dist",
              "zone.js/dist/zone-error"
            ],
            "assets": [
              {
                "glob": "**/*",
                "input": "apps/app/src/assets/images",
                "output": "/images"
              },
              {
                "glob": "**/*",
                "input": "apps/app/src/assets/icons",
                "output": "/icons"
              },
              {
                "glob": "**/*",
                "input": "apps/app/src/assets/static",
                "output": "/static"
              },
              {
                "glob": "**/*",
                "input": "apps/app/src/assets/translations/messages",
                "output": "/translations"
              },
              {
                "glob": "properties.js",
                "input": "apps/app/src/assets/",
                "output": "/"
              },
              {
                "glob": "**/*",
                "input": "libs/annotations/src/assets/translations/messages",
                "output": "/translations/annotations"
              },
              {
                "glob": "**/*",
                "input": "node_modules/pdfjs-dist/cmaps",
                "output": "/worker-libs/pdf-cmaps/"
              },
              {
                "glob": "pdf.worker.min.js",
                "input": "node_modules/pdfjs-dist/build",
                "output": "/worker-libs/"
              },
              {
                "glob": "**/*",
                "input": "libs/common-components/src/assets/translations/messages",
                "output": "/translations/common"
              },
              {
                "glob": "**/*",
                "input": "libs/common-components/src/assets/images",
                "output": "/images"
              },
              {
                "glob": "**/*",
                "input": "libs/common-components/src/assets/icons",
                "output": "/icons"
              },
              {
                "glob": "**/*",
                "input": "libs/internal-components/src/assets/images",
                "output": "/images"
              }
            ],
            "scripts": [
              "node_modules/pdfjs-dist/build/pdf.min.js",
              "libs/annotations/src/assets/libs/fabric.js",
              "node_modules/systemjs/dist/s.js",
              "node_modules/systemjs/dist/extras/named-register.js",
              "node_modules/systemjs/dist/extras/amd.js"
            ],
            "stylePreprocessorOptions": {
              "includePaths": [
                "libs/common-components/src/assets/styles",
                "apps/app/src/assets/styles",
                "libs/app/shared/src/lib/assets/styles"
              ]
            },
            "styles": [
              "node_modules/quill/dist/quill.core.css",
              "node_modules/quill/dist/quill.bubble.css",
              "node_modules/quill/dist/quill.snow.css",
              "node_modules/pdfjs-dist/web/pdf_viewer.css",
              "node_modules/dragula/dist/dragula.min.css",
              "libs/common-components/src/assets/styles/material-theme-custom.less",
              "libs/common-components/src/assets/styles/app.less",
              "apps/app/src/assets/styles/styles.less",
              "apps/app/src/assets/styles/app-material.less"
            ]
          },
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "apps/app/src/environments/environment.ts",
                  "with": "apps/app/src/environments/environment.prod.ts"
                }
              ],
              "optimization": {
                "scripts": false,
                "styles": true,
                "fonts": true
              },
              "outputHashing": "all",
              "sourceMap": false,
              "extractCss": true,
              "namedChunks": false,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true,
              "budgets": [
                {
                  "type": "initial",
                  "maximumWarning": "4mb"
                },
                {
                  "type": "anyComponentStyle",
                  "maximumWarning": "6kb",
                  "maximumError": "10kb"
                }
              ]
            },
            "development": {
              "buildOptimizer": false,
              "optimization": false,
              "vendorChunk": true,
              "extractLicenses": false,
              "sourceMap": true,
              "namedChunks": true
            }
          },
          "defaultConfiguration": "development"
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "browserTarget": "app:build"
          },
          "configurations": {
            "production": {
              "browserTarget": "app:build:production"
            }
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": [
              "apps/app/tsconfig.app.json",
              "apps/app/tsconfig.spec.json"
            ],
            "exclude": [
              "**/node_modules/**",
              "!apps/app/**/*"
            ]
          }
        },
        "test": {
          "builder": "@nrwl/jest:jest",
          "options": {
            "jestConfig": "apps/app/jest.config.js",
            "passWithNoTests": true,
            "silent": true
          }
        }
      }
    },
    "common-components": {
      "projectType": "library",
      "root": "libs/common-components",
      "sourceRoot": "libs/common-components/src",
      "prefix": "cc",
      "architect": {
        "build": {
          "builder": "@nrwl/angular:package",
          "options": {
            "tsConfig": "libs/common-components/tsconfig.lib.json",
            "project": "libs/common-components/ng-package.json"
          },
          "configurations": {
            "production": {
              "tsConfig": "libs/common-components/tsconfig.lib.prod.json"
            }
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": [
              "libs/common-components/tsconfig.lib.json",
              "libs/common-components/tsconfig.spec.json"
            ],
            "exclude": [
              "**/node_modules/**",
              "!libs/common-components/**/*"
            ]
          }
        },
        "test": {
          "builder": "@nrwl/jest:jest",
          "options": {
            "jestConfig": "libs/common-components/jest.config.js",
            "passWithNoTests": true,
            "silent": true
          }
        },
        "storybook": {
          "builder": "@nrwl/storybook:storybook",
          "options": {
            "uiFramework": "@storybook/angular",
            "port": 4400,
            "config": {
              "configFolder": "libs/common-components/.storybook"
            }
          },
          "configurations": {
            "ci": {
              "quiet": true
            }
          }
        },
        "build-storybook": {
          "builder": "@nrwl/storybook:build",
          "options": {
            "uiFramework": "@storybook/angular",
            "outputPath": "dist/storybook/common-components",
            "config": {
              "configFolder": "libs/common-components/.storybook"
            }
          },
          "configurations": {
            "ci": {
              "quiet": true
            }
          }
        }
      },
      "schematics": {
        "@nrwl/angular:component": {
          "style": "less",
          "changeDetection": "OnPush"
        }
      }
    },
    "internal-components": {
      "projectType": "library",
      "root": "libs/internal-components",
      "sourceRoot": "libs/internal-components/src",
      "prefix": "ic",
      "architect": {
        "build": {
          "builder": "@nrwl/angular:package",
          "options": {
            "tsConfig": "libs/internal-components/tsconfig.lib.json",
            "project": "libs/internal-components/ng-package.json"
          },
          "configurations": {
            "production": {
              "tsConfig": "libs/internal-components/tsconfig.lib.prod.json"
            }
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": [
              "libs/internal-components/tsconfig.lib.json",
              "libs/internal-components/tsconfig.spec.json",
              "libs/internal-components/.storybook/tsconfig.json"
            ],
            "exclude": [
              "**/node_modules/**",
              "!libs/internal-components/**/*"
            ]
          }
        },
        "test": {
          "builder": "@nrwl/jest:jest",
          "options": {
            "jestConfig": "libs/internal-components/jest.config.js",
            "passWithNoTests": true,
            "silent": true
          }
        },
        "storybook": {
          "builder": "@nrwl/storybook:storybook",
          "options": {
            "uiFramework": "@storybook/angular",
            "port": 4400,
            "config": {
              "configFolder": "libs/internal-components/.storybook"
            }
          },
          "configurations": {
            "ci": {
              "quiet": true
            }
          }
        },
        "build-storybook": {
          "builder": "@nrwl/storybook:build",
          "options": {
            "uiFramework": "@storybook/angular",
            "outputPath": "dist/storybook/internal-components",
            "config": {
              "configFolder": "libs/internal-components/.storybook"
            }
          },
          "configurations": {
            "ci": {
              "quiet": true
            }
          }
        }
      },
      "schematics": {
        "@schematics/angular:component": {
          "style": "less",
          "changeDetection": "OnPush"
        }
      }
    },
     "annotations": {
      "projectType": "library",
      "root": "libs/annotations",
      "sourceRoot": "libs/annotations/src",
      "prefix": "app",
      "architect": {
        "build": {
          "builder": "@nrwl/angular:package",
          "options": {
            "tsConfig": "libs/annotations/tsconfig.lib.json",
            "project": "libs/annotations/ng-package.json"
          },
          "configurations": {
            "production": {
              "tsConfig": "libs/annotations/tsconfig.lib.prod.json"
            }
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": [
              "libs/annotations/tsconfig.lib.json",
              "libs/annotations/tsconfig.spec.json"
            ],
            "exclude": [
              "**/node_modules/**",
              "!libs/annotations/**/*"
            ]
          }
        },
        "test": {
          "builder": "@nrwl/jest:jest",
          "outputs": [
            "coverage/libs/annotations"
          ],
          "options": {
            "jestConfig": "libs/annotations/jest.config.js",
            "passWithNoTests": true,
            "silent": true
          }
        }
      }
    }
  },
  "cli": {
    "defaultCollection": "@nrwl/angular"
  },
  "schematics": {
    "@nrwl/angular:application": {
      "unitTestRunner": "jest",
      "e2eTestRunner": "cypress"
    },
    "@nrwl/angular:library": {
      "unitTestRunner": "jest"
    },
    "@nrwl/angular:component": {
      "style": "less"
    }
  }
}

System info:

OS Name:                   Microsoft Windows 10 Enterprise
OS Version:                10.0.19041 N/A Build 19041
OS Build Type:             Multiprocessor Free
System Type:               x64-based PC
Processor(s):              1 Processor(s) Installed.
                           [01]: Intel64 Family 6 Model 142 Stepping 10 GenuineIntel ~1792 Mhz
BIOS Version:              HP Q78 Ver. 01.06.00, 03.01.2019
Total Physical Memory:     32Β 611 MB

I could send the cpu profiles if needed, but I am not allowed to share them (or the repo) publicly. Just let me know where I should send them :)

alan-agius4 commented 3 years ago

@mrucelum, you are using builders which are not supported by the Angular tooling team. This causes a migration that adjusts the options to provide equivalent behavior from prior to the update not to run. Ideally these 3rd party builders should provide their own migration.

You need to adjust the options by hand to retain the existing behavior. For more information, see the breaking changes section within the release notes: https://github.com/angular/angular-cli/releases/tag/v12.0.0

MadeleineCodes commented 3 years ago

@alan-agius4 Thanks for link! So if I understand you correctly, I have to adjust the configuration section of my angular.json manually, because I am using custom builders, right?

I checked the breaking changes and if I understand them correctly, with this addition to the angular.json:

          "configurations": {
           [...]
            "development": {
              "optimization": false,
              "buildOptimizer": false,
              "sourceMap": true,
              "extractLicenses": false,
              "namedChunks": true,
              "vendorChunk": true
            }
          },

I have the old default values (we had "aot": true before) already in place (when it comes to develop build and watch). But this is the exact configuration I did my tests with. So I guess I am missing something in addition? Or does the custom builder need to adapt something (I mean something I cannot influence by just adapting my angular.json)?

Thanks again :)

alan-agius4 commented 3 years ago

In the above table, you mentioned watch are you using ng build --watch?, Can you also try to replace the 3rd party builder with a supported builder @angular-devkit/build-angular:browser?

You can send the CPU profiles to alan.agius4[at]gmail.com.

MadeleineCodes commented 3 years ago

It seems to be indeed the @angular-builders/custom-webpack:browser that causes the slow down 😲

ng build --watch

1) with @angular-devkit/build-angular:browser

Initial Chunk Files                    | Names         |      Size
vendor.js                              | vendor        |   7.86 MB
main.js                                | main          |   6.66 MB
scripts.js                             | scripts       | 677.03 kB
polyfills.js                           | polyfills     | 213.39 kB
styles.css                             | styles        | 150.33 kB
runtime.js                             | runtime       |  14.33 kB

                                       | Initial Total |  15.55 MB
Build at: 2021-07-01T11:06:38.058Z - Hash: cd684dc7fcbc67560f0f - Time: 76208ms

2) with @angular-builders/custom-webpack:browser

Initial Chunk Files                    | Names         |      Size
vendor.js                              | vendor        |   6.67 MB
main.js                                | main          |   6.66 MB
scripts.js                             | scripts       | 677.03 kB
polyfills.js                           | polyfills     | 213.39 kB
styles.css                             | styles        | 150.33 kB
runtime.js                             | runtime       |  13.67 kB

                                       | Initial Total |  14.36 MB

Build at: 2021-07-01T11:43:51.105Z - Hash: 34bdac20b292943b28c9 - Time: 107267ms
√ Browser application bundle generation complete.
√ Index html generation complete.

15 unchanged chunks

Build at: 2021-07-01T11:44:36.147Z - Hash: e7860c484b03f51d78f9 - Time: 43856ms

3) with @angular-builders/custom-webpack:browser and without custom terser config in the referenced webpack config

Initial Chunk Files                    | Names         |      Size
vendor.js                              | vendor        |   6.67 MB
main.js                                | main          |   6.66 MB
scripts.js                             | scripts       | 677.03 kB
polyfills.js                           | polyfills     | 213.39 kB
styles.css                             | styles        | 150.33 kB
runtime.js                             | runtime       |  13.67 kB

                                       | Initial Total |  14.36 MB

Build at: 2021-07-01T11:12:49.818Z - Hash: 1ac2e18b2a871e0bf8a0 - Time: 103078ms
√ Browser application bundle generation complete.
√ Index html generation complete.

15 unchanged chunks

Build at: 2021-07-01T11:13:32.438Z - Hash: b8d53eea43833e670b2b - Time: 41681ms

4) with @angular-builders/custom-webpack:browser with empty webpack config

Initial Chunk Files                   | Names         |      Size
vendor.js                             | vendor        |   7.86 MB
main.js                               | main          |   6.66 MB
scripts.js                            | scripts       | 677.03 kB
polyfills.js                          | polyfills     | 213.39 kB
styles.css                            | styles        | 150.33 kB
runtime.js                            | runtime       |  13.67 kB

                                      | Initial Total |  15.55 MB

Build at: 2021-07-01T11:17:38.033Z - Hash: 223bbb0d807f62d6e34f - Time: 109983ms
√ Browser application bundle generation complete.
√ Index html generation complete.

15 unchanged chunks

Build at: 2021-07-01T11:18:26.881Z - Hash: b76731d2fe86fcc023e6 - Time: 47707ms

btw this is the custom webpack config:

const webpack = require('webpack');
const TerserPlugin = require('terser-webpack-plugin');

module.exports = {
  externals: {
    'fabric': 'window'
  },

  plugins: [new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /en|de/)],
  optimization: {
    minimizer: [new TerserPlugin({
                                   terserOptions: {
                                     ecma: undefined,
                                     warnings: false,
                                     parse: {},
                                     compress: {},
                                     mangle: true, // Note `mangle.properties` is `false` by default.
                                     module: false,
                                     output: null,
                                     toplevel: false,
                                     nameCache: null,
                                     ie8: false,
                                     keep_classnames: true,
                                     keep_fnames: false,
                                     safari10: false
                                   },
                                 })]
  }
};

Conclusion:

  1. with the default angular builder a. times are the same as with v11 (or even a bit better) b. there is no immediate recompile on watch πŸ₯³
  2. with the custom-webpack builder a. it takes much longer even if the custom webpack config does not contain anything b. bundle is quite a bit smaller because of moment locale exclusion

However... we need the custom webpack config as we do not want to have all the unnecessary moment locales in our bundle and also need to be able to specify 'fabric' as external for some legacy lib we are using. So I guess I will head over to the @angular-builders/custom-webpack:browser project and file an issue there. Thanks a lot @alan-agius4 !

DavidBowdoin commented 3 years ago

Success! I found steps to get good performance when using @angular-builders/custom-webpack

TLDR; before upgrading angular, remove all traces of custom-webpack so the migrations run in full, and then re-install custom-webpack

Here is what worked for me, starting with an Angular 11 project:

  1. In angular.json, replaced all traces of @angular-builders/custom-webpack:browser with @angular-devkit/build-angular:browser (and delete the customWebpackConfig block)
  2. Removed @angular-builders/custom-webpack from package.json
  3. Deleted node_modules and package_lock.json
  4. Ran npm install
  5. Ran ng update @angular/cdk @angular/cli @angular/core
  6. Added v12 of @angular-builders/custom-webpack back into package.json
  7. Ran npm install
  8. In angular.json, changed back to @angular-builders/custom-webpack:browser and restored the customWebpackConfig block.

I confirmed that the migrations in angular.json (that were getting skipped) make the difference (2x slower ng serve build time)

Benchmarking gives similar results as with angular 11 and markedly better results when I use NG_PERSISTENT_BUILD_CACHE=1

Like @mrucelum our project uses @angular-builders/custom-webpack to specify several packages as externals (legacy code needs the package as well, so don't want to double load them) Is there any chance ng update could do migrations when custom-webpack is in use? Or the ability to specify external packages without using custom-webpack? Thanks everyone for the info that lead me to this solution!

simeyla commented 3 years ago

@mrucelum Thanks for all the stats. I'm actually using @angular-builders/custom-webpack:browser too and for the exact same reason (moment.js size). However I just ran a dozen builds and with or without the custom builder it was taking 38-40 seconds each time. And it definitely did change because it told me to remove the part of the config that was due to the custom builder.

However... as I was writing this though I saw you managed to get them working.....

But, could you confirm that running the migrations did not in fact disable AOT compilation in your angular.json file. Depending upon your exact version of the CLI it's possible to end up disabling it when running migrations (due to a change in what was considered the default). If you in fact did disable AOT then that would explain the much faster compilation. Again though I'm using the same builder and wasn't seeing any noticeable difference between them. (Also version 12.1.0 of the custom builder was just published today - not sure if there were changes or just a version bump)

terencehonles commented 3 years ago
  • NG_BUILD_CACHE is enabled by default, and is mainly used to opt-out all build caching, this supersedes NG_PERSISTENT_BUILD_CACHE.
  • NG_PERSISTENT_BUILD_CACHE is disable by default, and can be used to opt-in to cache the entire build on disk, which will make the 2nd build warm. Typically you don't want this on CI since typically the "cache" will be discarded with node_modules after every CI run.

That being said, this issue is about build times and not memory, hence if you are experiencing memory issues please file a new issue providing all the necessary profiles and/or a reproduction.

Thanks @alan-agius4 for the explanation and sorry you'll probably end up marking this "off topic", but maybe not since it is about NG_PERSISTENT_BUILD_CACHE and I do care about any build speed improvements I can get since my build does seem slow to me.

I reviewed https://github.com/angular/angular-cli/pull/20756 to confirm I understood and I wasn't taking a corner case that was unexpected. I use NG_BUILD_CACHE to point to a directory that is external to the node modules and in a location the CI will preserve, and this looks like it's still OK to do based on https://github.com/angular/angular-cli/blob/736a5f89deaca85f487b78aec9ff66d4118ceb6a/packages/angular_devkit/build_angular/src/utils/environment-options.ts#L70-L81 does that mean I should also be able to turn on NG_PERSISTENT_BUILD_CACHE in order to persist the webpack cache? I noticed this was said to be experimental, but any reason I might not want to turn it on in this context? It looks like the cache key is pretty comprehensive and I would think the serialized build options should probably be good :thinking:

Edit: After thinking about it more I definitely have places I can enable NG_PERSISTENT_BUILD_CACHE and hopefully it speeds up those paths, so thanks again regardless!

terencehonles commented 3 years ago

This actually looks to really help a lot for my build time :tada: , but I've found a few errors and I'm reporting them (and fixing the one I can fix simply)

whyboris commented 3 years ago

After upgrading from Angular 11 to Angular 12 the build time went up from ~1 second to 22 seconds 🀯

https://github.com/whyboris/Video-Hub-App/pull/648

JoostK commented 3 years ago

@whyboris It doesn't for me:

image

Is there a particular change I should be making?

whyboris commented 3 years ago

@JoostK thank you for testing! I was so frustrated I quit for the day, but thanks to your message I had new hope πŸ˜…

I ran rm -rf node_modules and npm install again ~and it looks like I'm back to fast~ πŸš€

Build at: 2021-07-07T20:46:38.298Z - Hash: f2c33b8ef37564ec1ef0 - Time: 1713ms πŸ™‡

~Sorry for the scare~ πŸ™‡

update: 🀦 turns out it still takes ~22 seconds when you just add console.log in some component

JoostK commented 3 years ago

@whyboris Thanks for getting back. Good to hear it's fast again, hopefully it stays that way. If you do run into it again please report back so we can have another look.

whyboris commented 3 years ago

@JoostK 🀦 sorry -- the reload was fast because I simply saved the file with no changes ... but when I add console.log somewhere - thereby changing the file, the compilation takes a long time again:

Build at: 2021-07-07T20:50:32.591Z - Hash: 0a430155980e29d73d08 - Time: 23324ms 😒

It seems to hang on the ... bundles (phase: sealing)... step

JoostK commented 3 years ago

@whyboris Oh, it's just a misconfiguration. In Angular 12 some builder defaults have changed in support of the new production builds by default for ng build. I am not sure how you updated but I don't see any changes to angular.json in the pull request; ng update should have updated it to pin the configuration options to their prior defaults to retain the previous behavior. If I run ng update @angular/cli --migrate-only --from 11 --to 12 then the angular.json file is indeed updated. Please review the changes as I notice in your case that aot will be set to false, which may or may not be desirable.

whyboris commented 3 years ago

@JoostK thank you very much for the suggestion! I went back to my main branch (before my attempt to upgrade to angular 12) and ran the command you gave: ng update @angular/cli --migrate-only --from 11 --to 12 It updated my angular.json file and now the app recompiles quickly after every save πŸš€ https://github.com/whyboris/Video-Hub-App/pull/666/files Thank you 🀝 πŸ™‡ ❀️

the-ult commented 3 years ago

@whyboris it seems like you set "aot": false which should be set to true (if I'm not misstaken)

MadeleineCodes commented 3 years ago

Just wanted to let you know that I did the migration again the way @DavidBowdoin suggested (remove custom builder before ng update). Aaaand there is no slowdown anymore! πŸ₯³

Not sure what the issue was, maybe it was actually fixed with the newest version of the custom webpack builder (as @simeyla suggested). My angular.json was not touched by the migration at all (although I removed the custom builder before the migration!), so I guess that was not the problem.

But anyway, I am happy that we can update now! Thanks again everyone! :)

vugar005 commented 3 years ago

Maybe this can solve this problem https://dev.to/brandontroberts/speeding-up-the-development-serve-after-upgrading-to-angular-v12-5db5

alan-agius4 commented 3 years ago

It appears that the root cause of the problem is misconfigurations and not an issue in the Angular CLI.

If you are still experiencing slow production builds please open a new issue with a production.

zeshan321 commented 3 years ago

Removing "emitDecoratorMetadata": true from tsconfig.json reduced our build time significantly for production.

monsieur-ricky commented 3 years ago

Success! I found steps to get good performance when using @angular-builders/custom-webpack

TLDR; before upgrading angular, remove all traces of custom-webpack so the migrations run in full, and then re-install custom-webpack

Here is what worked for me, starting with an Angular 11 project:

  1. In angular.json, replaced all traces of @angular-builders/custom-webpack:browser with @angular-devkit/build-angular:browser (and delete the customWebpackConfig block)
  2. Removed @angular-builders/custom-webpack from package.json
  3. Deleted node_modules and package_lock.json
  4. Ran npm install
  5. Ran ng update @angular/cdk @angular/cli @angular/core
  6. Added v12 of @angular-builders/custom-webpack back into package.json
  7. Ran npm install
  8. In angular.json, changed back to @angular-builders/custom-webpack:browser and restored the customWebpackConfig block.

I confirmed that the migrations in angular.json (that were getting skipped) make the difference (2x slower ng serve build time)

Benchmarking gives similar results as with angular 11 and markedly better results when I use NG_PERSISTENT_BUILD_CACHE=1

Like @mrucelum our project uses @angular-builders/custom-webpack to specify several packages as externals (legacy code needs the package as well, so don't want to double load them) Is there any chance ng update could do migrations when custom-webpack is in use? Or the ability to specify external packages without using custom-webpack? Thanks everyone for the info that lead me to this solution!

This solved my issue! Thanks :)

angular-automatic-lock-bot[bot] commented 3 years ago

This issue has been automatically locked due to inactivity. Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.