 Today I'm going to be talking about building progressive web apps with Polymer. Before I go into that, though, I just want to back up, and I'll tell you a little story. So a few months ago, I was on vacation. This was right after the Polymer summit. So I was in the Netherlands. Lovely place if you ever get a chance to go there. And I was kind of off just doing my own thing. And meanwhile, back home, I noticed in Mountain View all my buddies, all my co-workers, they started emailing back and forth, and they were all talking about progressive web apps. I'm really excited about this notion. And I was on vacation, and I was like, huh? What is everybody talking about? I felt like I was kind of out of the loop over there. And maybe I was missing out on something really, really big, and that there's all these new technologies that I was going to need to learn. And to be honest, I was kind of approaching this whole thing with a sense of dread at first. So I went and I dug up Alex Russell's blog post. And I was like, all right, what is the criteria for a progressive web app? Now it's going through there, and it's like progressive web app is responsive. It's connectivity independent because it uses service workers. Cool. It's got app-like interactions. So as I was going through, I realized progressive web app is really using all of the same cool features and things that we've been working with and have been talking about at Chrome Dev Summit for the past few years. But now we have this sort of umbrella term to bring them all together and kind of a set of criteria to aim for. There's a line in that same blog post where Alex says that a progressive web app is just a website that took all the right vitamins. And I think that's a really good way to think about things. So what I wanted to do today was just build a Polymer app to try and hit all those guidelines and demonstrate the areas where I think Polymer can really give you a leg up if you're building a progressive web experience. So this is the little app that I built. It's called Super Cool Blog. I built this with some members of the Polymer team. The idea is that it's just kind of like a little news site, the kind of thing you might want to pop up in your phone and read when you're waiting on a bus or on the subway or something like that. Maybe your connection is a little spotty. And what I want to do in this talk is just kind of jump around and highlight some of the areas in here where I think Polymer can really help you build that progressive web app experience. So these are the areas that we're going to be covering in this talk. I want to look at ways that Polymer can help you make a responsive app. I want to look at ways to make it load fast and make sure that we're really hitting that L in rail and getting a good, fast first paint. I want to look at ways to make it work offline because our user's connection might be spotty. I want to figure out how the user can take it with them anywhere they go by putting it on their home screen. And lastly, I want to talk about how we can reengage with our users using push notifications. But let's lead off with that first point, which is making the application responsive. And this is one of those areas where I think web components and Polymer in general just really excel. Because we can take complex layouts and then compartmentalize them into these elements. So you can reuse those, you can mash them up, and you can get the kind of scaffolding that you want for your app. And it's nice and responsive. Now last year here at Chrome Dev Summit, I built an app using our paper element set for material design, which I thought was cool then. But I thought for this Chrome Dev Summit, it would be cool to use the app layout elements a little bit. And as Taylor mentioned, these are still really experimental. But I just wanted to play around with them a little bit, show you a preview of them here at Chrome Dev Summit. And as Taylor mentioned, the whole deal with app layout elements is that we want to provide some elements that are a little bit more flexible, a little more general use, so that they're not just for material design, but they're for any layout that you might want to put together. So walking through this example here, I'm going to start by just building a toolbar. If you've ever seen me demo stuff before, I always start with toolbars. And I've got a little app toolbar element, and then I've thrown a paper icon button inside of there. And automatically, this is kind of one of the cool, beautiful things with web components. I've got elements from two different sets, and I'm just like mashing them together. And it's OK, their styles play nice together. Now, the next thing I want to add to this is the title for my site. And the title is going to be a bit bigger, and I kind of want my toolbar to stretch. And this is actually one of those areas where paper toolbar could be a little inflexible, because paper toolbar relies very heavily on shadow DOM distribution to project content into different layers in this hierarchy. So you have to go read the docs of paper toolbar, figure out the special class you need to put on your content to get it to show up in the right place. With the layout elements, if I just want to extend my toolbar, I can actually just tack on another toolbar. And now I'm just building another hierarchy inside of this thing. So they just stack and kind of fit together like Legos. And when I'm happy with this little hierarchy that I've constructed, I can wrap them all up in an app header layout, or an app header element, excuse me. And an app header is going to allow me to differentiate all of this content that I'm building here from the rest of the content in my application. And it's going to let me add special effects to this header. And so the last thing I want to do is wrap it in an app header layout. I can throw in a little main tag down there at the bottom for my site content. And now that I'm contained within that header layout, I can add attributes to my app header to give it special behaviors. I can say that I want it to be fixed all the time. I can say that I want it to cast like a waterfall shadow as the user is scrolling around. If you've worked with paper elements before, this should feel familiar to you, except for these elements just are a little bit more flexible. They're a little bit easier to style, a little bit easier to snap together. They kind of rely a little bit less on shadow DOM and more on just what you would expect to work there. So it's kind of an evolutionary step, is how I like to think of these. One thing that I really want to highlight is just a difference between the paper elements and the app layout elements that always bugged me. The paper elements, you'll notice here, is my little URL bar is not actually scrolling away, which I feel kind of detracts from the appy feel of this thing. And that has to do with the way that the paper elements implemented their scrolling behavior. With the app header layout, it scrolls away, and I get this nice, it feels more like a real application that you would have on your phone. So I just want to highlight that difference. It's one of those quirks that's always really bugged me, especially if you have to bring up a keyboard. That's not a lot of real estate for someone to see the content of your page. So it's nice that's been improved with those new elements. Now, if you want to play around with these, they are actually up on GitHub at polymerlabs.github.io slash app layout. There is a version of the site that I'm showing today. It's kind of a strip-down version. It doesn't include all the service worker stuff and things like that that I'm going to be showing. But it does show off how to use the app layout elements. And there's also other sites that are up there as well, including the Polymer Summit site. So you can go through and you can see some different templates and demos to play around with, all the sources available. And as we are adding new patterns and new templates, we'll be putting them up there as well. So using those app layout elements, I feel like I have good tools to make a nice responsive layout. The next thing that I want to do is make sure that this loads really fast. I want to make sure that the user of my application has kind of like a good instant feeling experience. And to do this, I want to explore some async design patterns that you can use with Polymer to kind of optimize for a fast-perse paint. So I'm going to show you this video here. And this is my site, totally unoptimized right now, running in an incognito window in Chrome. So it's not bad, but we kind of have that little white screen at the beginning, right? We're just really, I don't know, is anything happening? And if a user is on a 2G connection or 3G, you could imagine that white screen is going to be there for even longer, and they're going to be scratching their head, like, is the site working? I don't know. So this isn't necessarily a Polymer problem. This is just kind of like a web platform problem in general. If you're loading a bunch of content up front, you're going to be blocking your first paint, and the user is going to be sitting around staring at a white screen. So I'm going to look at some ways that I can improve that for this app. Now, this is the index file for my application. And if you've ever built a Polymer app, this is pretty typical boilerplate that you see here. We've got our web components polyfills up there at the top in the head, and then we've got a link tag to import all of our elements. And the reason that we put those in the head is because we want to prevent a flash of unstyled content. We want to make sure that our elements are there, they're registered in the document before we try and paint them, otherwise they're just going to kind of upgrade in place, and the page will look a little weird. But these are also render blocking, right? As most of you know, if you put a script tag in the head, it's just going to hold things up while it's doing its thing. And if you put an import in the head of your document, it's also going to hold things up. It's going to prevent rendering because it behaves basically just like a style sheet. It's trying to prevent a flash of unstyled content by being up there. But from my app, I really, really, really want to optimize for first paint. So the first rule that I kind of adopted here was making sure that I'm not blocking the renderer, waiting on polyfills or elements to load in. So how do we fix that? Well, back in my application, instead of just having these tags right in there as is, I'm going to add async attributes to both of those. And that's going to free up the renderer to move past them and head down to the body and do its thing. But looking at this, I'm also kind of wondering, like, right now I'm always loading the Web Components polyfills. And should I always load the Web Components polyfills? How many of you think I should always load the Web Components polyfills? Good. OK, good. No, you should not always load the Web Components polyfills. There are browsers out there which already have support for Web Components, Chrome and Opera. And so for those browsers, for the users that are under data caps or are bandwidth constrained, it's kind of wasteful to just force them to download these polyfills. So instead what we should do is we should conditionally load those polyfills using feature detection. So what I'm going to do is instead of just having that script tag for Web Components.js, I'm going to pull that out and I'll add a little script to the bottom that's going to be a little feature detect script. And inside of that script, I can check to see if Web Components are supported. So I'm checking, hey, is custom element there, imports, template, right? If not, then I can go ahead and lazy load the polyfills with a little dynamic script element. OK. So now we're not holding anything up in the head of our document. The renderer is free to move down to the body, which is awesome. Now looking at the body tag, you might notice this unresolved attribute right here. And wonder what's up with that. So this is a feature that Polymer adds. It's another feature to prevent flash of unstyled content. It's basically going to hide the body until all of the elements have loaded in. And then it just kind of reveals the whole thing. And it's a really convenient feature. But again, in our case, since we are chasing that fast-first paint, it's also kind of a bottleneck, because it's hiding the body until all of our elements have loaded. So I'm going to remove that. Now at this point, there really is nothing holding up the paint of my page. And now we enter some interesting territory, which is depending on how you've structured your application, there are a few different ways that you can get a fast first paint out of it. So if you've just got custom elements in the body tag just sitting there, one option is to use the unresolved pseudo-class to style those unupgraded elements. Now at the moment, the unresolved pseudo-class only works in browsers that have custom element support. So you're limited to the browsers where this will work. But I believe that in the future, this will be a more common technique that we can take advantage of. So I do want to show how this works today. And basically what I'm doing here is I have an inline style tag for my critical CSS, because I do want to paint these components as fast as possible. And I'm styling that app header layout element using that unresolved pseudo-class. And what I want to do is paint the element so that it matches its final version as close as I can get it, and then let the element just sort of upgrade in place. Now you can simulate the unresolved pseudo-class using attributes. So you could do this today, and this will totally work. This is kind of like what Polymer was trying to do with the unresolved attribute on the body, except for in this case, you've got to sort of manage it yourself. So this would work, right? I could paint my element. I would need to go in afterwords with JavaScript and remove those unresolved attributes. But this is another approach that you could take to sort of paint the individual elements as they're loading in. Another alternative to this, which might be easier, is to just create a skeleton that mimics the look of your final app shell, paint that skeleton with inline styles, and then hide it when all of your elements upgrade. So what I'm doing here is I literally just have a div with some dummy markup that's going to represent my skeleton. And then I've got styles that are inline to paint that skeleton as fast as I possibly can. And then once my elements load in, maybe I have my whole app continue in a single element. Once that upgrades, I hide that skeleton. Everything reveals itself at the same time. Now I realize that this is kind of coloring outside the lines, like people don't like the idea of adding dummy markup just to paint something. But I feel like the improvement for user experience is well worth it. This is coming from a good place. There's some good intention here. And I want to show you kind of a side by side comparison. So we've got the original version, and then the async version using that skeleton approach. So as these run, you see immediately there's something on screen with the async version. Now it's just the toolbar, but that sends a signal to the user that, hey, something's happening. The site is not dead. Things are working. We've got content coming to you soon. So I haven't gone crazy with the skeleton. I didn't write like reams and reams of CSS or anything like that. Just enough to build a quick shell and let the user know that stuff's coming. All right, so now I feel like I've got a good, fast first paint with that shell approach. Now the next thing that I want to do is tackle offline. Because as the user is browsing the site, I don't actually have a guarantee that they're going to have really solid connectivity. And so to tackle offline, what I want to do is add a service worker to this application. And I know that we've covered service workers a lot today, but for anyone who maybe is just tuning in to the live stream or is watching this video later on YouTube, I'll just give you a brief summary. Service worker is a script that's run by a browser in the background separate from your web page. And it enables a lot of really cool things like caching and push notifications. But a service worker in building it is not necessarily a trivial process. It is by design, a low level API. So it is very powerful, but there can be a fair bit of code involved. Now we've been building libraries on top of service worker to try and improve this experience. So as Jeff mentioned, we have libraries like Service Worker Toolbox and Service Worker Precache, which abstract those complexities away and make it easier for developers to work with it. But on the Polymer team, we wanted to take that even a step further and see if we could build some elements on top of those libraries to make the entire process declarative so a developer of really any skill level can just get in and add a service worker to their app. Now these elements live in our Platinum element product line. And as it says on the 10, these are elements to turn your web page into a true web app. And I would add progressive to that statement by adding things like push, offline, Bluetooth, and a lot more. Again, our goal here is just to make it really, really easy if you leverage these powerful features in your app. So if you want to add a service worker to your Polymer app, it is as easy as dropping a tag in the page. So this is the Platinum Service Worker register element, and it's going to go ahead and handle all the things that I need it to do to create and register a service worker for me. And I can configure it the same way that I can figure any other HTML element, just using attributes. So these attributes here, what they do is auto register tells it to go ahead and immediately register my service worker versus waiting on me to call a method and kick it off. Skip waiting tells the service worker to skip its waiting phase and immediately go active. And clients claim tells the service worker to start handling all of the requests on the page and take over the page and start serving responses for it. Now, I've got my service worker in place, which is really cool. The next thing I wanted to do is take advantage of some of those cool features that service worker affords me. So I can add caching, right? And again, I'm just dropping in more elements. Now, this Platinum Service Worker cache tag actually builds on top of the service worker toolbox library, but it just makes it nice and declarative. So what we're doing by adding this element is we're telling the application to start dynamically caching requests as they go through it. And there are a few different caching strategies that we can take advantage of. The fastest strategy is going to tell the service worker to race the cache in the network and return whichever one comes first. Network first is going to hit the network. And if that fails, it'll try the cache. And network only is just going to hit the network. If that fails, it's just going to fail the whole request. So from my app, I'm going to opt for the fastest approach because I think it's OK if the user is getting slightly stale content, so they're getting something and they're getting it really fast. And I can use the default cache strategy to just configure my cache to use that. But I'm not limited to dynamic caching. I can actually also have this element be proactive and go out and start pre-fetching and pre-caching things for me as well. And kind of a general rule of thumb is pre-fetch all the things that are required for your app shell to render really quick for the user. Now, we can do that by configuring the element with a pre-fetch attribute. I can give it an array of file pads that I want it to pre-fetch and pre-cache for me. But some people might not like the idea of having an array of file pads in their HTML that might feel a little wonky, in which case you could instead use a cache config JSON file. This is just a JSON file full of file pads. So that actually looks like this. I can give my cache an ID. Tell it in that array what to pre-cache. And I can also give it a pre-cache fingerprint, which is just a little identifier to show out the uniqueness of the cache itself. So if I want to, I can change that pre-cache fingerprint at any point, and that'll tell my service worker to go out and pre-cache the things from the array over again. Now, in this case, the pre-cache fingerprint is just a hash that I generated. If you're curious how to do that at build time, you can check out our Polymer Starter Kit project. We actually have a little cache config task in the gulp file for it there. I can go and check out that task. It'll actually generate that whole file for you, including the fingerprint, just at build time, so you don't have to manage it yourself by hand. OK, so adding service worker, adding the pre-caching features, let's see what our app looks like now. So my user's using it, and reading an article. Meanwhile, it's dynamically caching all these things. Let's say they go offline for whatever reason. They go into a tunnel or something like that. And let's say for whatever reason they refresh the page, maybe by accident, or they think they need to. So they refresh the page. Well, everything loaded, even though they're still offline, they can actually go back to that article they were reading and just continue the experience. As far as they're concerned, they don't know if they're online or offline. They don't know if they have a spotty connection or what. They just have this nice continuity to their experience, which is awesome, and one of the really powerful things that you get from service worker. OK, so my app is now working offline, which is awesome. But admittedly, most of us, when we know we're already offline, we don't go and open Chrome and expect to find a bunch of content inside of there, right? We're kind of trained to, if you know you're offline, you're trained to expect the offline dinosaur if you open Chrome. Instead, we've been trained to look to home screen apps for content if we know that we're offline. And this is interesting because the app that we've built at this point, it basically meets all the same criteria as those home screen apps. So why don't we just see about getting it on the user's home screen? And to do this, I'm going to use web app install banners. And if you haven't seen this before, it's basically a little prompt coming from the browser, which asks the user if they would like to save the application to their home screen. Now, I'm curious, how many of you know about the Add to Home Screen button? Show of hands? All right, keep them up, keep them up. How many of you use the Add to Home Screen button, I would say, have used it more than three times in the past month? OK, all right, all the hands go down, yeah. OK, why is that? Well, one, I mean the UI is a little buried and a little hard to find. But two, you don't really know if that thing that you're adding to Home Screen is going to be a good experience, right? Is it going to work offline? I don't know. I can't tell just by looking at it. And so one of the things that's cool about web app install banners is there's a set of criteria that your application needs to meet before the browser will actually prompt the user and ask them if they would like to save it. So to trigger a web app install banner, your app must have a web app manifest, which we'll talk about in just a bit. It's got to have a registered service worker. And we're getting that basically for free using those platinum elements, which is awesome. It's got to be served over HTTPS. And lastly, it's got to be visited twice by the user with at least five minutes in between. And I put a little asterisk there because that last heuristic might change. We're still sort of dialing it to figure out what is the sweet spot for user engagement. But there is at least some degree of user engagement that needs to happen before it will trigger that banner. So most of these are self-explanatory. But let's look at the web app manifest, because that might be new for folks. So web app manifest is really just a simple JSON file. It's got fields for your application's name, the icons that it should use when it's added to the home screen, background color, which we'll actually show off in just a sec. Again, many of these are sort of self-explanatory. One that I do want to highlight is the start URL down here. So what the start URL does is it tells your application what URL to boot to when it's open from the home screen. And as a signal to your app that it's being loaded from the home screen, you can do this kind of clever little trick where you put a query string on the end of your root URL and say, oh yeah, home screen one. And that way your application JavaScript, if it sees that, it knows that maybe it should behave a little different because it's in home screen mode or something like that. It could choose to show something different to the user. So that's just a little pro tip. If you're launching something from a home screen, you want to have a slightly different experience there, that's one way you can do it with that signal. So when you're happy with your manifest file, including it in your application is pretty straightforward. You have a link tag with rel manifest, and you point it at your manifest JSON. But there are browsers out there which actually don't support web app manifest yet. And for those browsers, you need to include some fallback meta tags. And those look like this. And I'm sure you're looking at all these, and you're like, mm, but I don't want to remember any of that. And yeah, it's kind of annoying to have to remember all these things and copy and paste them. And so I gave a little plug to our Polymer Starter Kit project earlier, and I'll give it another one here. If you go check out Polymer Starter Kit, which is just, you can just Google Polymer Starter Kit or go to developers.google.com slash web slash tools. Polymer Starter Kit includes already a working web app manifest. It includes all those meta tags for you. It includes all the different icons that you need at all the right sizes. And all you have to do is take that and start adding your own content. So if you're lazy like me, you don't remember all that stuff. You can just go there and do that. Now, once you got that squared away, it kind of brings up this other interesting question, which is figuring out if the thing is even working. Because I mentioned there's this user engagement heuristic to web app install banners. The user's got to visit the page a few number of times over a few minutes. And as a developer, it's super annoying to have to sit there and just stare at my website in a clock and be like, ah, yes, try to get in. Did that work? I don't know. So one of the things that I found as I was building this app is this sweet little flag that's hidden in your Chrome flags called bypass user engagement checks. So if you want to go add a web app manifest to your application, you want to try and get an install banner running, you can go to this little flag. You can enable the bypass. And then you don't have to wait around for the user engagement bits. It's just going to verify all the other items from that checklist. It's going to verify HTTPS is looking good, your manifest is looking good, your service worker is looking good, et cetera. So that's a little helpful pro tip there. Another thing to watch out for, which is a little gotcha that I ran into, is make sure that you don't accidentally send the user to a screen that you have not cached yet. What I'm talking about is, remember this little line that I just showed you? And I was like, oh, this is like a really cool trick that you can use to signal to your application that it's being booted from the home screen. Well, if the user is offline and you have not cached that URL with your service worker, they're just going to see an offline dyno. And the reason is because, by default, service worker request URLs must exactly match. And this includes query parameters. So if you're using that trick, you want to make sure that you either prefetch that URL or that in your service worker, you're handling that and you're serving a proper response. Otherwise, your user might see an offline dinosaur. And that would kind of violate the whole expectation of this thing being an awesome offline app. So another thing to watch out for, but once we got all that squared away, let's check out the whole experience. So the user is going to go to our website. They visited it a few times. They dig it. It says, hey, do you want to say this to your home screen? And they're like, yeah, sure. I like this site. So they close it. Hey, there's an icon. Now when they click on it, it's actually going to give them this awesome splash screen and that icon generated from our web app manifest. And now they're right back in the experience, right where they left off. So now when we've got a web app manifest, we've got a service worker. This app is installable, which is awesome. And actually, because we have a web manifest in a service worker, now we're able to unlock even more interesting features. This is our app entering Pokemon mode, where it's just evolving and getting more powerful. Because we can add things like push notifications because we have service worker and app manifest, which is awesome. And push notifications are a wonderful way to re-engage with your users. So there's a lot of websites out there which have newsletters, right? You've probably seen this where you go to a website and it's like, sign up for the newsletter and we'll email you when we post some new content. But to be really rad, if they could just send me a notification, I could just click on that and go right back into the experience. So that's what I want to add to my app. But as I'm sure many of you have heard today, the thing about push notifications is great power, great responsibility, right? And the main takeaway is just don't spam people. Seriously, you definitely don't want to get blocked. That would not be fun. And it would just annoy the crap out of your users. So this don't spam policy applies both to asking for permission to send push notifications and to the number of notifications that you're sending and the content of those notifications as well. So if you're asking for permission to send push notifications, let the user decide when they want to opt into that, make it very clear how they can opt out, and make sure there is a clear value associated with the ask for permission. So in the case of Super Cool Blog, I added this little thing here where it says, hey, notify me of new content. And they're like, yeah, sure, right? So I'm telling the user exactly what they're going to get when they click that switch. It's not like they just hit the website and I'm just like, yo, can I send you push notifications? Because that would be super weird. OK, now how did I do that? Well, in my application, I've got a paper toggle button. I've got another one of our platinum elements called platinum push messaging. And I'm just linking the state of these two using a data binding. So the check state of the paper toggle button affects the enabled state of my push messaging element. Next, I get my push messaging element, a message URL. This is the URL that it should go look to for notification data when the service worker gets woken up and told, hey, there's a notification. Go display it to the user. So to give you an example of what that response looks like, this is the actual response from my little node server. So I'm sending back a response for that JSON file and I'm just sending back basically a little object with a title, a message to display to the user in the notification, a URL, which when they click to, they're going to end up there. I can show them an icon in the notification, a lot of cool stuff. So let's take a look at that experience. Let's say I'm on Web Fundamentals, really, really awesome website, which you should all be checking out. And as I'm cruising around up in my little tray, I see, hey, I got a notification. I open it. I see it's from Super Cool Blog. I click on it right back into the experience. I'm checking out that awesome new article that they just posted. Pretty sweet, right? Now, if you're interested in this and you want to add push notifications to your own site, you're curious how to set up the server and set up the database to manage subscriptions and all those other things. We have a project which has been created by a couple of our team members, Monica Ninkalescu and Matt Scales. It's called a Cater Day post. It shows you how to use push notifications through the form of cat haikus. It's a very serious example. An example haiku, right? Ponder that in your infinite wisdom. OK, so you can get to get that project on GitHub. It's really awesome. So now I built that user engagement mechanism into my application. Feels good. App experience feels really complete. I'm pretty happy with things. In closing, before I go, I just want to wrap up and say, this is you, right? This is you plus the web, OK? Things are getting super awesome right now if you're a web developer. Progressive web apps give us this really, really cool model for successful applications. And libraries like Polymer give us the tools to build those experiences. Now, if you're interested in the content that we're talking about today and everything, and you're not already a subscriber to our YouTube channel, you should absolutely go to Chrome Developers on YouTube and subscribe. Many of the speakers here today have reoccurring shows on there where we talk in greater detail about service worker and push notifications and all these awesome things. If you're interested to learn more about Polymer, we just completely redid all the material for our academic polytechnic events. So these are a series of events which we run all over the world. I can go to that website, it'sacademic.com. There's a little map there which will show you nearby polytechnic events which you can go to and do like a boot camp or a workshop. You can also just download all the material and do it yourself if you want to do it from home. Or if you want to run your own event, you can grab the material and do that as well. So that is it for me today. Thank you all for having me here. Hope you all enjoy the rest of Chrome Dev Summit. Thanks.