Angular Universal en la práctica – Cómo construir aplicaciones de una sola página amigables con el SEO con Angular

Se ha hablado mucho de Angular en los últimos meses y de cómo usarlo para construir aplicaciones de cliente, pero una de sus innovaciones más importantes está ocurriendo en realidad en el servidor.

Se trata de una tecnología que podría ayudar a habilitar un tipo completamente nuevo de aplicaciones web: Angular Universal. Conozcamos más sobre ella. Repasemos los siguientes temas:

  • Ventajas de las aplicaciones de una sola página
  • ¿Por qué entonces no usamos aplicaciones de una sola página en todas partes?
  • Entender las implicaciones SEO de una aplicación de una sola página
  • ¿Qué es Angular Universal, qué permite?
  • El renderizado del lado del servidor no es sólo renderizar en el servidor
  • Demostración de una aplicación de una sola página renderizada en el lado del servidor en acción
  • Pre-realización en tiempo de construcción – subir aplicaciones pre-renderizadas a Amazon S3
  • La característica asesina de Angular Universal: Inyección de dependencias
  • Conclusiones

Este post es una introducción a Angular Universal. Para una guía más detallada que cubra cómo utilizarlo en la práctica, echa un vistazo a este post:

Angular Universal: una guía práctica completa

Ventajas de las aplicaciones de una sola página

Las aplicaciones de una sola página llevan tiempo existiendo, y frameworks como Angular, React o Ember son probablemente las librerías Javascript que más atención reciben en el mundo Javascript.

Las ventajas de las SPAs son realmente una sola cosa

Las ventajas de las single page apps son potencialmente muchas:

  • cuando el usuario navega por la página, sólo se reemplazan partes de la misma, lo que hace que la experiencia sea más fluida
  • después de la primera carga de la página, sólo los datos pasan por el cable cuando el usuario navega por la app: JSON se entrega al navegador y se aplica a las plantillas HTML directamente al navegador
  • esto conduce a un mejor rendimiento y abre la posibilidad de que esos servicios de backend se utilicen para otras cosas, ya que sólo devuelven datos

Podemos resumir esto en una sola cosa:

Las Single Page Apps pueden proporcionar una experiencia de usuario mucho mejor

Y la experiencia de usuario es crítica en el mundo de la Internet pública. Hay numerosos estudios que demuestran sin lugar a dudas que la caída de la página y el abandono del usuario aumentan muy rápidamente con el retraso de la página.

Si una página tarda 200ms más en cargar, esto tendrá un alto impacto potencial en el negocio y las ventas (ver esta investigación de Google). Esto es aún más en los dispositivos móviles, donde las aplicaciones tienden a ser más lentas.

¿Por qué no usar SPAs en todas partes entonces?

Dado estas estadísticas y el hecho de que las SPAs dan una experiencia de usuario muy mejorada, ¿por qué no está todo el mundo usando aplicaciones de una sola página para todo?

Han existido durante años, y cualquier sitio web con un sistema de navegación podría beneficiarse de ser construido de esa manera.

Entender las implicaciones SEO de una app de una sola página

Hay una razón principal por la que las apps de una sola página no se usan en todas partes hasta ahora (con dos causas distintas):

Las apps de una sola página no tienen un buen rendimiento en los motores de búsqueda

Las dos razones son:

El motor de búsqueda necesita «adivinar» cuando la página está completa

Cuando se recupera una sola página, un motor de búsqueda sólo verá muy poco HTML. Sólo cuando el framework MVC entra en acción, la página se renderiza por completo utilizando los datos obtenidos del servidor.

El problema es que el motor de búsqueda necesita adivinar cuándo el framework Javascript termina de renderizar la página, por lo que se corre el riesgo de indexar contenido incompleto.

La segunda razón por la que las SPAs no funcionan bien con los motores de búsqueda es:

Los enlaces profundos de las SPAs son difíciles de indexar

Debido a la falta de soporte del Historial de HTML5 en los navegadores, las apps de una sola página basan sus URLs de navegación en anclajes de marcadores HTML (URLs con #, como /home#section1). Estos no son fácilmente indexados como páginas separadas por los motores de búsqueda, hay maneras de hacerlo, pero es un dolor y siempre habrá dificultades para conseguir que esto se indexe correctamente en comparación con el uso de HTML simple.

La conclusión podría ser que no tiene sentido tener el sitio más fácilmente navegable si la forma en que se construye impide tener un buen SEO.

Ahora la buena noticia

¡La buena noticia es que ninguna de estas dos razones son 100% exactas ya! Google ha comenzado a indexar mejor las aplicaciones de una sola página.

Y la reciente desaprobación de IE9 significa que el Historial HTML5 está disponible en casi todas partes, haciendo que el uso de URLs de anclaje ya no sea necesario para las SPAs, podemos simplemente usar URLs simples (como /home/section1).

Estas son grandes noticias, pero hay otros motores de búsqueda que impulsan un tráfico significativo. Baidu, por ejemplo, dirige más de la mitad del tráfico en China (actualmente 1.300 millones de personas).

Además, sigue existiendo el problema del rendimiento: una aplicación de una sola página será más lenta debido a las grandes cantidades de Javascript que necesita y al gran tiempo de inicio, y por lo tanto tendrá un peor rendimiento que una solución basada en HTML.

Y esto significa caídas de la página, este problema no desaparecerá pronto especialmente en los móviles. ¿Hay alguna manera de tener lo mejor de todos los mundos, y obtener tanto la navegación instantánea, la facilidad de SEO y el alto rendimiento en el móvil?

La respuesta es Sí, con Angular Universal.

¿Qué es Angular Universal, qué permite?

En pocas palabras, Angular Universal nos permite construir aplicaciones que tienen tanto el rendimiento como las ventajas de compromiso del usuario de las aplicaciones de una sola página combinadas con la facilidad de SEO de las páginas estáticas.

El renderizado del lado del servidor no es realmente sólo el renderizado en el servidor

Angular Universal tiene varias otras características además de dar una solución para el renderizado de HTML en el servidor. Basándonos en el término «renderizado del lado del servidor», podríamos pensar que lo que hace Angular Universal es similar, por ejemplo, a un lenguaje de plantillas del lado del servidor como Jade. Pero tiene mucha más funcionalidad.

Con Angular Universal, obtienes esa carga útil inicial de HTML renderizada en el servidor, pero también arrancas una versión recortada de Angular en el cliente y a partir de ahí Angular se hace cargo de la página como una app de una sola página, generando a partir de ahí todo el HTML en el cliente en lugar de en el servidor.

Así que el resultado final que obtienes es el mismo, es una aplicación de una sola página que se ejecuta, pero ahora, debido a que obtuviste la carga útil HTML inicial del servidor, obtienes un tiempo de inicio mucho mejor y también una aplicación totalmente indexable por SEO.

Perfeccionamiento en tiempo de construcción – subir aplicaciones pre-renderizadas a Amazon S3

Otra posibilidad que abre Angular Universal es el pre-perfeccionamiento de contenido que no cambia frecuentemente en tiempo de construcción. Esto será posible utilizando los plugins Grunt, Gulp o Weppack. Así será una configuración de Gulp que pre-renderice el contenido de nuestra aplicación a un archivo:

Y luego simplemente subirlo a un bucket de Amazon S3 usando el CLI de Amazon:

Si enlazamos este bucket a una distribución CDN de Cloudfront, tenemos un sitio web muy asequible y escalable.

¿Qué pasa si el usuario empieza a interactuar con la página inmediatamente?

Hay un desfase inicial entre el momento en que el HTML plano se renderiza y se presenta al usuario y el momento en que Angular entra en acción en el lado del cliente y toma el control como SPA.

En ese lapso de tiempo, el usuario podría hacer clic en algo o incluso empezar a escribir en una caja de búsqueda. Lo que Angular Universal permite a través de su funcionalidad de prearranque es grabar los eventos que el usuario está desencadenando, y reproducirlos una vez que Angular arranca.

De esta manera Angular será capaz de responder a esos eventos, como por ejemplo mostrando los resultados de la búsqueda en una lista Typeahead.

¿Pero cómo se ve esto en el servidor en términos de código?

Cómo renderizar HTML con Angular en el servidor

La forma en que se renderiza el contenido en el servidor es usando el motor de renderizado Express Angular Universal expressEngine :

También hay un motor Hapi disponible si prefieres usar Hapi en lugar de Express. También hay motores de renderizado de servidor que están saliendo para todo tipo de plataformas: C#, Java, PHP, ver este post anterior para más detalles.

¿Cómo empezar con Angular Universal?

El mejor lugar para empezar es el starter oficial universal-starter, con el starter obtenemos una aplicación en funcionamiento que incluye un servidor express con renderizado del lado del servidor funcionando out of the box.

Lo innovador de Angular Universal es su simplicidad de uso. Una de las principales características de diseño de Angular Universal es la forma en que utiliza la inyección de dependencias.

El desarrollo de la renderización del lado del servidor no es como codificar sólo para el cliente

La mayoría de las veces queremos que nuestra aplicación haga exactamente lo mismo en el servidor que en el cliente, al no depender directamente de las API del navegador.

La realidad del desarrollo del renderizado del lado del servidor es que eso no siempre es posible, y hay ciertas cosas que queremos hacer de forma diferente en el cliente y en el servidor.

Tomemos como ejemplo el renderizado de un gráfico: probablemente queramos llamar a una librería de terceros que utilice SVG. No podemos llamarla en el servidor, así que ¿cómo la renderizamos?

Otro ejemplo, ¿cómo podemos renderizar páginas autenticadas? Porque el contenido depende de quién está conectado en ese momento.

Using Dependency Injection to implement Authentication

Para manejar la autenticación, esta es una forma de hacerlo:

  • En el cliente queremos que la identidad del usuario se tome de un token disponible en una cookie o en el almacenamiento local del navegador.

  • En el servidor, mientras se procesa la solicitud, queremos que el token de identidad se lea de una cabecera de solicitud HTTP.

¿Cómo tener la misma salida de página mientras se navega a esa página en el cliente a través de una transición del router vs en el servidor a través de un refresco del navegador?

Primero definimos una interfaz de Servicio

El primer paso es definir una interfaz que su servicio proporcionará, que es independiente del tiempo de ejecución:

Luego proporcionamos dos implementaciones para esta interfaz, una para el cliente y otra para el servidor. Por ejemplo, en el servidor no hay ninguna ocasión para llamar al método de inicio de sesión, por lo que lanzamos un error:

Mientras que en el cliente, vamos a activar la pantalla de bloqueo Auth0 (una biblioteca de terceros sólo para el navegador) para proporcionar un formulario de inicio de sesión:

Entonces inyectamos diferentes implementaciones de la interfaz en el servidor y en el cliente, para el mismo token de inyección:

Y así es como podemos hacer algo diferente en el cliente y en el servidor en Angular Universal, aprovechando el contenedor de inyección de dependencias de Angular.

De hecho, Angular Universal se construye también utilizando esta noción: por ejemplo, la forma en que se renderiza el HTML es, en lugar de inyectar un renderizador de DOM mientras se arranca el framework, inyecta un renderizador de servidor que genera HTML utilizando la librería de serialización de HTML parse5.

Conclusiones

Como cualquier tecnología, las ventajas del renderizado del lado del servidor evolucionarán con el tiempo. Pero ahora mismo, el renderizado del lado del servidor presenta una gran ventaja para construir aplicaciones amigables con el móvil y con los motores de búsqueda que tienen un alto compromiso con el usuario debido a la navegación instantánea sin problemas.

Hoy en día es más fácil que nunca construir este tipo de aplicaciones utilizando Angular Universal y el starter universal.

Con Angular Universal el uso de la inyección de dependencias hace que sea muy sencillo hacer algo ligeramente diferente en el servidor que en el cliente si lo necesitamos.

Cómo empezar con Angular

Si quieres aprender más sobre Angular, echa un vistazo al Curso de Angular para principiantes:

Otros posts sobre Angular

Si te ha gustado este post, aquí otros posts populares de nuestro blog:

  • Router Angular – Cómo construir un menú de navegación con Bootstrap 4 y rutas anidadas
  • Router Angular – Visita guiada ampliada, Evitar errores comunes
  • Componentes de Angular – Los fundamentos
  • Cómo ejecutar Angular en producción hoy
  • Cómo construir aplicaciones de Angular usando Servicios de Datos Observables – Errores a evitar
  • Introducción a los Formularios de Angular – Dirigidos por Plantilla, Model Driven o In-Between
  • Angular ngFor – Aprende todas las características incluyendo trackBy, ¿por qué no es sólo para Arrays?
  • Angular Universal en la práctica – Cómo construir aplicaciones de una sola página amigables con el SEO con Angular
  • ¿Cómo funciona realmente la detección de cambios de Angular?

Leave a Reply