Polymer Performance Patterns (The Polymer Summit 2015)
Key Takeaways
The video discusses Polymer performance patterns, focusing on speeding up first paint, lazy loading components, and other optimization techniques for web applications, specifically highlighting the importance of understanding mathematical foundations in optimizing web performance.
Full Transcript
[Music] 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 uh 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 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 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 API 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 kind of 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 um and 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 you do a mental contact switch by 10 seconds you should basically just give up try something else maybe go 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 iio 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 you're already you know your Baseline is already above where we started in 0.5 um but this could be these are relative numbers to our old version polymer right maybe it's 3x faster than dog slow who knows right I wanted to put some real numbers around an app written polymer some absolute numbers and show you how to build an app that's really fast from the get-go so let's hop in 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 that script tag at the top now 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 atom's capabilities the second thing you do is you load elements.html and here you're going to have all of your element Imports and dependencies on 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 concerned so let's jump in and dissect this what's wrong with this app the first thing is we're loading this polyfill this 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 you know degradating the performance so that's no good we should put a sync on that we should put a sync 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 elements at HTML loads none 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 stylesheets 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 stylesheets 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 is 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 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 let's assume inside of xu. HTML we have the import or sorry the element definition of the xfu 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 xfu and all of its properties and methods are ready to go that's the expectation and the inv variant that we always want true if this was a sync by default the developer would have to do a lot more work you'd have to kind of wait for an load event or or figure that out yourself um and you wouldn't be able to touch this element's properties or methods so that's why they're synchronous by default it's a more sane thing for developers to gr right away it's a lot easier to work with but you don't have to use them synchronous you can also Al load Imports dynamically using script so polymerize this really awesome method import href um that allows you to import it sorry that allows you to import an HTML file using our using our nice convenient function import HF 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 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 preparer can go off and discover elements.html and all the resources inside of it and so we 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 the user a blank screen for a long time that's no good if you remove that and you have a sync on both these resources here all of your markup is going to render right away and it's going to get upgraded when those resources uh 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 atraer po 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 you 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 toch today is actually really easy but as browsers Implement these different features of course this is going to get a bit harder and a 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 and 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 dev tools 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 stocks for you and that's 6.2 times faster just by doing those two or three improvements that we talked about 2332 Mill second paint awesome that app use one custom element so it's not really you know 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 uh 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 going to all load this using these uh two techniques it's important to not 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 right you're 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 to 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 want to compare it to to the old version um what this is going to do is this basically just going to 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 uh unresolved attribute on the body to say we want to render as quickly as possible so it was kind of cool and in building the slide deck I came to the realization um that custom elements are really just progressively enhanced markup and the idea with this is that you can declare an xfu 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 supercharge 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 up front your CS 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 kind of 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 this pseudo element that you can use to style markup custom elements before it gets upgraded so for this example maybe what I want to do for this this app drawer icon since it's not interactive yet maybe I just want to hide it so I actually do that I can style it 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 going to take care of our flash fun style content so we're on a 2G Connection in the dev tools we'll load the page and immediately what you're going to see is basically the final shell of the app and you can imagine you know 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 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 appell idea took off a 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 uh which is a version kind of that mimics the native Gmail app it's all written in polymer 10 it uses es6 classes and async imports and uh and all the cool stuff like service worker does offline caching it looks great it uses the gesture library that Dan talked about before um but all this stuff together let's see what this did on a real app that touches apis and and does login and all that stuff so on a cable connection on desktop this is what the app looks like and if you're curious the web page 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 1 second load and the speed index is a 1,144 and speed index is the measurement of the visually completeness of your app so that's actually really good on a 3G fast connection on a mobile connection on an actual hindered CPU let's see what the numbers are 1.66 first paint so pretty good 7c loow that went up a little bit I'll talk about that and then we have of course because of the low time went up the speed index also went up so let's dissect the waterfall bit and see what actually happened in that 7even 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 the uh some of the slowness I guess of our of our apis but the interesting part the polymer part's done very soon I also did the appell 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 is 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 and it was cool to show two different versions but the same idea pixels this 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 uh make your conditional make your polyfills conditional or make them a sync manually load and prevent FAL using the unresolved attribute remove that and then the app shell idea is really critical to get pixels the screen so these things together get you a really fast load time but load 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 been in the polymer team now for a couple 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 diam native Shadow diam is going to be faster than Shady diam if the browser has it and that's because it runs C++ a lot faster than your JavaScript it does recal faster layout faster it does scoping Dom scoping faster so you have to opt into this in polymer 1.0 if you set polymer DOD to shadow that will opt you into Shadow Dom if the browser has it otherwise you get the Shady diam polyfill but this will actually be faster than working with Shady di 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 in some mobile browsers Chrome and Firefox have fixed this if you have the right uh metav viewport tag iOS still suffers from this in certain cases but the moral of story is use on tap don't use on click if you're working with gestures and user interaction that's going to be faster and get us closer to that 250 millisecond Mark next thing is yo don't Jank those ripples those ripples are awesome in material design we have all these cool effects um a really common thing I see is people put an anchor inside of a paper button or a paper Fab the floting action button and what happens by default what happens is you can actually exhibit this on the polymer site Let's uh let's see that one more time when you click the button the Ripple just stops halfway through right and that's because the browser is 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 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 reflected attribute please don't use this unless you have to the reason is because you got 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 uh issues in your app the only reason you want to use reflect a attribute is if you want to style your element based on the fact that it has this attribute applied to it so if I want to put a border around my element when it's selected I can do that and I need reflect the 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 load you wouldn't do this in the world World outside of web components why do it in the world of web components do lazy render elements so what I mean 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 are kind of you know first class single page applications Google Maps contacts Google inbox calendar and GitHub and and others that aren't Google properties when they load the page they basically create most of them create pretty minimal amount of Dom noes so maps for instance only create 624 nodes at page Lo that's really good a small amount of markup and then as the user interacts with the page of course they generate more but on Pagel 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 learn more about each of the features um 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 one'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 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 the logos you see here so a lot of stuff is going on um 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 is 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 I was not being a responsible developer of course we can do better the more the stories 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 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 uh the template Dom if so I only uh generated the markup when someone actually expanded the card there was no reason to generate everything up front because 90% of the stuff would be totally invisible to the user unless they expanded the card please don't use for stuff like this so do not use it for HR tags first of all you shouldn't be using HR tags use CSS 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 and Dom repeat that's a really good time to use Dom if 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 that's about 844 milliseconds faster just by reducing the amount of stuff I was generating up front all right let's talk about a couple of really awesome new features coming down the pipeline since we have a little bit of time the first is if you're going to dynamically load things right if you're going to 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 cach and have it ready to go so this is a high priority resource that's going to go off and fetch that no matter what you can declare it as link ra preload with the uh resources to your 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 rail in preload in script the other thing that's really awesome is http2 push this is really cool you can permy when someone loads your index page push the resource to the browser's cach and have it ready to go I get so excited about this I spent a little time on app engine uh putting together a little demo so the URL is here and you can see the web page test results for the different runs the 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 http2 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 Push by 60% that's insane that's awesome what's even cooler is that if you drill into these uh web page test results you see that in it's actually faster to load a bunch of smaller files and push those rather than Vulcanizing your entire app so the browser is 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 catenate our JavaScript anymore we don't have to concatenate our CSS anymore and we don't have to have all these crazy build tools 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 um if you want to 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 polyd 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 uh performance bookmarklet if you want to install that it gives you some other stuff it gives you things like what's the fir first paint of your app um 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 uh 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 [Music]
Original Description
Let's face it, building a web app is hard. There's a lot to remember! Web components allow us to componentize the web's best practices but that doesn't mean footguns are a thing of the past. In this talk, we cover tips and tricks for speeding up first paint, lazy loading components, and various runtime optimizations.
Check out the slides deck to this talk here: https://speakerdeck.com/ebidel/polymer-performance-patterns
To learn more about building with Polymer, check out Polycasts by Rob Dodson: https://goo.gl/vdtIFR
Subscribe to Chrome Developers on Youtube here: https://goo.gl/n7mBHx
Playlist
Uploads from Chrome for Developers · Chrome for Developers · 1 of 60
← Previous
Next →
▶
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
Polymer Performance Patterns (The Polymer Summit 2015)
Chrome for Developers
Polymer Power Tools (The Polymer Summit 2015)
Chrome for Developers
Chrome Dev Summit 2014 – Chrome Case Studies
Chrome for Developers
Web Directions Code 2015 round up
Chrome for Developers
Maintainable Code - HTTP203
Chrome for Developers
iron-ajax… wat?! -- Polycasts #26
Chrome for Developers
The Guardian - Supercharged
Chrome for Developers
ES2015 (next version of JavaScript), Totally Tooling Tips (S2 Ep1)
Chrome for Developers
#AskPolymer: Rob answers all the questions ever -- Polycasts #27
Chrome for Developers
The Future of JavaScript - HTTP203
Chrome for Developers
Data Binding 101 -- Polycasts #28
Chrome for Developers
The Guardian part 2 - Supercharged
Chrome for Developers
The Future of Web Audio: with Chris Wilson and Chris Lowis
Chrome for Developers
Chrome 46: New motion-path animations, client hints and service worker improvements
Chrome for Developers
Sublime Snippets, Totally Tooling Tips (S2 Ep2)
Chrome for Developers
#AskPolymer: How do you make the show? -- Polycasts #29
Chrome for Developers
Critical Path CSS, Totally Tooling Tips (S2 Mini Tip #1)
Chrome for Developers
Binding to Objects -- Polycasts #30
Chrome for Developers
Player FM - Supercharged
Chrome for Developers
Where’s the Designer? #AskPolymer -- Polycasts #31
Chrome for Developers
Jake Beats Wikipedia - HTTP203
Chrome for Developers
Supercharged Observers! -- Polycasts #32
Chrome for Developers
Jai's Web blog - Supercharged
Chrome for Developers
Windows Command-line Tooling, Totally Tooling Tips (S2, Ep4)
Chrome for Developers
What about internationalization? #AskPolymer -- Polycasts #33
Chrome for Developers
Developing for Billions (Chrome Dev Summit 2015)
Chrome for Developers
Google+ Performance Improvement Comparison
Chrome for Developers
Deploying HTTPS: The Green Lock and Beyond (Chrome Dev Summit 2015)
Chrome for Developers
Progressive Web Apps (Chrome Dev Summit 2015)
Chrome for Developers
Instant Loading with Service Workers (Chrome Dev Summit 2015)
Chrome for Developers
Increase Engagement with Web Push Notifications (Chrome Dev Summit 2015)
Chrome for Developers
Engaging with the Real World: Web Bluetooth and Physical Web (Chrome Dev Summit 2015)
Chrome for Developers
Asking for Permission: respectful, opinionated UI (Chrome Dev Summit 2015)
Chrome for Developers
Polymer - State of the Union (Chrome Dev Summit 2015)
Chrome for Developers
Building Progressive Web Apps with Polymer (Chrome Dev Summit 2015)
Chrome for Developers
Introduction to RAIL (Chrome Dev Summit 2015)
Chrome for Developers
DevTools in 2015: Authoring to the max (Chrome Dev Summit 2015)
Chrome for Developers
RAIL in the real world (Chrome Dev Summit 2015)
Chrome for Developers
#ChromeDevSummit talks are up - W00T! -- Polycast #34
Chrome for Developers
V8 Performance from the Driver's Seat (Chrome Dev Summit 2015)
Chrome for Developers
Quantify and improve real-world RAIL (Chrome Dev Summit 2015)
Chrome for Developers
Owning your performance: RAIL (Chrome Dev Summit 2015)
Chrome for Developers
HTTP/2 101 (Chrome Dev Summit 2015)
Chrome for Developers
Leadership Panel (Chrome Dev Summit 2015)
Chrome for Developers
Build Processes, Totally Tooling Tips (S2, Ep 5)
Chrome for Developers
Accessibility (Chrome Dev Summit 2015)
Chrome for Developers
Binding to Arrays -- Polycasts #35
Chrome for Developers
HTTP2 - HTTP203
Chrome for Developers
Chrome 47: Splash Screens, requestIdleCallback and better desktop notifications (New in Chrome)
Chrome for Developers
Call For Submissions - Supercharged
Chrome for Developers
Cross Device Testing, Totally Tooling Tips (S2 Ep6)
Chrome for Developers
Testing AJAX with Web Component Tester -- Polycasts #37
Chrome for Developers
Slack: Extended Xmas Special - Supercharged
Chrome for Developers
Browser testing with Travis & Sauce Labs -- Polycasts #38
Chrome for Developers
Optimize for production with Vulcanize -- Polycasts #39
Chrome for Developers
Highlights from Chrome Dev Summit 2015
Chrome for Developers
Chrome 48: Custom buttons in notifications, DevTools Security panel, and Presentation mode
Chrome for Developers
Crisper: Protecting your Polymer app with CSP -- Polycasts #40
Chrome for Developers
How do I use Sass with Polymer? #AskPolymer -- Polycasts #41
Chrome for Developers
Colors – DevTools Tonight #0 (Pilot)
Chrome for Developers
More on: Maths for ML
View skill →
🎓
Tutor Explanation
DeepCamp AI