Saltar al contenido
¿Cómo mejorar el rendimiento de Angular aplicaciones?

¿Cómo mejorar el rendimiento de Angular aplicaciones?

¿Cómo mejorar el rendimiento de Angular aplicaciones? Lea esta publicación de blog para encontrar las formas, desde reducir JavaScript y CSS no utilizados hasta Angular la carga diferida.

8min read

Angular ha convertido en un marco muy popular y ampliamente adoptado para el desarrollo de aplicaciones web modernas. Esta tecnología es muy potente y rica en funciones. Todo lo que necesita como desarrollador web viene listo para usar y Angular permite configurar, mantener y expandir fácilmente cualquier aplicación construida sobre el marco.

Y a estas alturas, probablemente ya hayas reunido una o más aplicaciones Angular, pero ¿son óptimas?

A continuación, en la Parte 2 de mi serie Rendimiento del software, hablaré sobre la optimización de Angular, demostrando cómo mejorar el rendimiento de una aplicación de Angular utilizando una aplicación de ejemplo Angular que he creado. Usaré Chrome Dev Tools para derivar una puntuación de faro inicial para determinar dónde se encuentra inicialmente la aplicación. Echemos un vistazo a lo que se puede mejorar y cómo.

Otros blogs de esta serie:

Rendimiento del software [Web] Parte I

Cómo mejorar el rendimiento de Angular aplicaciones

Para este artículo, usaré un ejemplo de aplicación Angular que he reunido. En el momento de escribir este artículo, la aplicación utiliza las siguientes características y bibliotecas:

  • Angular 16
  • Ignite UI for Angular 16
  • RxJS 7
  • PWA (Angular service worker)
  • Server-side rendering (express server)
  • Angular localization

Angular Build

Todo parece funcionar bien cuando estoy ejecutando la aplicación en un entorno de desarrollo, pero la puntuación inicial del faro no es muy alta:

 Lighthouse score with development environment run

Cuandomirolas sugerencias para mejorar las secciones con menor puntuación, veo de dónde vienen los problemas. Elprimer gran problema es el tamaño de los recursos (JavaScript, estilos, recursos estáticos) que se transfieren al cliente. 

Oportunidades para mejorar el rendimiento de la aplicación Angular

Este problema se resuelve fácilmente ejecutando una compilación de producción de mi aplicación Angular en lugar de una de desarrollo. Construya siempre con la configuración de producción antes de la implementación. Esto resolverá la advertencia para reducir el tamaño deJavaScriptyCSS.Echemos un vistazoal archivo angular.jsonen la raíz de nuestrorepositorio A ngular para ver en qué se diferencia la compilación de producción: 

"configurations": {
  "production": {
    "budgets": [
      {
        "type": "initial",
        "maximumWarning": "2mb",
        "maximumError": "5mb"
      },
      {
        "type": "anyComponentStyle",
        "maximumWarning": "10kb"
      }
    ],
    "fileReplacements": [
      {
        "replace": "projects/common/src/environments/environment.ts",
        "with": "projects/common/src/environments/environment.prod.ts"
      }
    ],
    "localize": true,
    "optimization": true,
    "outputHashing": "all",
    "sourceMap": false,
    "namedChunks": false,
    "extractLicenses": true,
    "vendorChunk": false,
    "buildOptimizer": true,
    "serviceWorker": true,
    "i18nMissingTranslation": "error",
    "ngswConfigPath": "projects/bellumgens/src/ngsw-config.json"
  },
  "bg": {
    "localize": [
      "bg"
    ]
  }
}

There’s quite a lot of configuration here. However, the most important one, in this case, is the"optimization": true one. Once I run the application with a production configuration, the difference in score is significant in terms of load-time performance: 

Puntuación de Lighthouse con compilación de producción en el entorno de desarrollo

Si vuelvo a mirar la lista de oportunidades, el número de sugerencias es mucho menor. Lasmayores oportunidades enumeradas en Acerca de la compresión de textosonJavaScript no utilizado y el almacenamiento en caché de recursos estáticos:

Oportunidades restantes para mejorar el rendimiento

Angular Pre-Rendering and Server-Side Rendering 

Angular es un marco de aplicación de una sola página (SPA). De forma predeterminada, el ciclo de vida de la aplicación es tal que, a petición de un cliente, el servidor que aloja la aplicación sirve un archivo HTML que incluye todas las referencias de estilo y script necesarias. Sin embargo, está vacío de contenido corporal. Una vez que se solicitan y sirven los scripts y estilos, la aplicación se arranca y se rellena con contenido basado en la lógica de JavaScript para la aplicación determinada. Angular proporciona dos mecanismos para mejorar este ciclo de vida mediante la publicación de contenido real en el documento HTML inicial. Para ello, la lógica de JavaScript de la aplicación debe ejecutarse antes de entregar el documento. Las formas de hacerlo:

He habilitado la representación del lado del servidor para la aplicación de ejemplo Angular y estoy usando el motor exprés para habilitar la compresión de texto y el almacenamiento en caché de recursos estáticos. Esto se hace agregando lo siguiente a mi lógica de servidor express:

export const app = (lang: string) => {
  // server scaffolded by [ng add @nguniversal/express-engine]
...
  // enable compression [npm install compression]
  const compression = require('compression');
  server.use(compression());
...
  // Serve static files from /browser with 1y caching
  server.get('*.*', express.static(distFolder, {
    maxAge: '1y'
  }));
...
}

Serviré la aplicación con renderizado del lado del servidor y volveré a ejecutar la prueba del faro. La carga inicial ha mejorado aún más, llevando la primera pintura contenta a menos de un segundo, mientras que el índice de velocidad se reduce a 1,2 segundos.

Puntuación de Lighthouse con renderizado Angular del lado del servidor

Las oportunidades restantes para la optimización de Angular son reducir JavaScript y CSS no utilizados.

Oportunidades sobrantes para mejorar el rendimiento

Para lidiar con estos, tendré que hacer una refactorización de aplicaciones.

Angular Lazy-Loading 

Para reducir el JavaScript no utilizado, el mejor enfoque sería crear rutas de carga diferida. Esto le dirá al marco de Angular qué componentes no son necesarios en el módulo de nivel superior y dividirá el JavaScript en módulos, cuya lógica se carga solo cuando se carga la ruta solicitada.

La aplicación de ejemplo Angular que estoy usando para este blog utiliza componentes más grandes, como igx-grid, que no forman parte de la ruta de inicio. Estoy separando las rutas usando este componente en un módulo separado. De esta manera, voy a tener ese componente cargado solo después de que se carguen las rutas que usan el componente. Después de separar los módulos, las rutas se ven así:

export const routes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'register', component: RegistrationComponent },
  { path: 'unauthorized', redirectTo: 'unauthorized/', pathMatch: 'full' },
  { path: 'unauthorized/:message', component: UnauthorizedComponent },
  { path: 'emailconfirm', component: EmailconfirmComponent },
  { path: 'strategies', loadChildren: () => import('./strategies/strategies.module').then(m => m.StrategiesModule) },
  { path: 'emailconfirm/:error', component: EmailconfirmComponent },
  { path: 'players', loadChildren: () => import('./player-section/player.module').then(m => m.PlayerModule) },
  { path: 'team', loadChildren: () => import('./team-section/team.module').then(m => m.TeamModule) },
  { path: 'notifications', loadChildren: () => import('./notifications/notifications.module').then(m => m.NotificationsModule) },
  { path: 'search/teams/:query', component: TeamResultsComponent },
  { path: 'search/players/:query', component: PlayerResultsComponent },
  { path: '**', component: HomeComponent }
];

The team.module is the one loading the grid I’m using, so the code for it looks like this:

@NgModule({
  imports: [
    CommonModule,
    FormsModule,
    // ...
    IgxGridModule,
    // ...
    TeamComponent,
    // ...
  ]
})
export class TeamModule { }

En cuanto a la construcción, este es el resultado de la división inicial:

Separar la aplicación Angular en módulos de carga diferida

Otra cosa que hay que hacer para mejorar el rendimiento de la aplicación Angular es limitar el tamaño del CSS a los estilos que se utilizan. Estoy usando Ignite UI for Angular como mi biblioteca de interfaz de usuario y hay un excelente artículo instructivo sobre cómo personalizar y optimizar los temas de los componentes.

Optimizing Images 

Otro aspecto de la optimización de la Angular que se debe realizar es la optimización de las imágenes. Lighthouse check te dirá si estás utilizando imágenes subóptimas por tipo o tamaño. Asegúrese de que las imágenes que cargue no sean más grandes que los contenedores en los que van y que tengan una codificación óptima. Ahora uso el formato .webp para las imágenes. Reduce un poco la calidad, pero, aún así, la aplicación no requiere imágenes de la más alta fidelidad.

Las imágenes provocan cambios de diseño después de cargarlas. Por lo tanto, es una buena idea establecer los atributos de ancho y alto en las imágenes para que el navegador conozca las dimensiones antes de cargar las imágenes. Si te faltan ajustes de relación de aspecto (anchura y altura) en las imágenes, Lighthouse te avisará. Esto reducirá o eliminará por completo los cambios de diseño.

NgOptimizedImage to Enforce Image Best Practices 

Angular exposes a directive that enforces image best practices and optimizes image loading for you. It’s called NgOptimizedImage and it is rather easy to use. All you need to do is import CommonModule if you’re still in an NgModule based Angular application, or import NgOptimizedImage in the component where you want to use it. Then, instead of using src to set the image source attribute, you use ngSrc instead.

<img ngSrc="/assets/wallpapers/strat-editor.webp" width="600" height="347" class="preview-image" alt="Strategy Editor" />

Por último, puedeespecificar aún más la prioridad de carga de cada imagen y decirle a la aplicación que cargue de forma diferida todas las imágenes no críticas. Si elimino los atributos de ancho y alto, lo que obtengo al ejecutar la aplicación es:

 NgOptimizedImage enforcing best practices

Y eso es todo.

Envolver...

Mejorar el rendimiento de Angular aplicaciones puede requerir supervisión continua, optimización y procedimientos recomendados para garantizar que la aplicación funcione de manera eficiente y confiable en diversas condiciones. Pero al final, así es como se ofrece la experiencia de usuario definitiva, se atrae y retiene a los usuarios, se mantiene la competitividad y se logra el éxito empresarial.

Ignite UI for Angular

Solicitar una demostración