Conf42 JavaScript 2020 - Online

- premiere 5PM GMT

Offline web apps don't exist anymore!

Video size:

Abstract

Progressive Web Applications are the state of art of modern web solutions. With the proper caching strategy it is possible to drastically improve the overall performance and providing data even without a network connection.

In an increasingly mobile first world, optimising the time to load of web pages can be the success of our business. In this presentation, we’ll focus on how to ensure that our apps are fast, native-like and able to provide a truly seamless experience, delivering a unique experience to our users.

Summary

  • progressive web apps can bring a lot of functionality and feature to our projects. Building a progressive web app is much cheaper than a native app. The used memory on the device is much smaller compared to a native apps. In this session we will see how it's possible to build such an application.
  • Workbox is a set of libraries and node modules that makes very easy to cache assets and to create or implement caching strategies. Demo shows how easy is to create a progressive web app starting from an angular project.
  • There is no network response or payload going back and forth while the search API for the cat image just comes back. We can provide the data even though we are offline from the cache. This is to show how easy is to create a progressive web app with very few steps.
  • Cloud Firestore is a NoSQL database that provides also offline storage. All requests that we ship will be cached by cloud firestore and will be saved locally. Not only it's possible to access this data while offline, but also to interact with it.
  • Before concluding, I would like to give you some links that might stimulate further your interest for progressive web apps. PWA Rocks and Upscope is a kind of media or application gallery where you can find a lot of samples of progressive apps. If you have questions please contact me in Twitter or just follow me if you are interested to get updates.

Transcript

This transcript was autogenerated. To make changes, submit a PR.
You. Hello everybody. Would you like to be able to create an application that is always offline or at least it looks like make? It would be always alight for our users even though there is no Internet connectivity, this today is possible thanks to progressive web apps and other modern technologies. In this session we will see how it's possible to build such an application and also we will see the different benefits that progressive web apps can bring into our project. When I talk about the progressive web apps, I'm always a bit sad to see that very few people are aware of the potentiality of this technology and even less people are using actively in their own project. Progressive web apps. That's a bit indeed, because progressive web application can really bring a lot of functionality and feature to our projects, no matter of complexity of the project or how big it is. And let's start seeing first of all, the differences between a progressive web app and a native application, either Android or iOS. This doesn't want to be at all a competition nor a fight, but just list out some concrete differences. First of all, we don't have to fulfill the requirements or the rules of a play store or App Store. We can just deploy our progressive web app that it is simply a web application enriched with some other functionalities and once live on the server it's available to everybody. So immediately online then we don't have to save and provide different versions of it, we just have one versions. Of course, if some functionalities will not be available in some of the browser, then these will be progressive, hidden or not provided to these users that cannot have the latest browser or a compatible browser. But still, the experience has to be very smooth and there should be no showstoppers on the other side. Typically building a progressive web app is much cheaper than a native app. This because we can reuse the know how we have internally in our team. For example, we can reuse our web team to create also a progressive web app. The know how is exactly the same as to create a normal web application. And lastly, it has a much smaller memory footprint because we don't have to download many packages and indeed we will see later on. Indeed, the used memory on the device is much smaller compared to a native app. Before going on, just a couple of words about me. My name is Francesco Leardini and I work as a software engineer, a consultant for Trivadis, a consultancy company in Switzerland. But I'm originally from Italy, from the north on the Algria coast. It's a very nice place, especially in summer. The photo indeed is taken from my location. That said, let's start our progressive web apps journey. Let's imagine a very common scenario. We are traveling or just commuting to the office and we are passing through an area that is not very well covered. So we can have an intermittent connectivity and in some pages even we could be completely offline. So if we are reading, for example, our favorite news website or a blog post, when we pass from one page to the next, this is what can happen. So simply a default offline page. Indeed, for our users this would be not a real good experience. But with progressive web apps we can provide a much better user experience. As a minimum, we can provide some corporate colors or icons with some static data so that even though the user is offline still it can recognize the logo or some colors of our company and eventually still benefit from this content. If we can provide some meaningful static data like some items on sale if you are an e commerce shop, or some telephone numbers on the other side, and this is the case of Trivago on the right side, we can provide even a further and richer experience. In this case, Trivago, when we access the website for a second time and we are offline, provides us a labyrinth game. This is a very clever move from them because we can keep the user attention locked on the website using this game so that as soon as the Internet connectivity is then restored, the user will be automatically redirected to the requested page. So that with this let's call it trick or good way of keeping interest of the user, we can save a potential customer that otherwise would have been most probably lost. So this is possible thanks to progressive web apps. Let's see also another difference. A little test trying to recognize which one is the native app of the Android this is a screenshot of my Android device and which one is a progressive web app. Of course we can see immediately the shape is different, but other than that there are not big difference. If we open it, we can see that the layout itself is quite similar. There are not really big differences and indeed it's very difficult to recognize which one is the progressive app and on the other side which one is the native app. Indeed it's very difficult. As I said, I give you a little so called hint and this probably should really help you to understand which one is the native app and which one is a progressive web app. Most probably yes, you got it. From the size the native app we can see it takes much more space or memory space on a user device, while a progressive web apps is almost minimal or really minimal. If we look again at the layout once again we can see that the differences are really, really small and is almost impossible to understand and to see which one is the native app and which one is the progressive web app. And this indeed is one of the core goals of a progressive app being able to provide an experience that is as close as possible as a native app, not only in the functionalities provided, but also in the layout. So we want to enrich the experience for a user assessing our web application and make it as close as possible to what could have been if the user would have used a native app. Before going further, just some small words about what are the core components that are present in a progressive web app. First of all, we have to talk about service workers. Service workers are just a JavaScript component very similar to a web worker. They operate on a separate thread from the one used by the main application, so that even though the service worker crashes, so stop running or it's very very lengthy or executing a very heavy task, this will not affect at all our main application and this is exactly what we want. Let's see how a service worker operates on our client side. So when we request our progressive web app, we get the response and we also download the service worker. That is, as we said, is just a JavaScript file. Then according to how we implement caching strategies for this service worker, we could eventually already save in the local cache some assets and some other files. This makes it possible that from next time the user assess our progressive web apps, even though there is no Internet connectivity still we are able through the service worker to provide this requested data from the local cache. So there is no need to go at all over the network and the user not only receives this response extremely quickly, but also when he or she is offline. So no need of being connected to the network at all. Web manifest is a JSON file that contains all the instruction to tell the user agent how our progressive web apps should be rendered. Once open, it's also a very important file that we have to create in a proper way. So to fill in a proper way in order to be able to be installed on a client's device, our progressive web app let's see, the first two proper name and short name will be used as a label or as a text string under the icon. Once this will be installed on a user device display mode tells how the browser should render our progressive app. We can use a browser value. In that case it's just a default way of or view that we get once we assess with the mobile device our progressive web app. But it's more interesting standalone where we can see that some UI elements of the browser, for example the address bar are removed. So gives a much more feeling of a progressive of a native app. And on the other side full screen that as the name side says we can use the whole device screen and this is more suited for device for application that are media rich or for games. For example we can define a starting URL for our PWA because we want to provide, as again we said native feeling so that when the users open our progressive web apps, we want to provide always the same home page or always the same starting page and not the last visited URL. Lastly, we can define some icons that can be used not only on the user device home screen but also as a splash screen. If the browser supports that. Typically we can provide a different resolution or different sizes so that we can have a pixel perfect experience for our users. As a minimum we should provide two sizes, 192 for 992 or 512 per 512. We can even provide a purpose. Purpose that says how this icon will be displayed on a user device. In this case we can see we define the maskable and as a fallback any that is the default value. We will see just in a second what are maskable icons. So these are the minimum properties that we can define in a manifest file in order to be able to make it installable on a user device. Let's see what are maskable icons. Let's start saying before that some manufacturers like for example Samsung at the beginning decided to have all icons on a device with the same shape. And after this also other producers decided to have the same idea but giving a different size. So because of this Android from the version Oreo of Android OS decided to introduce the concept of adaptive icons. So being able to provide images with an extra space around that can be cut, it cropped in order to be able to provide different shapes according to our or the user wish. This is okay, this is nice, but it's a problem if we define some or we already created some progressive web apps and we provided our icons that are not maskable. If we do that, we will see that our icons will be either cropped so some parts will be cut away or they will have a white background instead of using the whole background as wished or as desired. To do that we can create maskable icons. So we define a circular area where radio is 40% of the image size and this is called the safe area. So we can place within this safe area all the part that we want to be sure that won't be cropped in any kind of shape and everything that is outside might be cropped according to the final shape that will be used. So if we target Android devices for our progressive web apps, we have to keep in mind these aspects. So we have to create icons that are maskable. That said, let's see how can we make our web application extremely fast and also how can be possible to provide data even while offline? This is possible thanks to caching strategies because by default a service worker doesn't know anything about which assets to cache and when to provide from the cache. These assets we have to define thanks to caching strategies. Yes, we can see that the mobile traffic in the past years really took over the desktop traffic over Internet and this is something we have really to keep in mind, being able to optimising our web application even for mobile devices. So not only for desktop application, but mobile devices nowadays have a really strong weight on the market. So we have to keep this in mind. The first cache structuring we will going to see is the cache first. As the name suggests, we make a request and this request gets intercepted by the service worker and then the service worker. If there is a match with some cached assets that we define, then these will be immediately provided from the cache. So no need to go over the network and respond extremely fast. On the other side, if the assets are not available on the cache, there will be a normal network request. As a fallback, this caching strategy is to be chosen if we want to implement an offline first approach. On the other side, we can implement a network first caching strategy. As the name suggests, we go first over the network because we want to provide the very latest response with the most up to date data or values. This is the case for example when we want to provide values from a caching stock exchange API and so we don't want to provide the cache the data unless there is no network connectivity. So as a fallback we can go over the cache if possible. We want to provide the latest up to date data from the network. And aside these there are also kind of hybrid services or strategies. One of these is called stale while revalidate strategy. What this does is that when the service worker intercepts a request, it goes immediately over the cache and tries to provide from there the requested assets so that the response is extremely fast. But in the background it also goes over the network and tries to fetch any new updated asset and updates the relative version in the cache. So that any following request will get a newer version straight from the cache to implement. This strategy is not very complex, but there are some lines of code we have to provide. We don't go over the code because it's quite simple, but just to say that there is some work that we have to implement, especially if we wanted to create some more complex strategies of logic for our application. However, thanks for us, there are some tools that we can use. One of these is workbox. Workbox is a set of libraries and node modules that makes very easy to cache assets and to create or implement caching strategies. We can see in this case with just three lines of code we can say, or we can implement the stalewall revalidate strategy, the one we saw just before. And thanks to that we can say that we want to cache all JavaScript and the CSS file. For example, we define routes where we can provide a string or in this case regisc in order to match some specific path or some specific files that we want to cache. So workbox, it's a really powerful tool or set of libraries that nowadays is kind of considered a state of art in order to implement advanced scenarios for progressive web apps. It's also important to say that workbox is a framework agnostic, so we can work with Forbox in our react project Vue JS angular no matter, or even vanilla Javascript, it will just work on the other side if we are working with some framework like for example angular, it's also possible to start with the progressive web apps and it's very easy. Thanks to the NGraD schematics, we can inject progressive web apps capabilities into an existing file. We will see shortly a demo that shows how easy is to go and to create a progressive app starting from an angular project. There is the code on GitHub. You can see and download the code there so you don't need to pay attention to all the details. And the goal of this demo is to see and to demonstrate how easy is to create a progressive web app application starting from an angular project. So we can see here I have my visual code with the simple basic new angular project and I already ran the NgAd angular PWA command. What this command does is that it downloads the service worker module and register for us. Plus it creates some other files that we will describe very soon. We can see that we register the file ng serviceworkerworker Js file. This is the real service worker that so is stored in the node modules. We cannot manually change this service worker file otherwise every time our solution is built, all the changes that we did will be wiped out and we enabled this registration. So this service worker we wanted to register only when we have a production build this because we want to go over only for our production releases. One of the files that is created is the manifest file. As we saw before, there are some properties that are already prefilled with some default values for us. Of course we can customize as we want and we can see that there are also many more sizes that are created for us per default. But much more interesting is the NGSW so angular service worker configuration file. This is a JSON file that is created for us. And here is the real magic here. Actually we can define the assets, static assets or APIs that we want to cache by default. Angular creates only an asset groups array where it's possible to define static assets. So JavaScript files or ATML files that will be cached according to different installed mode strategies. Let's calculate this. The first object has an installed mode prefetch and here we can put all the files that we want to be cached already when the service worker is loaded and installed. These are for example all the core files that we want to provide immediately when the user access our website and is offline. So with this install mode prefetch value we can tell to the service worker grab all these files and install already or download and save in the cache already while you are installing. It's important to note that if one of these files fails to be downloaded, the service worker installation fails, will be aborted and so it will be obtained again. Next time the users assess the pages or we refresh the page itself so we don't have to put their big files or too many files, just a bare minimum. On the other side we have another array with name property assets in this case and installed mode lazy. We wanted to target here all assets files or font files for example that are not so crucial for our application. By defining install mode lazy, we tells the service worker that we wanted to download and store in the cache those files only after they have been requested a first time and then we can see we have an update mode property with value prefetch. This means tells to the service worker to upload the stored value the assets in the cache as soon as a new value is available on the server. We could have users here a value instead of prefetch a value of lazy. In that case we would have updated our stored assets only after they have been requested a second time. So these values are created by default for us with the ngrad angular PWA command, but it's possible also to go further and to cache also APIs. For that we have to create a data groups array and create different cache names. In this case, for example, I wanted to target an API where URL providing dead jokes and we want to define strategy performance. Strategy performance in angular means a cache first. So we go immediately over the network, sorry, over the cache, and we can have a retain policy of five entries and a max age of 15 minutes. After that time the cache will be renewed. So this strategy is to provide extremely faster responses. And even though there is no network connectivity on the other side, we create another group and we want to cache an API that provides cat's image. We are really fans of cats, so we want the very latest images. Because of this we use a strategy freshness and strategy freshness means network first. As we saw before, we can provide again a maxi and max age values as in the previous cache configuration group. But here we can also define a timeout can be 5 seconds one day or a different timeout. One day actually would be way too long. So means that if we trigger a request and the timeout occurs, then we instruct the service worker that the user could be eventually offline, or in the case the network is too slow. So there will be a fallback and the service worker will try to provide the response from the cache. So this is everything we have to create, nothing else. And we are already able to create and to provide an angular application with just these a few commands. But let's see now, how does it look like this is our application that we just saw? Where on the left side we have the joke that is coming from the dead joke API, and on the right side the freshness strategy with the cats images. If we open the devtools, in this case I'm using chrome and we go on the application tab, we can see that over the service workers menu we can have an overview about the service worker that is installed. If we click on a manifest, we can see just a nice representation of all the values that are coming or properties that are coming from the web manifest. In the cache storage we have all the assets that have been cached. Now if we switch on the network tab and we refresh the page first time and now refresh it again, we can see that the joke doesn't change. And if we check the network tab, we can see that API providing the joke comes from the service worker. There is no network response or payload going back and forth while the search API for the cat image just comes back. Now if I go offline and I refresh the page, we can see that the images and that joke are provided. And if we check the network tab, we can see that both endpoints now are provided from the cache. So there is no network connectivity and we can provide that thanks to these caching strategies and the service worker. We can provide the data even though we are offline from the cache. Very nice and it's in a very simple way. So now I'm going online again, I refresh and again we can get a very new fresh image. And this is to show how easy is to create a progressive web app with angular very few steps. Let's continue with our application, with our presentation, sorry. And let's see one limit of progressive web apps. We can see that we could cache some get calls when we try to fetch some data. But would it be possible to provide a better experience? Because what is the case if we want to provide also the possibility of to store somehow or persist somehow, even put and post changes while the user is offline? How this is possible? This is not possible by default with the cache API interface, but we can create some custom solution. For example, we can implement indexdb that stores while the user is offline all the put or post requests that are attempt. And then as soon as the user restore its connectivity, then we can implement our logic that we go in order one by one to these appending requests and we trigger them one by one. Indeed, not very complex, but we have to implement quite some logic. There are so other tools we can use. For example, Farbas platform provides a set of functionalities and services for mobile devices implementation and web implementation. But we are in this case much more interested in cloud Firestore in the umbrella of services and products offered. Cloud Firestore is a NoSQL database that provides also offline storage. And this is great for us because with just one command we can create this indexdb and store all the changes for us in a very transparent way for the user. Once we imported the library, we have to enable the offline persistence if we are implementing a web application, while for a mobile application it's already enabled by default. So we invoke the enable persistence method and that's all what we have to do. From that moment, all requests that we ship will be cached by cloud firestore and will be saved locally. There is a 40 megabyte megabyte cache threshold, but we can define a bigger or a smaller value according we want. As soon as then we reach this limit, all the oldest values or records will be wiped away, wiped out from the cache, and then these value that are stored locally will be available even when the user is offline. So that not only it's possible to access this data while offline, but also to interact. So make changes over this data while offline, and cloud Firestore will keep track of all these pending changes. And then as soon as the network is restored so the connectivity to the server is restored again, cloud Firestore will go over these appending changes and ship them one by one, synchronizing them to the server. All this is done out of the box for us. We don't have to do absolutely anything. So let's see now a slightly more complex solution that indeed tries to justify the title of this session, so that offline web application nowadays don't exist anymore. We will see. The demo is also an angular application, sorry, using angular material for the layout, we can see the cards and using cloud Firestore as a NoSQL database. With offline storage aside, I will try to mirror my phone. Just a second. Yes, connected please. I will see how it is the progressive web applications on my Android device and on the server. Let's say like this, sorry, like this, side by side. So this application I implemented, it's a progressive application, as we said, I implemented in order to keep track of all restaurants or nice bars that I visited while traveling with my wife. So it's a nice way to keep track of good bars and suggest to my friends, or even not suggest if they were being so bad. One good things of it of the progressive apps is that they are responsive. So for example, in the web view we can see that if I narrow the window, the layout adapts automatically. On the other side, if I open my progressive web app on the device, we can see that we have one line of cards only and there is no label aside of the icons. Another nice things is that we can see that my progressive web app is displayed as it would be a separate application, as it would be a native apps, and not as a party of Chrome browser. So indeed another aspect to show much more close to a native app. So if I now change one entry, so I just write edit and I save it automatically. This change is propagated thanks to sockets and thanks to cloud Firestore is propagated to all the other clients that are listening to it. So that's why on the right side I can see that this entry has been also updated on my phone. But now let's see a much more interesting scenario. So I switch off connectivity. So I go in airplane mode on my phone and I refresh the page. So not only I can see all the content because I store these documents locally and this is a progressive web apps. So all the assets are here, icons and so on are here available. But I can also open a completely new entry in restaurant and for example let's write it offline, save it for a title and then let's see that this change affects only my phone. So my progressive app on the phone because of course there is no connectivity, I'm cut off, I'm offline and there is no offline server synchronization. And now the interesting thing is that as soon as I will go online again, let's just make, for the sake of demo, just change the other one. Also the title and let's save it. So we have the first two entries that have been changed, the other are still here visible, but of course we don't change them. So now I switch my airplane mode off and I will go online again. What I would expect is that here on the left side, so on the web view this client will get these two values. So the Sagami Milano and the bar North island entry will be updated with the entries that I edited on my phone. So I go online again and according to my connection, if faster, yeah, it's quite fast. So we can see that the changes that I did on my phone, so on the progressive web, apps stored on my phone have been propagated on the server and then to all the other clients listening to that. And this indeed it's quite cool because for the user now let me switch off again the connectivity, so let me go again offline for the user. Actually there is absolutely no difference whether being online or offline. We just provide a great experience because everything is working exactly in the same way, either offline and online. So this is a very nice combination of technologies with this progressive web app and also other cool technologies like cloud, Firestore and its functionality of offline storage, offline persistence. So should we now replace all our native apps with progressive web apps or should we just go with the progressive web apps? Well, I would say it depends on the cases. Of course, there is no silver bullet. As always, there are some limitations still in progressive web apps. Some of them are, for example, that many functionalities are still not fully supported by Apple. So if we wanted to target also Apple devices or iOS, we won't be able to use the full spectrum of functionality of progressive web apps, for example web notification or some web manifest properties. This is quite unfortunate, but it's still the case on the other side. Progressive web apps can do only what web applications can do. One thing is that it's not possible to assess the device contacts, even though Google is bringing on the contact Picker API, but it's still something experimental and not really widely used. And lastly, native apps have in general much better performances. So if we have to provide an application that is extremely media rich or is a game, then it's better we go with native apps because native apps can be tied to the underlying operating system while PWAs are provided through the browser. Before concluding, I would like to give you some links that might stimulate further your interest for progressive web apps and give you even more information about them. The first two websites, PWA Rocks and Upscope is a kind of media or application gallery where you can find a lot of samples of progressive apps. So to get an idea of what is possible to create with the progressive web apps, it's really cool. They are really cool websites. Progressivewebapstats.com shows all successful stories and in which measure progressive web app benefit or improved the Roy and other metrics for different websites and domains and the last two websites. So PWA is a stack overflow collection of the the biggest requested or most viewed requested about progressive web apps and service worker and what PWA can do today collects a set of functionalities and features that they are possible to implement in progressive web apps. So these are very interesting links and websites that I really strongly suggested to visit if you are interested to dig deeper in progressive web apps. That said, thank you very much for your attention. You can reach me on Twitter handle or from time to time I write articles on the dev IO portal and that's it. Thank you very much. I hope you enjoyed my talk and if you have questions please contact me in Twitter or just follow me if you are interested to get updates. Thank you very much.
...

Francesco Leardini

Senior Software Engineer, Angular Trainer @ Trivadis

Francesco Leardini's LinkedIn account Francesco Leardini's twitter account



Join the community!

Learn for free, join the best tech learning community for a price of a pumpkin latte.

Annual
Monthly
Newsletter
$ 0 /mo

Event notifications, weekly newsletter

Delayed access to all content

Immediate access to Keynotes & Panels

Community
$ 8.34 /mo

Immediate access to all content

Courses, quizes & certificates

Community chats

Join the community (7 day free trial)