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:
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.