lit-HTML (Chrome Dev Summit 2017)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[MUSIC PLAYING] JUSTIN FAGNANI: Hello. My name is Justin Fagnani. And I work on the Polymer team here at Chrome. And I'm going to talk about a HTML Templating and give you an early look at a new library and approach to client-side Templating that we're very, very excited about on the Polymer team. First, I want to talk a little bit about why Templates are so important. Templates are absolutely critical for today's web. Just about every single site that you visit or build uses some form of a template system. Whether you're building a pure content site that might use server side templates or rich dynamic applications that are rendered completely client side, one of the primary jobs of your code is building the user interface. And on the web, our user interfaces are built with HTML, a declarative document format. And because so much of what we're doing is taking data and transforming it and displaying it, this HTML is usually generated from data. It's not completely static. Some of it is, like I covered here in green. And some parts are dynamic, like I have in pink. And merging and managing this static and dynamic content, it can lead to some really nasty code that's hard to maintain, like our old friend Manual DOM manipulation, where we had to create elements individually, build them together into a tree, maybe hold onto some nodes that were going to be dynamically updated a little later on. And this is, you know, really difficult to maintain. And so Templates can help save us from this fate. Templates let us express our intent in a declarative format that's much closer to the output. And they let us mix static and dynamic content via expressions. So this is easier to write, easier to read, and easier to get correct. So this is great, right? Templates solve all of our problems. Well not quite, especially because writing a good Template system is incredibly hard. Template systems have some very challenging requirements to meet. And they sometimes have to make very difficult trade-offs. So first, Template systems have to deliver a great developer experience. Because that's maybe their main reason for existing. So this includes things like how Templates look. Developers really like Templates to look like their output. Even JSX has shown the popularity of using markup for Templates, because it brings markup directly into JavaScript. It also includes how Templates are structured. Most developers seem to like their Templates to be pretty declarative. But they can't be completely declarative sometimes, because you know, often you do need to do some interesting logic to build up your user interface. It also includes how expressions and control flow work. Do your developers need to learn a new expression language? And it includes tools. Do you need a compiler? If the template has its own file type or syntax, is that widely supported across editors? So even just getting developer experience right is very, very difficult. But as important as developer experiences, it's not nearly enough. Templates have to be fast. They have to boot fast, because they're on the critical rendering path for your application. The expectation for great websites is really, really high these days. Study after study shows that sites lose real users and real money for every extra millisecond it takes to render. And if that's not enough, template systems also have to update fast. Single page apps, especially really rich content creation apps, they need to respond to user input and data changes as quickly as possible. And this goal is often in tension with booting fast. Because one way to update fast is to do computation ahead of time to try to track what data is associated with what nodes. And complex Template systems that do that, they're often larger, too, which can increase the page load time. And then finally, Template systems end up being this bridge between the worlds of JavaScript and HTML, which can be challenging as well. So JavaScript is where your application logic and, more importantly, your data lives. And HTML is what we need to build. It's the stuff that the Template system manages. And it's the natural way in which a lot of developers think about their UI. So typically, if you write your Templates in JavaScript on the JavaScript side, they either don't look a lot like your output, or maybe the code might be too imperative and hard to follow. And if you write them on the HTML side, you might not have direct access to your data. The template system has to pipe that in for you, or you may lose or have to recreate many of the features of JavaScript, like expressions. So all together, these are some really, really challenging requirements with a lot of tough choices and unexplored territory. So it's no wonder that there are a lot of many different opinions and approaches out there as framework and library authors explore all the possibilities and the limits here. And this is actually really great, because we get to try out a lot of different things and see what works best. And if you are building a new Template system, this is a really, really great set of targets to aim for. which brings me to this new library that we're working on on the Polymer team, called lit-html, which aims to do as well as possible on all these criteria. So for a little background, like Taylor mentioned, a few months ago Polymer announced that we're moving away from HTML Imports, where Polymer users typically write their Templates, to JavaScript modules. And this necessarily means that we're crossing this JavaScript HTML bridge over to the JavaScript side. But for backwards compatibility, we're doing the simplest thing possible with the Templates. We're taking the Templates that were written in HTML, and we're just moving them into a JavaScript string inside of your component definition. So this is really easy to migrate to. But it's a little bit less satisfying than we'd like. So we started to think about how to make something a little more satisfying, especially now that we're writing our Templates inside of JavaScript. We want to be native inside of JavaScript. And that's how the experiment that became lit-html was born. So what is lit-html? Well, primarily, it's a library that lets you write HTML Templates in JavaScript that both boot and update fast. And it's a very, very small library. And it has a simple, easy to use, but extensible, API. So let's look at how we write HTML Templates in JavaScript. So this here is lit-html Template. And we're using a feature of ES6 called Tag Template Literals, which in my opinion is one of the most unsung features of ES6. So this looks like a string, except for that we use back ticks instead of quotes. And it can span multiple lines. And it can have JavaScript expressions embedded directly into it. Now this is really useful for building strings from data. But in addition, another really powerful feature is that Template strings, Template literals, can be tagged. And a tag as a special function that processes the Template literal and the values from expressions. And it can customize what's done with those values. And the tag goes right in front of the Template literal, like a prefix. And it's interesting. It doesn't have to return a string. It can return any type of value that it wants. And lit-html takes advantage of this to enable really fast updates. OK. So here's our lit Template. And the expression creates a JavaScript value. So to use it, we're going to have to do something with this value, like maybe put it into a variable here. But first, I want to talk about exactly what type of value this is. So this looks like it might be a string. But I mentioned that, you know, strings would be not that useful maybe. They're not that great for using with innerHTML, because if you produce innerHTML, you're going to have to, you know, blow away all your DOM when you produce some new innerHTML for a component. So maybe they could return some DOM. But we have kind of the same problem there. We don't want to rebuild an entire DOM tree every time we render or blow away the DOM for our component. So instead what we do is we return something called a Template result. And a Template result is an object that contains a reference to the Template that we want to render and the data that we want to render it with. So it's the instructions for how to render some DOM, not the DOM itself. To actually render the Template result, we pass it to lit-html's render function, and then give it a DOM container to render to. And the first time, this is going to render the complete Template. And then after that, it's just going to update what's already there. And I keep talking about updating. But this snippet doesn't really show how to do that. A more realistic and useful way to use lit-html is to write a function that takes some data, and then returns a Template result, like this. So here, we've moved the tag Template literal into a function that takes some data, passes that data to the Template, and returns the result. And once we have that function, we can call it over and over with new data. And then we can render it efficiently to the same container. So for those of you familiar with React, you might notice some similarities here. And there are some, as well as some major differences. So first, this definitely looks a little bit like JSX. But it's standard JavaScript syntax. And Templates being JavaScript expressions and JavaScript values are going to lead to some of the same patterns that you commonly see in building up JSX Templates. But under the hood, the systems are quite different. In particular, lit-html doesn't have any VDOM or doesn't do any diffing. But besides the similarities in syntax, there's another similarity in philosophy I want to talk about. And that's the idea of building UI as a pure function of state. For any given state that your application or component is in, it should always render the same output, the same UI. And to build your UI, you write a collection of functions that transform state into a description of the UI-- VDOM for React, and Template results for lit-html. And then the library takes care of making the UI reflect that description. So this is one way in which they are very similar. OK. So now, let's take a look at some examples of the things you can do with lit-html starting with the types of values that you can pass into Templates. So first is simple text content. Anything that you can turn into a string will just be rendered in place. And this works for attributes as well. And since we're using the full power of JavaScript in our Templates, you can put JavaScript expressions in line with the Template. So let's say you have a page index. And because we're computer scientists, that index is going to be zero-based. But our users are probably not computer scientists. And they expect their pages to start at page one, not page zero. So you can simply add a one in your expression here. And this is a great place to do that kind of Template and display logic. You can also pass a Template result to an expression in order to compose Templates with nested Templates. So here, we have a header Template that we can include into another Template. And we can actually include this in many other Templates as well. And then when lit-html renders the containing template, it'll render both of them together in place. And because Template results are values, we can compute them using the full power of JavaScript. I like using a regular if statement here to display a different message based on whether a user is logged in or not. lit-html supports arrays and iterables. So if you pass an array of data, it'll render each item in that array in place. And this is really powerful when combined with nested Templates. So we can use JavaScript array's map function here to transform a list of data into a list of Templates. And then when lit renders the containing Template there, it will render your UI with the list in it right in place. lit also supports nodes as a data type that you can pass to a Template. So sometimes the easiest or fastest way to create some DOM is actually by hand. Or maybe you're using a third party library that builds some DOM and just gives you a reference to it. Well, your Template library shouldn't get in the way here, and lit-html doesn't. So you can pass a DOM node into any expression, and lit will just render it there for you. And we support SVG as well. Since SVG elements have a different namespace than HTML elements, you can use a special SVG Template tag to create partial SVG Templates to build up dynamic graphics very easily. And this is very similar to D3 maybe, but in a declarative kind of way. And we support promises, too. So for instance, you can fetch some data off the network and put the promise of that data into your Template. And when the promise resolves, the Template will update and render the results right into your Template. So putting all of this together, you can build some really interesting and complex Templates by using the full power of JavaScript. And lit-html doesn't try to dictate a style to you either. If you prefer functional programming where you want to use map and reduce to build up, you know, your Templates, you can do that. If you're doing imperative programming and you want to build up Templates by bit using statements, you can do that. Or if you want to follow a more declarative style where you have a single Template expression and compose it out of other Templates, you can do that, too. So you can choose whatever style you want. OK. Next let's look at how the lit-html boots and updates fast. So the first thing that we use is we try to use the platform as much as possible. We use the HTML Template element under the hood. And for those of you who haven't used HTML Templates yet, they're a really, really useful part of the web component specs. And a Template is basically a container of inert DOM. And here, inert means the inside of a Template scripts don't run, styles don't apply, images don't load, and so on. And Templates can be really efficiently cloned to create new DOM. So typically, that would look something like this. You write your Template in HTML. And then in JavaScript, you go find the Template, and then you clone it with important node. And then you append it somewhere into your document. But we don't usually want to repeatedly clone a static chunk of DOM. Usually, we want to replace some of it with our data. And this is exactly what lit-html lets you do. In fact, you could describe lit-html as a JavaScript syntax for writing efficiently updateable HTML Templates. And it works like this. So here's a lit-html Template. And lit takes your Template, and it replaces all of the expressions in the Template with these generic placeholders. And so we get a string of HTML. And then it uses that string to create an actual HTML Template element with the placeholders inside of it. And then once we get that element back, we can walk the element and find the dynamic parts, find these placeholders, and remember where they are. And we create these things called parts. And these parts have an API that lets us set the value after we've created some content. So we remove the placeholders. And now, we have a Template without our expressions that we can clone over and over again to create DOM that's just waiting to accept data. And because we've remembered the locations of these dynamic parts, we can go back after the fact. And we can insert data into the parts, into the placeholders. And because we remember the locations of the dynamic parts, we can then really efficiently go back and do updates by adding new data directly to those parts. So one other thing that helps make a small fast is Template Literals. So they have a couple of nice properties. One of them is that the literals that are passed to a Template tag are the same for every call to that tag. with the same Template. So this lets us do one-time setup work like that HTML Template preparation I just showed you. So this is a little bit subtle, but really important. So lets go into a little more detail here. So I mentioned before how a Template tag is just a function. Well, the first argument to that function is an array of all the literal parts of your Template Literal. And if you evaluate a specific Template Tagged Literal multiple times, the tag is called multiple times. But that first argument is the same every single time. So this means we can use it as a cache key to look up our prepared Template. So all that work of transforming a JavaScript Template to an HTML Template and remembering the dynamic parts, that's only ever done once per Template no matter how many times you call it or no matter how many places in your application you use that Template. So this is really, really important to how lit-html works. And to visualize this, let's consider a really simple Template here that we call say hi. We're going to call it once to say hi to Amy. And then we're going to call it again to say hi to Alex. And both times, we return a Template result that contains a reference to the Template and the values. And these Templates, they're the same. And they're not just equal the same. They're actually identically the same object. So they share this template in here. And they only have to compute it once for your entire application. OK. Another property of Template Literals that we use is that they naturally separate static and dynamic content. So let's look at why that's important. Every HTML Template system is responsible for creating and maintaining a tree of DOM nodes. But only some of those nodes are ever updated after they're created. Templates have the structure that I talk about, the separation between static nodes, the blue ones here, and dynamic nodes, the green ones. And then we have the updates. Not every dynamic part changes all at once. Sometimes you just update one value. And so when thinking about the rendering costs of a Template engine, I find it useful to think about these two numbers here. One is how many nodes are updated when you make some changes. And two is what is the cost per node. And if we look at something like Polymer that has a very advanced Template system, it's able to analyze the relationship between your data and the DOM. And it knows exactly what DOM changes when certain data changes. And so Polymer can scale not with the number of nodes in the Template or even the number of expressions, but the number of changes that you have. And if we look at something like VDOM, it takes a very, very different approach. And with Virtual DOM, you render your entire virtual tree for your whole Template every single time. So VDOM scales with the number of nodes in your Template. But it tries to make up for this by driving the cost per node down as low as possible. And so with lit-html, we're trying to sit somewhere in the middle here and get the best of both worlds. So lit-html never has to look at or compare the static parts of a template after the initial render. It just leaves them alone. So it just looks at the expressions. So it scales with the number of expressions in your Template. But then it tries to drive that cost down as low as possible, because expressions are just JavaScript values. And it's mostly just forwarding that value. And if the value doesn't change, it doesn't update that DOM at all. And all of this falls out quite naturally from using Template Literals. Because we can tell exactly what parts are dynamic and might change and what parts are static and never change. And we don't even have to do any work to figure this out. The syntax of JavaScript just does it for us. Next, we're fast, because we take advantage of the fast built-in parsing of the browser. For parsing strings, which make up the biggest part of Template literals, parsing strings in JavaScript is roughly three times faster than parsing generic JavaScript expressions. The VM just has to churn through characters until it gets to the end of the string or the beginning of an expression. And then we take that HTML content of a Template, and we pass it to the highly optimized C++ written HTML parser. And so this gives us fast parsing speed. And it also means we don't have to ship any parsing logic with our Template system, which means that lit-html is very small. It's really small. The entire core library fits on a single slide here at 18 point font with a little bit of room to spare at the bottom. lit-html is roughly 2 kilobytes of size. And we're working really, really hard to keep it that way. OK. So here's a lot of things that should theoretically make the HTML fast-- JavaScript Template Literals, HTML Template Elements, not doing any differing, being really small. Does it really add up to speed? Well, it's still pretty early in the project. So we haven't, you know, released 1.0. And we haven't done all the optimizations we want to. But we have started to port some benchmarks. And one of the first ones that we've done is called the Marko Search Results Benchmark. So eBay released their internal UI framework a little while ago. And they included some nice benchmarks implemented across many frameworks, like Preact, React, View, and Inferno. And so I implemented this benchmark using kind of the full vision for lit-html, which is combining lit-html with web components using custom elements and Shadow DOM. And these are very, very preliminary results I'm about to show you. But they still need to be double and triple checked. But so far, it's looking pretty good. So here we go. We've run it against these other frameworks here. And lit-html is amongst the fastest in this benchmark. Here, higher is better. These are operations per second. And this benchmark also tracks the bundle size for each benchmark for each framework they implemented. And here, lower is better. And lit-html is also the smallest of the frameworks in there, coming in at just over 6K for the whole benchmark. So that's not the library. That's the library plus the benchmark components, including all of their Templates at a size that's smaller than most complete libraries on their own. So it's really early, but I think we're off to a pretty good start. We've also started to port the DBMON benchmark where lit-html is also competitive with the fastest frameworks there. And it also shows really good stability across a wide range of update workloads. So at least our assumptions about how to make something simple and fast appear to be on the right track. And we still have a lot more optimizations to do. So next, let's look at the API and what makes it easy to use and extensible. So in earlier examples, you already saw most of the lit-html API. It's really just the HTML Template tag in the render function. Those alone get you a lot of functionality with the types of values that lit supports. But lit-html is also trying to be as small and as unopinionated as possible. And it can't possibly stay that way and give you all the functionality that you're going to want. So lit is extensible in two different ways. The first is what we call directives. So I showed you how a value can go into an expression there. And I showed you how every expression creates a part, where there's an API for the part that you can call. Well this is what a directive looks like. A directive is basically a function that gets invoked instead of the value being passed through. And you mark something as a directive by using this directive kind of decorator function here. And that tells lit-html to call the value instead of passing it along. And what it calls is a function that takes an argument, which is the part. And now that you have the part, you can do whatever you want with it. But the part really only has one API, which is a set value. So this is the simplest directive you can write. It's kind of a pass-through directive that just takes a value and puts it into the part like you would have with a simple expression. So that's how easy directives can be to write. Let's look at a real example. One of the built-in directives is called until. So I talked about how promises, if you pass them to a value, lit waits for the promise to resolve, and then writes the resolved value to the Template. Well, sometimes you're going to want to have some placeholder text that shows up before the promise resolves. And so until let's you do that. You give it both a promise and some placeholders, some fallback content. And it displays the placeholder first, and then displays the promise when it resolves. And it's implemented in only two lines of code. So first, here is the example of using it. We get the response from the network as a promise. And instead of passing it directly to the Template, we call this until directive with the promise here, and then some placeholder, that's loading text over here. And then here's the implementation of until. So it's a function that takes some arguments there and returns a directive. And that directive only has two real lines of code in it. The first one immediately sets the content to the placeholder. So that shows up right away. And then the next one goes ahead and, right afterwards, sets the value to the promise. And this is going to let lit overwrite the placeholder when the promise resolves. So that's a really simple example, but a real world example. And your directives can be as complex as you need to handle custom logic inside of there. And so the other thing that you can do to extend lit-html is to use what we call custom parts. These are ways that you can customize how values are handled across an entire Template, including the Templates that are nested inside of them. So we've packaged together a couple of custom parts into an optional library that we call lit-extended, which gives you a little bit of sugar for your Templates. First, it sets properties by default instead of attributes. And then it lets you fall back with an explicit syntax to set attributes if you want. And it also adds declarative event handlers. And the entire lit-extended library weighs in at only 540 bytes [INAUDIBLE].. So here's an lit-extended Template. It looks just like a lit-html Template. First, we have a property binding. And I want you to notice something here is that I use mixed case property name there. Even though lit Templates are HTML, because we write them in JavaScript, we can actually go back into the JavaScript value and pull out the original case sensitive property name, so that we don't have to do any lowercase to uppercase mapping here. We can set any property name we want. And then if you want to set an attribute, you can add a dollar sign after the name. And here we're going to set the class attribute, not the class property. And finally, if you want to add an event handler, you can just prefix the name with on-. And lit will take the rest of the name there and add an event handler for you. OK. So one thing that helps make lit simple is that we have a very focused API. lit-html is doing templating only. It's not a framework. It doesn't have any component model. And we actually designed this to complement web components very well. So to show you what that's like, I wrote a little web component mix in here that adds some lit rendering behavior to HTML element. And the way this works is that your class that you write is going to implement a render function that returns a Template result, a lit Template kind of like React actually. And then when you want to trigger a rerender, when you notice that something changed that you want to render, your element can call the invalidate method. And the invalidate method simply batches calls to lit's render function, and then renders the result to the shadow group. And then here is a custom element using this mix-in. So the first thing we do is we apply the mix-in to our base class. And then we want to implement a property. So here I implement a property as a getter, setter pair. This is something like Polymer will do automatically for you. But I wanted to show you something that wasn't magic. And so what we implement here is a setter that calls invalidate when the value changes. And that's going to enqueue a render of the element. And then finally, you implement a render function, which returns a lit-html Template. So this is how simple a custom element can be. And in the future, this is actually going to get even simpler. When JavaScript gets decorators or if you're already using decorators with Babel or TypeScript, we can use a decorator to automatically generate that getter setter pair for us. So this can be really, really simple and lightweight with a focused templating library, like lit-html. I think a full-featured base class that does some other things, too, might weigh in at less than 3K for the whole thing. That's including lit-html. So together, directives and custom parts, they let you craft kind of your own Template system with the capabilities and opinions that you want. You're not stuck with our choices. So we hope that lit-html can do really well across a lot of different measures-- ease of use, using standard JavaScript syntax, speed size, expressiveness, extensibility. We really hope to do well on all of these different requirements the Template systems have. So where are we today? We have browser support across the latest version of all major browsers. And we're working on IE11 support, which should come very soon. We're also starting to get some great community contributions. People have made fixes and commits to lit itself. And some people at Microsoft have made IDE plug-ins for VS Code and their Language Service. They'll let you have syntax highlighting, and code completion, hover over documentation, and all the full intellisense features right inside of your HTML templates. So next up, like I said, we're going to be working on benchmarks and optimization, IE11 support. We want to get feedback from users. We'll show integration with web components, get some documentation finally written. And then we're going to work towards a 1.0 release. And we would really, really love for you to try it out and give us your feedback. The API is very simple. So we're not worried that the API is going to change a lot. But we want to see what people do with it and how they like working with the system here. So you can install it off of npm, just npm install lit-html. And if you want to leave some feedback or find some issues, you can do it at our GitHub repository. It's the lit-html repo in the Polymer Labs Organization. All right, that does it for me. So thank you very much. You can find me on Twitter here and ask questions. Or I'll be in the lounge, and you can ask questions there, too. All right, thanks a lot.
Info
Channel: Google Chrome Developers
Views: 42,651
Rating: 4.8321996 out of 5
Keywords: Chrome dev summit 2017, chrome dev summit, chrome summit, HTML, dev summit, Justin Fagnani, google dev summit, google conference, web developers, web developer, web development, progressive web app development, progressive web apps, web app, mobile web application, web design, mobile web development, google progressive web apps, mobile web, developer news, developer updates, Location: other, GDS: Full Production, Fullname: other, Product: Chrome
Id: Io6JjgckHbg
Channel Id: undefined
Length: 29min 43sec (1783 seconds)
Published: Tue Oct 24 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.