The Background
MPAs (Multi-Page Applications)
First, there were MPAs (Multi-Page Applications). When the web was first introduced in the mid-nineties, server-rendered HTML was the only way to build a website. Users interacted with these websites through forms that were submitted to specific URLs. Initially, this approach was effective and simple, but as applications became more dynamic, full-page refreshes became an issue, prompting developers to seek an alternative.
SPAs (Single-Page Applications)
Enter SPAs (Single-Page Applications) were developed to handle more complex interactions on the client side, creating snappy, responsive applications that users enjoyed. They minimized full-page refreshes and improved user experience. However, SPAs also had their downsides. Developers often faced challenges with duplicated code, complex build processes, and having to glue different technologies together. Despite its drawbacks, there are more developers writing code in SPAS than there are in any other architecture, even if they in involve server rendering in some fashion. However at the end of the day, everyone agrees that SPAs have a great UX (User Experience) but a terrible Developer Experience
PEMPA (Progressively Enhanced Multi-Page Applications)
Meanwhile, not every application or organization could make the switch to SPAs easily due to factors like legacy codebases or the cost of a complete overhaul. As a result, PEMPA (Progressively Enhanced Multi-Page Applications) emerged as a hybrid approach. PEMPA allowed developers to maintain their MPA structure while adding client-side code to support more dynamic user interactions. This helped bridge the gap between MPAs and SPAs, providing a better user experience without requiring a complete transition to a new architecture. Companies like Amazon have a sort of PEMPA in place.However, PEMPA also had its downsides. While improving user experience, this hybrid approach led to code duplication across different languages and the need for separate endpoints for AJAX requests and traditional form submissions.
What is PESPA (Progressively Enhanced Single-Page Applications)
PESPA is a concept that bridges the gap between MPAs and SPAs. It aims to provide the user experience of a SPA with the developer experience of an MPA. The key to PESPA's success is using the same language for front-end & back-end rendering. Data fetching methods (REST, GraphQL) matter less, as long as there's a designated section for data retrieval. PESPA provides a framework for seamless communication between client & server. It manages tasks like data loading, server rendering, and client transitions. This eliminates the code duplication problems often associated with traditional MPAs and SPAs How PESPA Works In a PESPA-based application, the server renders the initial document request, calling functions responsible for getting the data for the UI. The generated HTML is then sent to the client, which takes over from there. As users navigate between pages, the router calls the backend, which routes the request to the correct function for the target page. This process is relatively simple and efficient, as the entire network tab is managed by the framework. The PESPA approach does not require developers to worry about the specifics of data fetching, as the framework takes care of communication across the wire. In the case of Remix, they call these functions responsible for getting data for the UI "loaders." These loaders run on the server-side and typically send a JSON response to the client. Developers also don't need to think about updating specific parts of the UI, as the framework will handle this automatically. When the user submits a form, for example, the framework will revalidate the entire page, update the data, and trigger a re-render of affected components. PESPA is designed to feel like building an MPA, with the added benefits of SPA-like user experiences. This includes features such as animations between different actions, focus management, and error messages. The architecture also supports progressive enhancement, enabling developers to add features like pending states and optimistic UI easily.
Validation in PESPA:
Validation is an essential aspect of any web application. In PESPA, the validation process always occurs on the server side. However, developers can enhance the user experience by adding client-side validation as well. For example, when a user is typing in a form field, the client can trigger a fetch request to the server to validate the input in real time. This improves the overall user experience by providing instant feedback without requiring a full page refresh.
Offline-first code in PESPA
Offline-first code is an approach to developing applications that prioritize the user experience in offline or limited connectivity scenarios. This involves creating applications that can function seamlessly without a constant internet connection, allowing the user to interact with the app and access its features, even when offline. To achieve offline-first capabilities in a Progressive Enhanced Single Page App (PESPA) architecture like Remix, developers need to consider several factors. First, it's essential to ensure that the application can run in both online and offline contexts without duplicating code. This means writing the code once and allowing it to work efficiently in both scenarios. While Remix was initially built with CloudFlare workers in mind, it can also be adapted to run within a service worker, enabling offline-first capabilities. This would involve running the client side of the application within a service worker and queuing up requests made during offline periods. When the application reconnects to the internet, these queued requests can be replayed and managed using conflict resolution techniques such as CRDTs (Conflict-free Replicated Data Types).
However, it's important to note that creating an offline-first application with Remix is currently unexplored territory, and its complexity may vary depending on the specific use case. While some applications can benefit from offline capabilities, the increasing prevalence of internet connectivity worldwide has made offline-first features less relevant for many applications. For some use cases, building a mobile app might be a more suitable solution.
Does PESPA’s use of API affect performance?
The use of APIs in a PESPA architecture does not necessarily have a significant impact on performance. However, since any application would need to communicate with a server, whether through JSON or HTML, the performance difference might not be significant. The performance difference between these approaches is minimal. However, there might be a slight performance trade-off if developers choose to rely on stale data on the client side and avoid revalidating it. This approach is not suitable for most applications, as users typically expect up-to-date information. If a mutation is made, such as marking messages as read, it's necessary to make a request to validate the updated data. Consequently, the same number of requests would likely be made regardless of the architecture, resulting in a minimal impact on performance due to the use of APIs in a PESPA.
Adoption of PESPA into Remix and other Frameworks
As a co-founder of Remix, I've been deeply involved in incorporating the PESPA (Progressively Enhanced Single Page App) ideas into the framework. During the development of Remix, I had numerous discussions with Michael Jackson and Ryan Florence about the framework's direction. These conversations influenced the framework's evolution, and now Remix has become a popular choice among developers. Since the release of Remix, many other frameworks have begun to adopt PESPA's principles, validating its effectiveness. For example, Remix popularized nested routing, which has since been adopted by Next.js and SvelteKit. The forms API in Remix, which emulates browser behavior, has also been adopted by SvelteKit, and I believe that Next.js will likely follow suit. Additionally, Solid, a new framework, is adopting a similar mutations API, and the concepts of actions and loaders are being embraced by other frameworks as well. Several large companies like Microsoft, Netflix, and LinkedIn are using Remix in their projects, while others like GitHub and Tesla are exploring it. As for the limitations of Remix, there really aren't any when compared to a regular React app. Remix doesn't restrict you in any way, and it actually provides better primitives for building your application. It works seamlessly with various backends, such as Airtable, and can be used for small to mid-sized applications without any issues.Remix doesn't impose any limitations on what you can do compared to a regular React app. In fact, it offers better primitives for building applications. Comparison with Other Frameworks:
PhoenixLiveView and HotWire
PESPA shares similarities with other frameworks such as Phoenix LiveView and Hotwire. The core concept is the same – using a consistent language for generating UI code on both the client and server sides. This eliminate the need for full page refreshes when requesting new data from the server while also avoiding code duplication. However, one aspect that sets Remix, a PESPA implementation, apart is its approach to progressive enhancement. Remix makes it easy to add features like pending states and optimistic UI, enhancing user experience without complicating the development process. It is unclear how Phoenix LiveView and Hotwire manage these specific use cases. Ultimately, these approaches all aim to simplify the mental model for developers by reducing the need to manage client-side state while delivering a seamless and responsive user experience akin to that of a SPA.
Remix vs. Nuxt:
Both Remix and Nuxt.js involve rendering HTML in a Node environment. However, while Nuxt.js mainly focuses on server-side rendering (SSR) for SEO purposes, Remix handles both server rendering and client-side interactions. In particular, Remix takes care of mutations (e.g., data updates), which Nuxt.js does not address. With Nuxt.js, developers need to manage data updates and revalidation themselves.
Remix vs. Flux:
The Flux architecture was created by Facebook to solve issues related to state management and data updates. One example is that, in the past, marking a message as read would not immediately update the notification count. Flux aimed to address this issue by introducing a unidirectional data flow and a centralized state management system. In the context of Remix, such a problem would not occur because it automatically revalidates the entire page when a mutation is made. While this might sometimes be suboptimal, Remix provides options to opt-out of revalidating specific areas of the page if necessary. This means that, unlike with Flux, there is no need for complex client-side state management when using Remix, as it defaults to doing what the browser would have done in terms of revalidating and updating data.
Conclusion:
PESPA is a promising concept that aims to bridge the gap between MPAs and SPAs, providing a better user and developer experience. By leveraging a consistent language for rendering HTML on both the client and server side, PESPA eliminates code duplication problems and simplifies the development process. With progressive enhancement, PESPA allows developers to build feature-rich applications that deliver an enhanced user experience without sacrificing ease of development.