Skip to content

Instantly share code, notes, and snippets.

@jsebrech
Created October 19, 2024 14:54
Show Gist options
  • Save jsebrech/91e0c0db56a98b5eba1532603cac3dff to your computer and use it in GitHub Desktop.
Save jsebrech/91e0c0db56a98b5eba1532603cac3dff to your computer and use it in GitHub Desktop.
Notes on Ryan Carniato's livestream about web components

Ryan Carniato "We should probably talk about web components"

https://www.youtube.com/watch?v=0F9t_WeJ5p4 (October 11, 2024)

The notes of what Ryan said are like this. They are paraphrased but I tried to accurately represent the view.

Quotes from articles are like this.

My comments on what was said are like this.

Jump straight to the summary

Opener: why did I write the article

The article: https://dev.to/ryansolid/web-components-are-not-the-future-48bh

I was annoyed by discussion around web components in the solid community. This discussion keeps going around and around. Always the same idealistic arguments that don't match to reality. Supporting web components is peeling back layers of problems, always more problems.

Web components are here. When I say "they're not the future" I don't mean they're not here, and actually some of us (framework authors) were hoping it wouldn't get here. People are actually using it, and now the framework authors notice the uptick in web components, because those people create issues about how they want them supported better.

Regardless of whether they're here to stay or not, that doesn't mean they're a good thing. I have not stepped back from my position, this path shouldn't be continued down any further. That's why "they're not the future".

We need to bust web component myths. For example: people think they protect you from getting burned when you have to switch frameworks.

Old school vanilla vs Next: people learn Next because it can do everything (websites and web apps), but old school vanilla is perfectly viable to build a content site.

25:30 I'm going to read you an article

https://ryansolid.medium.com/b-y-o-f-part-1-writing-a-js-framework-in-2018-b02a41026929

This is an article written by Ryan that is pro web components, back in his idealistic fase around them. Brought up to show his opinion is based on experience, not prejudice.

I wanted to do a follow-up article but didn't know how to approach it, so did this instead. This will be a bit of a journey explaining how we got here.

I was originally intending to build a framework around web components so that I wouldn't have to have a component model. You see the mindset of the 2018 article today active in the community.

(Diversion about skate.js, way to build web components.)

Demo of early solid hackernews demo (2018) which was using custom elements.

"I was completely on board [with custom elements] until I wasn't."

Reviewing Rich Harris' criticism of web components

43:30 how to frame this discussion

What do we want to talk about (primary use cases of web components):

  1. Consuming web components
  2. Authoring web components
  3. Web components as framework components
    • Composition
  4. Idealized "universal" traits

All these things get conflated, and we need to treat them separately.

Almost every framework that came out after 2014 (vue, svelte, riot, lit, solid) started with use case 3, trying to use web components as framework components.

"We thought that we could do this, this is where the disillusionment started."

What are web components?

  • A bunch of standards around custom modular DOM elements.
  • HTML imports --> not a standard anymore
  • HTML templates --> everybody loves there, they don't do much but they're fine
  • Custom elements
  • Shadow DOM

When people talk about web components, they're largely talking about custom elements and shadow DOM.

51:30 Q&A section

Audience: I see value in shipping universal UI components libraries (based on web components)

Answer: yeah, but how many new UI component libraries come out for React each year? It's not like if you have a web component library that people won't continually reinvent the wheel and make more and more UI libraries. We're just going to be rewriting crap over and over again. There's no end to that, don't fool yourself otherwise.

This is a very unsatisfying viewpoint for me, because it feels like giving up on web development ever getting past the awkward teenager stage. Anyone who has been in the game long enough gets very tired of the pointless frontend treadmill. Things don't really improve as much as they just change, and change some more, and keep changing whether you want them or not. At some point web development needs to find the off ramp of this crazy merry go round. We need to stop "rewriting crap over and over again". It does not benefit users.

Audience viewpoint: you're making more of web components than what they're intended to do. Shows comment on article, starts with "you're trying to make web components more than what they are", then smoothly switches to "web standards are closing the gap and offer native solutions to challenges frameworks came to solve.".

This is the two sentence later thing: first underselling web components and then two sentences later overselling them. If you're a web components supporter be careful to not do this thing. Pick one or the other, not both.

If you don't pick a framework you'll end up making a framework. Someone will build a layer of abstraction and it will become a framework.

Maybe there is some shared part of frameworks or component libraries that could be put into the base browser platform, but I'm incredibly skeptical of that. My gut is: actually no.

Frameworks are not some magic mystery thing that must exist as a separate thing from browsers. As browsers keep adding framework-like foundational tech they start approaching what frameworks do, and at some point the browser IS a framework, and you don't need more abstractions on top of it.

Is this the browser of today? Not really, I think my plain vanilla website proves that even if you try to explain it as a framework there's gaps that need filling with framework-like elements, mostly around reactive templating and state management. But, that doesn't mean all that much is needed to make the browser be a framework.

Is it a good or bad thing if we add that stuff? Pro: there's a default solution that allows people to not (yet) pick a framework and eases learning of web development as well as building code bases for the long haul. Con: it locks those same people into one way of doing things, forever, even if "fashions" change. Pro: it doesn't prevent frameworks from doing something else, so fashions can still change regardless. Con: unless people expect interop with the "base" framework that's in the browser and this limits framework architecture, which sort of brings us to today.

Whether it's desirable or not therefore depends on whether the evolution of web components ends up cramping the abilities of frameworks to do interesting things. Engaging with standards is the best way to avoid that situation, because browsers will keep gaining more and more framework-like abilities whether you want it or not, because there's a large group of people (like myself) who want that.

Companies with own design systems have the most compelling use case for web components. The ebay team, web components made sense for us. But you have to be careful about how you're managing that. What is the ideal world here? Once you have multiple versions of the same thing you're duplicating code, once you have to upgrade those things on lockstep you're potentially breaking stuff.

I would approach this by writing new components to replace the old ones and gradually phase them out. But does that mean bringing three different versions of frameworks into a page? How do you phase out that old stuff? If you view it across decades, how many times will you have to do rewrites? Do web components still really help?

Audience: we did it successfully at Microsoft

It might actually be the best way out for a period of time. If that helps you get by 5, 6, 7 years of this stuff, that might buy you enough time to get to the next thing.

For me this is a pretty compelling case for web components. Build a design system once and use it across frameworks and framework releases for the duration of that branding cycle (5 years or so). But it doesn't work unless frameworks support them a lot better than today.

On the small scale you don't care [about the downsides of having multiple framework versions on the page] because it's not really important. On the large scale you don't care because you can't really do any better anyway.

This is not an issue specific to web components, because frameworks suffer from this issue as well. Whenever I open the hood on a large web app I find lots of duplication in dependencies.

What's irksome to me is that it's never the best choice. If you don't have web components everything will be nicer. And do you really want web components in that case?

Audience: do you agree that a well-crafted web component library will reduce the need for companies to rewrite their components library?

It depends. At least for a time period. Generationally you probably don't need a rewrite. You can make a WC components library last for one generation of stuff written in different frameworks.

Why is stuff written in different frameworks? Because someone wanted to do something new.

This sort of ties into how developers "age out", with new developers entering the field with new ideas of what framework they want to work with. When you're an organization hiring developers from the broader market, in time you sort of are forced to follow along with where the market of frontend developers is headed, even if you don't have a technical reason to do so, because hiring developers is always tough, and it's even tougher if you want to hire them to work on "dated" technology.

Discussion of the solid / react bridge that was built by Ryan. Using web components as an intermediary makes that bridge worse because it's a lowest common denominator. Building direct bridges to do migrations or combined codebases is better.

Audience: [at microsoft] our perf metrics and real user monitoring data shows that switch from react to web components improved perf by 20-50%.

This is often the fallacy of the rewrite. When people rewrite they often get a better result, but it would always have improved things. It would probably have also been faster had you rewrote it in react, because you might have realized how to do it better the second time.

If this is about the 'MS Edge replacing react by WC' use case, I think the issue there is react bootstrap cost multiplied over so many different embedded web ui's. I've run into this myself when we tried to use react to build web components and got horrible overhead when too many of those were put on the page.

The bridges are similar in complexity between frameworks as building a framework to web component bridge, but they're more efficient because you know what you're targeting on either end. It would maybe would be easier if you treated web components like a custom renderer, as if it were webgl.

Exactly. Frameworks struggle with web components because they try to take ownership of what happens inside. If a framework is trying to reach inside the shadow DOM, there's already something wrong. The discussion should be on what's needed to allow frameworks to treat web components like a black box.

The best solution here might involve more build tooling. And many of the people that want web components want less build tooling, not more.

Build tooling opposition isn't just about avoiding complexity, it's about avoiding things that break underneath you. In my experience build tools are by far the most fragile and quickly broken part of modern frameworks, and are the thing that will force framework and library upgrades soonest.

It's about: how can I make my developers more efficient to continually deliver? It's the best way to speed up releases. You know me, I'm never going to get excited about something that isn't the best.

1:17:00 Web components are not the future, they're the present

(Attempt to discuss Cory LaViska's article that was immediately side-tracked by chat.)

The framework mentality is: we look at the platform as a tool and try to find the best way to leverage it by building an abstraction on top.

Where are web components really good?

  • Micro frontends-ish at large companies
  • Environments with multiple frameworks, sharing of design systems

Even if you build everything with web components at some point you'll want to replace all of them on your site. Design changes, UX changes, eventually you get a new way of building UI.

You always have to consider the underlying library thing. Usually you're using something like Lit and you have to consider how many copies you get, so your WC's are going to be sharing code. You can build vanilla but then you get a lot of duplication of code. Lit is something like 15 KB, and you don't want that 40 times in a page, so you're going to be sharing code anyway, and at that point it somewhat breaks the isolation of WC's.

But you don't have to treat every WC the same. You can write the easy ones vanilla, and use Lit in the harder ones, and still keep full isolation, and maybe the math still works out.

1:28:30 inherent cost

Why are WC's not the future?

  • There is inherent cost to these implementations
  • There is an inherent opportunity cost to future design space

This second argument is the fear of framework authors of getting "boxed in" by web components because compatibility with a growing API surface is expected by the web dev market.

I'm not convinced by this argument. If the framework's way is better and prevents WC compat, break compat and sell people on the vision. If WC's are so good that developers expect support for them, why oppose the wishes of your own user base?

(Finally discussing Cory LaViska's article.)

https://dev.to/claviska/web-components-are-not-the-future-theyre-the-present-347m

From the article:

The thing is, we don’t need to agree on how to write components, we just need to agree on the underlying implementation, then you can use classes, hooks, or whatever flavor you want to create them.

I'm not sure I agree with that. A framework is about the interaction between components, not just the components themselves.

I agree with Ryan here. The fundamental super power of a framework is the control flow it enables, not the encapsulation into components.

Audience: framework authors are basing their opinions on WC tech of 6 years ago, before things like declarative shadow DOM.

No, I started specifically here to show how this is not the case. We know the technology just fine.

Agreed. I think framework authors know WC technology very well.

Audience: it's kind of crazy to expect components to be portable between frameworks when every framework has a completely different definition of what a component is.

Ryan seems to agree with this take.

I can agree with this take as well.

But.

It's not wrong to ask for some kind of universal interoperability shim in which you can wrap framework components, or which you can plug into a framework's rendering and control flow, and web components are the closest thing to that shim.

And.

We do agree on what an element is. And ultimately a framework should be flexible enough to cope with new elements getting added to HTML, without needing a new framework release to do so. It doesn't matter if those are built-in elements or custom elements.

The computer deals with assembly instructions. Abstractions like frameworks and components are there for the human, not for the computer. They exist so you can organize your thoughts.

Audience: standards are not opinionated like frameworks.

Even abstracting out classes with inheritance is laying out opinions. The farther you get away from base assembly the more opinions you have. You can argue by being a standard the opinion is no longer an opinion, but they remain opinionated on how they come to be.

Audience: standards are 100% opinionated. That's the point.

Hilarious to see these audience viewpoints juxtaposed. I get Ryan's take of how WC's cause people to say opposite things and how this distracts from the real conversation.

It's very hard to weed through this discussion and even do basic fact checking.

1:45:30 returning to Cory's article

Web Components is a bit of a misnomer but it's the label that stuck, agreement between Cory and Ryan.

Cory:
We got document.querySelector() from jQuery. CSS Custom Properties were inspired by Sass. Tagged template literals were inspired by JSX. Soon we’re getting signals from Preact.

Ryan was very amused by this take.

Solid was pushing signals years before Preact. If you said Vue that would be fair.

Cory:
More importantly, we all need to stop being salty when our way isn’t what makes it into the browser.

OK

We can have the foresight to go "this is probably not an area we know enough about and maybe we should slow it down".

Cory:
I’m sure Ford could have made the original Model T way better if they had spent another decade working on it, but do you know what made the next version even better than 10 more years? The feedback they got from actual users who bought them, sat in them, and drove them around on actual roads.

Standards shouldn't be some platform for experimentation of approaches.

I don't think any framework was really involved in the design of web components, except perhaps the Google Polymer people. Signals are different, because there they had the conversation with frameworks.

However, standards people are always open to feedback, talking about solutions to problems, a real desire to see the web get to a better place.

Cory:
Would it be better if every site was Flash or a Java applet? (Remember Silverlight? lol)

Sometimes I think if we built a framework into the browser it would be like flash all over again. We'd get to a point where we collectively go "hmmm".

In 2011,2012 when the web components spec work was happening, modern frameworks weren't there yet, and the frameworks that were happening weren't interested. So waiting on the frameworks would have prevented web componetns from happening. But interestingly, waiting a few years would have brought a very different perspective and a different design of the specs.

This is probably true. The mismatch of WC's to a functional-reactive programming style is jarring. In some ways it feels like going back to an older generation of tech.

Cory:
Web Components are a threat to the peaceful, proprietary way of life for frameworks that have amassed millions of users — the majority of web developers. Because opinions vary so wildly, when a new standard emerges frameworks can’t often adapt to them without breaking changes. And breaking changes can be detrimental to a user base.

Vue has slots because they pictured web components as foundational tech.

An issue with WC's is eager loading. If you conditionally hide a part of a web component using CSS, it still gets rendered. Frameworks don't do that, they project to DOM lazily. Using WC's as a layout control flow mechanism doesn't really work.

Everything in the light DOM always gets rendered.

Interesting topic to do some experimenting on. This might be twisted into a WC advantage instead of a downside depending on how you approach it. Sort of dovetails with framework views that DOM is just a projection vs WC view that DOM is owner of state.

Audience: light dom children of an element are not rendered into the composed tree unless there are slots for them to go into. It will not be laid out or painted.

I'm using react terminology for rendering. The element will still exist and be instantiated, so you're paying the cost for that.

Audience: if you don't want the constructor and connectedCallback to run you need to put it in a template. That makes it completely inert.

If you use a template, you have to figure out how to interpolate over the values that you want to render in the template.

Maybe we need a different standard for templating.

Reactive templating is definitely the key missing part in the WC set of standards.

Further discussion on a theoretical map-each web component that renders a list as items. This is something that's very common in components, but that WC's are not a good fit for.

Cory:
This is why I believe that the next generation of frameworks will converge on custom elements as an interoperable component model, enhance that model by sprinkling in awesome features of their own, and focus more on flavors (class-based, functional, signals, etc.) and higher level functionality. As for today's frameworks? How they adapt will determine how relevant they remain.

Interestingly enough, it's not the next generation, it's actually the last generation. You could argue that maybe it was too early. But the problem with this line of argument is assuming it hasn't already happened.

Cory:
So Web Components aren’t the specific vision you had for components. That's fine. But that's how it is. They're not Solid components. They’re not React components. They’re not Svelte components. They’re not Vue components. They’re standards-based Web Components that work in all of the above. And they could work even better in all of the above if all of the above were interested in advancing the platform instead of locking users in.

Not interested in locking users in. Most framework authors understand that their framework will not be the last framework. I'd rather see a better solution come up than to see solid keep succeeding.

We're not that different in goals. We all want to make building on the web better.

With polyfills you could do web components even a decade ago, especially since 2018. The development experience was actually fine.

Audience: framework authors are very concerned with perfection, users are more concerned with stability.

Framework authors do care about stability because that's how we lose users.

But you don't want that level of stability anyway. If React was compatible to the 2013 way of writing React, you wouldn't want to write code like that.

Hmmm, not quite in agreement. It's a bit like the Obj-C to Swift transition. You want to use Swift in the new code, but sometimes you go into an Obj-C part and you add a feature there. A large codebase is always going to have multiple generations of technology and the upgrades are going to be coarsing through it like overlapping waves. It's impractical to want a large codebase to be all of a same style.

Audience: the composability will come from improving the HTML templating language in the standard.

This is tricky, because the templating language is something frameworks don't agree on, for aesthetic or mechanical reasons.

2:22:00 declarative javascript templating API

Discussing the proposal to add a html function directly into the standards.

WICG/webcomponents#1069

Basically builds Lit into the browser.

Exploring the discussion of people worrying about signals and how that integrates into the proposal.

The core issue is that in this model it would reevaluate, and you don't want signals to cause reevaluation of the template.

I actually think that tagged template literals are a great fit with signals because tagged template literals are so cheap to reevaluate.

That's not the response. This is a very slow way of rendering to DOM.

(Shows benchmarks from 2019 where he compared different frontend rendering strategies and lit was the slowest.)

You ask me about stuff being dangerous. Picture if we couldn't pull the stops on something like this proposal.

The Polymer and later Lit team basically built a framework and then worked with the chrome team to get their framework into the browser. The long term goal is to make this thing "the chosen one".

This is the same kind of distrustful thinking as "framework authors want lock-in". A more charitable view is to say there are people who have built a framework who have an opinion on what would help frameworks do less work, and who try to get that functionality in the browser.

(returning to Cory's article)

Cory:
Of course, this is from the perspective of a framework author, not from the people actually shipping and maintaining software built using these frameworks. And the people actually shipping software are the majority, but that’s not prestigious so they rarely get the high follower counts.

That is the universal condition. That has nothing to do with web components or not.

Audience: the churn got so extreme that its severely affecting the quality of end-user software.

I don't think anyone forced the churn. You can just stay on your old technology and be fine with it.

Yeah ... no. I think Ryan shows his blind spot here, and probably other framework authors have this blind spot as well. They don't have experience maintaining web apps built on popular frameworks in the way that the average web developer has.

Audience: combine dom parts with signals and you have some low-level primitives to build a templating system on.

We should avoid any kind of interaction between signals and the DOM, because framework authors haven't settled on the right way.

Maybe that's not up to framework authors to decide for the whole web dev field? Web dev is a lot bigger than frameworks. Let's have the conversation to spec it up and see where there's disagreement.

2:36:30 Going back to Ryan's original article

The article was mostly not giving people specific things to argue against. Only one part went into technical detail, but had one liners that weren't explained, like the clone vs import node thing. Rich Harris explained some of these things in detail on twitter.

Audience: did you ever consider trying to group up with other framework founders to build one framework to rule them all

I've tried to get framework authors together to have a conversation and share information. Standards people try to find commonalities and sometimes succeed in figuring those out. I appreciate the work done by standards people to try and facilitate those kinds of conversations, but sometimes the conversations are too early.

Most of the frameworks try to take on pretty much everything and try to be the one-size fits all solution. Users don't agree on the one solution and pick different frameworks.

Audience: there's nothing a non-custom element framework can do that a custom element framework cannot do.

I don't know if I agree with that. Sometimes the fact that something is a DOM element gets in the way. Sometimes that boundary is not in the right place. Yes, you could find solutions, but.

Audience: I wish everyone came together to fix React

I think you can do this with every framework. And react is what it wants to be, it doesn't think it needs any "fixing".

Discussing the article again. Talking about attrs vs props, and the way those are handled in templates. Lit does it one way, solid a different way, solid's way performs better. If lit's way gets standardized that's a suboptimal solution.

2:48:30 Web components are okay

Review this article: https://nolanlawson.com/2024/09/28/web-components-are-okay/

This is actually the best response I've gotten.

Nolan:
I fully believe that Ryan knows how to build the fastest possible framework. Again, the results for Solid on the js-framework-benchmark are a testament to this.

That said – and I might alienate some of my friends in the web performance community by saying this – performance isn’t everything. There are other tradeoffs in software development, such as maintainability, security, usability, and accessibility. Sometimes these things come into conflict.

In agreement with this.

Nolan:
When I see this kind of stuff, I’m reminded of speedrunners trying to shave milliseconds off a 5-minute run of Super Mario Bros using precise inputs and obscure glitches. If that’s your goal, then by all means: backwards long jump across the entire stage instead of just having Mario run forward. I’ll continue to be impressed by what you’re doing, but it’s just not for me.

For frameworks working with web components is actually the backwards long jump. We can work with the DOM to get good performance, it's tricky but can be done. As soon as web components come in you start hitting the exception cases.

Nolan:
That said, if it does matter to you – if you’re building for resource-constrained environments where every millisecond counts: great! Ditch web components! I will geek out and cheer for every speedrunning record you break.

This is how Solid got an in with TV companies. Companies like Netflix. They need maximum performance.

Nolan:
But assuming you don’t want to freeze your brain in amber, then yes: you do need to account for new stuff added to the web platform. But this is also true of things like Symbols, Proxys, Promises, etc. I just see it as part of the job, and I’m not particularly bothered, since I know that whatever I write will still work in 10 years, thanks to the web’s backwards compatibility guarantees.

Proxy upended JS because suddenly obj.value = 5 became reactive and could execute any JS code.

Custom elements upend things because suddenly el.innerHTML = '<my-el></my-el>' will synchronously execute unknown JS code. You get into a world where arbitrary javascript runs at arbitrary moments.

Nolan:
From my own personal experience: at Salesforce, we build a client-rendered app, with its own marketplace of components, with strict backwards-compatibility guarantees, where the intended support is measured in years if not decades. Is this you? If not, then maybe you shouldn’t build your entire UI out of web components, with shadow DOM and the whole kit-n-kaboodle. (Or maybe you should! I can’t say!)

I'm glad about this. Me and Nolan can check up in 7 or 8 years and see how this held up.

3:00:00 Web components are not the future - part 2

Discussing Ryan's unpublished part 2 article.

Why are web components not the future?

Web components aren't new. Frameworks looked at them, and if they have slots that are different from the standard it's because it wasn't the right fit.

Web components are not doing frameworks a favor. Some of the greatest criticism of WCs comes from frameworks that support them the best.

Finding success with web components does not preclude them scrutiny. Platforms and general tools like frameworks have to stand by wider criteria for success.

Discussing weird behavior of attributes and properties from Rich Harris article. https://dev.to/richharris/why-i-don-t-use-web-components-2cia

As a framework author you bump into these interesting edge cases all the time. To be fair none of these things have much to do with web components themselves. But you have to understand there's quirkiness in the DOM.

Some things to consider:

  • attribute values can only be strings
  • attribute names are case-insensitive
  • only HTML can be serialized for SSR

To handle this in a framework there's a few ways to handle this.

Runtime heuristics (as Nolan mentions in his article, a prop in element check). Svelte and React 19 use this. That works if attribute is exact match for the property. Web components authors have to do work to make it possible to set these properties, and if the props are set before upgrading this creates more work.

Imagine some kind of templating syntax like htmx, and it contains this: <my-element someProperty={someValue()} />. What do you expect that to do when it renders to HTML?

Would you expect <my-element someProperty="hi"></my-element>? Or <my-element></my-element>? Or maybe <my-element some-property="hi"></my-element>?

The heuristic is runtime, so if you're doing this on the server there's no DOM element and you can't ask the DOM for whether it has a property.

Honestly I find this whole line of discussion kind of misses the point. This is HTML behavior, not WC behavior. The only reason frameworks can cope with HTML being this way is because they encode the behavior of each type of element, and that in a way blocks HTML from evolving. I think it's fair to say that only frameworks that are agnostic of the shape of elements, built-in and custom, are not brittle by design.

Discussing the challenges of passing objects or lists, because if you serialize them to strings the performance cost is severe. Good luck passing signals that way.

SSR of non-WC has this same problem? I feel like I need to do a deep dive into SSR approaches. I don't quite see what the essential uniqueness of WCs is here. SSR + hydration is always a hard thing it seems (which is why we probably shouldn't be doing it, but that's another thing entirely).

3:10:50 explicit convention

The other option is explicit convention. Describe in the templating prefixes what behavior you want, like name for attributes, .name for properties, ?name for boolean attributes, @name for event handlers.

Discussing lit's syntax with explicit conventions. Peculiar about this is that Lit only does this intelligent handling if the value assigned is interpolated and not static in the markup, because it uses string literal templating.

In my mind this is a lot for developers to think about. It still doesn't solve all the SSR issues because you can lose props when serializing.

If you use declarative shadow DOM you will actually render the full realized markup and don't have to worry about losing props along the way (lossy encoding), and you get a guarantee connectedcallbacks occur from the top down.

Most frameworks view components as an input format and HTML/DOM as an output format. Web components intertwine these things.

If you don't want web components to be framework components, you should probably only use string attributes. This is probably workable by defaulting to attributes in frameworks. But if we didn't have WCs we wouldn't even need to look at this.

3:23:15 lifecycles

As a web component author you don't know when your component upgrades, so you don't get a clean slate. Props and attributes may or may not have been set before you initialize, and you have to deal with that.

Discussion of clonenode vs importnode. Web components must be imported into the document. But importnode is measurably slower. It was enough of a performance difference for us that we special-case web components and only do import for those and clone for the rest. It's fair to criticize that it wasn't reported to browsers sooner.

Discussing an issue reported to solid that was due to custom element weirdness wrt documents. solidjs/solid#1740

We have to bring DOM specific behavior into non-DOM parts of the framework.

This stuff is all examples of a categorical thing. We can nitpick the details, but the category of issues doesn't go away.

The document upgrade thing is an example of "it never ends". Framework authors keep running into more and more problems related to WCs. At the same time we don't realistically have the choice to not support them.

Booking issues against browsers for this stuff is disheartening, because they'll often tell you it's not a real problem because it matches the standard. You can go to the standards, and try to fix it there, but I don't really have the time to do that.

But we are stuck here, because we let it pass. We have to get ahead of stuff now and focus on slowly managing expectations around WCs.

When we look at web components we think: who ever asked for this?

OK, how many React users asked for RSC? This is what happens when your dependency has a bright idea that you didn't ask for but still have to deal with. Although it's fair to say that the bar is higher for standards to make something universal.

This is kind of the crux of the people part of the problem. If someone finds a bug in a framework they won't report the bug, just work around it. Frameworks on top of the platform are sometimes the same.

I got to the article not because of any individual one of these things, just because of this large scale myth of web components being the future. They aren't and they make things more complicated.

3:44:00 reactivity and context apis

If the same framework is on the outside and the inside of a custom element, are we in a good spot?

Context is problematic because you can't guarantee that the children won't already be upgraded when the parent is rendering. Context is accessed synchronously, and if it's not already initialized when the child is upgrading this can cause problems.

There's a solution: using events to obtain context, per the community protocol. But in server-side rendering that means you need a way to emulate DOM events as well.

SSR becomes a lot faster if you don't have to emulate the DOM but can do string templating instead. Rendering web components on the server is hard to do without emulating the full DOM API.

There are also idiosyncracies around events in the shadow DOM. Some events don't bubble beyond shadow DOM boundaries. Some events don't bubble consistently because they retarget to the shadow DOM.

Event delegation is very important to javascript frameworks. They're mechanically important for things like portals, or partial hydration. With partial hydration we look where you interact with the page to capture and replay events and prioritize hydration for the parts of the page that you interact with.

There's a conflict: if you're building declarative UI's you need to control the whole zone of the UI, but it's awkward if some of the code is not controlled, like custom elements. The solutions for problems related to SSR / hydration are all based on event delegation.

If event delegation breaks stuff gets weird.

Audience: isn't the whole idea behind web components that it is an isolation level? and shouldn't frameworks treat it as such?

Maybe. But look at lit. It authors framework components, and you can put it on both sides of the web component boundary. A lot of people use solid to author web components. You should be able to make a web component in your framework of choice, but that means the framework has to be able to solve these problems.

Discussion of focusin event and how clicking a button inside the shadow dom doesn't properly bubble beyond the shadow root. Showing how the event handler inside solid now is gigantic to deal with all this stuff.

A lot of the work that we do as a framework is to undo things that the shadow dom does to events, like retargeting events back to the original target.

You can always set composed: true on an event to make it bubble up, and you can fire built-in events in this way to make them bubble out of shadow roots (example given: dispatching a composed submit event from form submit), but now you have to consider this as a component author.

Audience: this is probably fixable

Not making events composed seems like an intentional thing. And this is ok. If shadow dom is a contained thing, and it gets focus, then shifting focus inside that contained thing should still be focusing the whole thing.

You could offer a way for frameworks to override all this behavior, but that is like giving god mode to web component consumers, and as a web component author you probably don't want that. Frameworks don't want to give up their own internals either, like not offering signals as an API to the framework user but wanting to use it internally.

Most of these things aren't necessarily bugs, they're differences in perspective.

Audience: web components are fine, they just have an encapsulation model that breaks frameworks that try to control the render cycle.

Ryan: so basically like every framework. In frameworks we are going to a place where components are only in your head, they're just a construct that doesn't end up in the final page. We don't want anything that gets in the way of that.

4:16:30 The cost of abstraction

As a framework author you end up thinking: why are we even fighting this thing. Web components are not a thing of particular value to us, they just get in the way.

You can go through this list of issues that we covered, and think maybe these are solvable. I'm not convinced that this works, because we will hit a point where the problems don't make sense to fix, because people will say "that's how it should work". And at that point, what can I do with that as a framework author? It's almost easier to pretend web components are non-native, and hand it off to a separate renderer.

Now that react has said "we're going there" in v19 they're going to feel the full pain of it.

The accusation that frameworks aren't following the platform is B.S., because frameworks are built directly on top of the platform and try to use it to the fullest.

Shadow dom does too much. People initially wanted only two things: an on connected event, and style isolation. Had they been given only those things we might not have gotten to this place.

I feel a lot better about standards these days, and I think web components were a learning of what not to do. So there are positives there today. And we're not stuck with it, but we are also kind of stuck with it.

4:26:20 Twitter feedback time

Justin:
Lit is not a framework. The browser is the framework.

What he's saying is: lit is just a way to author web components. Just because a web component is built in lit doesn't mean it has to be consumed by lit.

But lit has a renderer, and context, and those are beyond this scope. You don't have context unless you expect web components to be used in web components. Lit is creating a whole application out of web components, and then it becomes a framework.

Lit, react and solid are all about the same level, solving the same problems.

Ryan seems to struggle with the perspective of "the browser is the platform", that what Lit is doing is create the world where the browser offers all of the primitives that a framework offers, and you no longer need a framework beyond the browser. To him Lit is just another opinionated framework.

Framework vs library is a mindset. It's about the breadth of opinions. It's when you cross the line from "here it is, take it or leave it" to "this is how all the pieces go together".

Treating lit as if it is something special, not just another framework, is disingenuous. This is one of my pet peeves in this whole discussion.

Basically his view boiled down to: lit has too many opinions to not be a framework.

4:45:00 wrapping up

This was long and meandering but I hope some people got value out of this.

Web components can do a lot of things. There's a lot that they do that people assume they don't do.

I hope we can continue to fix issues, but at a certain point I'm wondering: why am I still doing this.

In summary

So, taking all of the above, what does that boil down to?

Technical criticisms

  • Eager loading

    • "An issue with WC's is eager loading. If you conditionally hide a part of a web component using CSS, it still gets rendered. Frameworks don't do that, they project to DOM lazily. Using WC's as a layout control flow mechanism doesn't really work."
  • Missing standard: reactive templating standard

    • How to implement a map-each component that accepts an array and outputs items based on a template, while still getting good performance?
    • How to integrate signals well?
    • "The core issue is that in this model it would reevaluate, and you don't want signals to cause reevaluation of the template."
    • "We should avoid any kind of (direct) interaction between signals and the DOM"
  • Breaks expectations of when JS code runs

    • "suddenly el.innerHTML = '<my-el></my-el>' will synchronously execute unknown JS code"
  • The attributes vs props thing

    • Attributes: are strings, are case-insensitive, are the only thing that serializes in SSR
    • When to assign to the prop, when to the attribute?
      • Heuristics like prop in element: only works if attr is exact match for prop, props should only be set after upgrading, must run inside DOM emulation on the server
      • Explicit convention like .name for prop assignment: complicated to use, still doesn't solve SSR serialization problems
  • Missing standard: SSR

    • How to serialize props in SSR?
      • Only serialize attributes = potential data loss, some CE's fail to render
      • Also serialize props = unclear how to do this, what and how to encode to string
      • Use declarative shadow DOM to send the rendered markup = possible but needs work
  • Lifecycle is unpredictable

    • Props and attributes might be set on a WC before it initializes (mostly an authoring issue)
    • Context is tricky when you can't guarantee the parent element upgrades before the child element
    • Challenging in partial hydration situation that you can't control when upgrades occur
  • Events in shadow DOM don't always bubble or get retargeted

    • Breaks event delegation, needs lots of workarounds to undo default shadow DOM behavior
    • Event delegation is essential to partial hydration (prioritize what gets hydrated based on captured / replayed events)
    • focusin event doesn't bubble
  • must use importNode, which is slower than cloneNode

Philosophical criticisms

  • Universal UI component libraries (based on web components) are not a desirable thing

    • "It's not like if you have a web component library that people won't continually reinvent the wheel and make more and more UI libraries."
    • "Once you have multiple versions of the same thing you're duplicating code, once you have to upgrade those things on lockstep you're potentially breaking stuff."
    • "I would approach this by writing new components to replace the old ones and gradually phase them out."
    • "What's irksome to me is that it's never the best choice. If you don't have web components everything will be nicer. And do you really want web components in that case?"
    • "Even if you build everything with web components at some point you'll want to replace all of them on your site."
    • "You always have to consider the underlying library thing. Usually you're using something like Lit and you have to consider how many copies you get, so your WC's are going to be sharing code. [...] at that point it somewhat breaks the isolation of WC's."
  • Using web components as a framework bridge is not a desirable thing

    • "The bridges are similar in complexity between frameworks as building a framework to web component bridge, but they're more efficient because you know what you're targeting on either end."
  • Putting a framework in the browser is not a desirable thing

    • "Maybe there is some shared part of frameworks or component libraries that could be put into the base browser platform, but I'm incredibly skeptical of that. My gut is: actually no."
    • "If you don't pick a framework you'll end up making a framework. Someone will build a layer of abstraction and it will become a framework."
    • "A framework is about the interaction between components, not just the components themselves."
    • "Sometimes I think if we built a framework into the browser it would be like flash all over again. We'd get to a point where we collectively go hmmm."
    • "the templating language is something frameworks don't agree on, for aesthetic or mechanical reasons."
    • "Most of the frameworks try to take on pretty much everything and try to be the one-size fits all solution. Users don't agree on the one solution and pick different frameworks."
  • Prevents framework evolution / locks in an opinionated strategy

    • "There is inherent cost to these implementations" (meaning: frameworks have to spend engineering resources support this that could go to something else)
    • "There is an inherent opportunity cost to future design space"
    • "Standards shouldn't be some platform for experimentation of approaches."
    • "The Polymer and later Lit team basically built a framework and then worked with the chrome team to get their framework into the browser. The long term goal is to make this thing the chosen one."
  • WCs are not suitable as framework components because they are DOM elements

    • "Sometimes the fact that something is a DOM element gets in the way. Sometimes that boundary is not in the right place."
    • "Most frameworks view components as an input format and HTML/DOM as an output format. Web components intertwine these things."
  • Doesn't solve a problem frameworks have

    • "As a framework author you end up thinking: why are we even fighting this thing. Web components are not a thing of particular value to us, they just get in the way."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment