Luego de de nuestra extensa recopilación de datos pudimos resolver esta incógnita que suelen tener muchos los lectores. Te regalamos la respuesta y nuestro deseo es que sea de gran apoyo.
Esta guía describe Angular Universal, una tecnología que procesa aplicaciones angulares en el servidor.
Una aplicación Angular normal se ejecuta en el navegador, renderizando páginas en el DOM en respuesta a las acciones del usuario. Angular Universal se ejecuta en el servidor, generando static páginas de la aplicación que luego se inician en el cliente. Esto significa que la aplicación generalmente se procesa más rápidamente, lo que brinda a los usuarios la oportunidad de ver el diseño de la aplicación antes de que se vuelva completamente interactiva.
Para obtener una visión más detallada de las diferentes técnicas y conceptos relacionados con SSR, consulte este artículo.
Puede preparar fácilmente una aplicación para la renderización del lado del servidor utilizando Angular CLI. El esquema de CLI @nguniversal/express-engine
realiza los pasos necesarios, como se describe a continuación.
Nota:Descarga el código de muestra terminado, que se ejecuta en un Node.js® Express servidor.
Tutorial universal
El tutorial Tour of Heroes es la base de este tutorial.
En este ejemplo, Angular CLI compila y agrupa la versión universal de la aplicación con el compilador Ahead-of-Time (AOT). Un servidor web Node.js Express compila páginas HTML con Universal en función de las solicitudes de los clientes.
Para crear el módulo de la aplicación del lado del servidor, app.server.module.ts
, ejecute el siguiente comando CLI.
ng add @nguniversal/express-engine
El comando crea la siguiente estructura de carpetas.
src/ index.html app web page main.ts bootstrapper for client app main.server.ts * bootstrapper for server app style.css styles for the app app/ ... application code app.server.module.ts * server-side application module server.ts * express web server tsconfig.json TypeScript base configuration tsconfig.app.json TypeScript browser application configuration tsconfig.server.json TypeScript server application configuration tsconfig.spec.json TypeScript tests configuration
Los archivos marcados con *
son nuevos y no están en la muestra del tutorial original.
Universal en acción
Para comenzar a renderizar su aplicación con Universal en su sistema local, use el siguiente comando.
npm run dev:ssr
Abra un navegador y navegue hasta http: // localhost: 4200 /. Debería ver la página del panel familiar Tour of Heroes.
Navegación a través de routerLinks
funciona correctamente porque usan el ancla nativa () etiquetas. Puedes ir desde el Panel de control a la página de Héroes y viceversa. Puedes hacer clic en un héroe en la página del Tablero para mostrar su página de Detalles.
Si reduce la velocidad de su red para que los scripts del lado del cliente tarden más en descargarse (instrucciones a continuación), notará:
- Hacer clic en un héroe en la página de Héroes no hace nada.
- No puedes agregar ni eliminar un héroe.
- Se ignora el cuadro de búsqueda en la página del Panel de control.
- los atrás y Ahorrar los botones de la página Detalles no funcionan.
Eventos de usuario distintos de routerLink
los clics no son compatibles. Debe esperar a que la aplicación cliente completa se inicie y se ejecute, o almacene los eventos usando bibliotecas como prearranque, que le permiten reproducir estos eventos una vez que se cargan los scripts del lado del cliente.
La transición de la aplicación renderizada por el servidor a la aplicación cliente ocurre rápidamente en una máquina de desarrollo, pero siempre debe probar sus aplicaciones en escenarios del mundo real.
Puede simular una red más lenta para ver la transición con mayor claridad de la siguiente manera:
- Abra las herramientas de desarrollo de Chrome y vaya a la pestaña Red.
- Encuentra el Limitación de la red menú desplegable en el extremo derecho de la barra de menú.
- Pruebe una de las velocidades “3G”.
La aplicación renderizada por el servidor aún se inicia rápidamente, pero la aplicación cliente completa puede tardar unos segundos en cargarse.
¿Por qué utilizar la representación del lado del servidor?
Hay tres razones principales para crear una versión universal de su aplicación.
- Facilite los rastreadores web a través de optimización de motores de búsqueda (SEO)
- Mejore el rendimiento en dispositivos móviles y de baja potencia
- Muestre la primera página rápidamente con un pintura de primer contenido (FCP)
Facilitar los rastreadores web (SEO)
Google, Bing, Facebook, Twitter y otros sitios de redes sociales dependen de los rastreadores web para indexar el contenido de su aplicación y hacer que ese contenido se pueda buscar en la web. Es posible que estos rastreadores web no puedan navegar e indexar su aplicación Angular altamente interactiva como lo haría un usuario humano.
Angular Universal puede generar un static versión de su aplicación que se puede buscar, enlazar y navegar fácilmente sin JavaScript. Universal también ofrece una vista previa del sitio, ya que cada URL devuelve una página completamente renderizada.
Mejore el rendimiento en dispositivos móviles y de baja potencia
Algunos dispositivos no son compatibles con JavaScript o ejecutan JavaScript tan mal que la experiencia del usuario es inaceptable. Para estos casos, es posible que necesite una versión de la aplicación sin JavaScript, renderizada por el servidor. Esta versión, aunque limitada, puede ser la única alternativa práctica para las personas que de otra manera no podrían usar la aplicación en absoluto.
Muestre la primera página rápidamente
Mostrar la primera página rápidamente puede ser fundamental para la participación del usuario. Las páginas que se cargan más rápido funcionan mejor, incluso con cambios tan pequeños como 100 ms. Es posible que su aplicación deba iniciarse más rápido para atraer a estos usuarios antes de que decidan hacer otra cosa.
Con Angular Universal, puede generar páginas de destino para la aplicación que se parecen a la aplicación completa. Las páginas son HTML puro y pueden mostrarse incluso si JavaScript está desactivado. Las páginas no manejan eventos del navegador, pero hacer apoyar la navegación a través del sitio usando routerLink
.
En la práctica, servirás un static versión de la página de destino para mantener la atención del usuario. Al mismo tiempo, cargará la aplicación Angular completa detrás de ella. El usuario percibe un rendimiento casi instantáneo desde la página de destino y obtiene la experiencia interactiva completa después de que se carga la aplicación completa.
Servidores web universales
Un servidor web universal responde a las solicitudes de la página de la aplicación con static HTML renderizado por el motor de plantilla universal. El servidor recibe y responde a las solicitudes HTTP de los clientes (generalmente navegadores) y sirve static activos como scripts, CSS e imágenes. Puede responder a solicitudes de datos, ya sea directamente o como un proxy a un servidor de datos separado.
El servidor web de muestra para esta guía se basa en el popular Rápido estructura.
Nota:Alguna La tecnología de servidor web puede servir a una aplicación Universal siempre que pueda llamar a Universal
renderModule()
función. Los principios y puntos de decisión discutidos aquí se aplican a cualquier tecnología de servidor web.
Las aplicaciones universales usan Angular platform-server
paquete (a diferencia de platform-browser
), que proporciona implementaciones de servidor del DOM, XMLHttpRequest
y otras funciones de bajo nivel que no dependen de un navegador.
El servidor (Node.js Express en el ejemplo de esta guía) pasa las solicitudes de los clientes para las páginas de la aplicación al NgUniversal ngExpressEngine
. Debajo del capó, esto llama Universal’s renderModule()
función, al tiempo que proporciona almacenamiento en caché y otras utilidades útiles.
los renderModule()
la función toma como entradas un plantilla Página HTML (normalmente index.html
), un Angular módulo que contiene componentes, y un ruta que determina qué componentes mostrar. La ruta proviene de la solicitud del cliente al servidor.
Cada solicitud da como resultado la vista adecuada para la ruta solicitada. los renderModule()
La función renderiza la vista dentro de la
etiqueta de la plantilla, creando una página HTML terminada para el cliente.
Finalmente, el servidor devuelve la página renderizada al cliente.
Trabajando alrededor de las API del navegador
Debido a que una aplicación universal no se ejecuta en el navegador, es posible que falten algunas de las API y capacidades del navegador en el servidor.
Por ejemplo, las aplicaciones del lado del servidor no pueden hacer referencia a objetos globales solo del navegador, como window
, document
, navigator
, o location
.
Angular proporciona algunas abstracciones inyectables sobre estos objetos, como Location
o DOCUMENT
; puede sustituir adecuadamente estas API. Si Angular no lo proporciona, es posible escribir nuevas abstracciones que deleguen a las API del navegador mientras está en el navegador y a una implementación alternativa mientras está en el servidor (también conocido como shimming).
De manera similar, sin eventos de mouse o teclado, una aplicación del lado del servidor no puede depender de que un usuario haga clic en un botón para mostrar un componente. La aplicación debe determinar qué renderizar basándose únicamente en la solicitud entrante del cliente. Este es un buen argumento para hacer que la aplicación sea enrutable.
Motor de plantilla universal
Lo importante en el server.ts
el archivo es el ngExpressEngine()
función.
// Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine) server.engine('html',ngExpressEngine( bootstrap: AppServerModule,));
los ngExpressEngine()
función es un envoltorio alrededor de Universal renderModule()
función que convierte las solicitudes de un cliente en páginas HTML renderizadas por el servidor. Acepta un objeto con las siguientes propiedades:
bootstrap
: La raízNgModule
oNgModule
factory que se utilizará para iniciar la aplicación al renderizar en el servidor. Para la aplicación de ejemplo, esAppServerModule
. Es el puente entre el renderizador universal del lado del servidor y la aplicación Angular.extraProviders
: Esto es opcional y le permite especificar proveedores de dependencia que se aplican solo cuando se procesa la aplicación en el servidor. Puede hacer esto cuando su aplicación necesita información que solo puede determinar la instancia del servidor que se está ejecutando actualmente.
los ngExpressEngine()
la función devuelve un Promise
devolución de llamada que se resuelve en la página renderizada. Depende del motor decidir qué hacer con esa página. Este motor Promise
callback devuelve la página renderizada al servidor web, que luego la reenvía al cliente en la respuesta HTTP.
Nota: Estos envoltorios ayudan a ocultar la complejidad del
renderModule()
función. Hay más envoltorios para diferentes tecnologías de backend en el Repositorio universal.
Filtrado de URL de solicitud
NOTA: El comportamiento básico que se describe a continuación se maneja automáticamente cuando se usa el esquema NgUniversal Express. Esto es útil cuando se intenta comprender el comportamiento subyacente o replicarlo sin utilizar el esquema.
El servidor web debe distinguir solicitudes de la página de la aplicación de otro tipo de solicitudes.
No es tan simple como interceptar una solicitud a la dirección raíz /
. El navegador podría solicitar una de las rutas de la aplicación, como /dashboard
, /heroes
, o /detail:12
. De hecho, si la aplicación solo la procesara el servidor, cada el enlace de la aplicación en el que se haga clic llegará al servidor como una URL de navegación destinado al enrutador.
Afortunadamente, las rutas de las aplicaciones tienen algo en común: sus URL carecen de extensiones de archivo. (Las solicitudes de datos también carecen de extensiones, pero son fáciles de reconocer porque siempre comienzan con /api
.) Todos static las solicitudes de activos tienen una extensión de archivo (como main.js
o /node_modules/zone.js/bundles/zone.umd.js
).
Debido a que usamos el enrutamiento, podemos reconocer fácilmente los tres tipos de solicitudes y manejarlas de manera diferente.
- Solicitud de datos: solicitud de URL que comienza
/api
. - Navegación de la aplicación: URL de solicitud sin extensión de archivo.
- Activo estático: todas las demás solicitudes.
Un servidor Node.js Express es una canalización de middleware que filtra y procesa solicitudes una tras otra. Configura la canalización del servidor Node.js Express con llamadas a server.get()
como este para solicitudes de datos.
// TODO: implement data requests securely server.get('/api/**',(req, res)=> res.status(404).send('data requests are not yet supported'););
Nota: Este servidor de muestra no maneja solicitudes de datos.
El módulo “API web en memoria” del tutorial, una herramienta de demostración y desarrollo, intercepta todas las llamadas HTTP y simula el comportamiento de un servidor de datos remoto. En la práctica, eliminaría ese módulo y registraría su middleware de API web en el servidor aquí.
El siguiente código filtra las URL de solicitud sin extensiones y las trata como solicitudes de navegación.
// All regular routes use the Universal engine server.get('*',(req, res)=> res.render(indexHtml, req, providers:[ provide:APP_BASE_HREF, useValue: req.baseUrl ]););
Servicio static archivos de forma segura
Un solo server.use()
trata todas las demás URL como solicitudes de static activos como JavaScript, imágenes y archivos de estilo.
Para asegurarse de que los clientes solo puedan descargar los archivos que se les permite ver, coloque todos los archivos de activos de cara al cliente en el /dist
carpeta y solo respeta las solicitudes de archivos del /dist
carpeta.
El siguiente código de Node.js Express enruta todas las solicitudes restantes a /dist
y devuelve un 404 - NOT FOUND
error si no se encuentra el archivo.
// Serve static files from /browser server.get('*.*', express.static(distFolder, maxAge:'1y'));
Usar URL absolutas para solicitudes HTTP (datos) en el servidor
El tutorial HeroService
y HeroSearchService
delegar al Angular HttpClient
módulo para obtener datos de la aplicación. Estos servicios envían solicitudes a relativo URL como api/heroes
. En una aplicación renderizada del lado del servidor, las URL HTTP deben ser absoluto (por ejemplo, https://my-server.com/api/heroes
). Esto significa que las URL deben convertirse de alguna manera a absolutas cuando se ejecutan en el servidor y dejarse relativas cuando se ejecutan en el navegador.
Si está utilizando uno de los @nguniversal/*-engine
paquetes (como @nguniversal/express-engine
), esto se soluciona automáticamente. No necesita hacer nada para que las URL relativas funcionen en el servidor.
Si, por alguna razón, no está utilizando un @nguniversal/*-engine
paquete, es posible que deba manejarlo usted mismo.
La solución recomendada es pasar la URL de solicitud completa a la options
argumento de renderModule () o renderModuleFactory () (dependiendo de lo que use para renderizar AppServerModule
en el servidor). Esta opción es la menos intrusiva ya que no requiere ningún cambio en la aplicación. Aquí, “URL de solicitud” se refiere a la URL de la solicitud como respuesta a la que se está procesando la aplicación en el servidor. Por ejemplo, si el cliente solicitó https://my-server.com/dashboard
y está procesando la aplicación en el servidor para responder a esa solicitud, options.url
debe establecerse en https://my-server.com/dashboard
.
Ahora, en cada solicitud HTTP realizada como parte de la representación de la aplicación en el servidor, Angular puede resolver correctamente la URL de la solicitud en una URL absoluta, utilizando el options.url
.
Recuerda que tienes autorización de añadir una estimación acertada si te fue de ayuda.