00:00:15.160
Hey everyone, thank you for making it to this talk. I hope today you learn something interesting and that you leave here ready to create your first Progressive Web Application (PWA).
00:00:20.920
I'm Alicia Rojas, a software engineer at Telos Labs. I recently completed my second year there in August. Additionally, I am a music composer and a natural resources engineer. I am passionate about technology and sustainability, which is the focus of this application. I was born in Chile, but I'm currently based in Mexico City.
00:00:33.239
Telos Labs is a software consultancy founded in 2017 by Horacio Trino, a Mexican entrepreneur. Our mission is to tangibly enhance society through clarity of thought, creativity, and technology. We are committed to developing products that deliver a significant impact, and we aim to build purposeful products. In this talk, I will cover several topics: first, we will discuss what a PWA is and why you should convert your app into one. Then, I will introduce a case study that highlights the challenges that led to the creation of this Progressive Web Application. I will also explain how to set up the main components to create a PWA starting from a Rails application. Finally, we will dive into the more substantial part of the app which involves performing CRUD actions - create, read, update, and delete - using Hotwire and IndexedDB.
00:01:17.720
So, what is a PWA, and why should you consider turning your app into one? PWA stands for Progressive Web Application. In formal terms, these applications are web applications that are gradually enhanced with modern APIs to deliver improved capabilities. PWAs provide benefits such as better page performance, push notifications, offline support, and they are installable, allowing them to offer a native app-like experience without sacrificing the benefits of the web.
00:01:35.359
PWAs effectively combine the best features of both web and native applications. Web apps excel in reach since they are platform-independent and can be indexed by search engines, making them advantageous for SEO. They are also budget-friendly and accessible through any web browser without the need for installation. On the other hand, native apps take advantage of platform specificity to offer more complex functionalities. PWAs fall somewhere in between with a slightly lower capacity compared to native apps but retain all the positive aspects of web apps while being less costly to develop.
00:02:09.240
The impetus for this application stemmed from a request by the Chilean government, specifically an agency related to agriculture. They needed a tool for farmers and agricultural technicians to conduct on-field sustainability assessments on their farms. The challenge was to create an app that could perform these CRUD actions in regions where internet connectivity can be unreliable or entirely absent. The app needed to be user-friendly and easy to share since we were targeting users who may not be particularly tech-savvy, such as farmers in rural areas, and it should work on mobile devices.
00:02:43.200
Initially, we considered developing a native app, but given our limited time frame and budget, we decided to build a web application using our favorite framework, Rails. We gradually introduced PWA enhancements to provide offline support. The goal was to create an application in which farm technicians could complete a lengthy questionnaire, which includes various questions and map features, while working in areas where reliable internet access is not guaranteed.
00:03:05.440
To set up the main pieces for a Rails application to become a PWA, there are two critical components needed: the service worker and the manifest. The service worker is a small application that runs parallel to your Rails app and intercepts network requests, providing caching of assets and background synchronization capabilities, among other features. Service workers act as proxies between your web server and the browser, aiming to enhance reliability by offering offline access and other conveniences. It is important to ensure that the service worker is positioned at the root or global scope so it can effectively control all routes.
00:04:05.840
The second component, the manifest, specifies to the browser how the PWA should behave, including how it displays within the operating system of the user's device. It is crucial for ensuring that the application looks and feels like a native app. It defines elements such as the splash screen appearance and how the home screen icon should look. The manifest file is typically referenced as manifest.json. To incorporate these elements into your application, I explored various approaches, ultimately deciding on the MVC pattern, inspired by a blog post from Mike Rogers several years ago.
00:04:51.200
The initial step is to create a service worker controller where you will define the actions for the service worker and the manifest. Next, you need to add routes for both actions and treat these files as view templates within your application. You will then create a companion JavaScript file to connect these pieces. The service worker operates independently, while the JavaScript file serves as the bridge between your app and the service worker. By adding functions to your service worker, you can ensure they manage authentication problems when necessary.
00:05:28.680
Now let’s dive into performing CRUD operations using Hotwire and IndexedDB. The first step is creating records while offline and later synchronizing them once the connection is available. IndexedDB is a JavaScript API that provides a way to manage a database of JSON objects right in the browser. During the development process, I explored different storage mechanisms, such as session storage and cookies, but ultimately chose IndexedDB for its ability to persist data across sessions and tabs. It is capable of storing larger, more complex data types, like files and images, and it allows for searching and storing larger data amounts compared to the alternatives.
00:06:29.440
Using IndexedDB does come with its challenges—essentially relying heavily on promises—so it’s beneficial to have at least a basic understanding of asynchronous JavaScript. If you find it tricky, there are libraries available that provide a more developer-friendly API for working with IndexedDB. Now, let’s examine how this functions in practice. When a client attempts to create a record and they are offline, the request to the web server will fail. This is where IndexedDB comes into play, allowing you to store the record locally in the browser until a connection is restored. Once back online, you can synchronize this data with the server.
00:07:33.320
To implement this functionality, I utilized Stimulus to check the network status. In my experience, a reliable method was to fetch a small image, ensuring it was not cached by the service worker. The goal here is to verify that you have internet access and that you are not just connected to a network with no actual service. As you submit forms or create records, check the network status. If the connection is down, prevent the default behavior from initiating the AJAX request and store the record in IndexedDB instead.
00:08:05.040
I discovered that these actions are commonly used across different controllers, so I created a mixin to enable code reuse across my Stimulus controllers. This setup involves checking for network connectivity and ensuring that before the submission of any data, valid form information is available. If the conditions aren’t met, you will save the record in IndexedDB for later synchronization, similar to how records are handled in the local storage.
00:09:05.600
The syncing operation can be initiated with a button in the user interface. When clicked, the button calls a Stimulus controller which verifies network connectivity. Only when confirmed connected will it allow synchronization to take place. This process sorts through records stored within IndexedDB and creates requests to your server to upload each record. During this phase, you can also handle potential errors and mark records as synchronized based on the outcome of the request.
00:09:57.360
After posting records, it is important to remove them from IndexedDB if you choose to do so, although leaving them there is also an option. This decision depends largely on the requirements of your application. Consequently, your users will be interacting with data that might not have been immediately visible until the synchronization process occurs. The goal is to provide updates through user actions while keeping them informed about the status of their records and actions regarding offline functionality.
00:10:58.920
Next, to facilitate user interactions with offline data, I adopted a template approach which uses template tags to hold discrete pieces of content that can be revealed upon user actions or conditions within the application. This is particularly useful for guiding the application’s behavior when users are online. Leveraging service workers, you can cache the templates as well as accompanying JavaScript for rendering while ensuring new content is available when required. The Mustache.js library proxies this rendering process, which populates and updates the UI with the data fetched from IndexedDB dynamically.
00:12:44.960
Some additional features I found useful included an option for users to toggle their offline/online preferences, which provides control in situations where the user may have unreliable network connectivity or may prefer not to utilize mobile data. The interface can effectively indicate to users when they are online or offline. Implementing the synchronization button or integrating background sync via the service worker could also enhance the user experience. However, users should have some level of control over when these actions occur to prevent unwanted background processes.
00:13:51.680
For updates, you would follow a similar approach by creating a template version of the form within your views. This template could be dynamically loaded, enabling users to edit existing records within IndexedDB. The underlying logic ensures that if the record already exists, updates will reflect appropriately without creating duplicates. The mixin from earlier can be applied here to maintain accuracy and efficiency when submitting records and updating IndexedDB.
00:14:47.680
The power of Hotwire and Stimulus frameworks allows you to build an effective PWA without the need for excess JavaScript frameworks. This integration streamlines the process of enhancing backend applications with offline capabilities through existing features. Overall, incorporating features and leverage of these frameworks enables you to empower users more efficiently, maintain engagement, and implement the application’s functionality seamlessly.
00:15:25.600
The importance of validations cannot be overstated. Ensuring the integrity of each record submitted within IndexedDB must match the backend requirements. Mismatch can lead to unnecessary validation issues when syncing later. Consequently, stay mindful of maintaining consistency between frontend validations and backend mechanisms. You want to have a reliable experience without validation conflicts that could disrupt functionality.
00:16:13.680
Moreover, understanding your user base and their browsers is crucial when implementing features for your PWA. There are various resources available, such as caniuse.com, which detail the features supported by different browsers, particularly regarding service workers and background sync APIs. Certain features may not work as expected across all platforms, especially iOS versions of Safari, which may cause compatibility issues for users. By keeping these factors in mind, you can better strategize and implement the necessary features.
00:17:31.440
In conclusion, PWA features can significantly enhance the usability and accessibility of your application across varied audiences, including those in regions with unreliable internet connectivity. Feature-rich applications allow you to engage with users who may otherwise be overlooked due to their offline circumstances. Utilizing frameworks like Stimulus enables the creation of almost native-like experiences without overwhelming amounts of JavaScript.
00:18:21.280
I've documented much of this process within a series of blog posts. The discussion encompassed how to cache assets and provide proper offline fallbacks to improve the overall user experience. Ensuring users do not encounter obstacles—like being greeted by the dinosaur game while offline—is a priority, and transitions can help mitigate these occurrences.
00:19:03.200
If you have any questions or would like to discuss Progressive Web Apps further, please don’t hesitate to reach out to me on any of the platforms. Thank you for your attention. If there are any questions, I have time to answer them.
00:19:26.000
Thanks.