Otimize o tamanho do pacote Angular com estas etapas
Introdução:
Muitos grandes projetos são construídos com a estrutura Angular, que é escalável e robusta, mas sentimos falta de nos preocupar com o tamanho do pacote.
Porque ter projetos com grandes tamanhos de pacote pode ter um impacto na experiência do usuário
Portanto, neste blog, descobriremos juntos como analisar o tamanho atual do pacote e aplicar algumas técnicas para otimizá-lo.
Leitura feliz!
Primeiro passo: monitorar o tamanho atual do pacote:
A primeira etapa que precisamos é analisar o tamanho do pacote atual, portanto, nesta seção, listarei as ferramentas necessárias para isso
Ferramentas necessárias:
Opção A: Webpack Bundle Analyzer
O webpack-bundle-analyzer é uma ótima ferramenta que ajuda a mostrar o conteúdo do pacote atual como um conveniente mapa de árvore interativo com zoom.
Uso:
Instalar webpack-bundle-analyzer:
npm install --save-dev webpack-bundle-analyzer
Precisamos construir nosso projeto angular com stats-jsonopção de usá-lo após a análise do pacote
Adicione este comando ao seu pacote.json
"build:stats": "ng build --stats-json",
npm run build:stats
webpack-bundle-analyzer dist/project-name/stats.json
Você terá esta saída entrando emhttp://127.0.0.1:8888/
O tamanho inicial do pacote é 1,54MO
Opção B: explorador do mapa de origem
O explorador do mapa de origem determina de qual arquivo veio cada byte em seu código minificado. Ele mostra uma visualização de mapa de árvore para ajudá-lo a depurar de onde vem todo o código
Uso:
Instale o source-map-explorer:
npm i --save-dev source-map-explorer
ng build --prod --source-map
"analyze-bundle": "source-map-explorer dist/project-name/main.ea52d6960c8f284dfbec.js --no-border-checks"
Resultado:
Obteremos um treeMap nos mostrando a visualização dos arquivos e módulos que contribuíram para o tamanho do pacote atual
Outras etapas para diminuí-lo
Nesta seção, descobriremos outras etapas realizadas para reduzir e otimizar nossa aplicação angular
1) Otimize a importação de terceiras bibliotecas
A primeira coisa com a qual começaremos é revisar as terceiras bibliotecas usadas e a maneira como importamos os módulos necessários em nossos componentes!
É recomendável importar apenas o que precisamos, depois de fazer alguma revisão e investigação do código
Eu encontrei esta importação delodash
Implementação de código:
import { Component } from '@angular/core';
import * as _ from 'lodash';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
constructor() {
console.log((_.includes['a', 'b', 'c', 'd'], 'b'));
}
}
Solução: otimizar a importação da 3ª biblioteca lodash
// install these packages
npm i lodash-es
npm i -D @types/lodash-es
//Change how we do our import
//import { includes } from 'lodash';
import includes from 'lodash/includes';
// Add this config to tsconfig.json
"allowSyntheticDefaultImports": true,
"baseUrl": "./",
"typeRoots": ["node_modules/@types", "manual_typings"],
"paths": {
"lodash/*": ["node_modules/@types/lodash-es/*"]
}
2) Refatore o módulo compartilhado
O módulo compartilhado é composto por diretivas, pipes e componentes que podem ser reutilizados em comum entre diferentes recursos do aplicativo
Problema ❗:
Mas com o tempo, quanto mais nosso aplicativo cresce mais vamos colocar em nosso módulo compartilhado , então as dependências vão crescer o que resulta em crescimento do tamanho do pacote ↗️↗️↗️
Como você pode ver, ilustrado neste diagrama, temos muitos recursos dependendo do módulo compartilhado
Implementação atual: (Inspirado em aplicação real em produção)
Este código simula um exemplo de shared-moduleimplementação para um projeto Angular que possui muitos imports, componentes e terceiras bibliotecas usadas…
código-módulo-compartilhado :
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ArrowIndicatorComponent } from './arrow-indicator/arrow-indicator.component';
import { MinusPipe } from './pipes/minus.pipe';
import { AgePipe } from './pipes/age.pipe';
import { FilterPipePipe } from './pipes/filter-pipe.pipe';
import { FileSizePipePipe } from './pipes/file-size-pipe.pipe';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { AgGridModule } from 'ag-grid-angular';
import { SqrtPipePipe } from './pipes/sqrt-pipe.pipe';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatChipsModule } from '@angular/material/chips';
import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { MatPaginatorModule } from '@angular/material/paginator';
import { MatTableModule } from '@angular/material/table';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatTooltipModule } from '@angular/material/tooltip';
import { BannersComponent } from './banners/banners.component';
import { RatingComponent } from './rating/rating.component';
import { GenericTableComponent } from './generic-table/generic-table.component';
import { GenericDialogComponent } from './generic-dialog/generic-dialog.component';
@NgModule({
declarations: [ArrowIndicatorComponent, MinusPipe, AgePipe, FilterPipePipe, FileSizePipePipe, SqrtPipePipe, BannersComponent, RatingComponent, GenericTableComponent, GenericDialogComponent,],
imports: [CommonModule,FormsModule,ReactiveFormsModule,HttpClientModule,AgGridModule,
MatButtonModule,
MatCardModule,
MatChipsModule,
MatIconModule,
MatMenuModule,
MatPaginatorModule,
MatTableModule,
MatToolbarModule,
MatTooltipModule,],
exports: [ArrowIndicatorComponent, MinusPipe, AgePipe, FilterPipePipe, FileSizePipePipe, SqrtPipePipe,BannersComponent, RatingComponent, GenericTableComponent, GenericDialogComponent,],
})
export class SharedModule {}
// StockqQuoteModule needs only ArrowPipe and MatToolbarModule only
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { StockQuoteComponent } from './stock-quote.component';
import { SharedModule } from 'src/app/shared/shared.module';
@NgModule({
declarations: [StockQuoteComponent],
imports: [
CommonModule,
SharedModule
],
exports:[StockQuoteComponent]
})
export class StockqQuoteModule { }
// StockMonthSentimentModule needs only ArrowPipe and MatIconModule
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { SharedModule } from 'src/app/shared/shared.module';
import { StockMonthSentimentComponent } from './stock-month-sentiment.component';
@NgModule({
declarations: [StockMonthSentimentComponent],
imports: [
CommonModule,
SharedModule
],
exports:[StockMonthSentimentComponent]
})
export class StockMonthSentimentModule { }
A solução para reduzir esse tamanho de módulo compartilhado é usar módulos SCAM (Single Component Angular Module)
Solution-for-components : temos arrow-indicator-componentum componente usado em stock-quote-module e stock-month-sentiment não há necessidade de exportá-lo para outros módulos
vamos criar um módulo arrow-indicator.module e importá-lo para ambos os módulos usados
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ArrowIndicatorComponent } from './arrow-indicator.component';
@NgModule({
declarations: [ArrowIndicatorComponent],
imports: [
CommonModule
],
exports:[ArrowIndicatorComponent]
})
export class ArrowIndicatorModule { }
// SCAM to be used in the needed modules
Removeremos as terceiras bibliotecas não comumente usadas entre todos os recursos, o que ajudará a reduzir as dependências importadas
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MinusPipe } from './pipes/minus.pipe';
import { AgePipe } from './pipes/age.pipe';
import { FilterPipePipe } from './pipes/filter-pipe.pipe';
import { FileSizePipePipe } from './pipes/file-size-pipe.pipe';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { AgGridModule } from 'ag-grid-angular';
@NgModule({
declarations: [ MinusPipe, AgePipe, FilterPipePipe, FileSizePipePipe, SqrtPipePipe,],
imports: [CommonModule,FormsModule,ReactiveFormsModule,HttpClientModule,AgGridModule,
],
exports: [MinusPipe, AgePipe, FilterPipePipe, FileSizePipePipe, SqrtPipePipe,
],
})
export class SharedModule {}
Fontes:
Sou muito grato por esses recursos, que me ajudaram muito a escrever este blog
- https://coryrylan.com/blog/measuring-angular-performance-with-source-map-explorer
- https://github.com/ivanblazevic/ngx-unused-css
- https://stackoverflow.com/questions/44758755/how-to-enable-gzip-compression-in-angular-cli-for-production-build
- https://github.com/depcheck/depcheck
- https://dev.to/dylanvdmerwe/reduce-angular-style-size-using-purgecss-to-remove-unused-styles-3b2k
- https://www.youtube.com/watch?v=8lUkVsvCsl8
- https://indepth.dev/posts/1191/stop-using-shared-material-module
- https://pham.codes/blog/how-to-make-bundle-size-smaller-lodash-angular
- https://stackoverflow.com/questions/41991178/correct-way-of-importing-and-using-lodash-in-angular
Se você gostou deste post, sinta-se à vontade para deixar um e me seguir no Twitter e no Github
Obrigado por ler





































![O que é uma lista vinculada, afinal? [Parte 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)