angularwebpackangular-materialchunksangularbuild

Angular 17/18 multiple chunk files after build


For the past few months I've been working on my Angular 17 app (in one language only), and when I built it for production, I've noticed that a few "chunk" files were generated.

After some investigation (and with the help of ChatGPT), I've made some changes to the configuration and build command, ending up with only 2 chunk files, among others in the built folder.

Until a few days ago, this was fine and was working for me the way I wanted.

Suddenly, now when I run this build, without making any changes to the configuration or build command, there are over 30 (!) chunk files.

When setting "namedChunks": true, under angular.json, those files are named after some of the components in the app.

Yesterday, I upgraded the app to Angular 18, for other general reasons and which went through just fine as itself, but this issue still occurs.

I don't understand why this sudden change in the build outcome.

Another sub-issue is that I am trying to install the "custom-webpack" package to have more control over the build process (and maybe this will also narrow down the number of chunk files), but I get an error regarding compatibility with the version of "@angular-material-components/datetime-picker" (16.0.1). When trying to upgrade only this package, it says that this is the latest version of this package, so there's nothing to upgrade here.

So, I tried to install version 16 of custom-webpack, but it still alerts about this compatibility issue and won't let me install.

This is my current configuration under angular.json: (the commented lines are things that I was about to check with custom-webpack, but didn't get to test because it wouldn't install, like explained in this post)

"architect": {
                "build": {
                    "builder": "@angular-devkit/build-angular:application",
                    //"builder": "@angular-builders/custom-webpack:browser",
                    "options": {
                        //"customWebpackConfig": {
                        //  "path": "./webpack.config.js"
                        //},
                        "outputPath": "dist/myapp",
                        "outputHashing": "none",
                        "index": "src/index.html",
                        "browser": "src/main.ts",
                        "polyfills": ["zone.js"],
                        //"polyfills": "src/polyfills.ts",
                        "tsConfig": "tsconfig.app.json",
                        //"aot": true,
                        "inlineStyleLanguage": "scss",
                        "assets": ["src/favicon_640.ico", "src/assets"],
                        "styles": ["@angular/material/prebuilt-themes/indigo-pink.css", "src/styles.scss"],
                        "scripts": []
                    },
                    "configurations": {
                        "production": {
                            "budgets": [
                                {
                                    "type": "initial",
                                    "maximumWarning": "10mb",
                                    "maximumError": "20mb"
                                },
                                {
                                    "type": "anyComponentStyle",
                                    "maximumWarning": "10kb",
                                    "maximumError": "20kb"
                                }
                            ],
                            //"outputHashing": "none",
                            "outputHashing": "none",
                            //"extractCss": true,
                            "fileReplacements": [
                                {
                                    "replace": "src/environments/environment.ts",
                                    "with": "src/environments/environment.prod.ts"
                                }
                            ],
                            "optimization": true,
                            "sourceMap": false,
                            "namedChunks": false,
                            //"aot": true,
                            //"vendorChunk": false,
                            //"buildOptimizer": true,
                            "extractLicenses": false
                        },
                        "development": {
                            "optimization": false,
                            "extractLicenses": false,
                            "sourceMap": true
                        }
                    },
                    "defaultConfiguration": "production"
                },
                "serve": {
                    "builder": "@angular-devkit/build-angular:dev-server",
                    "configurations": {
                        "production": {
                            "buildTarget": "Myapp:build:production"
                        },
                        "development": {
                            "buildTarget": "Myapp:build:development"
                        }
                    },
                    "defaultConfiguration": "development"
                },
                "extract-i18n": {
                    "builder": "@angular-devkit/build-angular:extract-i18n",
                    "options": {
                        "buildTarget": "Myapp:build"
                    }
                },
                "test": {
                    "builder": "@angular-devkit/build-angular:karma",
                    "options": {
                        "polyfills": [
                            "zone.js",
                            "zone.js/testing"
                        ],
                        "tsConfig": "tsconfig.spec.json",
                        "inlineStyleLanguage": "scss",
                        "assets": [
                            "src/favicon_640.ico",
                            "src/assets",
                            {
                                "glob": "**/*",
                                "input": "node_modules/tinymce",
                                "output": "/tinymce/"
                            }
                        ],
                        "styles": [
                            "@angular/material/prebuilt-themes/indigo-pink.css",
                            "src/styles.scss"
                        ],
                        "scripts": [
                            "node_modules/tinymce/tinymce.min.js",
                            "node_modules/tinymce/themes/modern/theme.js",
                            "node_modules/tinymce/plugins/fullscreen/plugin.js"
                        ]
                    }
                }
            }

And this is the current packages list of the app (package.json):

"dependencies": {
    "@angular-material-components/datetime-picker": "^16.0.1",
    "@angular/animations": "18.2.7",
    "@angular/cdk": "18.2.7",
    "@angular/common": "18.2.7",
    "@angular/compiler": "18.2.7",
    "@angular/core": "18.2.7",
    "@angular/forms": "18.2.7",
    "@angular/material": "18.2.7",
    "@angular/material-moment-adapter": "^18.2.7",
    "@angular/platform-browser": "18.2.7",
    "@angular/platform-browser-dynamic": "18.2.7",
    "@angular/router": "18.2.7",
    "@ckeditor/ckeditor5-angular": "^7.0.1",
    "@ckeditor/ckeditor5-build-classic": "^41.2.1",
    "@ckeditor/ckeditor5-build-decoupled-document": "^41.2.1",
    "@ckeditor/ckeditor5-core": "^41.2.1",
    "@ckeditor/ckeditor5-engine": "^41.2.1",
    "@ckeditor/ckeditor5-utils": "^41.2.1",
    "@ckeditor/ckeditor5-watchdog": "^41.2.1",
    "@fortawesome/angular-fontawesome": "0.14.1",
    "@fortawesome/fontawesome-svg-core": "6.5.1",
    "@fortawesome/free-solid-svg-icons": "6.5.1",
    "chart.js": "4.4.2",
    "lodash": "4.17.21",
    "rxjs": "7.8.0",
    "tslib": "2.3.0",
    "zone.js": "0.14.10"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "18.2.7",
    "@angular/cli": "18.2.7",
    "@angular/compiler-cli": "18.2.7",
    "@types/jasmine": "5.1.0",
    "jasmine-core": "5.1.0",
    "karma": "6.4.0",
    "karma-chrome-launcher": "3.2.0",
    "karma-coverage": "2.2.0",
    "karma-jasmine": "5.1.0",
    "karma-jasmine-html-reporter": "2.1.0",
    "moment": "^2.30.1",
    "typescript": "5.5.4"
  }

So, how do I set the build to stop generating so many chunk files, narrowing down this amount to 1 or 2, like it was, not so long ago??


Solution

  • Chunks are generally created through lazy loading modules, or if you have standalone components.

    Lazy Loaded Modules.

    If you have lazy loading enabled, then convert it to below, so that chunks are not generated.

    From:

    const routes: Routes = [
      {
        path: 'items',
        loadChildren: () => import('./items/items.module').then(m => m.ItemsModule)
      }
    ];
    

    To:

    const routes: Routes = [
      {
        path: 'items',
        loadChildren: () => ItemsModule
      }
    ];
    

    Standalone components.

    Standalone components should either have their standalone: true removed. Or can be added to the imports array of AppModule, but this might still generate chunks.

    Why it's good to have chunks:

    1. The browser supports parallel fetch of upto 10 API calls simultaneously. So fetching through chunks improves the fetch time of your angular javascript assets in your application.

    2. Lazy loading enables reduced main bundle size, since it's either fetched/ preloaded when the module is absolutely needed.

    3. The flags "buildOptimizer": true and "aot": true, reduce your final bundle size.

    TLDR: Don't, since it boosts your application performance and are good to have, even though the bundle number is high.