angular / angular-cli

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

ng serve --watch is as slow as ng build on rebuild #24832

Closed wesselvdv closed 1 year ago

wesselvdv commented 1 year ago

Command

serve

Description

It's as if the incremental compilation isn't working properly for my setup.

I've debugged it a bit, and I can see that when following the instructions in this comment upon changing the main.ts with console.log(1) all my lazy loaded routes are being marked as physicallyChangedTsFiles when putting a debug break on L189 in incremental.ts in @angular/compiler-cli.

Not sure if the above is intended, but it's something that I noticed.

Minimal Reproduction

ng serve --proxy-config proxy.config.json --host 0.0.0.0 --port 4200 --watch

Exception or Error

No response

Your Environment

_                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/

Angular CLI: 15.2.1
Node: 18.14.2
Package Manager: npm 9.5.0
OS: linux x64

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

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1502.1 (cli-only)
@angular-devkit/build-angular   15.2.1
@angular-devkit/core            15.2.1
@angular-devkit/schematics      15.2.1
@schematics/angular             15.2.1 (cli-only)
rxjs                            7.8.0
typescript                      4.9.5
webpack                         5.75.0

Anything else relevant?

I have been unable to make a cpu profile for entire rebuild, but I've managed to split it into 3 cpu profiles that have overlap. Trying to do it in one haul causes DevTools to hang.

cpu-1 cpu-2 cpu-3

tsconfig.app.json:

{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "outDir": "../out-tsc/app"
  },
  "exclude": ["test.ts", "**/*.spec.ts"]
}

../tsconfig.json:

{
  "extends": "../../tsconfig.json",
  "compilerOptions": {
    "rootDir": "./",
    "declaration": false,
    "declarationMap": false,
    "importHelpers": true,
    "lib": [
      "es2018",
      "dom",
      "dom.iterable"
    ],
    "emitDecoratorMetadata": false,
    "plugins": [
      {
        "transform": "@effect-ts/tracing-plugin",
        "__importTracingFrom": "@3ahm/effect/Tracing"
      },
      {
        "name": "@effect/language-service"
      }
    ],
    "target": "ES2021",
    "module": "ES2020",
    "useDefineForClassFields": true
  },
  "files": [
    "src/main.ts",
    "src/polyfills.ts"
  ],
  "include": [
    "src/**/*.d.ts",
    "src/**/*.ts"
  ],
  "angularCompilerOptions": {
    "strictInjectionParameters": true,
    "strictTemplates": true,
    "disableTypeScriptVersionCheck": true
  },
  "references": []
}

../../tsconfig.json:

{
  "extends": "./tsconfig.base.json",
  "files": [],
  "references": []
}

./tsconfig.base.json:

{
  "compilerOptions": {
    "downlevelIteration": true,
    "resolveJsonModule": true,
    "esModuleInterop": true,
    "declaration": true,
    "skipLibCheck": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "preserveSymlinks": false,
    "moduleResolution": "node16",
    "noEmit": false,
    "lib": ["es2021"],
    "sourceMap": true,
    "declarationMap": true,
    "strict": true,
    "noImplicitReturns": false,
    "noUnusedLocals": true,
    "noUnusedParameters": false,
    "noFallthroughCasesInSwitch": true,
    "noEmitOnError": false,
    "noErrorTruncation": false,
    "incremental": true,
    "allowJs": false,
    "checkJs": false,
    "forceConsistentCasingInFileNames": true,
    "suppressImplicitAnyIndexErrors": true,
    "stripInternal": true,
    "isolatedModules": true,
    "noImplicitAny": true,
    "noImplicitThis": true,
    "noUncheckedIndexedAccess": true,
    "strictNullChecks": true,
    "target": "ES2021",
    "module": "Node16",
    "typeRoots": ["./node_modules/@types"]
  },
  "exclude": ["node_modules", "build", "lib", "dist", ".vscode", ".direnv", ".cache"]
}

angular.json:

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "client": {
      "root": "",
      "sourceRoot": "src",
      "projectType": "application",
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "dist",
            "index": "src/index.html",
            "main": "src/main.ts",
            "preserveSymlinks": false,
            "tsConfig": "src/tsconfig.app.json",
            "polyfills": "src/polyfills.ts",
            "assets": ["src/assets", "src/favicon.ico"],
            "styles": ["src/styles.css"],
            "stylePreprocessorOptions": {
              "includePaths": ["src/styles"]
            },
            "scripts": []
          },
          "configurations": {
            "development": {
              "vendorChunk": true,
              "extractLicenses": false,
              "buildOptimizer": false,
              "aot": true,
              "sourceMap": false,
              "optimization": false,
              "namedChunks": true
            },
            "prod": {
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "namedChunks": false,
              "aot": true,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true,
              "fileReplacements": [
                {
                  "replace": "src/app/environments/environment.ts",
                  "with": "src/app/environments/environment.prod.ts"
                }
              ]
            },
            "staging": {
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": true,
              "namedChunks": true,
              "aot": true,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true,
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.staging.ts"
                }
              ]
            }
          },
          "defaultConfiguration": "prod"
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "browserTarget": "client:build:development"
          },
          "defaultConfiguration": "",
          "configurations": {
            "prod": {
              "browserTarget": "client:build:prod"
            },
            "staging": {
              "browserTarget": "client:build:staging"
            }
          }
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browserTarget": "client:build:development"
          }
        },
        "lint": {
          "builder": "@angular-eslint/builder:lint",
          "options": {
            "lintFilePatterns": ["src/**/*.ts", "src/**/*.component.html"]
          }
        }
      }
    },
    "client-e2e": {
      "root": "",
      "sourceRoot": "",
      "projectType": "application"
    }
  },
  "schematics": {
    "@schematics/angular:component": {
      "prefix": "ngx",
      "style": "css",
      "changeDetection": "OnPush",
      "skipTests": true
    },
    "@schematics/angular:directive": {
      "prefix": "ngx"
    }
  },
  "cli": {
    "analytics": "<snip>",
    "cache": {
      "enabled": true,
      "path": ".cache",
      "environment": "all"
    }
  }
}
JoostK commented 1 year ago

My main question is whether this works with the standard builder/the ngc compiler binary, compared to using @angular-builders/custom-webpack:browser. In any case, this isn't actionable for us unless we have a reproduction.

wesselvdv commented 1 year ago

I am unable to compile without that minor adjustment in the config.resolve.extensionAlias. I would assume that isn't that big of a deal. I can turn it into a patch I think, so I can drop the custom webpack builder stuff.

JoostK commented 1 year ago

I don't know how @angular-builders/custom-webpack:browser integrates the Angular compiler, but that does drive the compilation so it could certainly affect how this behaves.

wesselvdv commented 1 year ago

I've added the custom config as a patch in the @angular-devkit/build-angular:browser and @angular-devkit/build-angular:dev-server. Doesn't seem to make it faster or slower.

diff --git a/src/webpack/configs/common.js b/src/webpack/configs/common.js
index 3a014a9d62e7df059506d06e30623d0289b2482e..0be48f0ff1dd8edbbdcc668ab0f3780fd3eeb609 100755
--- a/src/webpack/configs/common.js
+++ b/src/webpack/configs/common.js
@@ -253,6 +253,10 @@ async function getCommonConfig(wco) {
         resolve: {
             roots: [projectRoot],
             extensions: ['.ts', '.tsx', '.mjs', '.js'],
+            extensionAlias: {
+                '.js': ['.ts', '.js'],
+                '.mjs': ['.mts', '.mjs', '.js'],
+            },
             symlinks: !buildOptions.preserveSymlinks,
             modules: [tsConfig.options.baseUrl || projectRoot, 'node_modules'],
             mainFields: isPlatformServer

I removed the references to the custom webpack.config.cjs, as I am no longer using that now.

wesselvdv commented 1 year ago

Also important to note, this is causing my dx to be very bad. I have to wait 40-60 seconds after each change to see the result. What additional info do you need?

JoostK commented 1 year ago

We would need a reproduction.

wesselvdv commented 1 year ago

Makes sense, here I was hoping there’d be a smoking gun in the cpu profiles that I had missed. I’ll try and see if I can get a good repro.

wesselvdv commented 1 year ago

I have managed to find a major culprit. I wasn't exporting my lazy loaded components. (e.g. no export class ...), because I am defining the routes in the same file and subsequently export the routes. Explicitly exporting all those components seems to have sped it up significantly. (~60 seconds to ~15 seconds)

I still believe 15 seconds is too slow for simply adding a console.log(1); statement in the main.ts, but I can create a profile in the devtools now.

alan-agius4 commented 1 year ago

@wesselvdv, unfortunately without a reproduction it's hard to investigate this any further.

alan-agius4 commented 1 year ago

Thanks for reporting this issue. However, you didn't provide sufficient information for us to understand and reproduce the problem. Please check out our submission guidelines to understand why we can't act on issues that are lacking important information.

If the problem persists, please file a new issue and ensure you provide all of the required information when filling out the issue template.

angular-automatic-lock-bot[bot] commented 1 year 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.