Skip to content

Decreased performance and excessive memory consumption for vitest #32759

Closed

Description

@Viktor-Ivliev

Which @angular/* package(s) are the source of the bug?

upgrade, Don't known / other

Is this a regression?

Yes

Description

When upgrading from 21.1.6 to 21.2.3, I noticed a noticeable decrease in performance in tests and excessive memory usage.

@angular/* 21.1.6

Image

@angular/* 21.2.3

Image

Complete package example:

{
  "name": "frontend",
  "version": "0.0.0",
  "packageManager": "pnpm@10.32.1",
  "browserslist": "> 5%, last 3 Chrome versions, last 3 Firefox version, last 2 Edge major versions, last 2 Safari major versions, last 2 iOS major versions, Firefox ESR",
  "scripts": {
    "watch": "pnpm store prune && ng build --watch --output-hashing=all",
    "start": "ng serve",
    "build": "ng build --configuration production",
    "test": "ng test --browsers=chromium",
    "test-headless": "ng test --browsers=ChromiumHeadless --watch=false",
    "test-ci": "ng test --browsers=ChromiumHeadless --coverage --watch=false",
    "lint": "ng lint",
    "bundle-report": "ng build --configuration production --stats-json && webpack-bundle-analyzer ../public/frontend/stats.json"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "21.2.3",
    "@angular/cdk": "21.2.2",
    "@angular/common": "21.2.3",
    "@angular/compiler": "21.2.3",
    "@angular/core": "21.2.3",
    "@angular/forms": "21.2.3",
    "@angular/platform-browser": "21.2.3",
    "@angular/platform-browser-dynamic": "21.2.3",
    "@angular/router": "21.2.3",
    "@ctrl/ngx-emoji-mart": "9.3.0",
    "@fontsource/inter": "5.2.8",
    "@fontsource/poppins": "5.2.7",
    "@fortawesome/fontawesome-free": "7.2.0",
    "@ng-select/ng-select": "21.5.2",
    "@ngstack/code-editor": "9.0.0",
    "@ngx-translate/core": "17.0.0",
    "@popperjs/core": "2.11.8",
    "@primeuix/themes": "2.0.3",
    "@rails/actioncable": "8.1.200",
    "@rails/activestorage": "8.1.200",
    "@types/crypto-js": "4.2.2",
    "@types/jquery": "3.5.34",
    "@types/sanitize-html": "2.16.1",
    "@typescript-plus/fast-memoize-decorator": "0.2.1",
    "angular-mentions": "1.5.0",
    "autolinker": "4.1.5",
    "bootstrap": "5.3.8",
    "chart.js": "4.5.1",
    "chartjs-plugin-datalabels": "2.2.0",
    "crypto-js": "4.2.0",
    "dayjs": "1.11.19",
    "deepmerge-ts": "7.1.5",
    "jquery": "3.7.1",
    "jspdf": "4.2.0",
    "jspdf-autotable": "5.0.7",
    "marked": "17.0.4",
    "monaco-editor": "0.52.2",
    "ngx-color": "10.1.0",
    "ngx-cookie-service": "21.1.0",
    "ngx-translate-multi-http-loader": "20.0.0",
    "object-to-formdata": "4.5.1",
    "primeicons": "7.0.0",
    "primeng": "21.1.3",
    "rxjs": "7.8.2",
    "sanitize-html": "2.17.1",
    "tslib": "2.8.1",
    "typescript": "5.9.3",
    "vite": "7.3.1",
    "zone.js": "0.16.1"
  },
  "devDependencies": {
    "@angular-devkit/core": "21.2.2",
    "@angular-devkit/schematics": "21.2.2",
    "@angular-eslint/builder": "21.3.0",
    "@angular-eslint/eslint-plugin": "21.3.0",
    "@angular-eslint/eslint-plugin-template": "21.3.0",
    "@angular-eslint/schematics": "21.3.0",
    "@angular-eslint/template-parser": "21.3.0",
    "@angular/build": "21.2.2",
    "@angular/cli": "21.2.2",
    "@angular/compiler-cli": "21.2.3",
    "@types/node": "25.4.0",
    "@typescript-eslint/eslint-plugin": "8.57.0",
    "@typescript-eslint/parser": "8.57.0",
    "@typescript-eslint/utils": "8.57.0",
    "@vitest/browser-playwright": "4.0.18",
    "@vitest/coverage-v8": "4.0.18",
    "eslint": "9.39.4",
    "eslint-plugin-import": "2.32.0",
    "eslint-plugin-jsdoc": "62.8.0",
    "eslint-plugin-prefer-arrow": "1.2.3",
    "eslint-plugin-unused-imports": "4.4.1",
    "postcss-preset-env": "11.2.0",
    "vitest": "4.0.18",
    "webpack-bundle-analyzer": "5.2.0"
  }
}

vitest.config.ts

import { defineConfig } from 'vitest/config';
import path from 'path';

export default defineConfig({
  resolve: {
    alias: { // mocks for sanitize-html lib
      fs: path.resolve('./src/vitest-mocks/fs.ts'),
      path: path.resolve('./src/vitest-mocks/path.ts'),
      qs: path.resolve('./src/vitest-mocks/qs.ts'),
      url: path.resolve('./src/vitest-mocks/url.ts'),
      '/frontend/browser/assets': path.resolve('./src/assets'),
      '/frontend/browser/media': path.resolve('./node_modules/@fortawesome/fontawesome-free/webfonts'),
    },
  },
  test: {
    setupFiles: ['./src/vitest.setup.ts'],
    fileParallelism: true,
    pool: 'threads',
    hookTimeout: 15000,
    retry: 1
  }
});

vitest.setup.ts

import { afterEach, beforeEach, vi } from 'vitest';
import { TestBed } from '@angular/core/testing';

// mocks for sanitize-html lib
(globalThis as any).process = { env: {}, cwd: () => '/', };

beforeEach(() => {
  vi.useFakeTimers();
});

afterEach(() => {
  vi.restoreAllMocks();
  vi.clearAllTimers();
  vi.useRealTimers();
  TestBed.resetTestingModule();
});

Please provide a link to a minimal reproduction of the bug

No response

Please provide the exception or error you saw

Although locally this could be tolerated, on the CI there are constant memory shortage errors or timeout crashes, even though the previous version worked perfectly.

Caused by: Error: [vitest] Browser connection was closed while running tests. Was the page closed unexpectedly?
 ❯ WebSocket.<anonymous> node_modules/.pnpm/@vitest+browser@4.0.18_vite@7.3.1_@types+node@25.4.0_sass@1.97.3__vitest@4.0.18/node_modules/@vitest/browser/dist/index.js:3055:16
 ❯ WebSocket.emit node:events:520:35

Please provide the environment you discovered this bug in (run ng version)

Angular CLI       : 21.2.2
Angular           : 21.2.3
Node.js           : 24.14.0
Package Manager   : pnpm 10.32.1
Operating System  : linux x64

┌───────────────────────────────────┬───────────────────┬───────────────────┐
│ Package                           │ Installed Version │ Requested Version │
├───────────────────────────────────┼───────────────────┼───────────────────┤
│ @angular-devkit/core              │ 21.2.2            │ 21.2.2            │
│ @angular-devkit/schematics        │ 21.2.2            │ 21.2.2            │
│ @angular/animations               │ 21.2.3            │ 21.2.3            │
│ @angular/build                    │ 21.2.2            │ 21.2.2            │
│ @angular/cdk                      │ 21.2.2            │ 21.2.2            │
│ @angular/cli                      │ 21.2.2            │ 21.2.2            │
│ @angular/common                   │ 21.2.3            │ 21.2.3            │
│ @angular/compiler                 │ 21.2.3            │ 21.2.3            │
│ @angular/compiler-cli             │ 21.2.3            │ 21.2.3            │
│ @angular/core                     │ 21.2.3            │ 21.2.3            │
│ @angular/forms                    │ 21.2.3            │ 21.2.3            │
│ @angular/platform-browser         │ 21.2.3            │ 21.2.3            │
│ @angular/platform-browser-dynamic │ 21.2.3            │ 21.2.3            │
│ @angular/router                   │ 21.2.3            │ 21.2.3            │
│ rxjs                              │ 7.8.2             │ 7.8.2             │
│ typescript                        │ 5.9.3             │ 5.9.3             │
│ vitest                            │ 4.0.18            │ 4.0.18            │
│ zone.js                           │ 0.16.1            │ 0.16.1            │
└───────────────────────────────────┴───────────────────┴───────────────────┘

Anything else?

It may be necessary to add test.config.json or something else that was previously used for karma.

angular.json

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "frontend": {
      "root": "",
      "sourceRoot": "src",
      "projectType": "application",
      "prefix": "app",
      "schematics": {
        "@schematics/angular:component": {
          "style": "scss"
        }
      },
      "architect": {
        "build": {
          "builder": "@angular/build:application",
          "options": {
            "outputPath": {
              "base": "../public/frontend/"
            },
            "deployUrl": "/frontend/browser/",
            "index": "src/index.html",
            "polyfills": ["zone.js"],
            "tsConfig": "src/tsconfig.app.json",
            "assets": [
              "src/assets",
              {
                "glob": "**/*",
                "input": "node_modules/monaco-editor/min/vs",
                "output": "assets/monaco/vs"
              },
              {
                "glob": "**/*",
                "input": "node_modules/@ngstack/code-editor/assets",
                "output": "assets/code-editor"
              }
            ],
            "allowedCommonJsDependencies": [
              "monaco-editor",
              "core-js",
              "crypto-js",
              "dompurify",
              "to-px",
              "chartjs-plugin-datalabels",
              "@typescript-plus/fast-memoize-decorator",
              "chart.js",
              "html2canvas",
              "raf",
              "rgbcolor",
              "object-to-formdata",
              "jspdf",
              "jspdf-autotable",
              "dayjs",
              "dayjs/plugin/utc",
              "dayjs/plugin/isBetween",
              "sanitize-html"
            ],
            "stylePreprocessorOptions": {
              "includePaths": [
                "../app/assets/stylesheets"
              ]
            },
            "styles": [
              "src/styles/app.scss",
              "./node_modules/@fontsource/inter/index.css",
              "./node_modules/@fontsource/poppins/index.css",
              "./node_modules/bootstrap/dist/css/bootstrap.min.css",
              "./node_modules/primeicons/primeicons.css"
            ],
            "scripts": [
              "./node_modules/jquery/dist/jquery.js",
              "./node_modules/@popperjs/core/dist/umd/popper.min.js",
              "./node_modules/bootstrap/dist/js/bootstrap.min.js",
              "../app/assets/javascripts/shared/dropdown-submenu.js"
            ],
            "aot": false,
            "extractLicenses": false,
            "sourceMap": true,
            "optimization": false,
            "namedChunks": true,
            "browser": "src/main.ts"
          },
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],
              "optimization": {
                "scripts": true,
                "styles": {
                  "minify": true,
                  "inlineCritical": false
                },
                "fonts": true
              },
              "outputHashing": "all",
              "sourceMap": false,
              "namedChunks": false,
              "aot": true,
              "extractLicenses": true
            },
            "test": {
              "optimization": false,
              "extractLicenses": false,
              "sourceMap": true
            }
          },
          "defaultConfiguration": ""
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "buildTarget": "frontend:build"
          },
          "configurations": {
            "production": {
              "buildTarget": "frontend:build:production"
            },
            "ci": {
            }
          }
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "buildTarget": "frontend:build"
          },
          "configurations": {
            "outputHashing": "all"
          }
        },
        "test": {
          "builder": "@angular/build:unit-test",
          "options": {
            "tsConfig": "src/tsconfig.spec.json",
            "runnerConfig": "src/vitest.config.ts",
            "buildTarget": "::test"
          }
        },
        "lint": {
          "builder": "@angular-eslint/builder:lint",
          "options": {
            "lintFilePatterns": [
              "src/**/*.ts",
              "src/**/*.html"
            ]
          }
        }
      }
    }
  },
  "cli": {
    "analytics": false
  }
}

Activity

  1. modified the milestone: needsTriage on Mar 12, 2026
  2. transferred this issue fromangular/angularon Mar 12, 2026
  3. clydin commented on Mar 12, 2026

    @clydin
    Member

    Does pinning the version of only @angular/build to 21.1.6 (leaving all other versions as-is) resolve your issue?

  4. Viktor-Ivliev commented on Mar 12, 2026

    @Viktor-Ivliev
    Author

    Does pinning the version of only @angular/build to 21.1.6 (leaving all other versions as-is) resolve your issue?

    Yes, it seems that if you leave “@angular/build”: “21.1.5” (21.1.6 is not available), it shows the expected result.

    Image

    "@angular/build": "21.2.0" also ok
    "@angular/build": "21.2.1" And that's when this problem arises.

    {
      "name": "frontend",
      "version": "0.0.0",
      "packageManager": "pnpm@10.32.1",
      "browserslist": "> 5%, last 3 Chrome versions, last 3 Firefox version, last 2 Edge major versions, last 2 Safari major versions, last 2 iOS major versions, Firefox ESR",
      "scripts": {
        "watch": "pnpm store prune && ng build --watch --output-hashing=all",
        "start": "ng serve",
        "build": "ng build --configuration production",
        "test": "ng test --browsers=chromium",
        "test-headless": "ng test --browsers=ChromiumHeadless --watch=false",
        "test-ci": "ng test --browsers=ChromiumHeadless --coverage --watch=false",
        "lint": "ng lint",
        "bundle-report": "ng build --configuration production --stats-json && webpack-bundle-analyzer ../public/frontend/stats.json"
      },
      "private": true,
      "dependencies": {
        "@angular/animations": "21.2.3",
        "@angular/cdk": "21.2.2",
        "@angular/common": "21.2.3",
        "@angular/compiler": "21.2.3",
        "@angular/core": "21.2.3",
        "@angular/forms": "21.2.3",
        "@angular/platform-browser": "21.2.3",
        "@angular/platform-browser-dynamic": "21.2.3",
        "@angular/router": "21.2.3",
        "@ctrl/ngx-emoji-mart": "9.3.0",
        "@fontsource/inter": "5.2.8",
        "@fontsource/poppins": "5.2.7",
        "@fortawesome/fontawesome-free": "7.2.0",
        "@ng-select/ng-select": "21.5.2",
        "@ngstack/code-editor": "9.0.0",
        "@ngx-translate/core": "17.0.0",
        "@popperjs/core": "2.11.8",
        "@primeuix/themes": "2.0.3",
        "@rails/actioncable": "8.1.200",
        "@rails/activestorage": "8.1.200",
        "@types/crypto-js": "4.2.2",
        "@types/jquery": "3.5.34",
        "@types/sanitize-html": "2.16.1",
        "@typescript-plus/fast-memoize-decorator": "0.2.1",
        "angular-mentions": "1.5.0",
        "autolinker": "4.1.5",
        "bootstrap": "5.3.8",
        "chart.js": "4.5.1",
        "chartjs-plugin-datalabels": "2.2.0",
        "crypto-js": "4.2.0",
        "dayjs": "1.11.19",
        "deepmerge-ts": "7.1.5",
        "jquery": "3.7.1",
        "jspdf": "4.2.0",
        "jspdf-autotable": "5.0.7",
        "marked": "17.0.4",
        "monaco-editor": "0.52.2",
        "ngx-color": "10.1.0",
        "ngx-cookie-service": "21.1.0",
        "ngx-translate-multi-http-loader": "20.0.0",
        "object-to-formdata": "4.5.1",
        "primeicons": "7.0.0",
        "primeng": "21.1.3",
        "rxjs": "7.8.2",
        "sanitize-html": "2.17.1",
        "tslib": "2.8.1",
        "typescript": "5.9.3",
        "vite": "7.3.1",
        "zone.js": "0.16.1"
      },
      "devDependencies": {
        "@angular-devkit/core": "21.2.2",
        "@angular-devkit/schematics": "21.2.2",
        "@angular-eslint/builder": "21.3.0",
        "@angular-eslint/eslint-plugin": "21.3.0",
        "@angular-eslint/eslint-plugin-template": "21.3.0",
        "@angular-eslint/schematics": "21.3.0",
        "@angular-eslint/template-parser": "21.3.0",
        "@angular/build": "21.1.5",
        "@angular/cli": "21.2.2",
        "@angular/compiler-cli": "21.2.3",
        "@types/node": "25.4.0",
        "@typescript-eslint/eslint-plugin": "8.57.0",
        "@typescript-eslint/parser": "8.57.0",
        "@typescript-eslint/utils": "8.57.0",
        "@vitest/browser-playwright": "4.0.18",
        "@vitest/coverage-v8": "4.0.18",
        "eslint": "9.39.4",
        "eslint-plugin-import": "2.32.0",
        "eslint-plugin-jsdoc": "62.7.1",
        "eslint-plugin-prefer-arrow": "1.2.3",
        "eslint-plugin-unused-imports": "4.4.1",
        "postcss-preset-env": "11.2.0",
        "vitest": "4.0.18",
        "webpack-bundle-analyzer": "5.2.0"
      }
    }
    
  5. added theissue type on Mar 12, 2026
  6. Viktor-Ivliev commented on Mar 17, 2026

    @Viktor-Ivliev
    Author

    I found the cause and the commit, but I don't know enough to understand why it was done this way.

    commit: 6ad8608

    if I delete this:
    661: externalPackages: false,

    The tests are working as expected

    pull: #32635

  7. alan-agius4 commented on Mar 18, 2026

    @alan-agius4
    Collaborator

    This should be solved via #32761

  8. Viktor-Ivliev commented on Mar 18, 2026

    @Viktor-Ivliev
    Author
    Image

    Yes, I can confirm that this has been fixed in version 21.2.3. Thank you.

  9. angular-automatic-lock-bot commented on Apr 18, 2026

    @angular-automatic-lock-bot

    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.

  10. locked and limited conversation to collaborators on Apr 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions