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