[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.