Single-page application

Una single-page application (SPA), o aplicación de página única, es una aplicación web ó un sitio web que cabe en una sola página con el propósito de dar una experiencia más fluida a los usuarios, como si fuera una aplicación de escritorio. En un SPA todos los códigos de HTML, JavaScript, y CSS se cargan una sola vez[1], los recursos necesarios se cargan dinámicamente cuando lo requiera la página, normalmente como respuesta a las acciones del usuario. La página no tiene que cargarse de nuevo en ningún punto del proceso y tampoco es necesario transferir a otra página las peticiones, aunque las tecnologías modernas (como el pushState() API del HTML5) permiten la navegabilidad en páginas lógicas dentro de la aplicación. La interacción con las aplicaciones de página única pueden involucrar comunicaciones dinámicas con el servidor web que está detrás.

Historia

El término single-page application fue utilizado por Steve Yen en 2005, aunque el concepto ya había sido discutido en el año 2003.[2] Stuart Morris escribió una página web de página única slashdotslash.com que tenía las mismas metas y funciones en el año 2002[3] En el mismo año Lucas Birdeau, Kevin Hakman, Michael Peachey y Evan Yeh describieron las implementaciones de aplicaciones de página única en la patente estadounidense 8,136,109.[4]

Los navegadores modernos que pueden parsear HTML5 permiten a los desarrolladores cambiar la Interfaz del usuario y las aplicaciones lógicas de los servidores hacia los clientes. Bibliotecas de código abierto soportan la creación de un SPA sin forzar al desarrollador entrar a lo profundo de JavaScript y pelearse con los problemas de la tecnología.

Técnicas

Existen varias técnicas que están disponibles y que pueden hacer que el navegador retenga en una sola página una aplicación que requiere comunicación con el servidor.

Frameworks de JavaScript

Frameworks de JavaScript para los navegadores web como AngularJS, Ember.js, Meteor.js, ExtJS y React han adoptado los principios de SPA.

  • AngularJS es una biblioteca del lado de cliente. AngularJS tiene templates que se basan en la tecnología de bidirectional UI data binding. Data binding es una forma automática de actualizar a la vista cuando el modelo cambia, así como actualizaciones al modelo cuando la vista cambia. El template de HTML está compilado en el navegador. Los pasos de la compilación crean un HTML puro, el cual el navegador lo interpreta y muestra. Los pasos se repiten para las vistas de las páginas subsecuentes. En la programación tradicional, donde se hace todo en el lado del servidor, los conceptos como controlador e interacción de modelo producen nuevas vistas de HTML desde el servidor. Dentro del framework AngularJS, el controlador y el modelo se mantienen dentro del navegador del cliente. Así haciendo que nuevas páginas puedan ser generadas sin interacción alguna con el servidor.
  • Ember.js es un framework de JavaScript ejecutado del lado de cliente y se basa en la arquitectura Modelo-vista-controlador. Permite a los desarrolladores crear SPA´s escalables incorporando las mejores prácticas que proveen Objetos de modelo, data-binding bidirecional y propiedades calculadas, templates de actualización automática que están impulsados por Handlebars.js, y un manejador del estado de la aplicación.
  • Vue.js Vue (pronunciado /vjuː/ en inglés, como view) es un framework progresivo para construir interfaces de usuario. A diferencia de otros frameworks monolíticos, Vue está diseñado desde el inicio para ser adoptado incrementalmente.
  • Meteor.js es un framework de JavaScript que se ejecuta de ambos lados(Full-Stack) especialmente para SPA's. Tiene funcionalidades más simples de data binding que Angular, Ember o ReactJS,[5] y usa el protocolo de datos distribuidos[6] y un patrón de publicación-suscripción para propagar los cambios de datos a los clientes en tiempo real, sin tener que obligar a los desarrolladores a escribir ningún código de sincronización. La reactividad Full-Stack asegura que todas las capas de la base de datos, se actualicen automáticamente cuando sea necesario. Paquetes de ecosistema como Server Side Rendering[7] resuelven el problema de Optimización de motor de Búsqueda.

AJAX

La técnica más prominente que se está utilizando es asynchronous JavaScript and XML (Ajax).[1] Predomina el uso del objeto XMLHttpRequest de JavaScript, otras aplicaciones de AJAX incluyen el uso de IFRAME o elementos de script HTML. Bibliotecas populares como jQuery, normalizan el comportamiento de AJAX entre diferentes navegadores y productores, haciendo que Ajax se haga más popular. [8]

Websockets

WebSockets son tecnologías de comunicación en tiempo real entre el cliente y el servidor y forma parte de la especificación de HTML5. Es superior a AJAX en términos de rendimiento y simplicidad.[7]

Plugins de navegadores

Aunque este método es antiguo, las llamadas asíncronas al servidor también pueden ser logrados utilizando tecnologías de los plug-ins de los navegadores com Silverlight, Flash, o Java applets.

Transporte de datos (XML, JSON y AJAX)

Las peticiones a los servidores normalmente resultan en datos crudos (XML o JSON), o son HTMLs nuevos que están siendo regresados. En los casos donde el HTML regresa como resultado, JavaScript en el cliente actualiza el área parcial de DOM (Document Object Model). Cuando el dato crudo es regresado, el JavaScript de lado del cliente procesa el XML o el JSON para hacer la traducción de los datos crudos a un HTML la cual es usada para actualizar la información del área parcial del DOM.

Arquitectura de servidor ligero

Un SPA se mueve lógicamente del servidor al cliente. Esto resulta en el rol del servidor web evolucionando en un servicio Web o un API de datos. Este cambio arquitectónico ha sido llamado como "Arquitectura de Servidor Delgado" para remarcar que la complejidad ha sido trasladado del servidor a los clientes, con el argumento de que esto reduce la complejidad del sistema.

Arquitectura de servidor pesado en estados

El servidor sigue la memoria del estado de los clientes en la página. De esta forma, cuando llega una petición al servidor, los servidores mandan el HTML adecuado y con los cambios concretos hacia los clientes para que puedan transicionar al estado correspondiente (normalmente agregando/borrando/actualizando parte del DOM del cliente). Al mismo tiempo, el servidor de estados se actualiza. La mayor parte de la lógica se ejecuta en el servidor y el HTML también es procesado en el servidor. En algunos casos, el servidor simula el navegador web, recibiendo eventos y realizando cambios delta en el estado del servidor la cual se propaga automáticamente hacia el cliente.

Este enfoque necesita más memoria del servidor y procesamiento del servidor, pero la ventaja es que el modelo de desarrollo es simple porque a) la aplicación está completamente codificado en el servidor, y b) los datos y el estado en el servidor están almacenados en el mismo espacio de la memoria sin que sean necesarios los puentes de comunicación entre el servidor y el cliente.

Arquitectura de servidor pesado sin estados

Es el variante del servidor de estados. En este caso, el cliente envía los datos que representa el estado al servidor, usualmente a través de peticiones de AJAX. Usando estos datos, el servidor puede reconstruir el estado del cliente y determinar la parte de la página que necesita ser modificado, lo genera con los datos necesarios la cual es enviado de vuelta al cliente para que pueda transicionar a otro estado, modificando el árbol de DOM según el acción del cliente que activó la petición.

Este enfoque requiere que se envíe más información al servidor y puede requerir más recursos computacionales por petición para poder reconstruir parcial o completamente la página del cliente en el servidor. Al mismo tiempo, este enfoque es más escalable porque no hay páginas de cliente que se almacenen en el servidor, por lo tanto las peticiones AJAX pueden transferirse a otro nodo del servidor sin la necesidad de compartir los datos de la sesión.

Ejecución local

Algunos SPA's pueden ejecutarse utilizando los archivos locales a través del esquema URI. Esto permite a los usuarios descargar un SPA del servidor y ejecutar el archivo desde un almacenamiento local, sin tener que depender de la conectividad al servidor. Si algún SPA requiere guardar y actualizar los datos, debe utilizar almacenamiento web, el cual está basado en los navegadores; Estas aplicaciones se beneficiaron con los avances de HTML5 respecto a este.[9]

Retos en el modelo SPA

Como el SPA es una evolución lejos del modelo "stateless page-redraw" en la cual se basaron para diseñar a los navegadores, algunos cambios han surgido. Cada uno de estos problemas tiene una solución efectiva[10] con:

  • Bibliotecas JavaScript de clientes
  • Frameworks de lado del servidor que se especializan en el modelo SPA[11][12][13]
  • La evolución de los navegadores y el especificaciones de HTML5 que señalan el modelo de SPA[14]

Optimización de motor de búsqueda

Por la falta de ejecución de JavaScript en los crawlers de los motores de Búsqueda populares[15][16] SEO (Search engine optimization) ha tenido problemas para páginas públicas que adoptaron el modelo SPA.[17]

Google hace el crawling de los URLs que contienen fragmentos de hash empezando por#!.[18] Esto permite el uso de fragmentos de hash dentro de un solo URL de un SPA. Los comportamientos especiales deben ser implementados por el sitio de SPA para permitir la extracción de metadatos relevantes para el crawler del motor de la búsqueda. Para algunos motores de búsqueda que no soportan la esquema de hash en URL, los URL en hash del SPA permanecen invisibles.

Alternativamente, las aplicaciones pueden procesar la primera página durante el cargado en el servidor y las actualizaciones subsecuentes en el cliente. Esto es tradicionalmente difícil, porque el código de rendering podría tener que ser escrito en otro lenguaje o framework en el servidor y en el cliente. Usando plantillas sin lógica o usando la compilación cruzada de un lenguaje a otro, o usando el mismo lenguaje en el servidor y en el cliente podría ayudar a incrementar la cantidad de código que puede ser compartido.

Como la compatibilidad de SEO no es trivial en los SPAs, no es conveniente utilizar SPAs en los contextos en donde la indexación para los motores de búsqueda son un requisito. Los casos de uso incluyen aplicaciones que manejan datos privados y escondidos atrás de un sistema de autentificación. En los casos en donde estas aplicaciones son productos de consumidores, se utilizan modelos como "redibujado de página" como en las páginas de publicidad donde suficiente metadato de la aplicación aparece en el motor de búsqueda. Blogs, foros de soporte, y otros artefactos de redibujado también se juntan alrededor del SPA donde los motores puedan hacer búsquedas con los términos relevantes.

Otro enfoque utilizado por los servidores de framwork Server-centric que es como ItsNat que se basa en Java para el render de los hypertextos en el servidor utilizando la misma tecnología de lenguaje y plantilla. En el enfoque, el servidor conoce con precisión el estado de DOM del cliente, y cualquier cambio o actualización requerida es generado en el servidor y luego transportado por AJAX, el mismo JavaScript cambia de estado al cliente ejecutando los métodos de DOM. Los desarrolladores pueden decidir en qué estados de página son capaces de ser leídos por el crawler para el SEO y deben poder generar el estado requerido en tiempo de cargado y en HTML en lugar de JavaScript. En casos de ItsNat, esto es automático ya que ItsNat mantiene el árbol de DOM del cliente en el servidor como W3C DOM de Java; y procesando el árbol en el servidor genera HTML plano en tiempo de cargado y los DOMs para las peticiones de AJAX. Esta dualidad es muy importante para SEO porque los desarrolladores pueden construir con el mismo código de Java y plantillas basados en HTML en el servidor; en el tiempo de cargado, el HTML convencional es generado por ItsNat haciendo que el DOM sea compatible con SEO. Desde la versión 1.3,[19] ItsNat provee un modo sin estados, en donde el DOM del cliente no se almacena en el servidor, ya que en ese modo el DOM del estado es parcialmente o completamente reconstruido en el servidor cuando se procesan las peticiones AJAX y requiere que el cliente envíe los datos completos de DOM de su estado; el modo sin estados también puede ser compatible con SEO porque esa compatibilidad sucede en el tiempo de cargado de la página inicial sin haber sido afectado por los modos de estado.

Hay varias alternativas para hacer que la página sea capaz de crawling. Ellas involucran la creación de páginas HTML separadas que hagan el espejo de los contenidos de SPA. El servidor podría crear una versión basada en HTML del sitio y entregarlo a los crawlers, o también es posible usar un navegador sin cabeza como PhantomJS para ejecutar aplicaciones de JavaScript y mostrar el resultado en HTML.

Ambas técnicas requieren de trabajos manuales y pueden terminar siendo un dolor de cabeza para el mantenimiento de las páginas complejas. También hay varias trampas de SEO. si el HTML generado del servidor es muy diferente al SPA del contenido, entonces la página será penalizado. Corriendo PhantomJS para mostrar el HTML puede alentar la velocidad de la respuesta de las páginas la cual los motores de búsqueda, en especial Google, lo baja del ranking.[20]

Partición de código cliente/servidor

Una forma de incrementar la cantidad de código que deben ser compartidos entre los servidores y los clientes es usar las plantillas sin lógica como Mustache o Handlebars. Estas plantillas pueden interpretarse en lenguajes diferentes, como Ruby en el servidor y JavaScript en el cliente, aunque para compartir las plantillas se necesita duplicar la lógica de negocio utilizada para elegir las plantillas correctas y llenarlas con datos. Interpretar esas plantillas puede impactar negativamente en rendimiento cuando solamente se está actualizando una pequeña parte de la página, así como un valor de la entrada de texto dentro de una plantilla muy grande. Reemplazar una plantilla completa también podría molestar la selección del usuario o la posición del cursor, mientras que solamente actualizar el dato no lo afectaría. Para evitar estos problemas las aplicaciones utilizan data binding o manipulación granular del DOM para solamente actualizar las partes apropiadas de la página en lugar de redibujar toda la plantilla.

Historial del navegador

Por la propia definición del SPA, una aplicación de página única rompe el diseño de los navegadores que utiliza los botones adelante/atrás. Esto presenta un obstáculo en la usabilidad cuando el usuario aprieta el botón de atrás, se estaría esperando la pantalla anterior de SPA pero en lugar de eso abriría la página anterior al que accedió antes de entrar a la aplicación SPA.

La solución tradicional para SPA ha sido cambiar el URL del navegador con el hash que identifica el fragmento de acuerdo al estado actual de la pantalla. Esto puede ser logrado a través de JavaScript, y causa que se construyan eventos en el historial de URL del navegador. Mientras que SPA sea capaz de redibujar la misma pantalla con la información contenida en el hash del URL el comportamiento esperado se mantiene.

Para resolver esto de otra forma, las especificaciones de HTML5 introdujeron los métodos pushState y replaceState que proveen un acceso programático al URL actual y al historial del navegador.

Analíticas

Las herramientas de análisis como Google Analytics dependen mucho de las páginas que se cargan en un navegador iniciado por un cambio de URL. En un SPA, después de que la primera página se carga, la aplicación pasa a manejar internamente todas las páginas siguientes y los cambios en el contenido, así que el navegador nunca activa una recarga completa de la página, ni se agregan entradas a la historia del navegador. Es por ello que la herramienta de análisis en cuestión no tiene ni idea de quién está haciendo qué en esa página.

Añadir cargas de página en un SPA

Es posible agregar los eventos de carga a un sitio SPA utilizando las funciones de historial de HTML5; esto ayuda a integrar las analíticas. La dificultad está en manejarlos y asegurar que todo sea rastreado con precisión. Esto involucra revisar reportes faltantes y entradas dobles. La buena noticia es que no hay necesidad de construir todo desde cero. Hay varias integraciones de analíticas de código abierto para Angular que están disponibles en la red, localizando la mayoría de los proveedores de analíticas. Los desarrolladores deben integrarlos en la aplicación y asegurarse de que todo esté funcionando correctamente, pero no hay necesidad de empezar todo de cero.[20]

Velocidad de carga inicial

Los SPAs tiene una velocidad de carga más lenta que las aplicaciones basadas en el servidor. Esto es porque la primera descarga tiene de traer a todos los frameworks y el código de la aplicación antes de dibujar lo que se requiere para el navegador de HTML. Una aplicación basada en el servidor solamente necesita enviar el HTML que se requiere al navegador, reduciendo la latencia y el tiempo de descarga.

Incrementando la velocidad de carga inicial

Hay varias formas de incrementar la velocidad de un SPA, así como módulos de lazy-loading que los descarga cuando se necesita. Pero no es posible alejarse del hecho que los SPAs tienen que descargar los frameworks, el código de la aplicación y probablemente el API para los datos antes de mostrar algo en el navegador.[20] Esto es algo así como el escenario de "Págame ahora o págame después". La pregunta del rendimiento y el tiempo de espera permanece en la decisión del desarrollador.

Ciclo de vida de la página

Un SPA se carga completo durante el cargado de la página inicial y luego las regiones se reemplazan o se actualizan con los fragmentos de las nuevas páginas según petición del servidor. Para evitar descargas excesivas de características inutilizadas, un SPA descarga progresivamente las características cuando se necesiten, pueden ser fragmentos de las páginas o módulos completos de la pantalla.

De esta forma existe una analogía entre los "estados" de un SPA y las "páginas" de un sitio web tradicional. Como la navegación de estados en la misma página es análogo a la navegación de las páginas, en teoría, cualquier página de sitio web podría convertirse a un sitio de página única reemplazando las páginas solamente en las partes donde se generen un cambio. El enfoque de SPA en la página web es similar a Single Document Interface (SDI), que es una técnica para las aplicaciones de escritorio.

Referencias

  1. Flanagan, David, "JavaScript - The Definitive Guide", 5th ed., O'Reilly, Sebastopol, CA, 2006, p.497
  2. «Inner-Browsing: Extending Web Browsing the Navigation Paradigm». Archivado desde el original el 27 de marzo de 2014. Consultado el 3 de febrero de 2011.
  3. «Slashdotslash.com: A self contained website using DHTML». Consultado el 6 de julio de 2012.
  4. «US patent 8,136,109». Consultado el 12 de abril de 2002.
  5. «Meteor Blaze». Archivado desde el original el 5 de diciembre de 2020. Consultado el 24 de abril de 2015. «Meteor Blaze is a powerful library for creating live-updating user interfaces. Blaze fulfills the same purpose as Angular, Backbone, Ember, React, Polymer, or Knockout, but is much easier to use. We built it because we thought that other libraries made user interface programming unnecessarily difficult and confusing. »
  6. Introducing DDP Archivado el 9 de febrero de 2015 en Wayback Machine., March 21, 2012
  7. «Server Side Rendering for Meteor». Archivado desde el original el 20 de marzo de 2015. Consultado el 31 de enero de 2015.
  8. Alex, Peter. «App Monetization Platform». Consultado el 8 de septiembre de 2021.
  9. «Unhosted web apps».
  10. «The Single Page Interface Manifesto». Consultado el 25 de abril de 2014.
  11. «Derby». Consultado el 11 de diciembre de 2011.
  12. «Sails.js». Consultado el 20 de febrero de 2013.
  13. «Tutorial: Single Page Interface Web Site With ItsNat». Consultado el 13 de enero de 2011.
  14. HTML5
  15. Michael Mikowski. «How to optimize single page sites for search engines». Consultado el 6 de enero de 2014. «When Google and other search engines index websites, they don’t execute JavaScript ».
  16. «What the user sees, what the crawler sees». Consultado el 6 de enero de 2014. «the browser can execute JavaScript and produce content on the fly - the crawler cannot ».
  17. «Making AJAX Applications Crawlable». Consultado el 6 de enero de 2014. «Historically, AJAX applications have been difficult for search engines to process because AJAX content is produced ».
  18. «Making AJAX Applications Crawlable». Consultado el 13 de enero de 2011.
  19. «ItsNat v1.3 release Notes». Consultado el 9 de junio de 2013.
  20. Holmes, Simone (2015). Getting MEAN with Mongo, Express, Angular, and Node. Manning Publications. ISBN 978-1-6172-9203-3

Enlaces externos

Este artículo ha sido escrito por Wikipedia. El texto está disponible bajo la licencia Creative Commons - Atribución - CompartirIgual. Pueden aplicarse cláusulas adicionales a los archivos multimedia.