Codeblox Blog

Entendendo o chunk common.js do Angular

Guilherme
08/10/2021

Depois de criar um projeto Angular, talvez tenha percebido que em algum momento do desenvolvimento a compilação vai gerar um arquivo common.js. Vou explicar aqui por que e quando ele passa a ser gerado.

Vamos considerar uma aplicação com algumas páginas carregadas dinamicamente (lazy load):

const routes: Routes = [
  {
    path: '1',
    loadChildren: () => import('../pages/pagina1.module').then(m => m.Pagina1Module)
  },
  {
    path: '2',
    loadChildren: () => import('../pages/pagina2.module').then(m => m.Pagina2Module)
  },
  {
    path: '3',
    loadChildren: () => import('../pages/pagina3.module').then(m => m.Pagina3Module)
  },
  {
    path: '4',
    loadChildren: () => import('../pages/pagina4.module').then(m => m.Pagina4Module)
  }
];

Cada uma dessas páginas tem a seguinte implementação (substitua mentalmente os nomes de Pagina1 por Pagina2, Pagina3 e Pagina4)

import { Component, NgModule } from "@angular/core";
import { RouterModule, Routes } from "@angular/router";

@Component({
    template: 'Olá, sou a página 1 - '
})
export class Pagina1Component {
    texto = 'x';
}

const routes: Routes = [{ path: '', component: Pagina1Component  }]

@NgModule({
    declarations: [Pagina1Component],
    imports: [RouterModule.forChild(routes)]
})
export class Pagina1Module {}

Ao compilar o projeto, os seguintes chunks são gerados:

image

Até então não existe nenhum compartilhamento de recurso entre essas páginas.

Neste projeto temos uma pasta de strings que podem ser reaproveitadas em qualquer ponto do projeto:

strings/texto1.ts:

export const TEXTO1 = 'TEXTO 1 - XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';

strings/texto2.ts:

export const TEXTO2 = 'TEXTO 2 - XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';

Se referenciarmos o TEXTO1 na página 1, e o TEXTO2 na página 2, ex:

import { TEXTO1 } from "src/strings/texto1";
@Component({
    template: 'Olá, sou a página 1 - '
})
export class Pagina1Component {
    texto = TEXTO1;
}

e

import { TEXTO2 } from "src/strings/texto2";
@Component({
    template: 'Olá, sou a página 2 - '
})
export class Pagina2Component {
    texto = TEXTO2;
}

Como as duas páginas são os unicos módulos que referenciam cada um dos textos, o compilador do Angular vai embutir esses textos nos respectivos chunks. É possível perceber isso na diferença de tamanho em relação às páginas 3 e 4:

image

Vamos referenciar agora o TEXTO1 também na página 3 para ver o que acontece:

import { TEXTO1 } from "src/strings/texto1";
@Component({
    template: 'Olá, sou a página 3 - '
})
export class Pagina3Component {
    texto = TEXTO1;
}

Compilando o projeto é possível ver agora a presença do chunk common:

image

O TEXTO1 foi movido para este novo chunk common pois é compartilhado por mais de um módulo. No caso, as páginas 1 e 3 que agora possuem exatamente o mesmo tamanho, enquanto as páginas 2 e 4 mantiveram-se inalteradas.

Agora veremos o que acontece se referenciarmos o TEXTO2 na página 4. (Atualmente ele está embutido no chunk da página 2):

import { TEXTO2 } from "src/strings/texto2";
@Component({
    template: 'Olá, sou a página 4 - '
})
export class Pagina4Component {
    texto = TEXTO2;
}

Após compilar:

image

O common ficou maior pois agora contém também o TEXTO2 que é compartilhado entre as páginas 2 e 4. Já essas duas páginas ficaram praticamente do mesmo tamanho.

Conclusão

O arquivo common.*.js é criado quando um recurso é compartilhado entre dois ou mais módulos. Qualquer recurso que caia nessa situação será colocado neste chunk.

Quando o common.js é carregado pelo navegador?

Quando for acessado o primeiro módulo lazy que compartilha recurso com outros módulos. Por exemplo, navegando para a página 1:

image

É possível desligar este comportamento?

Sim! Existe uma opção no angular.json onde é possível escolher por não gerar o common.js. Neste caso, cada módulo lazy vai copiar para seu chunk os recursos que precisa.

Basta colocar a opção commonChunk com o valor false:

  "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "commonChunk": false,
            ...
          }
  }

Se eu desligar esta opção no exemplo mostrado, os chunks ficam assim:

image

Todos ficam maiores e o common.js foi descartado. Cada módulo copiou o TEXTO1 ou TEXTO2 para si.

angular
frontend


Guilherme M. Abdo
Guilherme M. Abdo
Desenvolvedor fullstack .Net/Angular/Azure/GitHub