 Good morning. My name is Steven Fluen, and I am a developer advocate on the Angular team. And I'm Alex Rikabal. I'm a software engineer on the Angular team. Our talk here today is all about how to build great experiences with progressive web apps and Angular. And we're going to talk, basically, in three parts. First, we'll give you a little bit of background on Angular to make sure we're all on the same page. Then we're going to go ahead and talk about how we can build progressive web applications with Angular. And then we're going to get into a live demo that shows the latest tools that we've been working on that make it easy for you to do this. So let's get started. So first, we want to really kick things off with a basic understanding of what Angular is. I like to say that Angular is a platform that makes it easy to build applications with the web. And I use two of these terms extremely explicitly. I use platform because we're really trying to turn ourselves from being just a framework into more of a platform. And by becoming a platform, we're really focused on understanding and taking care of the entire developer experience from start to finish. All of the things that come up for you as a developer, all the challenges you face, we want to help you across the board. And I second say with the web, because while you can build Angular applications that target things like installed mobile or desktop use cases, we really, at the core, are building with the web as we do these things. So when we talk about Angular as a team, there's kind of three values that we talk about. First, we really value apps that users love to use, so building great experiences. Second, apps that developers love to build. So thinking about the developer experience that we're giving you with all the tools that we give you. And last, a community that feels, where everyone feels welcome. And this last one is very important to us. So if we look at something that GitHub actually did, so they did a state of the octaver study in 2016, where they studied what the top contributor projects were across GitHub, we saw that Angular is actually one of the top projects by number of contributors. And this was something that we were really happy about. We want a vibrant, rich community of contributors that are not only building and contributing back to Angular, but also contributing to the ecosystem across the board, whether it's things like helping with consulting, training, building dev tools, or even just building components. There are thousands of components that have been built for Angular applications that are all about helping you build applications more easily. So let's get into how Angular is really focused on becoming a platform rather than just a framework. So the first way that we do this, and the place that our really story starts, is around the CLI. So for those of you who don't know, the CLI is really designed to automate all of the different processes and all the tasks that you have to do as a developer. It starts with scaffolding out a new application where we're going to give you the best practices out of the box. Then we're going to help you continue your development journey by generating things like new components and new modules. Then we go ahead and we help you throughout the development environment by giving you this live serving environment. So every time you hit File, Save, we're going to do all the translation, all the compilation, all the bundling necessary for this application that you've just saved to be live in the browser. And every time you hit Save, we want that to live refresh in as fast as an incremental way as possible that makes it easier for you to develop. Then, once you've built your application, you actually want to go ahead and share it. And so using our ngbuild command, you can actually take all the work that you've done and put it into a state that's as minified and as small as possible ready to ship. And we really focus on making this disk folder that we produce by the CLI as easy and as portable as we can make it. Last, we feel that testing is a key part of the developer experience. So we use tools like Protractor and Karma under the hood to give you all of the tools you need to be testing your application from day one. Every component that we give you automatically comes with tests out of the box by the CLI. So the other thing we're really focused on is ID integration with our language services. So the Angular language service is a service that runs on your computer and gives your ID additional information about what's going on. And so you may be used to traditional HTML completion within your ID when you load a .html file. But when Angular sees an incoming reference coming from one of your components, we can actually establish a firm link between these things, giving you completion of all of the properties that exist within your component. But not only that, because we use TypeScript, we can actually be type aware with all of the completions that we give you. And so we understand the objects a little bit more inherently, and we can give you additional support because of that extra tooling. We also have very strong integration with data. There are a lot of different companies that integrate with data in different ways. Many companies integrate with Firebase due to its strong capabilities around real-time data. Some companies are starting to have GraphQL capabilities. Maybe they're using an Apollo back end with an Apollo front end, which has great support for Angular. Or many companies still have traditional restful APIs that they need to be pulling down and parsing JSON. But regardless of what way you're integrating with your data, Angular has integrated first-party support for pulling in, streaming, and then updating the views with all of that data as it's flowing in. There are a lot of integrated solutions that Angular is trying to do for common developer problems. And one of my favorites is internationalization. The world is getting bigger, right? We need to be building applications for broader and broader audiences, and doing so can really dramatically improve the success and the engagement that you get from your application. And so Angular has internationalization support built in. You just add an IETN tag to any of your templates, and we're actually able to automatically extract all of those things into what's called an XLIF file. An XLIF file is an industry standard translation file that you can give to an internal translation house or to a third party. And they'll give you back translated files, which then we build into the Angular application at build time. And because we don't do this at runtime, we're actually saving all of those performance challenges that might happen if you were trying to swap out these translations at runtime. Another very common developer challenge that we see is forms. You want to be pulling in data from your users, but you want to be doing it in a conversational way, where you're giving users information about what's going on, whether or not they're providing the right information at the right way live as they're entering data. And so whether you're building your validation reactively with our reactive-driven forms, or whether you're doing it directly in your templates, we really support both the common as well as a lot of the very advanced usage patterns within Angular, where we're going to give you a semantic understanding of the model that comes from your forms and combine that with the ability for you to express rules as well as CSS styles that then show up directly within your components as the user is interacting with them. And so it's really easy to reflect the state of your application as it exists to your users. Another thing that we're really focused on as a platform is making things better under the hood. So between Angular versions 2 and versions 4, we actually did something pretty dramatic under the hood. We rewrote our entire view engine, which is what your code looks like after it was compiled. And so without changing a single line of code, when you updated from version 2 to version 4, you saw about a 60% reduction in the file size of your generated code. And so this is something that we really want to continue doing as we continue to evolve Angular is look for ways that we can make your applications better without asking anything of you as developers. So this is actually a chart that one of our community members created. And what they were trying to show here was because the reduction in their file size was so dramatic, they believed that within a few versions, their file sizes might be negative, which would be a little bit funny to see. Another modern thing that we do is we really look across the ecosystem. And in particular, we look at the standards that are available on the web today. And one of those emerging standards is called server push, or oftentimes called HTTP to push. And so what HTTP to push allows you to do is it allows you to send either in your index file or in your headers of your requests, hey, you're going to need some additional files in order to run this page successfully. And what that means is your browser can start downloading all of the files that needs to run your application without waiting for that first round trip to complete. And we'll see how this technique can actually make your applications faster, sometimes cutting seconds off of your load time. We also help you target many different modalities for delivery. Because we focus on building applications that are very portable, so we're giving you a disk folder that is static and be hosted on really any server anywhere across the internet. But we're also focused on other modalities. Today, we're going to be talking a lot about PWAs. But we also support things like installed mobile with Ionic or with native script. We also support desktop use cases with a tool called Electron, which is basically shipping down a browser as well as a node instance and then connecting the two and running your application on there. And what this does is by having access to a node instance, you can suddenly from within your Angular application get access to things like the file system or anything that would come from a native system that may not be traditionally available via the web. A great example of a company using Angular and a lot of the tools that we're offering is ShopStyle. So they've built their web application as an Angular app, and then they added Angular Universal to it. Angular Universal is a technology that allows you to run your Angular application on the server side and then render it out to HTML, increasing the perceived performance of your application and also adding capabilities that improve things like SEO or screen scrapers, such as Facebook and Twitter. They've also recently announced that their application is now a progressive web application. And so when you visit their website, you're going to see all of the pages faster on every repeat load, and you're going to get a more reliable and engaging experience. So we've talked about Angular. I want to talk about how we can build even better experiences by looking into progressive web applications. On the Angular team, I really feel that progressive web applications are a big deal in the way that they improve the lives of both developers and users. At the core, progressive web applications are about building a more engaging experience for our users in three ways that we're going to talk about a few different times today. So we're going to talk about applications that are more reliable. So if I have a 2G internet connection, or maybe I have an unreliable connection where I'm going in and out of service, progressive web applications can help with that. We can also build applications that are more performant, and so that we give a better user experience that's going to be better, more engaging by giving a faster experience. And lastly, we can be more engaging by creating notifications and push notifications that allow us to interact with our user even when they're not using our application. So our goal on the Angular team is to make your applications better. And so we're doing this in regard to PWAs by providing Angular-aware tooling that allow you to more easily build progressive web applications that are customized and built based on the code that you're already writing. So our story really starts with the service worker. When you look at what the CLI is doing under the hood, we're providing you an entire build pipeline for your application. And there's one flag right now in the CLI called Service Worker True that adds a service worker automatically to your application. And with that tooling, we're actually looking at your application code, looking at the code that's generated by Webpack, and then using that as the configuration for the service worker so we know which files we need to store offline in terms of your application code. Then when the user is making requests to your application, the service worker lives in the middle of those requests and is acting as a proxy. So that instead of waiting for the server, you can actually respond immediately, giving a much faster experience for users. And because the service worker is the ultimate decision maker there, you, as an application developer, can decide if you want to go to the network or if you want to go to the local cache in order to serve out those files. We also handle notifications following the best practices. So there's a prescribed way that you need to, as a good citizen of the internet, handle incoming notifications to the user, such as displaying a notification at the top of the window if you're on mobile. And we handle all of those things automatically for you. Using our NG Service Worker service, we also allow you to do all of the registration for push as well as we give you an observable that lets you know whenever a new push notification comes in. So let's talk a little bit about vision for the future. So Angular Service Worker and all of the tooling that we're going to show you is available today. But we really have a more audacious goal on the Angular team. We really feel that at some point in the future, we're going to make these tools smart enough and we're going to make them awesome enough that we can make every Angular application a PWA out of the box. We really do feel that the benefits of building a PWA are so strong that if we can empower with great tooling every Angular developer to build PWAs by default, that's a really great world where users will ultimately benefit. Today, we're going to demo a number of different tools. So we're going to look at taking a static CLI application that we've built. We're going to add a service worker to it. Then we're going to make it route aware. Then we're going to go ahead and look at all the dynamic content that the application is pulling in and how do we cache those things. Then we're going to go ahead and add a service, or excuse me, an app shell, which will, as I said, increase the perceived performance of our application. Then we'll go ahead and increase the performance again by adding HTTP to push. And we'll finish things off by making things more engaging by adding push notifications to our application. With that, I'm going to hand it over to Alex. Awesome. Thanks, Steven. Hi, everyone. As I said in the beginning, I'm Alex Riccobal. I'm a software engineer on the Angular team. I work on a couple different parts of our platform. I work on HTTP, the Angular HTTP library. I work on Universal, which is our server-side rendering component. And I work on the Angular service worker, which is our implementation of a service worker in the browser. And aside from those specific things, one of my goals on the framework is to make Angular an awesome tool to build mobile and progressive web applications. So that's what I'm going to show you today. We're going to take this little demo application I've built and turn it into a fully-fledged, progressive web app. So this is the NG Store. It's a store for superheroes. So we sell masks and superpowers. I don't know how we managed to ship you a superpower, but we can do that. So let's take a look at this application under the hood. So I'm going to jump into VS Code, and let's look at the app module. Now, if you've written an Angular app before, this probably looks pretty familiar. If you're coming from AngularJS or you're just starting to use Angular, this is an NG module. NG modules are the building blocks of Angular applications. We use them and compose them together to make larger and more complex things. So here you can see we're importing HTTP module, which gives us HTTP support. And we're talking to Firebase with that. And we're using the Angular router. And we're actually using the Angular router in a kind of a specific way. We are lazy loading every single route in this application. And that's actually one of Angular's best practices for performance. We never want to ship code to the user that's not intended to render something on the screen right away. And so I built this application with the Angular CLI that Stephen was talking about earlier. And if you've used the CLI, you're probably familiar with NG serve, the dev server that he mentioned. What NG serve does is starts up a process that watches your code. And when you make changes, it recompiles on the fly and refreshes your browser. So you can kind of live edit, debug, build your application. So I built this app with NG serve. But we're actually not going to use it for the work that we're going to do to make this a PWA. And that's because a lot of the tasks that we have to accomplish happen after the time we take our application's production build. The CLI produces our disk folder with all the production assets. But happened before we deploy to the web server. And so I'm going to be using this little run script here that does a production build of the CLI and then runs an HTTP server in the disk directory. And in your applications, you probably have a little bit more sophisticated of a build system to do these steps. But I'm going to use this because we can see in one clear place where everything's happening. So let's jump back to our application here and talk about what we're going to do. As Stephen said, Angular PWAs are reliable. They're fast, and they're engaging. So those are our three goals. We're going to make this application reliable, fast, and engaging. And reliability is really about separating this application and making it independent from the network. Because our users are on planes or trains or submarines. They're places without internet or with flaky internet. And they need to load this application. They're going to install it to their home screen. And when they hit that button, they expect the application to load like a native app. They don't expect it to kind of wait or get caught up with network requests. So to make it reliable, we're going to take all of the assets we need to load this app and move them to the device with a service worker. Then to make it fast, we're going to take advantage of two different techniques. It's already using Angular best practices, but we can go a little bit further. So we're going to add an application shell, which is going to improve the perceived latency when you're loading this application. And we're going to use HTTP2 server push to deliver all the assets we need to load it before the browser even knows to request them. And finally, to make it engaging, we're going to add support for push notifications. For example, if we ship someone an order, we really should be able to give them a notification that lets them know that their package is on the way, and they're getting their new cape or mask. So let's go ahead and look at the tools that we're going to be using to do this. And there are two main ones. The first is the Angular service worker. Now if you've used a service worker before, you're probably familiar with SW Precache and SW Toolbox, which are tools that the Chrome team publishes to make generating service workers for your projects easy. There's a new one that they've come out with called Workbox that you may want to take a look at. And all of these tools work in a similar way. They generate a service worker which is specific to your application. It reads your application configuration and spits out a JavaScript file that you load in the browser. The Angular service worker is a little different. It ships with a worker script that we can just deploy the whole sale onto our web server. It doesn't know anything about our application to start with. So we'll also provide it with a JSON configuration file that lets us declare all of the assets and all of the resources that our application needs to load. So the second set of tools we're going to be using are the ngPWa tools. And this is a set of tools we've been working on to kind of automate some of the more configuration heavy parts of building progressive web apps. You can absolutely do everything we're going to do today without these tools. But I really recommend you use them because it'll make your life a lot easier. So I have these installed already. We don't need to run that. Let's go ahead and jump in and set up our service worker. We're going to work towards that first goal of making this application reliable. And there are three things we need to do with the service worker. The first is we have to take that prebuilt script that it comes with and copy it from the service worker install and node modules into our disk directory. So we're going to copy from node modules, Angular, service worker. And it's in a directory called bundles. And the script is worker basic.min.js. So we're going to copy this into disk. And you don't have to write this down. There are instructions on the service worker repo on how to do this. So we're going to copy the prebuilt worker into our site. Awesome. And now that we have it there, now that we're serving it, we need to actually register it in the browser. And there are a couple of different ways we could go about this. One of them is we could just register it in the index page. But we need to be a little careful about doing this. If we register it in index, it's going to immediately start trying to download all the assets that it needs to make this application work offline. But that'll happen while the app is loading. And so we'll have two kind of different uses of the network competing with each other. And we'll slow down the initial load. So really what we want to do is wait until Angular is done bootstrapping and then register the service worker. And we can do that in our main.ts file. Here we have our platform browser dynamic dot bootstrap module call. This is what loads the Angular application and bootstraps it in the browser. And you may not know, but this call actually returns a promise. And so we can wait for Angular to finish bootstrapping. And only then do we register the service worker using the navigator.serviceworker.register API. And remember, the script is worker basic min js. And if we load this in a browser that supports service worker, it'll work great. We'll download and install the Angular worker. But if your browser doesn't, this call will crash, right? We'll be calling register on something which doesn't exist. So we need to surround this with some feature detection and check whether this API actually exists before we try to call it. Not every browser out there has service worker yet. And if they don't, that's OK. Our application is not going to break, right? It's just going to not have the benefit of offline caching. And that's called progressive enhancement. So now that we've copied the worker script into disk and registered it, it's time to configure it. So what kind of configuration does it actually need? Let's take a look at what it takes to load this application. Here we have some CSS assets that we need, some JavaScript, some images to display. We also have this initial request for the home route, right, just slash. The worker needs to know that that is a route of our application and should be served with the index file. And finally, we have some data coming from Firebase, right? The capes, sale, and the products, they're not baked into this app. We're loading them from a database. And so we need to tell the service worker how to cache those as well. And we have to be a little bit careful with data, right? It changes frequently. So we should be a little more specific about how we want to cache it and when it should expire. So to get started doing this, we're going to use one of those PWA tools that I talked about. And this is called NGU, the U stands for Universal, SW Manifest. And if I just run this without any arguments, it's going to read the disk directory that CLI built and produce a static configuration that tells the service worker all of the assets in our application and how to cache them. In particular, it's going to include a content hash. And what the content hash does is let the service worker know when it's time to upload those files. So if you deploy a new version of your app with a new manifest and some of your content has changed, Angular worker can notice and will re-download and recache those files in the background. So next, we need a routing configuration. And we can write that by hand, but we can actually just give the tool our application module. And because it understands Angular, it can read this and figure out what our routes are from the application module itself. And so here we generate the routing configuration as well. And that leaves us with those URLs from Firebase. Those ones we have to describe ourselves. And so what we want to do is jump into our application and create an NGSW manifest file that's Angular Service Worker Manifest in our source directory. And here we can specify a dynamic caching configuration, which will let us cache those Firebase URLs. And this looks a little complicated, but I promise you it's not. So what we're doing here is declaring a group of URLs that will have a caching policy applied. And we can decide what that policy is. So we'll call this the Firebase group. And we really want to match the Firebase URL. And we don't just want to match the root of Firebase. We want to match every URL under this space. So we'll match it as a prefix. And then we get to decide exactly how the Angular worker should handle this data. One thing we might want to say, for example, is that we'll cache it for about an hour. We also want to set a limit on it. We don't want to fill up the user's device with all of our products that we sell. And finally, if the cache gets too full, we need a way to expire things. So we have to tell the service worker how we want to do that. I recommend least recently used caching or LRU. But the most important decision we get to make is how we want the worker to optimize for our data. One popular choice is to optimize for freshness. This is great for data that changes really quickly. It tells the service worker to go out and get it from the network always unless the network is down. So we always have up-to-date data. But if we happen to be offline, we can use the cache to fall back. But because our data doesn't change that often, I recommend caching for performance. So what this does is tell the Angular worker, it's OK to use the cache to speed up requests. We don't always have to have the freshest data. So it can go to the network only when the data is not in cache or when it's too stale. And our tool knows about this file and can actually merge the static configuration that we wrote or that it generates with the dynamic configuration that we wrote. And so we're going to take this and paste it into our build script here. So we're going to generate a service worker manifest from our app. And the last thing we have to do here is actually write this out to disk. So we write out this JSON file that the service worker knows to expect. That was a lot that happened really quickly. So let's just walk through it real quick. First of all, we copied the pre-built worker script from Angular service worker node modules into our app. Then we registered it with Navigator service worker register. And finally, we generated a manifest for it. So let's see what that did in the browser. If I refresh the page here, we can see that Angular service worker downloads and installs. And it's up and running for this app. And if we come back to the network tab and reload, we can see it start to work. No longer are we going out to the network to get all of these JavaScript and CSS assets. Even the images are cached. The only thing that's not are our Firebase URLs. What happened? Well, this is the first time the service worker saw those requests. They weren't in its cache. But if I reload the page, everything is now coming from the cache. This application no longer needs the network to start up. Even that initial home request comes from the service worker. And we can prove it by hitting the offline button in Chrome. And when we reload, we'll see our application doesn't care whether there's a network here. That's reliability for you. So next, whoa, yeah. Yeah, that's awesome. All right. So next, let's talk about making this app fast with App Shell. And to show you what an application shell is, I'm going to go in and turn off JavaScript in Chrome. And I'm not doing this because I expect the end user to have JavaScript disabled. I'm doing this because in between the time the index page downloads and the time all your scripts load and Angular bootstraps, the user will be effectively running in a browser without JavaScript. And they'll see your page as it would look. And on a MacBook, this is like a half a second or less. But on a mobile device, the user could be staring at the screen for a few seconds. And it's really not pretty. Here we have a blank empty screen with a little loading text up in the top. And if I were a user who didn't really understood how this work under the hood, I would think this application is broken. It's not doing anything. It's just sitting here. I'm supposed to see my app. I just see this loading text. There's no indication that it's actually loading anything. So let's fix this. And we can fix this by using Angular Universal to generate us a new index page that has our application already rendered. And we can do this with another PWA tool called NGU App Shell. And like before, we passed it our app module. We're passing it just the TypeScript file. We don't have to worry about setting up a build first. And we run this. It's going to generate a new index page for us. And on a first glance, this looks great. It has all of our application CSS. It has all the HTML that we would otherwise render. And this doesn't take JavaScript to display. But the problem is, it's actually done too much. This is the entire home route. It's gone to the Firebase. And it's downloaded our dynamic data. It's rendered out the product list and all of that. But we don't want that in the index. We're going to save that index and push it to our web server and cache it all over the world. And our data changes more frequently than we deploy the application. What we really want is not to display the home route, but to display some kind of loading route. So we can go and write one in our application. And I've actually set this up already. So we have a loading module, which registers a loading route, which shows a loading screen component with this H3 here. And you could go and imagine having a fancy CSS animated spinner here. I'm not great at animation, so I just have an H3. And this module isn't actually installed in our application. We don't actually need this loading route in production. What we want to do is insert it into our application shell. And we run this. We'll generate that new index page. But this time, instead of the home route, we render our loading route. And so we can take this command and paste it into our build script and set it up. All right, run.sh here. We're going to generate a new index HTML with an app shell. So I'm just going to format this, so it's a little easier for us to understand what's going on. And the last thing we want to do is actually write this out to dis-index that HTML. We're going to replace the one that the CLI generated for us with the one that we generated with an app shell. And so let's start this up. And I'm going to go in the browser. I'm just going to leave JavaScript disabled. But I am going to remove the old service worker because we've updated our code and we want to see the effect. Normally, it would update in the background, but this is faster. So we expect to see, when we refresh this page, we expect to see, instead of this loading text, we expect to see our material toolbar at the top and some better indication that this app is alive and running on the page. So when we refresh, that's exactly what happens. This is static. There's no JavaScript still. But this is a much better experience for our user. This is an application that's there. It's awake. It's running. It's loading for me. This looks like I expect it to. So when we turn on JavaScript again, what we'll actually see is Angular bootstraps on top of this and we'll render the home route right on top. Perfect. That's what we want. It shows the loading screen until JavaScript downloads, and then it renders Angular. Fantastic. So that's one of our techniques for making this application faster. Next, we're going to look at HTTP2 server push. And the best way I can show this to you is with a trace. So I actually pushed this application, as is, to Firebase and rendered it with web page test. And if you think seven seconds looks like a long time to load an application, you're right. And that's because this is a really low bandwidth, high latency network, and kind of a mid-tier device. This is a real world test of an app. And so Firebase delivers our index page here, this blue square, in about two seconds. That's pretty good. Kind of hard to shave this down anymore. And the browser immediately realizes that it needs some other resources to render this page. So it downloads a CSS file and four JavaScript files. And about six seconds in, Angular bootstraps. And Angular loads the router. And the router reads your route configuration and discovers, hey, there's this lazy route that I need to render. I need to go and get more code from the server. So it fetches this lazy chunk. And that's good. We didn't download any code that we didn't need to render this application. But we did manage to make it take almost seven seconds to render this app. And we can do better. And we know we can do better because we know the resources that this page needs to load, even if the browser doesn't. And so we can just send them to the browser anyway before it asks. And that's what HTTP2 pushes about. So with Firebase, you do this by writing some JSON configuration. And we can generate it with our last NGU tool of the day, NGU Firebase Push. And just like before, we pass in what our application module is. And when we run it, it spits out this header configuration for Firebase. And this sets up the header that Stephen was talking about that describes which assets are needed for each page and are pushed down. And the thing I want you to notice here is the home route pushes the first lazy chunk. And the cart route pushes the second one. We've used our knowledge of Angular to figure out exactly which lazy routes are going to be loaded when you go to each route. And so when you run that through Firebase, the trace looks a little bit different. We're still loading our index about two seconds. But this time, even before it's done, we start receiving data for all of the other bundles, including our lazy chunk. And by the time Angular bootstraps around five seconds, this chunk has already been on the device and is ready to go. So we can load our app in about five and a half seconds instead of seven. That's awesome. That's a lot faster. Woo, yeah. All right. And so the last thing we're going to do to this app is we're going to make it more engaging with push notifications. So let me talk to you a little bit about how push works on the web. It starts with us in our application registering to receive push notifications. So we're a user. We're using the app. We hit a button that says, yes, I want you to push data to me. It asks for permission. We say, yes, that's OK. What we get from that is a subscription object that defines an endpoint that our server can use to send data to that user. That's a URL and some encryption credentials. And we would send that to the server and save it in our database. And the next time we need to send data to that user, we could get it from the database and use an NPM package called web push to do the right things with the push protocol and deliver a message to this user. But we actually have no guarantee that the user will be using our application at the exact moment we push data to them. And so what the browser does is it delivers that message to the service worker. And the service worker can handle it in any way that it chooses. One thing it can do, for example, is display a UI notification. So on a desktop here, that'll show up as a pop-up in the upper right corner. On a mobile device, that shows up in your notification tray. The service worker could also check whether an application tab is open. And if it is, it can deliver the data to the app. And then in the app, you can do whatever you need to update the UI. Maybe you show a little badge on one of your icons up here saying, hey, you have a message. So let's set this up. The Angular service worker supports this out of the box. All we have to do is turn it on. So we go back to our manifest, the dynamic manifest that we generated. And we're going to add a push section. And all we're going to do here is set show notifications to true. And this turns on those UI notifications. It tells the Angular worker whenever you get a push, display a UI notification with a message in it. That makes it really easy to configure what UI notifications you want to see from your back end. And now that we've done this, we have to actually register to receive these notifications. And here again, we can take advantage of Angular service worker. Because it's Angular aware, it comes with a service that we can use to interact with it. So we can import that and inject it into our app. So we're going to import from the Angular service worker. And the service is called the ng service worker. And if you've used Angular, you know we probably need to provide a module to make this work. So we're going to import the service worker module as well. And we can add that to our app module. And now we can inject the service. So let's add a constructor to app module and inject the ng service worker into it. So we do this with TypeScript. Let's give it the right type. And Angular will figure it out. And there's a few things we can do with this API. We can ask the service worker to check for new updates of the app. If it has one, we can ask it to activate it. We can check the service worker logs or ping it to make sure it's there. And we can also register to receive push notifications. And we do have to pass one critical piece of data, which is an encryption key. And this makes sure that we're the only ones who can push data to our users. So we'll pass an application server key. Now you would normally generate this with a web push package on NPM. I have one ready to go because that's boring. And now let's go ahead and subscribe. And what we get back is a subscription. And the subscription object is the thing you send to the server that identifies this user and lets the server push data to it. So let's take a look at what it looks like. I'm going to call to JSON on it so we serialize it. Another thing we can do with this API is actually ask the service worker to tell us whenever a push message comes through. So if our application happens to be running, we can get the data and deal with it ourselves. So let's console log out, got to push, and we'll save the message. So let's go ahead and run this and jump over to the browser. Now I have a confession to make. I don't actually own a superhero store. So we don't have a back end that can push data to you when you ship orders. But that's OK because we can use a feature in Dev Tools under the Service Worker tab to emulate a push event and simulate what it's like to get a back end pushing data to us. So let's go ahead and reset this and make sure that it's deleted. And we reload the page. The first thing we should see is we actually get our push endpoint logged out. And this is that object I said that you would use to push data to the user. So it gives us a URL and our encryption keys that we can use with the push protocol. And now if we jump into our tab and emulate a push event, you can see the worker gives us a nice UI notification up here. I can do it a few times. If I reload the page, it still works. Clear this out. And if I go back to the console, the Service Worker is also sending us a message saying, hey, you got this notification. And what this means is in your application, in your back end, you can configure not only the UI notification to show to the user when you push a message, but you can also set up exactly what other data you want to send down in case the application is open, so it can handle the push in a more engaging way. And that helps us bring users back into the application over time. So with Service Worker, we've made this application reliable. With an app shell and with HTTP to push, we've made it faster. And with push notifications on the web, we've made it engaging. This is now a fully fledged Angular Progressive web app. I'm going to turn it back over to Stephen. Thank you so much, Alex. That was awesome. And if you can go back to the slides as well. So what's next for you as developers if you want to take advantage of this? So we've actually pushed all of the code he wrote and all of the links and guides to this tool onto GitHub. So we've got that top link there. I'd also recommend you take a look at a guide written by Rob Dodson about debugging Service Workers. Because Service Workers fundamentally shift a couple of the paradigms on how you develop applications in terms of how it refreshes, how it reloads. And so understanding how to debug Service Workers can be extremely helpful. So with that, go ahead. I hope you all go and build Service Worker in Progressive web applications with Angular. Please let us know on Twitter if you have feedback, if you love it, or you hate it. And thank you so much.