0

I have an Angular 16 application which has recently been migrated to standalone components and I was able to remove all modules from the entire codebase. That application has SSR set up for SEO purposes and I normally get a warning from the lighthouse indicating that I should try to reduce unused javascript.

Then I tried to optimize the main.js file which is the biggest JS file I've got and I took a look at the tour of heroes example in the Angular site. I ran ng build --configuration production and I got a main.***.js file of 320Kb (then if it is gzipped to the client you get around 100Kb).

Looking at my application I have 348Kb which isn't too bad compared to the tour of heroes example and only adding 28Kb for a medium-sized application. Is there any way to reduce the size of that file?

Perhaps we can get smaller chunks that may be more efficient but for now I have run the webpack-bundle-analyzer and I got the following:

enter image description here

Which to me seems fairly good. I thought that my app.component could be introducing extra dependencies through but that is not the case.

Taking a look at my main.ts file I've got:

import { AppComponent } from './app/app.component';
import { provideAnimations } from '@angular/platform-browser/animations';
import { provideHttpClient } from '@angular/common/http';
import { bootstrapApplication, provideClientHydration } from '@angular/platform-browser';
import { provideRouter, withEnabledBlockingInitialNavigation, withInMemoryScrolling, withRouterConfig } from '@angular/router';
import routes from './app/app.routes';

bootstrapApplication(AppComponent, {
    providers: [
        provideHttpClient(),
        provideAnimations(),
        provideRouter(routes, 
            withInMemoryScrolling({
                scrollPositionRestoration: 'top',
                anchorScrolling: 'enabled',
            }),
            withEnabledBlockingInitialNavigation(),
            withRouterConfig({
                paramsInheritanceStrategy: 'always',
                onSameUrlNavigation: 'reload'
            })
        ),
        provideClientHydration()
    ]
})
.catch(err => console.error(err));

And my angular.json for the production build looks like this (very standard):

"build": {
          "builder": "@angular-builders/custom-webpack:browser",
          "options": {
            "outputPath": "dist/browser",
            "index": "src/index.html",
            "main": "src/main.ts",
            "polyfills": ["zone.js"],
            "tsConfig": "tsconfig.app.json",
            "inlineStyleLanguage": "scss",
            "assets": [
              "src/favicon.ico",
              "src/assets",
              "src/robots.txt",
              "src/ads.txt",
              {
                "glob": "**/*",
                "input": "node_modules/leaflet/dist/images/",
                "output": "./assets"
              }
            ],
            "styles": [
              "src/styles.scss"
            ],
            "scripts": [],
            "customWebpackConfig": {
              "path": "webpack.config.js"
            }
          },
          "configurations": {
            "production": {
              "budgets": [
                {
                  "type": "initial",
                  "maximumWarning": "500kb",
                  "maximumError": "1mb"
                },
                {
                  "type": "anyComponentStyle",
                  "maximumWarning": "2kb",
                  "maximumError": "10kb"
                }
              ],
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],
              "outputHashing": "all",
              "buildOptimizer": true,
              "aot": true,
              "optimization": {
                "scripts": true,
                "styles": {
                  "minify": true,
                  "inlineCritical": false
                },
                "fonts": true
              }
            },
            "development": {
              "buildOptimizer": false,
              "optimization": false,
              "vendorChunk": true,
              "extractLicenses": false,
              "sourceMap": true,
              "namedChunks": true
            }
          },
          "defaultConfiguration": "production"
        },

Note that the webpack.config.json is for minimizing the CSS, just that; and the inlineCriticalCss flag is set to false because there is actually better performance server side with it disabled (https://github.com/angular/universal/issues/2106)

My app.component.ts is very small as well, only importing directly a reference to RouterOutlet, that's it.

I have been looking at many posts and articles and I mostly found the lazy loading approach which I am already doing and I am also delay the reference and load of many elements of the application so that the boostrap can be done the quickest possible way.

Carlos Torrecillas
  • 4,965
  • 7
  • 38
  • 69
  • 1) Only load the modules where you actually need them. 2) Organize your modules per feature, so don't use a `SharedModule`!!! 3) Use lazy-loading (=module per page) using the command `ng g module register --module account --route register` 4) For angular libraries, use a separate entrypoint per module/feature ([see also](https://stackoverflow.com/questions/74012408/using-single-component-from-library-causes-lazy-loaded-modules-to-end-up-in-main)) – Pieterjan Jul 22 '23 at 10:26
  • Thanks Peter, I migrated to a standalone-model application therefore I don't have any modules, so don't know if many steps are applicable to this. I listed the references I use from Angular in the main.ts file for the dependencies needed and I do lazy load some of the components in the app.component itself (navbar, footer, etc) to reduce the size of the bundle. Not sure of any extra action I can take here – Carlos Torrecillas Jul 24 '23 at 07:41

0 Answers0