 Ah, yes. It's our old friend, the offline dinosaur. We've talked about caching and the service worker, which can enable your app to work offline. But we haven't talked about what to do with slow or unreliable networks. We also need to think about performance and make sure your app remains fast to load under all conditions. Building a PWA does not mean starting from scratch. You can implement the steps progressively. First, you need to secure your connection. Service workers require HTTPS to keep malicious scripts out. However, given the importance of security and privacy, you should be using HTTPS anyway. Then you can cache your site's static assets using the service worker and cache APIs. This can improve the performance of your app and enable offline experiences. The next step is to migrate to an app shell. An app shell separates dynamic content from the logic used to render it. If you're building a modern single-page app, then you're probably using something similar to an app shell already. Using an app shell is the recommended approach to migrate existing apps and structure your PWA. This architecture provides connectivity resilience, and it is what makes a PWA feel like a native app to the user, giving it application-like interaction and navigation and reliable performance. Once you have an app shell, adding a manifest file and meta tags enables add to home screen. Adding an icon to the home screen makes it easier for users to return to your web experience. Finally, you can enhance your app with features such as push notifications, integrated payments, and automated login. These are built on the same underlying framework that enables PWAs. Here's an example app shell. The two screens on the left live in the app shell and contain all the common navigation parts. The screen on the right shows the content, which has been loaded from the network displayed in the app shell. If this looks familiar, it's essentially a single-page app. The service worker can cache this locally to make it available offline. Then as the user navigates around the app, the shell loads the content. The app shell plus dynamic content model keeps your UI local and pulls in content dynamically. This greatly improves app performance and works really well with service worker caching as a progressive enhancement. It's the secret to reliably good performance. Let's talk about the first step after enabling HTTPS, adding caching to your app. How you cache the app will depend on whether you're rendering it on the server or using a single-page app that renders on the client. Server-side rendering is a familiar technique used by many developers, where the server builds the whole page. This includes content-driven sites using a CMS. This is a difficult scenario to make work efficiently offline since the server returns the whole page. Client-side rendering is also a familiar technique, normally written as a single-page app. And in this case, the server has a static page with the content template and the client-side code. JavaScript running on the client makes requests to get data and display it on the page. And this can be a very good fit for the AppShell model. The AppShell also separates content from presentation, though you may need additional code to cache data for offline use. Caching server-rendered apps is simple. Cache the static parts that you can. And that normally includes your CSS files, JavaScript frameworks, and some images. If your server is rendering a small number of unchanging pages, you could cache them, though any forms will need logic to detect if the app is offline and disable the form. You can detect if the browser is on or offline by checking the Navigator offline property. And you can also listen for online and offline events on the Navigator. In any case, you should check your network requests for errors and fail gracefully. This will handle both offline access and unreliable networks. Caching client-rendered apps is also fairly simple. Single-page apps have a core that always lives on the client, so cache that. But they also depend on dynamic data, so you need to add code to handle that. We'll talk about this again after you've seen IndexedDB, but the general idea is that things with a URL go in the cache, and non-URL data goes in the database. One nice feature is to detect when the app is offline and remember user actions. For example, you could let the user build a shopping cart while offline and send it when they're online. We've talked about porting your existing app to include caching. Now, that gets you most of the way there, but we also need to think about some techniques for fine-tuning the user experience. Users will expect your PWA to act like a native app, so we have to take some pains to get things right. Many initial efforts to build a progressive web app always retrieve files from the network or from the cache. But we can use combinations of the cache and the network to improve your app. In a cache-first strategy, the service worker looks for a file in the cache and uses the network if that fails. Server-rendered apps might use this if they are also caching rendered pages and the app sees a new URL. On the other hand, a network-first strategy tries to get the file from the network and uses the cache if that fails. Use this strategy when you need the latest content, such as stock prices or the weather, but are willing to fall back on the cache when offline. In some cases, you may want to ask the cache and the network at the same time. In most cases, the cached data loads first and that is returned directly to the page. Meanwhile, the network response updates the previously cached entry, and this is useful for assets that change infrequently, but that you want to keep up to date, such as user icons. The next time the user loads the page, they'll see the updated asset. The good news is that we provide the code for these caching strategies. These libraries automate many of the details for you while also following best practices and avoiding common gotchas. SW Toolbox is an open-source library on GitHub that builds on top of service worker, cache, and fetch. It implements each of the strategies we discussed and makes them easy to integrate into your app. SW Precache Libraries is an open-source tool also on GitHub that can generate a service worker script for you. You can call it from the command line or integrate it into your build process. You can also use these tools to simplify your implementation. They support all of the standard caching strategies or you can add your own and include control over options such as maximum cache size and item lifetimes. I highly recommend you take a look at them, even if you want to build your own solution. Now that you have an app shell in the cache, let's see about adding other PWA features. Since your PWA behaves like a native app, the user will want to add it to their home screen. Each of the major browsers does this a little differently, so you'll need to add both a manifest file and meta tags to enable add to home screen. You might also add push notifications support. We'll go into the details in a later module, but at a high level, the service worker receives push message events, displays notifications, and responds to user actions on the notification. Progressive web apps can also simplify e-commerce. Instead of filling in a form with payment and address details, the browser pops up a simple UI for choosing these and then creates a secure transaction for the merchant server. The Credential Management API can securely remember the login details for a site and provide a one tap login. Both of these depend on the user being authenticated to their device, either by password or biometrics. We should take a moment to talk about performance. Caching can speed up your application, but don't depend on caching alone for speed. Users with browsers that don't support service worker or users who are seeing your app for the first time can suffer slow downloads if you're not careful. Remember, caching can only improve performance on subsequent page loads. All in all, we recommend four possible approaches. Now, the best option is a combination of server side and client side rendering. Your server can draw the first page quickly and then JavaScript takes over and renders future pages using dynamic data. This also works for users with browsers that don't support service worker. The next best option is a pure AppShell single page app approach. You should cache the AppShell and you can speed this up using HTTP streams to begin rendering content as it comes in. Option three is to use server side rendering and cache everything that you can. Finally, we come to the single page app that renders all its own content. Now, you might be surprised this is at the bottom of the list, but it's often slower to the first render than server rendered apps. That's due to the time it takes to load the JavaScript before rendering begins. The difference between this app and the AppShell is that the AppShell can render at least the navigation instantly and also often contains default content. Before I go, I want to emphasize two things. First, now, this is our recommended approach, but there may be use cases for each pattern. PWAs can be built with any mixture of server side rendering and client side rendering that best fits your needs. Second, the textbook that accompanies this video has a detailed chapter on PWA architectures with updated advice. If you want to see some real-world examples, we have a list in the slide deck, and these are just a handful of businesses reaping the benefits of progressive web apps. See PWA Rocks for a great showcase of businesses using PWA technologies to enhance their mobile web experience. There are loads of resources available where you can learn more. You can access these from the materials that accompany this video.