Single-page application

Last updated

A single-page application (SPA) is a web application or website that interacts with the user by dynamically rewriting the current web page with new data from the web server, instead of the default method of a web browser loading entire new pages. The goal is faster transitions that make the website feel more like a native app.

Contents

In a SPA, a page refresh never occurs; instead, all necessary HTML, JavaScript, and CSS code is either retrieved by the browser with a single page load, [1] or the appropriate resources are dynamically loaded and added to the page as necessary, usually in response to user actions.

History

The origins of the term single-page application are unclear, though the concept was discussed at least as early as 2003 by technology evangelists from Netscape. [2] Stuart Morris, a programming student at Cardiff University, Wales, wrote the self-contained website at slashdotslash.com with the same goals and functions in April 2002, [3] and later the same year Lucas Birdeau, Kevin Hakman, Michael Peachey and Clifford Yeh described a single-page application implementation in US patent 8,136,109. [4] Earlier forms were called rich web applications.

JavaScript can be used in a web browser to display the user interface (UI), run application logic, and communicate with a web server. Mature free libraries are available that support the building of a SPA, reducing the amount of JavaScript code developers have to write.

Technical approaches

There are various techniques available that enable the browser to retain a single page even when the application requires server communication.

Document hashes

HTML authors can leverage element IDs to show or hide different sections of the HTML document. Then, using CSS, authors can use the :target pseudo-class selector to only show the section of the page which the browser navigated to.

JavaScript frameworks

Web browser JavaScript frameworks and libraries, such as AngularJS, Ember.js, ExtJS, Knockout.js, Meteor.js, React, Vue.js, and Svelte have adopted SPA principles. Aside from ExtJS, all of these are free.

Ajax

As of 2006, the most prominent technique used was Ajax. [1] Ajax involves using asynchronous requests to a server for XML or JSON data, such as with JavaScript's XMLHttpRequest or more modern fetch() (since 2017), or the deprecated ActiveX Object. In contrast to the declarative approach of most SPA frameworks, with Ajax the website directly uses JavaScript or a JavaScript library such as jQuery to manipulate the DOM and edit HTML elements. Ajax has further been popularized by libraries like jQuery, which provides a simpler syntax and normalizes Ajax behavior across different browsers which historically had varying behavior.

WebSockets

WebSockets are a bidirectional real-time client-server communication technology that are part of the HTML specification. For real-time communication, their use is superior to Ajax in terms of performance [9] and simplicity.

Server-sent events

Server-sent events (SSEs) is a technique whereby servers can initiate data transmission to browser clients. Once an initial connection has been established, an event stream remains open until closed by the client. SSEs are sent over traditional HTTP and have a variety of features that WebSockets lack by design such as automatic reconnection, event IDs, and the ability to send arbitrary events. [10]

Browser plugins

Although this method is outdated, asynchronous calls to the server may also be achieved using browser plug-in technologies such as Silverlight, Flash, or Java applets.

Data transport (XML, JSON and Ajax)

Requests to the server typically result in either raw data (e.g., XML or JSON), or new HTML being returned. In the case where HTML is returned by the server, JavaScript on the client updates a partial area of the DOM (Document Object Model). When raw data is returned, often a client-side JavaScript XML / (XSL) process (and in the case of JSON a template) is used to translate the raw data into HTML, which is then used to update a partial area of the DOM.

Server architecture

Thin server architecture

A SPA moves logic from the server to the client, with the role of the web server evolving into a pure data API or web service. This architectural shift has, in some circles, been coined "Thin Server Architecture" to highlight that complexity has been moved from the server to the client, with the argument that this ultimately reduces overall complexity of the system.

Thick stateful server architecture

The server keeps the necessary state in memory of the client state of the page. In this way, when any request hits the server (usually user actions), the server sends the appropriate HTML and/or JavaScript with the concrete changes to bring the client to the new desired state (usually adding/deleting/updating a part of the client DOM). At the same time, the state in server is updated. Most of the logic is executed on the server, and HTML is usually also rendered on the server. In some ways, the server simulates a web browser, receiving events and performing delta changes in server state which are automatically propagated to client.

This approach needs more server memory and server processing, but the advantage is a simplified development model because a) the application is usually fully coded in the server, and b) data and UI state in the server are shared in the same memory space with no need for custom client/server communication bridges.

Thick stateless server architecture

This is a variant of the stateful server approach. The client page sends data representing its current state to the server, usually through Ajax requests. Using this data, the server is able to reconstruct the client state of the part of the page which needs to be modified and can generate the necessary data or code (for instance, as JSON or JavaScript), which is returned to the client to bring it to a new state, usually modifying the page DOM tree according to the client action that motivated the request.

This approach requires that more data be sent to the server and may require more computational resources per request to partially or fully reconstruct the client page state in the server. At the same time, this approach is more easily scalable because there is no per-client page data kept in the server and, therefore, Ajax requests can be dispatched to different server nodes with no need for session data sharing or server affinity.

Running locally

Some SPAs may be executed from a local file using the file URI scheme. This gives users the ability to download the SPA from a server and run the file from a local storage device, without depending on server connectivity. If such a SPA wants to store and update data, it must use browser-based Web Storage. These applications benefit from advances available with HTML. [11]

Challenges with the SPA model

Because the SPA is an evolution away from the stateless page-redraw model that browsers were originally designed for, some new challenges have emerged. Possible solutions (of varying complexity, comprehensiveness, and author control) include: [12]

Search-engine optimization

Because of the lack of JavaScript execution on crawlers of some popular Web search engines, [17] SEO (search engine optimization) has historically presented a problem for public facing websites wishing to adopt the SPA model. [18]

Between 2009 and 2015, Google Webmaster Central proposed and then recommended an "AJAX crawling scheme" [19] [20] using an initial exclamation mark in fragment identifiers for stateful AJAX pages (#!). Special behavior must be implemented by the SPA site to allow extraction of relevant metadata by the search engine's crawler. For search engines that do not support this URL hash scheme, the hashed URLs of the SPA remain invisible. These "hash-bang" URIs have been considered problematic by a number of writers including Jeni Tennison at the W3C because they make pages inaccessible to those who do not have JavaScript activated in their browser. They also break HTTP referer headers as browsers are not allowed to send the fragment identifier in the Referer header. [21] In 2015, Google deprecated their hash-bang AJAX crawling proposal. [22]

Alternatively, applications may render the first page load on the server and subsequent page updates on the client. This is traditionally difficult, because the rendering code might need to be written in a different language or framework on the server and in the client. Using logic-less templates, cross-compiling from one language to another, or using the same language on the server and the client may help to increase the amount of code that can be shared.

In 2018, Google introduced dynamic rendering as another option for sites wishing to offer crawlers a non-JavaScript heavy version of a page for indexing purposes. [23] Dynamic rendering switches between a version of a page that is rendered client-side and a pre-rendered version for specific user agents. This approach involves your web server detecting crawlers (via the user agent) and routing them to a renderer, from which they are then served a simpler version of HTML content.

Because SEO compatibility is not trivial in SPAs, it is worth noting that SPAs are commonly not used in a context where search engine indexing is either a requirement, or desirable. Use cases include applications that surface private data hidden behind an authentication system. In the cases where these applications are consumer products, often a classic "page redraw" model is used for the applications landing page and marketing site, which provides enough meta data for the application to appear as a hit in a search engine query. Blogs, support forums, and other traditional page redraw artifacts often sit around the SPA that can seed search engines with relevant terms.

As of 2021 and Google specifically, SEO compatibility for a plain SPA is straightforward and requires just a few simple conditions to be met. [24]

One way to increase the amount of code that can be shared between servers and clients is to use a logic-less template language like Mustache or Handlebars. Such templates can be rendered from different host languages, such as Ruby on the server and JavaScript in the client. However, merely sharing templates typically requires duplication of business logic used to choose the correct templates and populate them with data. Rendering from templates may have negative performance effects when only updating a small portion of the page—such as the value of a text input within a large template. Replacing an entire template might also disturb a user's selection or cursor position, where updating only the changed value might not. To avoid these problems, applications can use UI data bindings or granular DOM manipulation to only update the appropriate parts of the page instead of re-rendering entire templates. [25]

Browser history

With a SPA being, by definition, "a single page", the model breaks the browser's design for page history navigation using the "forward" or "back" buttons. This presents a usability impediment when a user presses the back button, expecting the previous screen state within the SPA, but instead, the application's single page unloads and the previous page in the browser's history is presented.

The traditional solution for SPAs has been to change the browser URL's hash fragment identifier in accord with the current screen state. This can be achieved with JavaScript, and causes URL history events to be built up within the browser. As long as the SPA is capable of resurrecting the same screen state from information contained within the URL hash, the expected back-button behavior is retained.

To further address this issue, the HTML specification has introduced pushState and replaceState providing programmatic access to the actual URL and browser history.

Analytics

Analytics tools such as Google Analytics rely heavily upon entire new pages loading in the browser, initiated by a new page load. SPAs do not work this way.

After the first page load, all subsequent page and content changes are handled internally by the application, which should simply call a function to update the analytics package. Failing to call such a function, the browser never triggers a new page load, nothing gets added to the browser history, and the analytics package has no idea who is doing what on the site.

Security scanning

Similarly to the problems encountered with search engine crawlers, DAST tools may struggle with these JavaScript-rich applications. Problems can include the lack of hypertext links, memory usage concerns and resources loaded by the SPA typically being made available by an Application Programming Interface or API. Single-page applications are still subject to the same security risks as traditional web pages such as Cross-Site Scripting (XSS), but also a host of other unique vulnerabilities such as data exposure via API and client-side logic and client-side enforcement of server-side security. [26] In order to effectively scan a single-page application, a DAST scanner must be able to navigate the client-side application in a reliable and repeatable manner to allow discovery of all areas of the application and interception of all requests that the application sends to remote servers (e.g. API requests).

Adding page loads to a SPA

It is possible to add page load events to a SPA using the HTML History API; this will help integrate analytics. The difficulty comes in managing this and ensuring that everything is being tracked accurately – this involves checking for missing reports and double entries. Some frameworks provide free analytics integrations addressing most of the major analytics providers. Developers can integrate them into the application and make sure that everything is working correctly, but there is no need to do everything from scratch. [25]

Speeding up the page load

There are some ways of speeding up the initial load of a SPA, such as selective prerendering of the SPA landing/index page, caching and various code splitting techniques including lazy-loading modules when needed. But it's not possible to get away from the fact that it needs to download the framework, at least some of the application code; and will hit an API for data if the page is dynamic. [25] This is a "pay me now, or pay me later" trade-off scenario. The question of performance and wait-times remains a decision that the developer must make.

Page lifecycle

A SPA is fully loaded in the initial page load and then page regions are replaced or updated with new page fragments loaded from the server on demand. To avoid excessive downloading of unused features, a SPA will often progressively download more features as they become required, either small fragments of the page, or complete screen modules.

In this way an analogy exists between "states" in a SPA and "pages" in a traditional website. Because "state navigation" in the same page is analogous to page navigation, in theory, any page-based web site could be converted to single-page replacing in the same page only the changed parts.

The SPA approach on the web is similar to the single-document interface (SDI) presentation technique popular in native desktop applications.

See also

Related Research Articles

Server-side scripting is a technique used in web development which involves employing scripts on a web server which produces a response customized for each user's (client's) request to the website. Scripts can be written in any of a number of server-side scripting languages that are available. Server-side scripting is distinguished from client-side scripting where embedded scripts, such as JavaScript, are run client-side in a web browser, but both techniques are often used together. The alternative to either or both types of scripting is for the web server itself to deliver a static web page.

<span class="mw-page-title-main">Web application</span> Application that uses a web browser as a client

A web application is application software that is accessed using a web browser. Web applications are delivered on the World Wide Web to users with an active network connection.

Jakarta Faces, formerly Jakarta Server Faces and JavaServer Faces (JSF) is a Java specification for building component-based user interfaces for web applications. It was formalized as a standard through the Java Community Process as part of the Java Platform, Enterprise Edition. It is an MVC web framework that simplifies the construction of user interfaces (UI) for server-based applications by using reusable UI components in a page.

In software engineering, the terms frontend and backend refer to the separation of concerns between the presentation layer (frontend), and the data access layer (backend) of a piece of software, or the physical infrastructure or hardware. In the client–server model, the client is usually considered the frontend and the server is usually considered the backend, even when some presentation work is actually done on the server itself.

Ajax is a set of web development techniques that uses various web technologies on the client-side to create asynchronous web applications. With Ajax, web applications can send and retrieve data from a server asynchronously without interfering with the display and behaviour of the existing page. By decoupling the data interchange layer from the presentation layer, Ajax allows web pages and, by extension, web applications, to change content dynamically without the need to reload the entire page. In practice, modern implementations commonly utilize JSON instead of XML.

<span class="mw-page-title-main">Dynamic web page</span> Type of web page

A dynamic web page is a web page constructed at runtime, as opposed to a static web page, delivered as it is stored. A server-side dynamic web page is a web page whose construction is controlled by an application server processing server-side scripts. In server-side scripting, parameters determine how the assembly of every new web page proceeds, and including the setting up of more client-side processing. A client-side dynamic web page processes the web page using JavaScript running in the browser as it loads. JavaScript can interact with the page via Document Object Model (DOM), to query page state and modify it. Even though a web page can be dynamic on the client-side, it can still be hosted on a static hosting service such as GitHub Pages or Amazon S3 as long as there is not any server-side code included.

A web framework (WF) or web application framework (WAF) is a software framework that is designed to support the development of web applications including web services, web resources, and web APIs. Web frameworks provide a standard way to build and deploy web applications on the World Wide Web. Web frameworks aim to automate the overhead associated with common activities performed in web development. For example, many web frameworks provide libraries for database access, templating frameworks, and session management, and they often promote code reuse. Although they often target development of dynamic web sites, they are also applicable to static websites.

<span class="mw-page-title-main">Dojo Toolkit</span> Open-source modular JavaScript library

Dojo Toolkit is an open-source modular JavaScript library designed to ease the rapid development of cross-platform, JavaScript/Ajax-based applications and web sites. It was started by Alex Russell, Dylan Schiemann, David Schontzler, and others in 2004 and is dual-licensed under the modified BSD license or the Academic Free License.

ASP.NET AJAX, formerly called Atlas, is a set of extensions to ASP.NET developed by Microsoft for implementing Ajax functionality. It is released under the Microsoft Public License (Ms-PL).

ZK is an open-source Ajax Web application framework, written in Java, that enables creation of graphical user interfaces for Web applications with little required programming knowledge.

Content Security Policy (CSP) is a computer security standard introduced to prevent cross-site scripting (XSS), clickjacking and other code injection attacks resulting from execution of malicious content in the trusted web page context. It is a Candidate Recommendation of the W3C working group on Web Application Security, widely supported by modern web browsers. CSP provides a standard method for website owners to declare approved origins of content that browsers should be allowed to load on that website—covered types are JavaScript, CSS, HTML frames, web workers, fonts, images, embeddable objects such as Java applets, ActiveX, audio and video files, and other HTML5 features.

AngularJS is a discontinued free and open-source JavaScript-based web framework for developing single-page applications. It was maintained mainly by Google and a community of individuals and corporations. It aimed to simplify both the development and the testing of such applications by providing a framework for client-side model–view–controller (MVC) and model–view–viewmodel (MVVM) architectures, along with components commonly used in web applications and progressive web applications.

<span class="mw-page-title-main">Ember.js</span>

Ember.js is an open-source JavaScript web framework that utilizes a component-service pattern. It is designed with the aim of allowing developers to create scalable single-page web applications by incorporating common idioms, best practices, and patterns from other single-page-app ecosystem patterns into the framework.

<span class="mw-page-title-main">MEAN (solution stack)</span> JavaScript software stack

MEAN is a source-available JavaScript software stack for building dynamic web sites and web applications. A variation known as MERN replaces Angular with React.js front-end, and another named MEVN use Vue.js as front-end.

<span class="mw-page-title-main">React (software)</span> JavaScript library for building user interfaces

React is a free and open-source front-end JavaScript library for building user interfaces based on components. It is maintained by Meta and a community of individual developers and companies.

<span class="mw-page-title-main">Vue.js</span> Open-source JavaScript library for building user interfaces

Vue.js is an open-source model–view–viewmodel front end JavaScript library for building user interfaces and single-page applications. It was created by Evan You, and is maintained by him and the rest of the active core team members.

Isomorphic JavaScript, also known as Universal JavaScript, describes JavaScript applications which run both on the client and the server.

Nuxt is a free and open source JavaScript library based on Vue.js, Nitro, and Vite. Nuxt is inspired by Next.js, which is a framework of similar purpose, based on React.js.

In web development, hydration or rehydration is a technique in which client-side JavaScript converts a static HTML web page, delivered either through static hosting or server-side rendering, into a dynamic web page by attaching event handlers to the HTML elements. Because the HTML is pre-rendered on a server, this allows for a fast "first contentful paint", but there is a period of time afterward where the page appears to be fully loaded and interactive, but is not until the client-side JavaScript is executed and event handlers have been attached.

References

  1. 1 2 Flanagan, David, "JavaScript - The Definitive Guide", 5th ed., O'Reilly, Sebastopol, CA, 2006, p.497
  2. "Inner-Browsing: Extending Web Browsing the Navigation Paradigm". Archived from the original on August 10, 2003. Retrieved May 16, 2003.
  3. "Slashdotslash.com: A self contained website using DHTML" . Retrieved July 6, 2012.
  4. "US patent 8,136,109" . Retrieved April 12, 2002.
  5. "Meteor Blaze". GitHub . 6 May 2022. Blaze is a powerful library for creating user interfaces by writing reactive HTML templates.
  6. Introducing DDP, March 21, 2012
  7. "Server Side Rendering for Meteor". Archived from the original on March 20, 2015. Retrieved January 31, 2015.
  8. "Single-page applications vs. multiple-page applications: pros, cons, pitfalls - BLAKIT - IT Solutions". blak-it.com. BLAKIT - IT Solutions. October 17, 2017. Retrieved October 19, 2017.
  9. "Real-Time Monitoring using AJAX and WebSockets". www.computer.org. Retrieved June 1, 2016.
  10. "Server-Sent Events". W3C. July 17, 2013.
  11. "Unhosted web apps".
  12. "The Single Page Interface Manifesto" . Retrieved April 25, 2014.
  13. "Derby" . Retrieved December 11, 2011.
  14. "Sails.js". GitHub . Retrieved February 20, 2013.
  15. "Tutorial: Single Page Interface Web Site With ItsNat" . Retrieved January 13, 2011.
  16. HTML5
  17. "What the user sees, what the crawler sees" . Retrieved January 6, 2014. the browser can execute JavaScript and produce content on the fly - the crawler cannot
  18. "Making Ajax Applications Crawlable" . Retrieved January 6, 2014. Historically, Ajax applications have been difficult for search engines to process because Ajax content is produced
  19. "Proposal for making AJAX crawlable". Google. October 7, 2009. Retrieved July 13, 2011.
  20. "(Specifications) Making AJAX Applications Crawlable". Google Inc. Retrieved March 4, 2013.
  21. "Hash URIs". W3C Blog. May 12, 2011. Retrieved July 13, 2011.
  22. "Deprecating our AJAX crawling scheme". Official Google Webmaster Central Blog. Retrieved February 23, 2017.
  23. "Implement dynamic rendering". Google Search Central. October 13, 2018. Retrieved January 7, 2021.
  24. "Fix a single-page app for Google Search". Google Codelabs. Retrieved 2021-12-15.
  25. 1 2 3 Holmes, Simone (2015). Getting MEAN with Mongo, Express, Angular, and Node. Manning Publications. ISBN   978-1-6172-9203-3
  26. "Single Page Applications (SPA)". Appcheck Ltd.