348: Getting lit-html with Justin Fagnani
Justin Fagnani from the Polymer Project is our guest and we're taking a deep dive into lit-html and Polymer elements, how those projects are different, and we'll discuss how Web Components is wrapped up in all of this.
Time Jump Links
- 01:02 Guest introduction
- 01:53 What's lit-html?
- 07:26 What about web components?
- 09:40 Does lit-html extend HTML?
- 11:27 The interoperability of web components
- 22:45 Does using host and style in our templates get us gains?
- 27:17 What are lit's best friends?
- 30:31 What do lit-html tabs look like?
- 31:51 Can people start dropping these in their projects soon?
- 33:26 Sponsor: Netlify
- 34:20 Why doesn't web components have higher adoption rates?
- 41:05 What's the future of web components?
- 49:46 Does lit loop?
- 52:33 Is there a lit version without classes?
- 56:04 What are some success stories?
MANTRA: Just Build Websites!
Dave Rupert: Hey there, Shop-o-maniacs. Welcome to a lit episode of the ShopTalk Show. [Laughter] What does that mean? I'm not a millennial. I'm Dave Rupert. With me is not a millennial, Chris Coyier.
Chris Coyier: I am too, aren't I? I think the cutoff year is right around where I am. I'm an '80 baby, so I don't know.
Dave: Oh, okay. We qualify, so we can say "lit," folks.
Chris: Say "lit."
Dave: Welcome to the rebrand.
Justin Fagnani: I'm at the Goog. I work with Jason quite a bit these days even though he's on the East Coast and I'm in San Francisco. I work on Chrome, on Web components, on Polymer, and lit-html, so that kind of thing.
Chris: You both work on libraries in which the class x extends something. [Laughter] No?
Justin: [Laughter] Oh, no, it's not functional.
Dave: Oh, okay.
Dave: What's the functional version? I'm confused.
Justin: There are functional versions of all this stuff.
Chris: Is there really?
Justin: We do. We do use--
Justin: Yeah, well, starting with Polymer kind of makes sense because that's where a lot of this work started, but Polymer has kind of evolved. It started as a library to help you implement Web components yourself. It has evolved more into an umbrella project, and so we try to refer to it as the Polymer Project now, which includes lit-html, element, and things like the PWA starter kit. Then we have the Polymer library that some people sometimes call Polymer Classic. We're trying to expand the brand to cover more projects that we have.
Chris: Okay. Interesting. Has Lit become a big part of it or it a tiny little buddy part of it?
Justin: It's basically the centerpiece of everything we're doing now.
Dave: Oh, wow.
Justin: Yeah. It was a big change in how we approach creating DOM and doing templating, and we're all in on it now.
Then we're like, "Well, but what's really nice about these other libraries like View and whatever that use these virtual DOM situations is that the virtual DOM is so efficient," right? If I change one little span, I literally open the dev tools and watch, and I only change data that will change that span and not the parents of parents of parents, that it's within only that little span change, that looks so efficient, so cool, and it feels so fast in the browser. That would be nice.
But now, if I'm writing my template literal piece of templated code and I need to re-render it, well, I'm inner-HTML-ing the whole thing or whatever. It's going to update a lot, and so along comes this library, Lit, that looks like it can do that kind -- it looks like virtual DOM, the thing, but it's not. You get the efficiency without it. Is that the core of it, or is that just a side benefit?
Justin: That really is the core of it. There is a lot to unpack in the thing you just said, which is what most people's understand of ES6 and template literals are. There's a lot of hidden power there that's not obvious at first because most people are exposed to just plain template literals, not tagged template literals. You have the backticks and you have the expressions. You're like, "Oh, this is like Python string interpolations.
Chris: Really?! I always thought it was just a nice little sugar for, like, take this string and pass it to this function, which it does, but it does even more than that.
The string's array, the literal parts of the template literal that get passed to the tag function, that array is the same object every single time you invoke that expression. And so, we take advantage of this by, basically, we have to do some setup work to create an HTML template from the Lit template. We only want to do that once the first time we render. And so, we do that by using the template string itself as a key into a map, like cache, right?
We can do this setup work, create a template, remember where the dynamic parts are, and then only do that the first time we ever see a template. Every other time that you update something or render a new instance of a component, it's reusing that same work we already did.
Chris: Cool, cool, cool.
Dave: Wow. When you say a template in HTML, you mean literally open bracket template, close bracket, all my stuff goes here, close template, tag. Wow, okay.
Justin: A lot of people don't know about that element either because it's not used by frameworks like UX.
Chris: Yeah, it is a little. You see it in View but, even then, it's kind of View's version of it, right?
Justin: Yeah, which I think more or less kind of has the same semantics. The magical part about template is that the contents of it are moved out of the main DOM and into an inert document fragment. If you put scripts, images, or styles inside of a template, they won't load or render.
Chris: Oh, they don't trigger the pre-loader or whatever? That's interesting.
Justin: Yeah, I don't know what the pre-loader does, but they don't -- like a style inside of a template won't apply to the page.
Chris: Wow, wow, wow.
Chris: I did not know that, actually. Let's take a detour and, instead of talking specifically about Lit, talk about just Web components, period, because Polymer and Lit care very much about that, right? They help along the idea of native Web components.
I could, today, if I wanted to play with Web components, I can play with Web components with no libraries at all. Right? I can write class Chris's component extends HTML element, or whatever, and I've kind of created a class thing. We mentioned class in the thing, and you're like, "There's a functional equivalent," but let's say it's a class.
Chris: I can kind of invent a Web component with no libraries at all, right?
Justin: Yeah. Web components are just part of the platform and so HTML element is just something you can extend. The shape of the component, kind of API, is very similar to most frameworks. You have kind of a lifecycle, so you have, when your element is created, you can implement the constructor. You can tell when you're connected or disconnected from the tree, so it's pretty similar to most things out there except for that it's just built in.
Chris: How can that not be appealing to people on some level? You're like, "What's the use case for this?" Well, the use case is every React component that's ever been written. [Laughter] Kind of.
Chris: I know they're different, but it's like no wonder that's at least a little appealing is that there's this library free version of components that's possible. I know there's plenty of stuff that Web components don't give you that those libraries do. The industry has decided, in a way, that these frameworks offer them what they want and people are using the hell out of them.
But it's kind of cool that the Web component, the native technology has moved along. And then, maybe they're starting to be little smaller libraries to append what Web components are able to do. Is that how Lit thinks of itself as, "Why don't you use regular Web components and we'll help you," I don't know, "make them better or more efficient in some way?"
Justin: Yeah, exactly. That's where Lit comes in. Lit is very focused, just as templating. I should say lit-html, because we also have LitElement, which is a Web component base class that kind of glues lit-html and Web components together.
Chris: I'm a little unclear on that, myself. Lit-html is just like little functions that you can call for re-rendering and stuff, but that doesn't help you construct an actual Web component, right? You need LitElement for that. Then, if you're using LitElement, no longer are you extending the native HTML element. You extend LitElement.
Justin: Sorry. LitElement itself extends HTML. It's just an intermediate subclass of HTMLElement or superclass for your element. You still extend HTMLElement.
Chris: Oh, interesting. Okay, so it's not.
I wonder about that moment, though. Even though it does that internally, you've kind of bought in, now. Now you're in framework land.
Justin: I mean I would really hesitate to call it a framework. I know people get kind of -- they try to figure out what exactly you mean, but LitElement adds some conveniences for essentially defining what is still a vanilla HTMLElement. From the outside, you still just have properties and you still can set attributes and listen for events. It's an element in every shape and form. It's just that you use this class to help you implement it.
Dave: Is this kind of the revival of sugar libraries, [laughter] semantic sugar? This feels good.
Justin: I hope so because the nice thing about opinionated sugar is that, when done right, it's optional and it's lightweight. And so, you can have a bunch of people choose the sugar that they like or none at all when they implement their component, but people don't have to agree on the sugar. It's all inside their implementation and these things still interop because of Web components.
Dave: One thing that is always pitched about Web components is it's interoperable - interoperable. When I write my View app and there's like, "Oh, I need a map," but that map is written in React or Angular, I can just install that and it should work. This a future where everything is on Web components. [Laughter]
In my brain, I don't really see it working that way. What has to happen to making--? I just don't see me dropping an Angular component in is going to be super easy and lightweight. It seems like it's going to bring all of Angular and all of--I don't know--so much stuff, you know. How do we get to that future where I can just seamlessly kind of move between component or, like, frameworks?
As frameworks get smaller, the incremental cost of adding one to a page becomes less. I think that it might not be ideal or common to mix a ton of different libraries together that do essentially the same thing on the same page, but one thing that even having the ability unlocks is that, especially like enterprises or long-lived projects or multiple project kind of organizations, that they don't get kind of stuck because they've bought into a framework and have no way besides rewriting the entire application to move to something different.
We've already seen this play out really nicely with Polymer, the library, and LitElement is that they interop on the same page and we have people who have a Polymer application and they want to start using LitElement and they just can't. They don't have to configure anything different, write wrapper classes, or rewrite the whole app. This gives them an incremental evolution path that really didn't exist for frameworks.
Even within the same framework, Angular had huge issues to deal with in the AngularJS or Angular 1 to Angular 2 transition. If that had been just different kind of opinions and extensions of Web components, people would have been able to mix and match and incrementally migrate to Angular 2.
Justin: I mean I'm optimistic. I have to be to be fighting this battle. But I think it can happen. I don't know if it will always come from the existing frameworks or whether or not there will be new libraries that offer the advantages of the frameworks and then some because they're on top of Web components.
You said earlier, like, you know, why would anybody not want this? That's kind of the way I look at it is, you know, the Web platform evolved into an application platform kind of by accident, right? Every application platform out there, like Android, Windows, iOS, they all have a component model. We say, should the Web, as an application platform, have its own component model? The answer to me is, of course. Why wouldn't we want it to have that.
Chris: Yeah, the whole world, if there's one thing we all agree on, it's that the components -- this is true of designers and developers, which is, we've all agreed that designing components is how we want to build stuff, now and forever.
Justin: Yeah, I think a lot of the problem comes down to kind of misconceptions about what Web components are. I think some people expect them to be as high level as what a framework would give you, and so have all the conveniences when, really, they're super low level. All custom elements do is let you define a new tag and then kind of notify you when that tag has been added to the page. That's it. It's not a lot of convenience or sugar there.
Chris: Right, right, right.
Justin: And so, people look at documentation like an MDN and, you know, MDN isn't going to go, "Web components, okay, step one, install lit-html," right?
They're going to go, "Web components, here is an attribute change callback, and here is how to render some DOM." Unfortunately, the platform has no great way to render a lot of DOM, right?
Justin: We have InnerHTML. We have Clone Node. They are really in a level themselves, so you see a raw Web component as an example, and you go, "Wow, this is really imperative, stateful, mutation heavy code, and that's not what I want to write." And so, you don't see the layer that puts that declarative sugar on top until you get to something like Lit, but you might not ever get there. You might look at the MDN docs and then say, "This is not what I want." That's a challenge we have, I think.
Dave: I think I experienced this myself when, I think, a couple years ago I said I was going to dive into Web components and just try to figure it all out, like, how could I start using this in my code? I realized the low level Web component isn't what you want. You kind of need something around it like Polymer, which that was kind of the only. I guess there are a couple of other frameworks like Skate and other things that kind of do Web components.
Justin: Skate and Stencil, now, yeah.
Dave: Stencil, yeah, and so, I was like, okay, I'll use those or maybe I'll look at those, but Polymer was kind of the big one because it hat the Google backing. But then I jumped into Polymer, and I was just like, this is a lot of action. [Laughter] There's iron first components and things like that.
Justin: Yeah. I mean Polymer, the library, in the early versions, there were a lot of things that I think were kind of hindering it. One was an overloaded term even then, so we had all these elements that were part of the PolymerElements projects. Some of them were iron, which was supposed to reference core, and some of them were paper, which was supposed to be material design.
Chris: It seems like there's almost more excitement about anything with Lit in the name than Polymer, in a way. It's like you need a reboot on the Polymer brand situation.
Justin: This is why we're trying to focus on the Polymer Project, which makes these libraries. Yeah, some people have some connotations with the Polymer library that are unfortunate. I think it's a misunderstanding in a lot of ways. But the future is bigger than the past, and I think most people will be excited about the things we actually build now.
Dave: I think that misconception definitely exists. I see it on Twitter, of course. People are like, "Web components sucks. I'm not going to use Polymer." You know? They kind of equate those two together like they're the same thing, but they were different. Polymer was just the abstraction over Web components.
Justin: This is why we're always happy to help promote other Web components-based libraries out there because we don't have to compete with as much total warfare. The same page can contain a Skate element and a Stencil element and a LitElement and probably be lighter weight than the mainstream frameworks.
What is it, cooperatition? We cooperate a little bit on mindshare for people already in the Web components universe, I think but, more, we're all interested in growing the Web components pie. So, that's a lot different than what people are used to with frameworks. We have to use one or the other. And so, I want people to know that Web components is not just Polymer and that there are these other options out there.
Chris: I think that the Shadow DOM thing, to some people, could and should be a little bit exciting because it's like real true style encapsulation that is not possible with the other frameworks unless they choose to go down a Shadow DOM-like root, which I don't think I've seen yet. It's like having a little iFrame on your page. The styles cannot escape from it. It's pretty cool, you know.
Justin: Yeah, it's amazing, and especially Chrome 73 is going to make native Shadow DOM even more amazing because it's shipping constructible style sheets and CSS shadow parts. But once you have a real encapsulated scope for your styles, all kinds of things that are possible or at least practical that weren't before, right? You can have really simple selectors. You can use just a tag name selector like P.
Chris: Right, right.
Justin: You would never want to do that without shadow. You can use IDs again because IDs are scoped to the shadow root too. You can start writing a lot less CSS--
Chris: I've heard this idea. You don't even name the root. You just frickin call it host or whatever. You don't have to even think of a name for the top level of the component, at least, because it doesn't matter. It's just the root.
Dave: It's BEM without the B.
Dave: It's just EM.
Chris: Oh, Dave!
Chris: You need to be rich from that. That's an incredible….
Dave: I know! Why am I not rich right now?
Justin: You can confuse everybody by referring to EMs in CSS as the thing.
Dave: Yeah, I know.
Dave: Yeah, that's got a branding problem. We're a workshop brand still.
Dave: HEM. HEM, Host Element Module. Got it. Okay. We're rolling….
Dave: 2019, the year of HEM. Okay.
Justin: I got it. I'm tweeting this right after we're done. Yeah.
Justin: Yeah, Host is amazing. It's like completely unambiguous. It can't point to the wrong element ever, right? Call on Host the selector.
Justin: You don't need to put a wrapper element around your contents.
Dave: Does this have advantages too, kind of the same template advantages again, say, technology which shall not be named or else we're going to catch in the Twitter feeds, but a certain technology that tries to put a styling language inside a scripting language? Using Host and these styles in our template, does that get us any gains, like cacheable or anything like that?
Justin: In some ways, definitely. Having a style scope and less selectors and simpler selectors means the browser has less work to do when it goes to do style resolution. But an even bigger gain is from something like constructible style sheets.
Up until just about now, we've been recommending that people just put a style tag in line with their template. As that style tag gets written to the shadow root is scoped, but it might seem that that's costly because you have all these style tags now on your page where you used to have one. What browsers have been doing is deduplicating those style tags based on their contents, so it'll try to only parse and make one style sheet for all of them.
Justin: Now that we're starting to add a few more features on top of shadow root, the benefits are getting even bigger.
Chris: I'm curious about the authoring of that, in a way, though. What is the -- [Laughter] It seems like people love View because it's just a style tag in every component, and that's where your styles go. What a clean, nice authoring experience that is, you know. Or, in React land, you pick from this landscape--
Chris: --of styling tools to go with your components, or whatever, or you use CSS modules, which is so nice. It's just a straight up CSS file that just lives alongside the component. If you're authoring a LitElement and you want to style it, what's the authoring experience like? Do I write a CSS file in my project that just lives right next to where I'm defining the component?
Justin: If you want to do something with no build step, what we have is, you just write static styles equals, and then we have a CSS template tag that's very similar to the HTML template tag for LitElement. Then you just write your CSS right inside the backticks right there. Then we take that and we do the most optimal thing we can depending on browser support.
That tends to work well because IDEs have gotten really good at syntax highlighting and giving you InteliSense and all that on template literals that are tagged, so we keep the tags simple.
Justin: CSS, HTML, SVG--
Chris: At worse, we've got to install a little VS code plugin that recognizes it or something, but it might not even need that.
Chris: Does it make a network request for that file when it grabs it that first time? Probably, but big deal, right?
Justin: Yeah, but you presume the bundlers will support that kind of thing and then figure out the optimal bundling strategy there. Or, in the future, we'll have Web packaging, which will take care of that.
Chris: Cool. What are Lit's best friends, in a way? What you get out of Lit or LitElement is a nice Web component structure, sugar, and stuff. Then you get templating, for sure, right? You get efficient re-rendering for sure and probably nice -- I don't even know what you get. Maybe nice, you know, hey, component did mount or whatever. [Laughter] I don't know if there's some native version of that.
But maybe what you don't get, which is certainly why some people choose React, is like, I need state management. Even Lit is telling me, "Hey, when there's new data, we'll re-render that super efficiently." Well, where does that new data come from? Is there some kind of internal state tool of Lit or does Lit, on purpose, stay away of the concept of state? Can I bring along a state management friend?
Justin: Yeah, that's a great question. You're right there that Lit tries to basically stay away from that topic and say bring your own, so very much like React does in a lot of ways.
We support top-down, unidirectional data flow. If you have new data, you set a property and that triggers the update pipeline and we re-render.
How you set that data and how you determine that you need data to be set is up to you. A component could manage a state locally if it's trying to be very independent and usable just in a page with no framework, or we definitely have a lot of people using Redux and tools like that.
Those things have been written for a world that weren't necessarily DOM oriented, so you still used -- if you used Redux, you use it in the same way that you have done. You have a dispatcher and you fire the dispatcher and all that.
One nice thing about being close to the DOM is that you can do some of these patterns without any libraries. The thing I recommend people do is, when they have a component that changes some data is, they just fire a custom DOM with it. That event will go all the way up the tree. Then in your app, or whoever owns the main data for the page, they just catch that event, they mutate the data, they set it back down, and then the page re-renders.
Justin: You kind of get Redux -- you can get Redux for free, in a way.
Chris: There are native DOM events like scroll and click, but there's no reason I can't fake one called Chris Click--
Chris: --and listen for it, right?
Justin: Even better, you don't name it Chris Click. You name it semantically over what that button meant.
Justin: Like Delete Chris.
Justin: No, never do that.
Justin: Yeah, Promote Chris could be an event that a button….
Chris: I don't have to ask permission or even register that event, right? I just fire it and something else can listen for it.
Justin: Yeah, and in a component, you just go, this.dispatchevent. Because the component is an element, you have all the element APIs at your disposal.
Chris: See, that's part of the rub, isn't it, that we get a bunch of stuff for free because it's the real--? We're not faking anything. It's just part of reality in the browser.
Justin: Yeah, there's a lot of benefit from doing less, I think. Part of that is not reinventing what the browser already has there.
Chris: Is there starting to be--? Let's say, okay, what do lit-html tabs look like? While we know we need one piece of state. Which tab is active?
People could this write this any number of ways, right? You almost don't want to get involved with this. You don't want to make iron tabs anymore for Lit because it's a little too opinionated, maybe. You just want to -- you want to write tabs? Do whatever you want.
Justin: I mean, yes, yes to both kind of things there. One of the things that brought a lot of people to Polymer was the fact that we had these elements ready to go. We had, kind of at the time, the canonical material design element set. We're working on a new material design element set called Material Web Components.
Chris: That's a good name. Paper, not so much. I mean, whatever. But I mean you know you had confusion, right? Paper meant material design. Well, just call it material design then. [Laughter]
Justin: I know. I mean an earlier name for Material Design internal to Google had "paper" in the name.
Chris: There you go.
Justin: Right, and paper is a material. That's--
Chris: I see.
Justin: That's where this came from.
Dave: If you dug in, it made sense. It made sense.
Justin: Yeah. Yeah, it's much clearer if you just say Material Web Components. People will know what you mean.
Dave: If there's a material Web component that comes out, I'm sure this appeals to a lot of people. I mean using somebody else's design system is all the rage. [Laughter] Is it just some people can just start dropping this in their projects soon or … Google…?
Justin: Yeah, there are actually published in pre-release form. It's kind of an interesting project. The way this works is that the material design team wants to make kind of the canonical DOM structure and styles and behavior for all the implementations.
They implemented this very, very agnostic system where they have these little adapters that you can wrap up in your framework. Then we're wrapping that up in Web components, so it's kind of all the same styling, so they all look the same. But it's an interesting problem there because they want to be able to support all frameworks and we're also like, "Hey, Web components support all frameworks," mostly. React has some troubles.
While we're building these Web components, we're also hoping that the Web components themselves can be the version that everybody uses, and so we're trying to smooth out any remaining rough edges. The material Web components are using LitElement. It's an implementation detail, but we are doing things like trying to work with, like, make a React wrapper that will automatically vend a React library out of the Web component library.
Justin: We're going to try to make these things more universal than just say, like, "If you're using Lit, these are the ones you use." We're going to try to say, "No matter what framework you're using, these are the material Web components to use."
Chris Enns: This episode of ShopTalk Show is brought to you by Netlify. Earlier this month, Chris Coyier wanted to build a website to track upcoming conferences for frontend developers just like yourself. He built something like this previously using forms for submissions and, basically, manually editing a blog.
This is 2019, so he wanted to do something a little more interesting. He used GitHub to host the code, which allows anyone with a free GitHub account to collaborate via a pull request. He built the site with 11ty.
He then turned to Netlify to host the site because Netlify makes it incredibly easy to do. He connected the GitHub repo to Netlify, told Netlify how to build it and where to find the files, and now, whenever he pushes to the master branch or accepts a pull request into master, the site automatically rebuilds and deploys in seconds. You can check out the completed version of the site at conferences.css-tricks.com, which has a link to the GitHub repo where you can contribute with a pull request of your own.
Be sure to check out Netlify.com for information on how to build, deploy, and manage your next Web project today. Thanks again to Netlify for sponsoring this episode of ShopTalk Show.
Dave: Where do you think--? Why doesn't Web components have 100% adoption by all popular frameworks right now and what would it take to get there or what concerns are there from those, we'll call them, companies? [Laughter] I guess, how do we get to this future where everything is a Web component?
There are a few remaining things to kind of tick off that are not usually a problem, but people can point to them and say, "Okay, Web components have this issue here. Therefore, we won't use them."
Server side rendering is another one of these, and that's what we're working on right now. It's like, a lot of Web components libraries are small and fast enough that you don't actually need server-side rendering to be fast, but a lot of people have a hard requirement; we want server-side rendering. Because Shadow DOM is not representable in Markup, this is a bit of a tricky problem to solve.
Dave: Yeah, that's kind of something we lost. I guess from Polymer 2 to Polymer 3, went over to LitElement, right? Went from a more HTML declarative to an all in JS flavor. Is that a fair assessment?
Dave: Moving over to all in JS, we've kind of lost the server side thing, unless you do some kind of, whatever, like render two string or something.
Justin: Well, Polymer -- I mean server-side rendering is funny because it means different things. Classic server-side rendering like PHP, Web components are actually amazingly suited to that like no other framework is because you can just put tag names in your server generated Markup and they just work. As long as you have the script tag that includes the element definition, they'll just boot up on the page and there you have components.
Dave: Oh, so like if I was running a wiki, some kind of doc site that needed a new header or something? [Laughter]
Dave: I'm just kidding. Hey, step out of that. Sorry.
Justin: Just putting it out. Just putting it out there. Yeah. Yeah.
Chris: I didn't catch that drama. Is there something weird about MDN having a React header or something? Is that what people are mad about?
Justin: Yeah. There was a little too much kind of heated conversation there.
Dave: There are a lot of misstatements all around, I find.
Chris: I didn't catch any of it. Oh, I'm sad.
Justin: Oh, it's typical Twitter drama. It's not really necessary.
Chris: Okay. Okay. Forget it, then.
Chris: We'll talk….
Justin: But we're friends with MDN. The thing is, choosing another framework library is totally fine. We just want people to know that Web components are well supported in Firefox and Safari.
Yeah but taking a step back to this use case of wikis and content management systems or Markdown, Markup already works in these systems, and so Web components are really, really suited for them. Sometimes you'll see people like, "Hey, I created a new flavor of Markdown that also supports React or View," or something.
You're like, "Well, I created an old flavor of Markdown that supports custom elements," because Markdown supports HTML. [Laughter] Yeah, so that kind of server-side rendering has been well supported from the beginning. What isn't supported is the deep server-side rendering where you want to render the guts and the implementation details of a component to a page, and it is possible.
Polymer didn't support it, so that's not something we lost with LitElement. But, yeah, what we're going to do is something similar to what all the frameworks do for server-side rendering now is kind of execute the component code in Node and then capture results, stream them to the browser, and then rehydrate. It's possible. It just requires a bit of work, and we're doing that.
Justin: --you know, claiming their--
Dave: You don't say. Okay.
Justin: I don't know how you solve that or if you solve that. Maybe there are other areas where people stopped fighting over something that should be table stakes that we could look to, to see if it ever happens.
Dave: Yeah, there's always -- I mean, you're on the Chrome team, Chrome side of things, but there is a heavy argument for performance that's good for users, I think that we can all agree. But then, you know, there's kind of a strawman that gets elevated like, "Well, what if users are fine to wait an hour and a half for my bundle, but they get a richer experience?" It's just like we can't agree on anything, so there's no progress made.
Justin: Why not both, a rich experience--
Justin: --that's fast.
Dave: Just because I've seen you on the threads, on the GitHub, can we talk about the future of Web components? I think there are two kind of specs out there, proposals, that are kind of interesting. There's the one from Apple for, like, true template interpolation, like four loops and things like that and if statements in a template. Then there's the single file component from, I guess it's Microsoft, the Microsoft Blink team. Can you comment on any of those? Do you think those are something we're going to have here in 2019-ish?
Justin: Yeah, happy to. First, the first proposal you referenced from Apple was called template instantiation.
Dave: Sorry. That was a big word I don't know.
Justin: Template making.
Justin: Yeah, that proposal, actually, has several layers to it. The thing you talked about with four loops and ifs is a super high layer that is not even really being discussed right now. The core of this is that the DOM doesn't have a way that it can recommend and make easy to say, like, "Here's how to create a bunch of DOM and update it later." Right?
You could imperatively create DOM and say, "Here is a reference to the span I need to update," or you could call in a template, but then you'd have to crawl into the template to find the parts you want to update. Template instantiation is all about how can we create a bunch of DOM, mark certain parts of it as dynamic, and then update those dynamic parts later.
Really, all it is, is kind of adding a new thing to the DOM that's similar to a range that we're calling a part right now. It just points to some location to the DOM and lets you update it, but it can be cloned along with the DOM that it points to, which range can't be. You could create a template, put some ranges in it or some parts in it that say where you're going to put data and then, when you clone the template, you can just get back those parts and set the data.
This has a proposal from Apple. People are experimenting with it now. We're writing Polyfills. It's essentially the core operation that lit-html does.
The nice thing here is we're going to be able to get smaller templating libraries. Lit-html should hopefully drop to under 1K if it was based on the standard. Then later layers could add syntax so that you can do some of the stuff with no libraries. That's a very exciting area, I think.
Chris: Okay, that's interesting. It's taken me a while to even understand this. Dave, it's been on your hot list for years, I feel like. [Laughter] And I feel like I'm way behind.
Dave: My next question is, [laughter] when can I do it in HTML, because I'm still mad about it? [Laughter]
Justin: I mean one way to look at these, also along with CSS modules and constructible style sheets and part is, we're really just finishing the story around these things. Template is a useful tag, kind of, except for that you just identified the Achilles heel there is that, like, okay, where do I put my templates? Right?
It has a useful primitive operation, but it's not exposed to where people need them, and so, HTML modules and template instantiation both help finish the story around templates. Then once they do, I think we'll see a lot more people use templates in useful ways.
Chris: Oh, I'm still -- like, why is my brain not processing this correctly? Can't you XHR for a chunk of template? Is that not okay? Is that not good enough?
Chris: Oh, okay.
Justin: Can the pre-scanners on the browser see that? The import graph is really important for tooling to make a performant app.
Chris: I see. That helps a lot.
Justin: Also, the nice thing about imports is, by the time your code runs, you know you've loaded all your imports, so you don't have to worry about, am I in a state where my code is running but I haven't loaded my template yet? Yeah.
Chris: It works with the spirit of the component whereas, if you're going to fetch a thing, you're on your own. Then you've got to wait for the promise and just deal with it all yourself or whatever.
Justin: Right, and we'd really like to reduce the number of weird states that your app could be in.
Justin: Once my dependencies are loaded, then I'm ready to go.
Dave: Go on.
Dave: I like that one.
Dave: Ready for that one.
Chris: Well, under the browsers of today, right? Unless browsers fundamentally change how they digest these things.
Dave: I think this single file component thing, I've been getting into View, and I really like it quite a bit. Actually, I don't know how View feels about lit-html, but View has a template function in their classes that works a lot like React's render, you know, so it's very similar to this. The delta between LitElement and how you kind of write out a View element or a View component is very small, so I wonder.
Chris: What's the story behind loops? In View, don't you go, like, V4 or whatever? In React, you just write a little map and you return crap in it. Does Lit have a little looper-dooper?
Personally, I prefer the lit-html approach, but I know a lot of people like writing their HTML in .html files, and so View is great for that. We're working on some dialects of lit-html that will also let you write the templates in HTML. But I hope things like HTML modules will mean that you don't have to be dogmatic about this. People can use the style that they like and still vend their components to anybody else.
Chris: Hey, we were talking really high level, but I have another little dumb, low level one that would help me understand a little bit. I think we teased a little bit in the pre-show. I don't know. The way it helps me understand what a Web component was at all was when I say that, like, "Oh, I get it," a native Web component is, like, class my component extends HTML element. I'm used to seeing that because that's a format that we use in our main React project at work. I can see that LitElement offers that same syntax.
Oh, I get it. It's this class syntax. It extends the thing and you use it. It's great. It made it sink in for me.
There's a wider sentiment that classes are not for everybody. I don't even get it, really, but it's like, "Oh, this is hard in classes and they're not as efficient because they can't be compressed as well." I don't know what all the talking points are exactly, but if that sinks in to everybody's mind in the whole world is that, okay, we've got classes but we hate them now, so we're not going to write them that way. There's a Lit version of not classes where you get it all but no classes, yeah?
Justin: Yeah, it's not one of the Polymer Project's things, but there's a guy who I'm Twitter friends with now because of the Web components ecosystem. His name is Matthew Phillips, and he made this project called Haunted, which is essentially hooks for Web components and lit-html. You just write a function that returns a lit-html result, and you can use hooks inside there.
Yeah, I can't remember if I mentioned this point earlier, but one of the things about Web components is that how you implement them is not the same as how you use them. This encapsulation boundary means that you can implement them imperatively or functionally and use them declaratively or however. It's nice that there are these options. You can use Haunted to implement fully functional Web components and then vend those to people who are using them in a different way.
Yeah, we might look at hooks as something official in LitElement but, honestly, I think the class hate sometimes comes from misusing classes. I think we saw the same thing with mix-ins. I'm a huge mix-in proponent, but my definition of mix-in, I think, is a little different than what most people are used to. I think a mix-in is a subclass factory. You give me a superclass; I'll give you a new subclass of it. Then you can use that with some added behavior.
I think classes sometimes are a bit misused. If you look at things where React is moving to hooks, their use of classes is a little weird because they put all their state in this, like, this.state and this.props. They can sometimes change that state from underneath you. If you define just a field on the class, I don't think that's really idiomatic in React. What you really want to do is write something into state.
When you write a class there, it's really not like a plain class with fields and gutters that you would store your state in. Sometimes I wonder if sometimes there's a problem that's created and then a solution just to solve that problem where, if you just went back to very plain classes, I think it would be more understandable. Again, though, we try to give everybody all the options, so we'll probably do something that lets them be more purely functional.
Dave: Mm-hmm. Maybe we could end with this because this is probably on people's mind to some degree is, I can write a native Web component in React. In my JSX, I could have a native Web component. It seems like not super common, but it's doable, isn't it? Wouldn't that be kind of a nice way to be like, "Oh, I really like this.set state. That's a nice API and it renders stuff nicely. But I also like baby stepping my way towards Web components because that feels native, too."
Is it really just never the twain shall meet, or are there some success stories of people using--I don't know--one of the big libraries with Web components or even with Lit?
Justin: Yeah, one of the biggest success stories, I would say, in terms of building that bridge has been SkateJS. SkateJS is a library that provides you the Web component kind of structure and the helpers, but it doesn't quite have an opinion on what you should use to render DOM. They have these adapters. I think they call them renderers for different libraries.
There's a React renderer, a Preact renderer, a lit-html renderer, and maybe some more. The idea there is you can use React to implement the guts of your Web component. That has more familiar concepts like props and state. Yeah, I think that's fine on the implementation side.
The only thing I would recommend if people do that is to think about how people consume their element. Most native elements in the DOM, they have their own properties and they don't have a state bag that you're supposed to set things in or a props bag, right?
Justin: Like an input has a value property. Right? That's a simple API to use from the outside. You don't tell people to call set props on input with a value key. Right? Again, in looking at things from the implementation side being different from the usage side, I would just say, try to make, on the usage side, things look like plain elements as much as possible.
Chris: Yeah, that makes sense. I'm sure I termed it just a little off base, like the fact that so few people are doing it probably is meaningful.
Dave: No, I'm excited. I was poking around this Haunted and it looks like--I don't know. It's a pretty cool way to get a--I don't know. [Laughter] It feels like -- Can I say it? -- a four kilobyte React or something. [Laughter] It feels kind of good, so anyway. But you know, there's a lot of other things out there. Yeah, so for people who--? Can I roll out LitElement today and ship products and would you recommend people doing that or does it need to get a little closer to final or something?
Justin: No, absolutely. I should have mentioned at the beginning is that, a week before last, or was it last week, early in the year--I'm forgetting my dates--we actually launched lit-html 1.0 and LitElement 2.0. These are the first stable releases of both. We had to do LitElement 2.0 because we got the NPM name from somebody who had done 1.0 already.
They're already used in production. Even in the pre-release form, we had people from SAP, William Sonoma, and ING, a lot of banks, Nordea, Rabobank, and BBVA, British Gas. Like a bunch of enterprises reached out to us to say, "Hey, we're using LitElement and it's really successful for us," so you can use it now. It seems to be especially popular with companies that have lots of projects and they want to make a common design system across those projects. Their projects are using Angular, View, React, and whatnot, so they can implement one library and use them all over the place.
Dave: Well, well, well, there you go. All right, well, thank you, Justin, for coming on. For people who aren't following you and giving you money, how can they do that?
Justin: Well, I get paid already, so I don't need money, but you can follow me on Twitter. @JustinFagnani is my handle. That's F-A-G-N-A-N-I, because you'll never spell it if I don't for you.
Dave: I put four or five vowels in there.
Justin: It's quite all right. Yeah, you can follow me on Twitter. On GitHub, we have projects that you can look at and watch. Yeah, I give talks occasionally but, hopefully, just check out lit-html and LitElement and see if you like it.
Dave: All right, well, thank you. Yeah, thank you. Thank you, dear listener, for downloading this in your podcatcher of choice. Be sure to star, heart, favorite it up. That's how people find out about the show. Follow us on Twitter, @ShopTalkShow for tons of tweets a month.
A little bit of housekeeping: I think we said it. We disappeared from some podcatchers. We should all be back online. If you heard this, that's a good sign.
Dave: Tell your friends everything is okay now.
Yeah, if you hate your job, head over to ShopTalkShow.com/jobs and find a new one.
Chris: There are some good ones on there.
Dave: People want to hire people like you. Yeah, it's kind of booming, isn't it?
Chris: It is.
Dave: All right, Chris. Do you got anything else you'd like to say?
Chris: Uh… ShopTalkShow.com. Bye-bye.