 My name is Patrick. Feel free to call me P. Diddy. No one actually does. But I'm here today to talk to you about keeping the progressive in progressive web apps. Like Paul said, my name is Patrick Kettner. If you google me, that's the photo you'll find over there. And despite what my shirt and my cake have, I actually work at Microsoft. Specifically, I work on the Edge team and the Edge browser. If you guys are up-to-date on your news, you might have seen a couple of days ago one of my co-workers Jacob Rossi released a wonderful blog post called The Progress of Web Apps, which is an awesome pun. High-fives were all around when we thought of that. And it's all about Microsoft's plan for what progressive web apps can be on our platform and maybe alternative install flows or stuff like that. It's a great blog post. The Edge team has done a lot of phenomenal work and we're continuing to commit a lot of resources to the progressive web app story. But that's not really what I'm here today to talk to you about. I'm here today to talk to you as a web developer. I've been a web developer for a pretty long time. When I started writing websites, they looked a lot less like medium and more like that. Well, that's not like that. But like that. Yeah, hey. That's Mosaic. And when I first started writing websites like about Ninja Turtles, it was just kind of really exciting that we had the ability to save a file and then someone around the world would open a file and see it. My mind was blown that I could actually show someone my Ninja Turtles and they would be excited about it as much as I was. Not that anyone ever was. This is the first time I've had an audience to show my favorite Ninja Turtle. But yeah, I was hooked at a really young age, basically. And it's been such an exciting experience being able to be a part of the web community and kind of see it evolve to when like DHTML was introduced. Do you guys remember that? Yeah, PPK. To the wired redesign where we showed that standards were actually a really good thing and you can make some really awesome websites that didn't need table layouts. And CSS Zen Garden, the responsive web article by Ethan Markott. There's all these big stages in web development. These kind of seminal moments where things changed and they never ever really went back. And so a while ago, I was sitting at my home in Seattle and I heard about this kind of really new, exciting way to make websites, one that would use the latest web technology that was safe and secure and would use the same encryption that our banks and e-commerce used and it would look and behave exactly the way that apps did. And one of the most compelling features being that they were easy to release. You could just change the code rather than go through this really complex update process. Has anybody ever developed on an Android or iOS app and you know how painful? Yeah, it's kind of painful to release anything. And in preparing for this talk, I was thinking about how far we have come, you know, in the last year, you know, all the different amazing progressive web apps that have been created and have been shown. And I was just really thrilled at how far we had come since Steve Jobs talked about all this in 2007 at WWDC when he introduced the original iPhone and all of the web apps that came with it. You might not remember that, but he actually did and there was a great collection of web apps that worked well for the web nine years ago. We actually just passed the nine-year anniversary of it. It was the middle of June 2007 and eight years after that, about a year ago from now, Alex Russell had dinner with his wife Frances and they came up with the concept that we now today call progressive web apps. He penned it the next night and it was, you know, what brings us here today. And progressive web apps are finally that fulfillment that we have been promised for nearly 10 years on the web. The idea that you can have this rich native experience that leverages all of the user's device and we have gotten some really, really beautiful, wonderful examples of what that can really be like. Stuff like the Flipkart API, the Flipkart redesign. Flipkart, if you're unaware, completely shut down their mobile website and then a month or two before Alex's article and brought it back with an amazing reference implementation of what progressive web apps can be. The Washington Post had their recent progressive web app demo that is incredibly fluid, incredibly slick. They have 80 millisecond load times on new articles. It's wonderful. One of probably the best reference implementations, AirHorner.com, of a progressive web app. It works across, I've yet to come into a device that it doesn't work wonderfully on, except if you don't support web audio, I guess. I was sitting there and thinking about how it was amazing that we could finally do all these things on the web. And something as excited as I was, something wasn't quite sitting with me right now. It wasn't the sites themselves. The teams that made them are wonderful. They do incredible work. But it was more of the way that as a community we're sort of focusing on progressive web apps. It wasn't the sites. It was this. It was that we're sort of thinking of them as standalone applications that are created wholesale for the mobile web. And what's been presented isn't really the mobile web. I mean, this is a better example of the web. Again, AirHorner is a phenomenal app. Even then, like AirHorner, sorry, not AirHorner, progressive web apps in general and how we thought of them, including AirHorner, isn't just like this. There's more than just this. I'm sure you guys are all aware that last year Google announced that mobile search had taken over desktop search for the first time in history. It's been well over a year now. And that's true. Mobile is the future in India, China, Africa, any emerging markets. Mobile is where people are going first. But if you think about what that is saying, that it's just now surpassing desktop, that means that there is still a huge, non-trivial part of the web that is still the desktop. People use computers, even though we spend a lot of our time on mobile. There is still a lot of people, my parents included, never hardly touch their smartphones. They touch their desktops at work. And there's a lot of content and a lot of ways that we can introduce progressive web apps and the ideas behind them, the APIs behind them, to produce stuff other than just new, wonderful mobile experiences but wonderful web experiences. Because progressive web apps are not just a radical new way to create sites, they are also a radical new way to update websites. As booking.com showed, you can take pieces of what make up progressive web apps, the new APIs, and update your existing app, have something that is a really compelling experience. And I like to go over a couple of different ways that I've, myself and my team have come up with them recently. First of all, the app manifest. We've mentioned it a number of times, so I assume everyone was at least paying attention at some point when we talked about the web app manifest. It is basically just a big text corpus, it's a JSON file that has a whole lot of metadata about your website. Stuff like the language, the direction of the text, a description for like search engines, an array of different icons that might be used, where you want to start, the orientation, a whole lot of stuff like theme college, just a lot of different metadata about your website. You can also include related applications, ways, if you also, for those few that raised their hands because they have helped to work on an iOS device, you can actually support a user being able to automatically jump into a native application, if that's what your company wants. You also have the ability to say prefer related applications, hopefully that's always false. And the great thing about the web app manifest is to add it to your web app today, or your website even, all you have to do is this. It's a link rel tag, it's a simple line of HTML, you just plop it into your website. And the great thing about a link rel tag is that there's no feature detection needed. You just add it to any website today and it'll parse in mosaic too. It'll work everywhere. If your website doesn't support manifest, it's fine, it ignores it, it skips right over it, but you can add it and enhance everyone's experience right away. Something that kind of bothered me when I started looking at the manifest first, when I compared it to the websites I've worked at, is that most of that content that's in the manifest file is also in my HTML already. It's just a little bit different. And so I created a tool to try and help people transition into using the manifest as soon as possible called Manifestation. It's available on NPM. And it does a lot, basically what it does is it goes, you give it a URL and it parses the HTML of that page and generates the most comprehensive manifest file possible. An example of one of the things we do is for the language detection. It will go ahead and load up some node modules, it will load the page in Cheerio, which is like a server-side jQuery. It will check for the lang attribute on the HTML. If that doesn't exist, we'll check for the XML language attribute. If that doesn't exist, we'll check for the Dublin core language attribute. Anybody ever heard of that? No one has, but it exists. And so we parse it. Yeah, you have? Hooray! Librarians! Yeah! Whoo! And so if none of those exists, which is unfortunately a common experience, we actually fall back to Google's Compact Language Detection, where we'll load up the entire text of your page, throw it through the tool that powers Google Translate's language detection, and we'll try and get the result out of that. It detects 140 languages, roughly, or 160 languages, and it's pretty reliable unless you're using a more obscure language. It almost certainly results in something. It's only ever broken when I've tried to break it, not on live websites. And finally, we grab all that stuff and return it. More complex check is like the icons check. I try and get every icon anyone has ever referenced on their website ever. You'll notice that the amount of modules that I use barely fits onto a slide, and rather than go into the logic, I'll just go over what it covers, the favicon? I've never said that out loud. That ICO file, it'll download it, parse it, check if it's multiple ICO files inside of that one, because that can be, you know, multiple icons within the one file. It'll also download it automatically if you don't have one declared on the page from the server's route. It obviously gets the Apple touch icons, all the different sizes available for that. It even downloads the MS application tile image, which I'm sure everyone has on their website, and or even the config inside of that where you can declare a tile image. It checks every possible place you could have a tile, and then some. Now, to make this even easier, I actually created a website. Web manifest, however you would pronounce that. If you go to it, you'll get this ugly website that I made in an hour. That is, all you do is you insert your URL, and then you'll get a pop-up dialogue that'll give you the Web manifest file. You can add it to your site right now in as much time as it takes you to deploy a single line of HTML. You should do that today, and your journey to creating a progressive Web app has already begun. Correct. Web manifest also has a couple of cool short URLs. If you're interested in the spec, it is pretty neat. Slash validator will give you Google's WebCache manifest validation tool if you want to modify what we give you. There's also slash spec, which will give you a hot link to the specification. Now, moving on, something called service workers. I'm not sure if anyone's ever heard of this because Google doesn't talk about it that much, but it is actually a really cool part of progressive Web apps. Now, like I mentioned, I am a web developer at heart. I work for a browser, but most of what I do is from a web development perspective, and an example of that is I'm actually one of the lead maintainers for Modernizer. Modernizer.com had a redesign about a year ago now, and the biggest change between Modernizer 2 and 3 was us going completely modular. Every single detect became its own module. We had roughly 262. I think we're up to almost 270 now. Individual detects along with a couple of dozen options modules. The idea, basically, is every single time you check off anything on that page, although you get a dependency, but that dependency might have subdependencies and subdependency, it goes on and on and on. And the problem is that a single module that you might be adding might be triggering dozens of requests on the network, and that really sucks. If you've ever traveled or used hotel Wi-Fi, by chance, you can know that if a website is doing a whole lot of network activity, it's going to be a really, really crap experience. And so we used a service worker to try and speed that up, and our service worker implementation was super simple because we didn't need complex content generation or anything like that, we just needed a really simple cache. And so we have two different sections, our prefetch cache, where we list a whole lot of files that we want to download in an array that prefetch checks in, and then we open up the cache when we load the page and we add all those files to our cache, and then they're available instantaneously. These are files that every single user is going to have, stuff like our icon, our CSS, stuff that's shared across browser, sorry, across the users. It's available everywhere. And the second part is, again, really simple. On fetch, we check to see if anything that is being requested is already cached, something that was in our pre-cache, and if it's not, we trigger off a new request. We check to see if it is in our cache, and if it's not, we fire off a new request and grab it and then cache that response later on. This is that, trust the cache, then hit the network after. It works really well for us because we only ever need to update files when we do a release, and so we can just update the hash file on our service worker the next time we have a new file to change. We can just, everything in the cache will be invalidated. So it's a really simple service worker and something that works for a lot of websites that I help. The only problem with service worker, if you can call it that currently, is its support. Obviously Chrome and Firefox have it shipping. This is actually a couple of months old, I apologize. And it's coming to edge, which is awesome, and hopefully to all other browsers that people use on Apple products. And it will be really exciting when it has there, but it's not there now. Even though we're lucky to have most of our content being served to Chrome and Firefox as a developer-focused website, it's only about 75% of our traffic that support service workers, which is great. Better than the average, about 50%, but it's not everybody. And that isn't acceptable. I can't serve a crap experience to 25% of my people. And so I did something that you were kind of told to never to do. I used AppCache. And don't yell at me yet. It is a douchebag. I'm not saying it's not. If you've never watched AppCache douchebag from the JSConf 2013, it is a wonderful talk, and it will educate you as to why everyone hates AppCache, if you've only ever been told that AppCache is terrible. It's great. ServiceWorker is much, much, much, much better than AppCache. And AppCache is going away on top of that. It's already deprecated in the HTML5.1 specification, but it covers our use cases. And on top of that, it's available basically everywhere. Every single browser that you'll probably ever counter will do that. It's like 90%. There's almost nothing on can I use that's 90%. It's out there. And so if you keep in mind the problems with AppCache and you're aware of all the problems you might hit, I think it's okay to use it. It's a douchebag, but it can be like that douchey friend you have that you have to have in high school until you can get rid of them. And so in order to use it, it's a really simple check. Obviously, we want to use ServiceWorker if it's available, and so we'll do a simple check for ServiceWorker in Navigator. If it's there, we register it. If that's not there, we check to see if application cache exists in window. And if that does, we add the AppCache. If you've never used AppCache, which seems pretty common, in order to add it to the page, it's an attribute on the HTML element. It's that manifest attribute. You just pass it a URL to your AppCache manifest file. And the problem with adding it via JavaScript is that it's a little bit complicated. That manifest attribute has to be there at page load time. You can't dynamically add that attribute and have the AppCache takeover. So in order to add it to the page, we had to do a little trickery. We create an iframe that is hidden with the source as a file that's just a really lightweight HTML page that just has that manifest, and then we append it to the page. So that file just looks like this. That's the entirety of the file. And we register it in that iframe container, and then it's available on the page instantaneously. It works really, really great. In fact, oh, sorry, yeah, actually, this is what a manifest file looks like. But basically that prefetch section that we showed in our Service Worker cache, we're able to shove into the section for AppCache manifest that's stuff that we know for a fact every single user is going to want and going to need in order to use our website. And it's able to function. Now, we now have over 97% or 98% of our website works completely offline. And it took our website from 20.7 seconds on non-Service Worker stuff from hotel Wi-Fi down to 190 milliseconds on reload. AppCache is a douchebag, but it can be useful if you know what you're doing. Just pay attention, know the problems, watch that video, and check it out. It can be useful for the short time until Service Workers are available everywhere. The next thing I'd like to talk about is Web Workers. Now, Web Workers are not a part of progressive Web Apps in the traditional sense, but they do enable one of the most important parts, and that is keeping your applications fast. Now, Web Workers have been around for a really, really long time. They were added to WebKit back in 2008, which is insane that it's been almost that long. It was version two of Chrome when it looked like that. I mean, it's been around for a really, really long time. And for some reason, every time I talk about it, I generally get this reaction from people. It's like, yeah, I've heard of Web Workers, but I have no idea what they do or why, like anything about it. And so Web Workers, if you're unaware, solve a really basic problem on the Web, and that is that it's single-threaded by default. If you've ever tried to create like a scroll handler or tried to create one of those really super cool parallax websites, and then all of a sudden everything gets terrible and slow and janky, like almost all of them, you'll know what I'm talking about. It's because everything fights for CPU time. You can only be doing one operation at a time. And so if you ever try and do a lot of calculations at once, you get a really, really janky experience, and it ends up being a really terrible user experience. So what Web Workers allow us to do is offload tasks to a background thread where I basically able to take stuff that would be too expensive to run and still have 60 frames per second, and be able to generate a much faster experience by having it go in the background. You lose access to the DOM, you lose access to most web APIs, but just about anything that's pure JavaScript and calculation that has to run can be done without a problem. As a result, super expensive functions become really, really, really cheap. You can able to do some crazy stuff that you would never imagine possible on the web without completely getting like this spinning beach ball of death or a blue screen of death or any other kind of death that you might imagine, and it's completely fine. You get 60 frames a second. It works great. Even better, Web Workers, like I said, 2008, it's green, baby. Like, it works everywhere. Just about anywhere where you can run JavaScript, so basically not Opera Mini guaranteed, you can run a Web Worker, and they work phenomenally well. One of my coworkers, Nolan Lawson, created Pokedex.org. It's a great example of a progressive web app. If you haven't checked it out before, I highly recommend it. One of the really cool things he did here is use virtual DOM. Virtual DOM is sort of a smaller version of React. It's the idea of being able to take a virtualized version of the DOM, and then when there's changes, you're able to do a diff of those changes to get the smallest number of JavaScript actions that have to happen to make that change. The concept is what makes React super fast. It's in Ember's glimmer engine. It's coming to Angular 2. You have the ability to use it in Angular 2 rather. The really interesting thing that Nolan did was that he used virtual DOM inside of a Web Worker. He used it to do all that expensive DOM diffing. He did that inside of the Web Worker, then responded over the post message API back to the website as far as what changes need to be made. It would make the DOM changes and wait to send back what changes need to be calculated again. As a result, he was able to run at 60 frames per second on a Galaxy Nexus. This is from 2011, a phone. It's nearly five years old, and he is getting just phenomenal experience on it. It's awesome. Just about anything. You might be thinking you might not do a whole lot of calculations on your website, but you'd be surprised. If you're not getting 60 frames per second, debug your JavaScript and your DevTools. Find out what bottlenecks are and see if you can do some off-thread calculations. It makes almost every website I've used it on much, much faster, and it's criminally underused on the Web. You can find out more about Nolan's website on its open source, and it's a great implementation. It's available on GitHub. It's Nolan Lawson, Pokedex.org. The last thing I wanted to cover, because I'm running short on time, is IndexedDB. IndexedDB is another API like Web Workers that have been around seemingly forever. Mozilla was one of the first implementers back in 2010, and that's, yeah, I think it was like Chrome version 5, version 4 of Firefox that's been around for a really long time. And if you've never used IndexedDB, there's probably a good reason for it. It's that you have other things that you can possibly use that make a lot more sense. Local storage, I'm sure most of us have checked out before. It's local storage that's that item and get item, and it just works. It's synchronous. It's simple. Your quote stays clean. This is a similar thing in IndexedDB. It hurts my head really hard to read that. There are cursors. There are transactions. If you come from a database background, if you're a DBA, then you might understand this, and you are way smarter than me. And I don't know, maybe I can hire you to make me something work better, but it is very confusing to me, and it's really difficult. And on top of that, Indexed... So when you're presented with the concept of using IndexedDB for something, a lot of people are like, well, I can just use local storage or app cache or document.cookie or any of the other possible web storage things that are available on the web. There's 15, 16, 17 different ways where you can try and store content. And IndexedDB becomes one of the more complicated ones, and therefore one of the less used ones. And that's a shame because there are wrappers around IndexedDB like dexed.js, which give you this really super clean, amazingly beautiful, promise-based API. And you have full access to IndexedDB. All of the content that you can store in there you can do through this beautiful promise-based API. It's like the jQuery of IndexedDB. It's beautiful. If you like local storage style implementations, there's local forage from Mozilla. And it gives you, literally, rather than just change the ST in storage to an F, you have localforage.setItem, localforage.getItem. It's packed by IndexedDB, and it works great. Nolan, the guy who created that Pokedex implementation, created a thing called PouchDB. And it's a full CouchDB implementation that works off of IndexedDB. And the great thing about all these things is that they can fall back to WebSQL, something that is supported in browsers even older than Firefox 4. Basically, just about any browser, they'll fall back to WebSQL, they'll fall back to local stores, they'll fall back to in-memory. So all of these libraries have phenomenal browser support because they are able to run and because they take into account that we're not necessarily planning on these cutting-edge browsers on the mobile space. They want to run as many places as possible. And if you choose one of these and you start to plan around using IndexedDB, you get storage that is way higher than most of us even realize. You can store gigabytes of data in IndexedDB on the desktop with a G, not anything else, gigabytes of data. I've created demos of podcast apps where I'm able to offline sync dozens and dozens of 120, 200 megabyte episodes completely offline and have it work fine. And it works great. Now, that storage isn't guaranteed to stay around constantly. It can be deleted by the browser if the user runs low on space. There is that persistent storage API that Ben Kelly mentioned that is coming from Google and hopefully all other browsers in the near future. But for stuff that can just help to be worked offline that just is better if it's offline, media content, even just static caching of your assets on browsers that don't support the full cache API. There's tons of stuff IndexedDB can be used for today and it works great. On top of that, if you've never checked out web storage, there's this awesome thing called the browser storage abuser that's made by one of the Google guys. And it's available online and you're able to see just how much storage you can shove into the browser, basically, and all the different types. It has file system API, the file API, IndexedDB, web SQL, local storage, session storage, all this type of stuff. I'm requesting five gigabytes right here without a problem. I've gone up to 200 gigabytes on my laptop and it's never once complained. It works great. The quote API can explain more about that. It's available at this URL. And, yeah, I can't say enough about why aren't you guys checking out IndexedDB. You can store so much phenomenal content. You can make your website scream if you store your assets offline and you don't have to wait for the cache API. You don't have to wait for the new APIs and all browsers to be there. This is stuff that you can do on a slightly crappier API than what's available, but have it available to all your users today. I guess the point of what I'm trying to get across is don't wait for a rearchitecture to start using these features. Check out what fallbacks exist. Check out what you can do to create a similar experience, something that you want to be in the future today, because most of the time those things already exist. Don't be afraid to use the new things in the web. If it's a feature that's only supported in one browser, don't wait for it to be everywhere. Do feature detections. Fall back to things that if you're able to and have a great experience today, make awesome websites and make your users love the web as much as we do. You can do phenomenal things with the web if you start pushing the limits. I would love to see more and more experiments that bring app-like experiences to stuff that is years and years old. Steve Jobs said we could do it, so let's show him that we were right about the web. Now, like I said, my name is Patrick Kettner. That's my handle pretty much everywhere on the web. That's also my email at Microsoft. I'd love to hear about anything other than Internet Explorer. Feel free to contact me. It's a great, great time. The Edge team is awesome. I'd love to hear you guys' feedback or questions or complaints about anything. Thank you very much. I'll be in the code lab later if you want to talk about progressive enhancement. Thanks for having me.