Cómo utilizar Angular Universal para la representación del lado del servidor

Introducción
Las aplicaciones de una sola página (SPA) consisten en un único documento HTML que se entrega inicialmente a un cliente. Las nuevas vistas que se requieren en la aplicación se generan únicamente en el cliente a través de JavaScript. El ciclo de solicitud-respuesta todavía se produce, pero normalmente solo se aplica a las API RESTful para datos o para obtener recursos estáticos, como imágenes.
Escribir aplicaciones de esta manera tiene muchas ventajas. Sin embargo, hay algunas cosas que se pierden, como la capacidad de los rastreadores web para recorrer la aplicación y un rendimiento más lento mientras la aplicación se carga, lo que puede llevar una cantidad significativa de tiempo. La representación del lado del servidor (SSR) llega para salvar la brecha.
En este artículo, aprenderá cómo usar Angular Universal para la renderización del lado del servidor.
Prerrequisitos
Para seguir este tutorial, necesitarás:
- Node.js instalado localmente, lo cual puedes hacer siguiendo Cómo instalar Node.js y crear un entorno de desarrollo local .
- Algunos conocimientos sobre la configuración de un proyecto Angular .
Este tutorial fue verificado con Node v16.4.2, npm
v7.19.1, @angular/core
v12.1.1 y @nguniversal/express-engine
v12.1.0.
Paso 1: Introducción a Angular Universal
Una aplicación Angular es una aplicación de una sola página: se ejecuta en el navegador de un cliente. Sin embargo, Angular Universal también te permite ejecutar tu aplicación Angular en el servidor. Esto te permite servir HTML estático al cliente. Con Angular Universal, el servidor renderizará previamente las páginas y mostrará algo a tus usuarios, mientras que la aplicación del lado del cliente se carga en segundo plano. Luego, una vez que todo esté listo en el lado del cliente, cambiará sin problemas de mostrar las páginas renderizadas en el servidor a la aplicación del lado del cliente. Tus usuarios no deberían notar ninguna diferencia, más allá del hecho de que en lugar de esperar a que finalice tu indicador de “Carga”, al menos pueden tener algo de contenido para mantenerlos interesados hasta que puedan comenzar a usar la aplicación del lado del cliente con todas las funciones.
SSR con Angular Universal requiere cambios tanto en la aplicación cliente como en la pila del servidor para funcionar. Para este artículo, asumiremos que se trata de una aplicación Angular completamente nueva, apenas creada con la CLI de Angular, en la versión = 7. Casi cualquier tecnología de servidor puede ejecutar una aplicación Universal, pero debe poder llamar a una función especial, renderModuleFactory()
, proporcionada por Angular Universal, que es en sí un paquete de Node; por lo que servir esta aplicación Angular desde un servidor Node/Express tiene sentido para este ejemplo.
Usaremos un esquema para ponernos en marcha rápidamente.
Desde el directorio de su aplicación, abra una terminal y ejecute el siguiente comando:
- ng add @nguniversal/express-engine
Notarás que este esquema realizó varios cambios en tu aplicación, modificando algunos archivos y agregando otros archivos:
Actualizacionesangular.json
projects.{{project-name}}.architect.build.options.outputPath
cambios a"dist/browser"
projects.{{project-name}}.architect
Se añade uno nuevo , llamado"server"
Esto permite que la CLI de Angular conozca nuestra versión de servidor/universal de la aplicación Angular.
Actualizacionespackage.json
Además de algunas nuevas dependencias (como era de esperar), también obtenemos algunos scripts nuevos:
"dev:ssr"
"build:ssr"
"serve:ssr"
"prerender"
Actualizacionesmain.ts
Esto se ha modificado para que la versión del navegador de la aplicación no comience a cargarse hasta que las páginas renderizadas por Universal se hayan cargado por completo.
Actualizacionesapp.module.ts
Se modificó para ejecutar el método estático .withServerTransition
en el archivo importado BrowserModule
. Esto le indica a la versión del navegador de la aplicación que el cliente realizará la transición desde la versión del servidor en algún momento.
Creaserver.ts
Este es el servidor NodeJS Express. Obviamente, no es necesario que utilices exactamente esta configuración de servidor tal como se generó, aunque toma nota de la línea:
server.engine('html', ngExpressEngine({ ... }))
ngExpressEngine
es un contenedor renderModuleFactory
que hace que Universal funcione. Si no usas este server.ts
archivo exacto para tu configuración, al menos copia esta parte e intégrala en la tuya.
Creatsconfig.server.json
Esto le dice al compilador Angular dónde encontrar el módulo de entrada para la aplicación universal.
Creaapp.server.module.ts
Este es el módulo raíz solo para la versión del servidor. Puede ver que importa nuestro AppModule
, así como el ServerModule
from @angular/platform-server
, y arranca de la misma manera AppComponent
que AppModule
. AppServerModule
es el punto de entrada de la aplicación Universal.
Creamain.server.ts
Este nuevo archivo básicamente solo exporta el AppServerModule
, que es el punto de entrada de la versión universal de la aplicación. Volveremos a analizar esto pronto.
Paso 2: Iniciar la aplicación universal
Desde una línea de comandos, ejecute el siguiente comando:
- npm run build:ssr
Y luego ejecuta:
- npm run serve:ssr
Suponiendo que no hayas tenido ningún problema durante el proceso de compilación, abre tu navegador http://localhost:4000
(o cualquier puerto que esté configurado para ti) y deberías ver tu aplicación Universal en acción. No se verá diferente, pero la primera página debería cargarse mucho más rápido que tu aplicación Angular habitual. Si tu aplicación es pequeña y simple, esto puede ser difícil de notar.
Puedes intentar reducir la velocidad de la red abriendo las herramientas de desarrollo de Chrome y, en la pestaña Red, buscando el menú desplegable que dice En línea . Selecciona 3G lento para imitar un dispositivo en una red lenta; deberías ver un buen rendimiento en tu página de destino y en cualquier página enrutada a la que accedas.
Además, intenta ver el código fuente de la página (haz clic derecho en la página y selecciona Ver código fuente de la página ). Verás todo el HTML normal en la body
etiqueta que coincide con lo que se muestra en tu página, lo que significa que un rastreador web puede rastrear tu aplicación de manera significativa. Compara esto con el código fuente de la página de una aplicación que no sea Universal y todo lo que verás en la body
etiqueta es app-root
(o como hayas llamado al selector de tu bootstrap AppComponent
).
Conclusión
En este artículo, aprendió a usar Angular Universal para la renderización del lado del servidor.
Dado que una aplicación universal se ejecuta en el servidor y no en un navegador, hay algunas cosas que debes tener en cuenta en el código de tu aplicación:
- Comprueba el uso que haces de objetos específicos del navegador, como
window
,document
olocation
. Estos no existen en el servidor. De todos modos, no deberías usarlos; intenta usar una abstracción Angular inyectable, comoDocument
oLocation
. Como último recurso, si realmente los necesitas, envuelve su uso en una declaración condicional, de modo que solo los use Angular en el navegador. Puedes hacer esto importando las funcionesisPlatformBrowser
yisPlatformServer
desde@angular/common
, inyectando elPLATFORM_ID
token en tu componente y ejecutando las funciones importadas para ver si estás en el servidor o en el navegador. - Si usas
ElementRef
para obtener un identificador en un elemento HTML, no usesnativeElement
para manipular los atributos del elemento. En su lugar, inyectaRenderer2
y usa uno de los métodos que se encuentran allí . - El manejo de eventos del navegador no funcionará. Su aplicación no responderá a eventos de clic ni a otros eventos del navegador cuando se ejecute en el servidor. Sin embargo, cualquier vínculo generado desde un navegador
routerLink
funcionará para la navegación. - Evite el uso de
setTimeout
, siempre que sea posible. - Hacer que todas las URL de las solicitudes del servidor sean absolutas. Las solicitudes de datos de URL relativas fallarán cuando se ejecuten desde el servidor, incluso si el servidor puede manejar URL relativas.
- De manera similar, la seguridad de las solicitudes HTTP emitidas desde un servidor no es la misma que la de las solicitudes emitidas desde un navegador. Las solicitudes de servidor pueden tener diferentes requisitos y características de seguridad. Deberás gestionar la seguridad de estas solicitudes tú mismo.
Continúe aprendiendo sobre lo que ofrece Angular Universal en la documentación oficial .
Deja una respuesta