Partendo dal presupposto che, anche grazie ad Angular, ci siamo liberati dal fardello jQuery, oggi ci sono alcune librerie javascript utili, molto popolari, ma che tendono a occupare più risorse del dovuto, ovvero:
- Banda (in particolare su 3g 4g)
- Cpu lato client (che, come minimo, deve parsarsi il js
- Cpu lato sviluppatore (che deve inserire tutte le dipendenze)
Due di queste librerie sono:
- Lodash: contiene funzioni utili per lavorare con i tipi/oggetti javascript, gestire correttamente null e undefined…
- Momentjs: contiene funzioni e oggetti utili a gestire le date in javascript (come dice la pagina ufficiale, parsare, formattare, validare e manipolare le date)
Progetto base e strumenti
Proviamo ora a creare un progetto Angular ”vuoto” (Angular 9 al momento della scrittura), compilare in produzione con le statistiche e analizzare i bundles generati:
npm install -g @angular/cli ng new EmptyNg --style=css --routing=false cd EmptyNg npm install webpack-bundle-analyzer --save-dev ng build -prod -stat-json npx webpack-bundle-analyzer .\dist\EmptyNg\stats-es2015.json
Abbiamo anche installato Webpack-bundle-analyzer in quanto ci permette di capire come sono organizzati i bundle generati da webpack (usato internamente da angular/cli). La situazione è la seguente:
per un totale di circa 170Kb di javascript (escludendo i file –es5 usati dai browser )
Aggiungiamo Lodash e momentjs
npm install moment npm install lodash
e usiamoli, altrimenti il l’algoritmo di treeshaking si accorge che non lo usiamo. Modifichiamo così app.component.ts in questo modo:
import * as moment from 'moment'; import * as _ from 'lodash'; … title = moment().format('YYYY-MM-DD') + _.isNumber(1);
Vediamo cosa è successo:
ng build -prod -stat-json npx webpack-bundle-analyzer .\dist\EmptyNg\stats-es2015.json
Il nostro applicativo è cresciuto drasticamente, il main è passato da 136Kb a 547Kb!
Ma vediamo come risolvere la cosa.
Minimizzare Momentjs
Subito si può osservare che, moment ha una grossa parte che sono le configurazioni delle lingue che difficilmente nel nostro progetto andremo a utilizzare (al più ne useremo alcune). Eliminarle si può, ed è anche semplice, basta utilizzare un plugin webpack apposito e passare la configurazione in fase di build di webpack:
- installare il plugin:
npm install moment-locales-webpack-plugin -save-dev
- creare un file di config di estensione di webpack (nel mio caso extra-webpack.config.js) e modificarlo quanto segue:
const MomentLocalesPlugin = require('moment-locales-webpack-plugin'); module.exports = { plugins: [ new MomentLocalesPlugin({ localesToKeep: ['it', 'en-gb'] //uniche lingue da tenere }) ] };
- aggiungere la configurazione in fase di build. Per far questo modificare angular.json e aggiungere in
"customWebpackConfig": { "path": "./extra-webpack.config.js", "replaceDuplicatePlugins": true },
- Occorre estendere il processo di build utilizzando il paccketto
npm install @angular-builders/custom-webpack
- e configurare il builder in angular.json:
"builder": "@angular-builders/custom-webpack:browser"
rebuildiamo e vediamo l’output:
e voilà. main.js è passato da 547Kb a circa la metà, 262Kb.
Minimizzare Lodash
Lodash è (quasi) una libreria contenente tante funzioni. L’idea è quella di importare le singole funzioni in base alle nostre necessità. Per farlo, occorre cambiare pacchetto npm (da lodash a lodash-es), e modificare gli import per importare le singole funzioni:
-
- Cambiare pacchetto nuget:
npm uninstall lodash npm install lodash-es
- modificare l’import delle funzioni richieste
import * as _ from 'lodash'; import { isNumber } from 'lodash/isNumber';
Questo il risultato:
Come si può vedere, lodash è letteralmente sparito. Ovviamente la dimensione di lodash sarà sempre più grande più funzioni andremo ad utilizzare (spoiler: ma è veramente necessario lodash?