 All right. Let's talk about performance of your Polymer apps. Not everyone has a Paul Irish in their pocket. They can take a run with them and debug their apps for them. So we need to learn how to build apps really fast from the start. Again, here's my information. If you want to follow me on Twitter, again, all the demos as well are going to be on GitHub. So everything I show you today is going to be up there. But let's hop right in. So there's two buckets when I think of performance. The first is load. How fast does your app paint pixels to the screen? How fast does your app load its resources? That's critical. That's the first experience when people come to your app. The next one is render. What happens when they've loaded your app? It's not enough that it loads fast. They actually have to have a good experience when they're in your app. No jank if you have animations. Or if they're interacting with your app, things need to be snappy and really fast. And if we have time, we'll talk about future APIs that are really exciting, really, really awesome for performance. So why should you care about performance? Well, you can actually just go to the definition, one of the definitions of performance, which reads, the extent to which an investment is profitable, especially in relation to other investments. I read this, and I said, hey, what if you replace a couple words? The extent to which an app is usable, especially in relation to other apps. That's performance. If people are leaving your app because you suck at performance, nobody wants that. We want to be successful developers. And the reason they leave our apps for another app should not be because performance is suffering. Paul Irish showed you this awesome unofficial table of user interactions. And I'm not going to dive too much into this. But the moral of the story here is 250 milliseconds is that sweet spot. That's where users really, really like in your app feels fast. If you start to go above 100 milliseconds, maybe a tap takes too long, something loads, something janks, you start to lose people. They do a mental context switch. By 10 seconds, you should basically just give up, try something else. Maybe go native, I don't know. So the good news is for Polymer 1.0, we've already leveled you up. Polymer 1.0 is faster than Polymer 0.5. And we talked about this at Google I.O. this year. It's 3x faster in Chrome. That's even with the native web component APIs. 4x faster in the polyfill browsers like iOS. So this is great. Again, your baseline is already above where we started in 0.5. But these are relative numbers to our old version of Polymer. Maybe it's 3x faster than Dog Slow. Who knows, right? I wanted to put some real numbers around an app written in Polymer, some absolute numbers, and show you how to build an app that's really fast from the get-go. So let's happen. Let's talk about load. What can we do to paint pixels to the screen as fast as possible? We need to dissect what we recommend to people. This is the basic scaffold of an application we typically have in our demos, our sample apps. The first thing you do is you have to load the web components polyfill at script tag at the top. This is already better than the old version of the polyfill, because it doesn't load the full shadow down polyfill. It loads the shady down polyfill, which is much smaller, and just tries to mimic shadow-downs capabilities. The second thing you do is you load elements.hml. And here you're going to have all of your element imports and dependencies. Now the Polymer team, we typically just have one of these files and all the imports inside of it, which is convenient to do that. But you can have a bunch of these on the page if you want. And the last thing we have here is this unresolved attribute, which I'll talk about. This is the Polymer feature that makes working with apps really easy. So this is great. This is really easy to reason about. But I wouldn't be here if we can't do better. And of course we can. So already from the start, because of that setup, you're hindering yourself as far as performance is a concern. So let's jump in and dissect this. What's wrong with this app? The first thing is we're loading this polyfill. The script tag is going to block rendering of our page right from the get go. So if we're on a slow connection, we're already kind of degrading the performance. So that's no good. We should put async on that tag. And then it won't block rendering. It'll just parse that code out, which is awesome. The second thing we can do is work with this import. So by default, imports actually block rendering of the page as well. Until this element said HTML loads, none of those resources and none of the markup is going to show up. It's going to block rendering of the page. And that's because imports behave exactly like CSS. So by default, style sheets block the page because you don't want to have this weird flash of unstyled content come in. And imports do that too because you can actually put style sheets inside of imports. So the behavior is the same. But the good news is we can pop an async attribute on this element as well. And so by doing this, we're no longer going to be blocking the rendering. So nothing in our head is blocking the page. It's awesome. This markup's going to render the user right away. It's worth kind of spending a little bit of time on talking about imports. If this is how we load web components, we use it for dependencies and loading resources, it's worth knowing what they do and how they behave. So you might be asking yourself, why don't we have async imports by default? Why isn't that the default behavior if it's better? And the reason is because we want this snippet of code to always work. Custom elements and imports have been designed together to work really well. So let's assume inside of exfoo.html we have the import, or sorry, the element definition of the exfoo element. By the time we run this script, which comes right after this import, the expectation is that file is loaded, it's registered the element, and you can create an exfoo, and all of its properties and methods are ready to go. That's the expectation and the invariant that we always want true. If this was async by default, the developer would have to do a lot more work. You'd have to kind of wait for a load event or figure that out yourself. And you wouldn't be able to touch this element's properties or methods. And so that's why they're synchronous by default. It's a more sane thing for developers to grok right away. It's a lot easier to work with. But you don't have to use them synchronous. You can also load imports dynamically using script. So Polymerize is a really awesome method, import href, that allows you to import, sorry, that allows you to import an HTML file using our, using our nice convenient function import href. And essentially what that's doing is creating a dynamic HTML import and loading that for you inside of your document. In this example, I've just wrapped it in a promise, import page, URL to the HTML file I want to import, and then I want to do stuff. So it's really easy to work with dynamic imports as well in script. The reason we like the declarative route is A, it's declarative, it's a lot easier to use. And B, it's actually a lot faster for the browser. The browser's pre-parcer can go off and discover elements.html and all the resources inside of it. And so it can go and fetch those resources, preemptively download things, stick it in its cache. And so by doing this high in the page, we can actually have stuff load quicker in our app. And so that's really awesome. This is one of the reasons I really want all browsers to implement imports for this, to take advantage of the browser's pipeline for loading resources. The last thing we need to deal with to make this app really fast, this scaffold really fast, is actually remove this unresolved attribute. So unresolved is really nice kind of awesome feature that Polymer has that you can opt into if you want. But what it does is it hides the page until all of the elements are ready to go. So if you're waiting on a resource, you're actually just showing the user a blank screen for a long time, that's no good. If you remove that, and you have Async on both these resources here, all of your markups gonna render right away, and it's gonna get upgraded when those resources come through. And so this is the fast loading scaffold that I kind of recommend to people. Async the imports, async the script tag, you're not blocking anything and remove the unresolved attribute Polymer. So of course we can do even better than this. You might be saying, hey, well what about this script tag up here? We're unconditionally loading that no matter what browser we're in, right? Even in Chrome where all the native APIs are available. So instead, as good web developers, we should be feature detecting the APIs and loading it conditionally based on feature detection. So let's remove that all together and inside of a new JavaScript file app.js, let's do that. Let's conditionally load the Polyfills only when they're needed. Can do that really easily today just by three feature checks. You check for custom elements, you check for imports, and you check for the template tag. So this feature to check today is actually really easy, but as browsers implement these different features, of course, this is gonna get a bit harder and bit more challenging. But right now this is what it is. If the web components native APIs aren't supported in the browser, you can dynamically load the script tag with the web components Polyfills. So that'll only provide this resource to the browsers that need it. All right, so we made a bunch of improvements. Let's see what it does to an actual application. On the left side, you see the synchronous version with none of the improvements that I made. That, you can see loads and you have this big white screen of depth for a number of milliseconds, right? So that's what I call the white screen of depth and people are just waiting for stuff to load. It first paints in about 1.4 seconds on a 3G connection in the DevTools. On the right side, you can see the improved version, the asynchronous version, immediately the page loads. You see the green bar. You see pixels on the screen. You see a loading message informing the user, hey, this thing's fetching stacks for you. And that's 6.2 times faster just by doing those two or three improvements that we talked about. 230-second millisecond paint. Awesome. That app used one custom element so it's not really a full-fledged app. It does something interesting. But let's take a look at a real app that uses a bunch of different custom elements that we have in the Material Design elements that we have. So this is the example markup here. It uses paper drawer panel with the app drawer panel, paper toolbar for that blue toolbar up top, paper menu, a bunch of different custom elements here. And we're gonna all load this using these two techniques. It's important to note I didn't write any CSS to make this look like this. This CSS all comes for free via these elements. It's one nice thing of web components, encapsulating your CSS and logic together. So let's see what happens in this example. This is the asynchronous version. We'll start to load the page on a 2G connection. Immediately you see those pixels of the screen, but what you see is the actual menu items of that unupgraded app drawer. So you're seeing that stuff before it's actually ready to go. So we're getting pixels of the screen and then eventually, boom, the entire app renders and you have the final layout. But that's no good because you have that flash of unstyled content. Now the synchronous version, if we just wanna compare it to the old version, what this is gonna do is this basically just gonna sit for a while. So we're not using any of the async attributes on the link or script. We have the unresolved attribute on the body. So it sits there, it sits there, it sits there. And then finally, when the app is ready, Polymer unveils the entire app, your layout's ready to go, but it's no good because we basically just have a white screen for a long time. So these two problems we have to deal with. We went async with everything, now we have to deal with this flash of unstyled content of that app drawer. And the reason for that again is because we went async with this HTML, import until elements.html loads and provides all of the CSS inside of it, we get nothing. And we remove the unresolved attribute on the body to say we wanna render as quickly as possible. So it was kinda cool, and in doing building this slide deck, I came to the realization that custom elements are really just progressively enhanced markup. And the idea with this is that you can declare an exfu or a paper toolbar on your page. And until you call document.register and tell the browser about this custom element, it basically just sits there as an unknown element to the browser. But it's cool because we can actually style this element using CSS and other parts of the platform until it's in this supercharged mode. And this is the idea of the app shell. It's progressively enhanced HTML. The idea is that you provide all the critical resources upfront. Your basic CSS, basic layout and basic markup have it ready to go on the page and style it to mimic what the final layout is going to be. So it's kinda cool because you get pixels to the screen right away, but users just see things upgrade in place. And since we can style markup before it goes to the supercharged custom element, we can do this very easily. So custom elements has this unresolved pseudo selector, the pseudo element that you can use to style markup custom elements before it gets upgraded. So for this example, maybe what I wanna do for this app drawer icon, since it's not interactive yet, maybe I just wanna hide it. So I'll actually do that. I can style using display none and hide that paper header panel based on the fact that it's in this unresolved state. It's not useful, so we'll just hide it. The second thing I can do is I can mimic some of the styling of the paper toolbar that the paper toolbar CSS actually provides. So I can style that and target it in its unresolved state and make it look like it's a blue, like the 192 pixel height and with a blue background. So this is mimicking some of the styles inside of paper toolbar. So let's take a look and see what this actually does. This is the same app using this notion of an app shell. So this is gonna take care of our flash fund style of content. So we're on a 2G connection in the DevTools, we'll load the page and immediately what you're gonna see is basically the final shell of the app. And you can imagine data requests and other things happening here. It's a very simple app now. But what you saw at the very end when everything loaded is the app drawer actually come in. It's been upgraded to its final state and now the user can interact with it. So I'm able to then style it appropriately. So for this app, this very simple app, the app shell idea took off 100 milliseconds of first paint. So you can see this stuff adding up over time, hundreds of milliseconds as you make these improvements. But I wanted to do this in a real app. So I made all these improvements to PolyMail which is a version kind of that mimics the native Gmail app. It's all written in Polymer 1.0. It uses ES6 classes and async imports and all the cool stuff like service worker does offline caching. It looks great. It uses the gesture library that Dan talked about before. But all this stuff together, let's see what this did on a real app that touches APIs and does login and all that stuff. So on a cable connection on desktop, this is what the app looks like. If you're curious, the webpage test results are below here. 589 millisecond first paint. So just over half a second. That's really good for an app that does a lot of stuff. One second total load. So that's everything. That's data loading. That's the user logging in really fast. The coveted one second load. And the speed index is 1144. And speed index is the measurement of the visually completeness of your app. So that's actually really good. On a 3G fast connection and a mobile connection on an actual hindered CPU, let's see what the numbers are. 1.66 first paint, so pretty good. Seven second load, that went up a little bit. I'll talk about that. And then we have, of course, because of the load time went up, the speed index also went up. So let's dissect the waterfall bin, see what actually happened in that seven seconds. It's interesting because most of the Polymer stuff, so you're loading elements.html, bundle.js is the vulcanized bundle. All that stuff is finished pretty early on. Maybe two seconds, three seconds. All the other stuff is actually Google's APIs. It's like loading iframes and RPC calls and analytics and fonts APIs and the list goes on. It's crazy. So it's actually showing some of the slowness, I guess, of our APIs. But the interesting part, the Polymer part's done very soon. I also did the app shell idea in Polymail. So on a desktop, you get the true app shell that we just talked about. It kind of mimics the final version of the app, styles it ahead of time, and then data loads in, images load in, the user's logged in as well. On mobile, it's just a splash screen. I decided to do something a little different for mobile because I thought it was interesting. It's kind of a mobile paradigm that was cool to show two different versions. But same idea, pixels is to the screen right away. So the changes we made for fast load, make your imports a sync, don't block rendering of the page, make your polyfills conditional or make them a sync, manually load and prevent Falk using the unresolved attribute, remove that, and then the app shell idea is really critical to get pixels to the screen. So these things together get you a really fast load time. Below time is just part of it. So let's talk about what happens when someone's loaded your app and they're inside of it. So I'm in the Polymer team now for a couple of years. I built a lot of apps in the old version of Polymer, a lot of apps in the new version of Polymer, but there's kind of commonalities between the two different versions. So here's some quick tips for building fast apps when you're inside of it. First is use native Shadow DOM. Native Shadow DOM is gonna be faster than Shady DOM if the browser has it. And that's because it runs C++ a lot faster than your JavaScript. It does recalc faster, layout faster, does scoping, DOM scoping faster. So you have to opt into this in Polymer 1.0. If you set Polymer.dom to shadow, that will opt you into Shadow DOM if the browser has it, otherwise you get the Shady DOM polyfill. But this will actually be faster than working with Shady DOM. So that's a pro tip, do that if you can. Dan talked a little bit about the touch stuff in Polymer. Use touch events rather than click events. We still suffer from that 300, that dreaded 300 millisecond delay on some mobile browsers. Chrome and Firefox have fixed this if you have the right meta viewport tag. iOS still suffers from this in certain cases. But the moral of the story is use on tap. Don't use on click if you're working with gestures and user interaction, that's gonna be faster. And get us closer to that 250 millisecond mark. Next thing is yo, don't shank those ripples. Those ripples are awesome in material design. We have all these cool effects. A really common thing I see is people put an anchor inside of a paper button or a paper fab, the full in action button. And what happens, by default what happens is you can actually exhibit this on the Polymer site. We'll see that one more time. When you click the button, the ripple just stops halfway through, right? And that's because the browser's no longer running your JavaScript in that CSS transition. It's gone to navigate to a new page. So an easy way around that is basically just hijack the click on the anchor tag and wait for the transition end event that ripple fires and then redirect the user to the new page. If you don't want the ripple at all, you can also have the no ink attribute on the paper button. So really easy to deal with the material design ripples. Server talked about this in his presentation, the reflect to attribute. I see a lot of people using reflect to attribute. Please don't use this unless you have to. The reason is because you can have a huge JavaScript object property or a huge array property and every time you make a change to those properties, it's going to get serialized back out from the property to an HTML string. So that could be a source of performance issues in your app. The only reason you want to use reflect to attribute is if you want to style your element based on the fact that it has this attribute applied to it. If I want to put a border around my element when it's selected, I can do that and I need reflect to attribute in this case. But only use it for styling purposes. A next one and a really important one that we kind of recently discovered is, yo, don't create thousands of elements on your page though. You wouldn't do this in the world outside of web components. Why do it in the world of web components? Do lazy render elements. So what do I mean by this? I actually did an audit of some of the interesting apps out there, some of the more modern apps that I think are kind of first class, single page applications, Google Maps, Contacts, Google Inbox, Calendar, and GitHub and others that aren't Google properties. When they load the page, they basically create, most of them create pretty minimal amount of DOM nodes. So Maps, for instance, only creates 624 nodes at page load. That's really good. It's a small amount of markup. And then as the user interacts with the page, of course they generate more. But on page load, they're doing a good job of kind of minimizing how much stuff they throw down. I ran into this myself. I ported Chrome status, which is a great resource if you want to know about new web platform features in Chrome. It's basically a list of features and people can expand the cards and kind of drill in and learn more about each of the features. I ported this to 1.0 and I saw my performance go down and I was like, what? That doesn't make any sense. Polymer 1's supposed to be faster, right? So it turns out what I did was that I moved from a font icon to using some of our iron icon elements. When someone expands one of these feature cards, I have a lot of custom elements inside of these features. So there's a custom element for the link that generates the link, custom element for these colored icons, custom element for the logos you see here. So a lot of stuff is going on inside of each one of these 350 features on the page. Way too much stuff on page load. Turns out, moving from that font icon to iron icon, I was generating over almost 2,000 icon elements. And so each one of those has to run its JavaScript and do its own thing to set itself up. So that's no good. It was not being a responsible developer. Of course you can do better. The moral of the story is to generate less upfront if you can. Now I had a list of stuff and there's no better element for that than the iron list element. Very awesome, easy to use element. It gives you a virtual scrolling list that works great on mobile and it only generates the DOM that's needed at the time. So the current viewport that the user is viewing. I popped that in and saw a huge performance gain. The second thing I did was I used DOM, the template DOMIF. So I only generated the markup when someone actually expanded the card. There's no reason to generate everything upfront because 90% of the stuff would be totally invisible to the user unless they expanded the card. Please don't use DOMIF for stuff like this. So do not use it for HR tags. First of all, you shouldn't be using HR tags. You see SS instead. But use it when the user is interacting with your app and you need to generate DOM based on the fact. So if you have a lot of custom elements or generating a lot of custom elements in DOM repeat, that's a really good time to use DOMIF. So let's see what these two improvements did for Chrome status. About 4,000 elements at 1.2 second load time down to 53 milliseconds on page load and 383 millisecond load time. So it's about 844 milliseconds faster just by reducing the amount of stuff I was generating upfront. All right, let's talk about a couple of really awesome new features coming down the pipeline since you have a little bit of time. The first is if you're gonna dynamically load things, if you're gonna dynamically load some CSS later on, maybe you're loading an import for later with a bunch of custom elements inside of it. We have the ability very soon to preload, to tell the browser, hey, put this resource in my cache and have it ready to go. So this is a high priority resource that's gonna go off and fetch that no matter what. You can declare it as link rel preload with a link to your attribute, your resource. You can set an HTTP header or if you want, you can dynamically load it as well. So you can set the rel in preload in script. The other thing that's really awesome is HTTP to push. This is really cool. You can parenthetically, when someone loads your index page, push the resource to the browser's cache and have it ready to go. I get so excited about this. I spent a little time on App Engine, putting together a little demo. So the URL is here and you can see the webpage test results for the different runs. The left side shows the version of the app that has a bunch of HTML imports on it. It's a Polymer app. And you can see the waterfall kind of load this stuff as time goes on. So no HTTP to push in this example. Traditional waterfall loads in about 516 milliseconds. On the right side, you can see what happens immediately when server push is enabled. So this is sticking all of the HTML imports in the browser's cache, the CSS, the JavaScript files. And the timeline is completely different, right? So there's no green. There's no network request being made because these resources are already in the browser. And you can see that reduces the page load time just by doing HTTP to push by 60%. That's insane. That's awesome. What's even cooler is that if you drill into these webpage test results, you see that it's actually faster to load a bunch of smaller files and push those rather than vulcanizing your entire app. So the browser's actually better at loading small chunks rather than loading this huge file with JavaScript, CSS, and HTML in it. So it means we don't have to concatenate our JavaScript anymore. We don't have to concatenate our CSS anymore. And we don't have to have all these crazy build tools that Addy spent a lot of time talking about. This is really exciting. And a lot of servers are actually enabling this. This is really well supported now. If you wanna check out the code, App Engine actually has a special header that supports this today, so you can push resources on App Engine. So lastly, before I leave you, if you can't measure it, you can't improve it. Paul Irish talked about the PolyDev Chrome extension that gives you kind of the atomic weight of all the custom elements on your page. You can identify what's kind of at fault. I've also worked on a little performance bookmarklet if you wanna install that. It gives you some other stuff. It gives you things like, what's the first paint of your app? How long do the HTML imports take to load? Maybe there's one that's kind of hindering your page load. It also gives you a number of elements created and it gives you things like, what properties on these custom elements are using that reflect to attribute property. So check that out. That's actually really useful. Anyways, thanks for sticking around for the entirety of the show. I know it's late. You guys have had a lot of information thrown to you today. Feel free to, again, hit me up on Twitter or Google Plus. Really appreciate your time. Amsterdam has been awesome. Thank you.