/Let’s build some apps with Polymer! – Chrome Dev Summit 2014 (Rob Dodson)

Let’s build some apps with Polymer! – Chrome Dev Summit 2014 (Rob Dodson)

Video: Let’s build some apps with Polymer! – Chrome Dev Summit 2014 (Rob Dodson)

Subtitles

Thank you guys so much. This is really awesome to be on the stage today. Over the past year, I've spent a lot of time talking about web components, really teaching developers the basics of the standards and teaching folks how to focus on building elements. And we're now at this place where we have this burgeoning ecosystem of elements that are out there. There's a lot of developers out in the open source world who are creating elements but also got element sets that have been created by the Polymer team. We've got the core and the paper elements.

And so we're at this point where we have this flourishing ecosystem and I think it's time for us to start to think about the next challenge, which is how do we leverage that ecosystem to actually build real applications. And I'm particularly interested in figuring out how to build compelling experiences on mobile. The mobile web has a ton of opportunity, but it's one of those areas where for web developers, it's always been a challenge to create a real compelling experience on a mobile device. And so when I was preparing for this talk, what I wanted to do was just like pop my phone out and look at the applications that I use all the time, things I consider sort of successful experiences. And I wanted to go through them and just sort of catalog what I see as the kind of common UI and UX expectations in a successful app. So what I've got here is Twitter, I've got Pocket Cast for listening to podcasts, and I've got RDO. And one thing that struck me as I was doing this is if I just take these applications and I put them side by side, even though each of them kind of feels unique when I'm looking at it in isolation, when they're all lined up like that, it feels like they're just like a ton of commonalities in their interfaces.

And so using Twitter as an example here, I want to just catalog some of those common UI patterns that I see. So up at the top, we have a toolbar. Pretty familiar. And oftentimes, if you've got a toolbar, you're going to fill it up with some icon buttons. And below that, you've got some tabs for switching between content. You've got a primary content area, and oftentimes, you're going to have like an infinite list of contents inside of there, or you might just be lazy loading more content as the user is scrolling down the page. And down at the bottom, you've got a secondary toolbar for doing additional actions of some kind. Now, if we take a step back again and we line these apps up again, like when I was looking at Twitter a moment ago, it felt like a very unique experience. It felt kind of aligned with its brand and it had kind of its own thing going on. But again, I line these guys up and I can see that they all kind of have those same UI patterns going on. They're all kind of doing the exact same thing.

And the reason they all look the same is because they're all built using an SDK. So these are examples coming from Android, but the same is true if you're working in iOS. If you're building on one of those platforms, you already have this SDK that's available to you, grab a bunch of components out of it. Maybe you kind of tweak them a little bit, color them differently. But in general, you're using stuff that's already available to compose your application. Now, on the web, we've kind of never really had this thing. We've never had app building primitives. We've never had a mobile web SDK, and I think it's time for that to change. And I really think that the way that we're going about doing this is using Polymer and Web Components. So my goal today is to teach you how to build mobile web applications using these new technologies.

And I basically split this up into four parts. [? The very ?] part, I'm going to show you just how you can structure the UI for your application, then we're going to look at how you can transition from one state of your application to the next. After that, we're going to look at ways to make sure your application is performant, because that's really crucial for a mobile application. And lastly, we're going to look at ways you can make sure your application runs offline because if your mobile app doesn't run offline, then you really don't have a mobile app. People are oftentimes on their mobile devices when they're in low connectivity to no connectivity situations. So it's got to run offline for it to be a real, compelling mobile app experience. Let's start with structure and just think about ways that we can compose the UI for our application.

And really, that's the key word here– compose. What I want to do is I'm going to take as many preexisting elements from the Polymer core sets to the paper sets and I want to bolt them together to build my application. So this is the app that we're going to be working from today, just a really simple contacts app that I threw together. And I'm trying to utilize a lot of the same patterns that I was showing in the previous successful apps that I had before. So you've got the toolbar at the top with some icon buttons. You start scrolling around, you're going to get this sort of infinite list of content inside of there. You've got a drawer panel that you can pop out for your menu. Clicking on any one of the contacts is going to do kind of like an animated transition to show you that person's contact details.

I get it's really nice, cool condensing header effect as I scroll around. And also, I've got a little floating action button down there in the corner. I can click that, pop open another screen. These are all animated transitions that I'm using here. Now, if you've seen me talk before, you've probably seen me start off by using this element. Anytime I'm building an application, it seems like I'm always starting off with this core toolbar element, which is just a really simple container. It lays out its children using Flexbox and it's a really good place to get started with one of your screens. And because composition is really the name of the game, what I want to do first is I want to just throw some additional elements inside of here, and I just want to compose the UI for my toolbar. So I've dropped a paper icon button inside of there. I've configured it with an icon attribute to give me the hamburger menu from that application, and so I'm going to slide out my menu later. I've also dropped a div inside of here for the title of my application.

Now, one of the cool things about the core toolbar is that since it uses Flexbox, I can kind of take advantage of that a little bit. There's things called layout attributes in Polymer, and what I can do is I can actually tell the title of my toolbar that I want it to flex to take up as much space is it can inside of the toolbar. This is a really handy trick to know because it means that I can then pin controls to the other side of my toolbar. What I want to do here is actually add a little context menu so I can have things like settings and feedback. So to do that, I'm going to use another element called paper-menu-button, and paper-menu-button's pretty interesting because by itself, it really doesn't do anything. It's kind of useless. If you just put a paper-menu-button tag on the page, you get really nothing. It only really comes into its own when you start composing other elements inside of it.

That's really how you unlock the potential of it. So I've got another paper icon button that I've thrown inside of here, and that's going to give the user something to click on. Then I'm going to throw in a paper drop down, and that's going to give me this little animated rectangle thing up there. So when the menu expands, it's going to kind of like come out from the corner, expand towards the center of the site. The halign attribute that I've thrown on there is going to indicate which direction it should animate from. So here, we're telling it to animate from the right edge towards the center of the screen. Lastly, I'm going to throw a core menu inside of here, and that's going to give me the actual menu items that users are going to select for my sending them feedback. Now, the cool thing here is that each of those elements that I threw inside of my paper menu button is useful on its own.

READ  Minimalist Football Wallpaper Android App

I can use core menu elsewhere my site if I need a menu. What's awesome, though, is when I start to compose these things together, I get different interesting complex behaviors. And it's also important to point out that I didn't write any CSS or JavaScript to make this happen. I just nipped together these– oh, yay. Thank you, [? Demetri ?]. These elements just know how to work together because they're app building primitives, which is awesome. And once I'm happy with the look of my toolbar, then you take all of this markup and I could throw it inside of another element called core-header-panel. And the core-header-panel is just a really simple container. It's got a header section up at the top, which will hold the toolbar, content area down below. And the cool thing about the core header panel is it only really cares about managing the scroll behavior from my application.

If I put a toolbar inside of it, it's going to make sure that that toolbar stays sticky up there at the top of the document and all my other content is just going to move underneath it. Again, no CSS or JavaScript to make this happen. These are just smarter primitives. They know how to work together like that. Now, when someone's actually looking at one of my contacts, I want to have this cool, big shot of Addy Osmani's face basically, and I want it to do this cool animating effect. So as the person is scrolling down, it kind of collapses, and it's sort of crossfading with the background image. And to do that, I'm using a cousin of the core-header-panel called the core-scroll-header-panel. It's basically the same component, but it adds this nice condenses attribute, and it gives me that kind of cool effect.

Now, once I have the different screens for my mobile site laid out in a way that I like them, I can drop all of this into another element called core-drawer-panel, and that's going to give me a responsive scaffold for desktop and mobile. And the way this element works, it's basically got a drawer area. Any content that I place inside of there is going to end up in my sidebar. It's got a main area. Any content that I place inside of there ends up in the primary content area. And the cool thing is, this element is responsive by default. So if I'm on my desktop and I just start dragging it out, you'll see the drawer panel opens there. I can open and close it. I drag this thing out, and when I hit a certain size, the toolbar just pops out for me. This is really nice.

Again, I'm not writing any breakpoints or media queries to make this happen. The element's just responsive by default, which is really nice. Now, at this point, I've built the skeleton of an application. I've kind of shown you how to put the shell around everything, but what we're still missing is the lifeblood of our application. We're missing the content. And when I'm showing these apps earlier, I mentioned that oftentimes what they're going to do is they're going to do like an infinite list, or of a lazy load of content so the user can keep scrolling through all of their tweets, or all of their albums, and things like that, and we can achieve the same thing in our application using an element called core-list. And core-list is one of my favorite elements because I feel like it's sort of the thing that knits all the scaffolding and the content together in this way that I really love. The core-list is basically a virtualized infinite list.

You connect it to a data provider and then it stamps out a template for every single instance in that data provider's array. So here, I'm saying list.data equals some array. I've got objects inside of that array. Each of those objects has a name. And inside my core-list, I have a template element and I'm just binding to each of those instances as they come in. It gives me this really, really performant infinite list so I can go through all of my contacts. Now, as I was building my application, I kind of came across this thing– which I'm going to share with you as a tip if you want to go out and start using core-list yourself. One of things that core-list does is it recycles its children. That's actually how it's so performant. It makes a fixed set of children and as they're moving, it's pulling them back around the other way. So if you have image tags inside of your core-list, you can end up in a situation where you're basically racing the network and you're having stale images fly past the screen, and then they catch up and change, which sort of looks weird.

So I found that there's an element called core-image which you can use to prevent stale images in your application. It's pretty easy. You just drop it in here. You give it a preload attribute, and what that does is it says, hey, if I'm loading an image, I'm not going to display the stale image that perhaps was inside of here before. I'm just going to display a little background color. And so what we can do now is we can actually have this cool contacts list. We can sort of race the networking and you can see the images loading in, but what you're not seeing is stale images, which is good. The other thing that I discovered as I was doing this is that it's really important to make sure to set your core-list scroll target to your core-header-panel-scroller. I know that this is a little bit of a rough edge, but I wanted to make you guys aware of it if you're going to go out and start hacking on these things today.

Basically what happens when you do this is you're telling the core-list to listen to the scroll events that the core header panel is firing and that way, the two can work together in harmony. Now, there's two ways that you can go about doing this. You can either set the scroll target in JavaScript. You could say list.scrollTarget equals hPanel.scroller, or you can do this with bindings if you want to be really fancy and impress your friends. You could just say scrollTarget equals hPanel.scroller. Now, this is one of those things which, again, I think it's a little bit of a rough edge. Perhaps we might be able to clean this up in the future so that you don't have to wire this up yourself, but I wanted to make you aware of it because it was like the first thing I wanted to do was put one of those lists inside of one of those fancy headers, and I needed to set up this linkage to make it all work.

Now, through the beauty of composition, I've taken my list and I've thrown it inside of my scaffold, and I have this really, really cool application now. Now, I want to give you a quick recap of what we have inside of here. So up at the top, I've got a core toolbar. After that, a paper-icon-button, a paper-menu-button for my contacts menu. I've got a core-header-panel, which is controlling the scroll behavior for my home page. I've got a core-drawer-panel, which gives me that responsive scaffolding so it works on desktop and mobile, and I've got a core list for my infinite content provider. Now, one thing that's really cool to do once your application has reached the state where you feel like it's kind of shaped up a little bit is to think about ways that you could change it.

And if I look at this and I just imagine perhaps applying a little CSS to that toolbar and perhaps adding a little bit more content to the list, then I'm really not that far from something that looks a lot like Inbox, right. All the parts remain the exact same, we're just tweaking slightly the appearance of them– changing some colors, adding a little bit more content– but we've now got a very different experience. And because the core list supports variable height content– meaning that our rows don't all have to be the exact same fixed size– we can think about throwing cards inside of here. And if we do that, then we have an experience that looks kind of like G+. And again, none of my markup actually changed. I still have a core-toolbar, I still have paper-icon-button, still have paper-menu-button, header-panel, core-panel, and core-list. So my markup remained the exact same. The only thing that changed was the content that I'm placing inside of it, which is pretty cool.

READ  NEC Terrain : Caller ID

Now in my mind, this is the power of composition. When we have a mobile SDK that's full of these really good generic building blocks, we can build vastly different experiences just by arranging them differently and tweaking them slightly. I think that's huge. So let's go back to our contacts app for a second. We've got the basic pages kind of figured out, but I haven't really shown you how to move from one state to the next, and this is a dilemma for a lot of folks. They start building components, they get really excited, they throw them together on a page, and then they're like, how do I go from point A to point B. Basically, how do I do transitions? And this is one of those areas where we're still working on it, but I think we've got some really cool stuff in the pipeline. One of the elements that I've shown before which I think is really awesome– I put this little experimental badge on it because it also is a little experimental– but it's so freaking cool I like to show it. It's this element called core-animated-pages, which gives you a pluggable system for transitioning of one state of your application to the next.

And basically, the way this works is I put some sections inside of my core animated pages. I configure its selected attribute to tell it which section should be displaying at the time, and I give it a transitions property and I tell it– or sorry, transitions attribute to tell it which transitions I would like it to play as it moves from one state to the next. And with basically just that I've wired up this is really cool system for animating through different states in my application. So inside of my app, my markup kind of looks like this. I've got a whole bunch of markup that makes up every single page and it's all kind of composed together. And so the way that I'm going to transition from one state to the next is actually take all this markup and turn each section of my application into a custom tag. Keep all that markup, make an element out of it. Then I start nesting those elements inside of core-animated-pages.

So I start with my contacts page. I drop in an info page for when you click on a contact and you actually can see their profile. So I created a little custom transition here called fade scale. It's on my info page as an attribute. It's also in the transitions attribute for core-animated-pages. So now when you click on a contact, which is going to animate up, so you're adding there and then it goes away. And again, for the page where I add a user, it's basically the same thing. I nest that element inside of here. I give it a transition. I add that transition to animated-pages transitions attribute. I click on my floating action button now, pops up. I can add a new user if I want and it goes away. Now, another tip that I want to share with you is something that I came across as I was building this. Core animated pages does this thing where if an element is not displaying, it's going to make it display none, which can totally screw it up if it's trying to figure out its height or do anything like that.

So this magical event here called core animated pages transition prepare, which is the longest this event name in the history of the world. But this event does magical things because it basically fires the moment that your element goes from being display none to being display block. And that means that you can then do all the work that you need to do to make sure that things are measured and have the right height and everything like that. Again, this is one of the things that I'm sure if you see this, you're like dude, that feels like a wart, and I totally agree. I think you're right. And this is one of the things that I know the team is aware of and we're going to work on to see if we can actually smooth this out for people so you don't have to do all that finagling yourself. But again, I wanted to make you aware of it so if you're following along with this video or something afterwards, you want to try and implement this stuff yourself, you know how to do it.

So at this point, I have all the sections of my site together. They animate, they do really cool stuff, but really that's just animation. We're not really changing the state, per se. We're missing the other half of the puzzle, which is routing, and this comes up a lot. Developers are always like, how do I do routing in Polymer? And Polymer and Webfluenz don't really have an opinion here. We're not going to tell you specifically you have to do routing this way. There's really two ways that you can go about this. You can do it imperatively in JavaScript or you can do it declaratively with element. And so I'm going to show you both approaches, and you can decide which you prefer. So if you're going the imperative route, looks something like this. It's really as simple as just listening for a route change using some sort of routing library.

Here, I'm using flat iron director library, so when I hear a route match, I tell core-animated-pages, hey, change whichever page is currently selected. It's pretty straightforward. Now, one of the nice things about routing in JavaScript is it gives you pretty fine grained control if you want it. So if there's parameters in my route, I can catch those when the route matches. I can go fetch more data if I need to and feed that to the page, or I can just pass those parameters to the page itself, be like, here you go, here's the parameter that's coming in, and change. So some interesting stuff there. One thing that is pretty cool, which I wasn't actually using my contacts as I experimented with it. I think it's a really cool idea. It's something that we're probably going to be using a lot more in the future is this notion of lazy loading imports.

So actually, let's say you've got part of your site that's four or five pages deep, someone doesn't need all of those components right away. There's this mechanism in Polymer called Polymer Import which you can use to just sort of dynamically import things. So you can add that to your router. You can say, hey, when that route matches, that far away route, let's import some of that new stuff, maybe throw a loading screen up during that time. And when it's ready, Polymer Import gives us a call back and we can change that page. So that's the JavaScript way of doing it. There are also projects out there which do this in markup with elements. In particular, there's this really cool one called app-router by Erik Ringsmuth. It allows you to handle URL changes and update the views in your application.

It handles hashchange URLs, as well as HTMLs history API. So you get either flavor that you prefer. The other cool thing is that it actually already supports core-animated pages and doing lazy importing with Polymer import. But it does all that under the hood for you so you don't have to do it yourself. So again, two options. It really depends on which flavor you prefer, but definitely try both out and see what you like in your application. So this one, I feel like I have my application pretty sewn up. It does all sorts of really interesting behaviors. I'm pretty stoked with the way it looks, and now it's time to focus on performance. Sorry, that's the wrong slide– performance.

There we go. I love that lady's face. One of the areas that people run afoul with Polymer often is the route file size. You'll even hear this. People will be like, Polymer's too big. It's just bloated, whatever. And there's some ways that you can mitigate this. First is this thing that I stole from Glen Maddern, who is the creator of x-gif, which is the most important custom element ever made. Yeah. Thank you. If you haven't seen x-gif you should take some time and spend it with x-gif. So one really quick win that you can get is just conditionally loading the polyfills. You don't have to load the polyfills on every platform. There are platforms that support them. Chrome supports it, Opera supports it, Chrome for Android supports it, and hopefully very soon Firefox. So all we're doing here's is just checking to see if the different standards are implemented on the page. If they are, we just move right along.

READ  UTEP Student Email

If they're not, then we load the polyfills. So this is an easy way to save yourself quite a bit of kilobytes. Just conditionally load stuff. That's one trick. And the other thing you've got to do is you've got to actually pop open the dev tools and you got to make sure that you're inspecting your page. So I looked at the contacts app after I built it and was very proud of it. I popped open the network panel there and I saw that I was making 109 requests– which is a lot– and I'm loading 943 kilobytes of stuff. Now, keep in mind, I have excluded the images from this network panel, so that's just my code. Holy crap, that's a lot. I recognize that 109 requests for some of you might be concerning. But what's going on there is under the hood, I'm importing elements.

Those elements have dependencies. They're importing their dependencies, and so on and so on. It's basically this whole tree that's growing out of my application. And so to mitigate this, we created a tool called Vulcanize. And Vulcanize is a module which will actually take all of your imports, concatenate them together, smoosh them all together, take all your JavaScript and your CSS, mash it all into one file, and allow you to just load that one thing into your application. Now, it is available as a node module, but if you are not so stoked about doing everything on the command line, it's also available in a Grunt task and a Gulp task. And for the contacts app, I just used the Grunt task. I set it up once and I just never thought about it again. It just runs every time I'm about to push to production, which is cool. Now, after I Vulcanize and I make sure to put my stuff on a server that supports [INAUDIBLE], my application is now three requests, which is a significant change. And I've got it down to 114 kilobytes, which is pretty nice. Now, this is all the code for my entire application. This is all the JavaScript, all the CSS, all the HTML for my entire application. So I've got it down to 114 K, and this number gets actually even smaller, much smaller, in Polymer 0.

8, which is cool. Now, the last thing we've got to do, we've got our app to the point where we're ready to put it up there, share it with the world, but we've got to make sure we're thinking about offline. Because again, if your app doesn't work offline, you really don't have a mobile experience. And I know that we've talked a lot about ServiceWorker today, so I will talk about it again here because it's so freaking awesome and I'm so excited about it. What I did was I added service worker to this application. Pretty straightforward. I just checked to see if ServiceWorker exists. If it does, I install it. Important thing to note here is that as I'm installing my ServiceWorker, I've got to make sure that I'm using the root scope so that I can catch any request at sort of the top level of my application.

If you nest your ServiceWorker inside of a subdirectory or something like that, then it's only going to have access to the request in that scope, which sort of sucks. You want to put it high up if you can. Inside my application, as soon as we boot up, I just try and cache as much stuff as I can. You'll notice that I'm caching the vulcanized bundle of all of my elements. So my UI is just like instantly available. I'm also caching the initial response from my data service so that there are contacts to populate my list there. And then the other thing that I did was as the user is scrolling around, I'm dynamically caching any sort of image that has a host name from S3.amazon. So as you pass through an avatar image and call this S3 response method.

And really, all it's doing is it's fetching that image, it's caching it, and then serving up for people. So as user kind of uses my app, it just consumes things for them. Now, if we pop this open in Canary and we've got Service Worker running, we started running our app. And what I'm doing here is at first, I'm just racing to the bottom of my application. And right now, there's no Service Worker in play, and so what it's doing is loading all 300 of my contact images at once and just hammering the crap out of the network. And you'll see it's like, oh God, why are you doing this to me. And it finally all starts to load in. Now let's refresh it and see what happens when ServiceWorker's in play. Let's turn our Wi-Fi off, refresh the page. You'll see here over in the column that our assets are now coming from ServiceWorker.

So I race to the bottom of my application. All those things are just coming in immediately. There's no wait on those assets, which is really cool. [APPLAUSE] So, wrap up. What did we learn? For structuring your application, for structuring your UI, you've got the core and the paper elements. So you can compose those together to make a really awesome mobile experience. From moving from one state of your application to the next, you've got core-animated-pages, and you've also got imperative or declarative routing. Kind of depends on how you like to do that. For performance, conditional polyfills. And most importantly, vulcanize all the things. Use Vulcanize to bundle up as much as you possibly can. It'll save you a lot. Also, consider exploring lazy loading. It's one of those things that we're still trying to figure out what's the right pattern, what's the right UX there. But it's something that I think we'll be seeing a lot more in the future, especially in the world of Polymer. Lastly, for offline, ServiceWorker's got your back. So as that starts to land in the various browsers– I mean, even today, experiment with it.

As it starts to land in various browsers, put it in your app. It's going to be really awesome. If you want to play around with this contacts app, it's available up on the GitHubs. It totally has a lot of bugs, so please file bug reports, but even better, submit pull requests. If you want to learn more about Polymer and you're just excited by everything you've seen this afternoon, as Matt mentioned, we're running Polymer events all over the world. We call these Polytechnics. I see some of you wearing the shirts, which means you are cool. If you go to itshackademic.com, you can find a Polytechnic near you. If you want to participate in one, maybe you want to run your own, whatever, all the material is up there. If you set one up, please let me know. Tweet about it, whatever. It's freaking awesome, so you should all go check it out.

Most importantly, polymer-project.org. As you've all been sitting here, we've actually secretly been updating the website. So there's kind of a new experience there. It's just a slight– it's just a nicer coat of paint. It's not a full blown reboot of the site, but now it's a lot easier to find the content that you're looking for. The getting started experience is a lot easier if you just want to get up and running with Polymer, so definitely check out the site, go through some of the tutorials. And I'm looking forward to seeing all the really cool stuff that you guys build, so thanks. [APPLAUSE] .