I've found webcomponents to be really good at encapsulating anything that doesn't directly query application state.
Specifically there are two type of components that really thrive as web components (as opposed to react):
1. Highly interactive components - Components that implement complex interaction management (but sort of agnostic to application state) are ideal web components. You don't need to mess around with `useEffect` or `useMemo`. You get really tight control of rendering and state updates.
2. Highly internally stateful components - Components that track a lot of state that doesn't escape the component, work great as web component. You get strong encapsulation without a framework requirement.
React conflates two concepts that I think are better when separated: templates, and components. Templates provide a "re-render the world" approach, and components encapsulate state and interaction patterns. Conflating these two things causes the standard useEffect and useMemo headaches. It also means that any consumer of your component, must also use your templating system (react's render function).
The `lit` library does this separation extremely well, allowing you to implement components using templates if you want, or not. And consumers do not care how the internals are implemented.
I completely agree. Recently I listened to a podcast where Brad Frost talked about web components being useful for design systems, as you can make a button in a web component and have that defined no matter what JS framework the dev team (or teams) want to use company-wide.
One issue I see though and I almost feel dumb for saying it, I don't like how web component code looks. Using innerHTML feels really weird when your team is so used to using JSX for react components for example. I don't think this would stop me from researching web components more but does anyone feel similarly or have a solution or obvious answer for me in this area?
You don't have to use innerHtml. The ShadowRoot pretty much acts like a document. So you can also use appendChild. Combined with a template element you can completely avoid innheHtml. You could even use jsx to create the template element I suppose.
> You don't need to mess around with `useEffect` or `useMemo`. You get really tight control of rendering and state updates.
You don't need those in React either. Whatever you do in Web Components can probably (most likely) be done in React.
After all, Web Components are a solidified 2010-era design. The reason React has hooks now because people have moved on, and are exploring other ways of building stuff. The only mistake React did was to keep reactivity on component level (hence all the hooks and their weird rules) when most people moved on to more granular reactivity. Hell, even Angular did.
I mean... sometimes you do, that's why they exist. But yeah, most of the time you don't.
> Whatever you do in Web Components can probably (most likely) be done in React.
Of course! React is a good and powerful framework. But everything you do in React can be done in Angular 1.0 or even backbone.js. As always with frameworks it's about the productivity / performance ratio for your team (or for libraries, the ratio for your consumers).
> After all, Web Components are a solidified 2010-era design.
A lot of the web components related APIs are being actively developed including constructable stylesheets, shadow DOM APIs and more. Regardless, the era of design is not a great point in either the "pro" or "con" column, and is usually an ambiguous shorthand for the actual quality being critiqued.
> I mean... sometimes you do, that's why they exist.
They exist because they're useful, but you can write traditional React components that look a lot closer to Web Components, if you think that's better.
Forgot to mention, the knock-on effect of this thought process is that if you want to adopt web components, you still need a templating approach. And you'll find that most of your code is templates, and only a few are really components.
I find that they can work very well with state but since state is typically passed via attributes (downstream), it means that components can only share state with each other via strings. I found this to be an advantage, not a drawback because simple interfaces are at the core of my coding philosophy and strings make it infeasible to pass complex instances or functions to other components.
Well, this is only sort of true. When you’re writing HTML you’re restricted to attributes but custom elements are JavaScript objects and are free to respond to property updates on the object. Relying solely on strings is a limitation of your templating engine.
For example lit-html templates support syntax like:
Interesting. I recognize that lit-html is much more lightweight than React and others but personally I really like to avoid any magic at all and I like being forced to pass strings between components. It reminds me of an Alan Kay quote about OOP "The big idea is messaging". You want your components to be passing around messages, not state. This seems to go against FP philosophy but I've found that it really works for OOP. After all, OOP is traditionally about state encapsulation and prioritizing concern boundaries over logic/state boundaries as in FP.
Note that it's still possible to pass complex objects to native we components but only imperatively via properties so it's a lot higher friction (as it should be).
One of the linked articles [1] makes an interesting claim that feels like a reach to me, but I'd be interested in hearing HN's take on it:
> At this point React is legacy technology, like Angular. Lots of people are still using it, but nobody can quite remember why. The decision-makers in organisations who chose to build everything with React have long since left. People starting new projects who still decide to build on React are doing it largely out of habit.
I'm going to withhold my own thoughts about that quote, cause I'm curious what everyone else thinks.
Wrt. Web Components, I played around with Web Components about half a decade ago and they felt promising but not ready for prime time yet. They were pretty messy and felt like they did a poor job of encapsulation. (At least at the time.) I haven't looked at them recently, but the code examples in these articles look much better (and cleaner) than what I remember.
"Lots of people are still using it, but nobody can quite remember why."
I can remember why. This, and every other article I've ever read arguing to replace React with Web Components, completely misunderstands the point of React. It isn't about JSX. It isn't about encapsulation. It isn't about reusability.
It is about enabling a design pattern where *the user interface is a pure functional transformation of the application state.*
I kind of feel like people get tripped up by the fact that "virtual DOM" and "shadow DOM" sort of sound similar. They have literally nothing to do with each other. The React "virtual DOM" allows you to *completely re-output the entire user interface* on every state change, which is not possible with any other design pattern, and is not possible without a framework, because actually re-rendering the entire tree on every state change isn't performative (or usable).
Anybody who is advocating an alternative to React needs to do one of two things:
(A) Make a convincing argument that a different design pattern is better. Some things we've tried, which most people think are worse:
1. Using the DOM as your data model (jQuery)
2. Manually writing virtual representations of every view (Backbone)
3. Auto-magically two-way binding some data structure with the DOM (Angular 1)
4. Observables (Ember, maybe Angular 2+?)
(B) Advocate a framework other than React that uses the same pattern as React, but improves the usability. I think the two places there is the most room for improvements are:
1. Animations
2. useEffect() in general
I have not seen anybody successfully do either A or B.
Don't forget Knockout which was the OG. You can also make the case that Svelte, Vue, and Qwik all are different takes on Observables (at least as much as Angular 2+ is) all with more or less magic and more or fewer escape hatches from Observable best practices to imperative(-looking) code.
I got a "What if we did Knockout but with with the compile-time benefits of TSX and Pure RxJS Observables?" itch a couple months back and have made some wild progress on it. I certainly don't think it is ready yet to advocate as an alternative to React, but it's probably in an interesting A4+B2 tangent on your map right here, and I find that interesting.
I remember 2012, ASP.NET MVC Razor pages, combined with individual page knockout Js. Actually worked quite well. Infact that system is still running for that company. Sure we could have made a angularJS 1.0 SPA at the time, but knockout meant we only had to apply the pattern to the pages that needed it.
I even used Durandal some in those cases where we really did want a SPA, but Knockout was good enough. That was something I appreciated about Knockout too was that the SPA framework was around it, not a part of it or implemented inside of it. Same with routing frameworks like Crossroads.js if you wanted something lighter than Durandal for just boring hash-navigation somewhere in the boundary spectrum between full SPA and MPA.
It was something that was also attractive about early React that React was similarly just a view engine and could do MPA or SPA or things in between and it didn't try to have the full kitchen sink. I don't know exactly where React stopped being that, but it always feels harder to argue that current React is "just" a view engine.
In the larger context here with this article, libraries that are just view engines should be great for building the internals of Web Components. (I'm hoping the view engine I've been working on might serve that role well, though with a dependency like RxJS I'm not sure if it would be towards the top of the list for many developers. It will certainly feel bigger than Lit, for example, no matter how well it tree shakes.)
I used Knockout to implement the very very very first ZeroTier network control dialog. Nice paradigm, but I think React beat it when things got really complex.
Interesting, thanks. Your mutation tracker isn't enough like "pure" RxJS Observables for my tastes and what I've been doing with my itch, but you captured a few of the things I'm covering in my system and are probably the next closest I've seen to what I've been doing (and I tried to research a deep dive). I think the only other thing is that I took an approach that observable change bindings look different from static HTML-like attributes. I did that in part because that's how Knockout used to do it, and also in part because I think it should better facilitate SSG/SSR/progressive enhancement when I get back around to those ideas (it's not a current priority, but definitely an idea I'm tracking).
I was also influenced quite a bit by knockout. SSR was explicitly not a goal of mine. To me, SSR as a feature in a framework like this is mostly interesting in the context of server/client continuity like rehydration. But I have a feeling the constraints imposed by anything like this aren't going to be worth it. If I was doing pure server rendering, flat text templates seem like the sweet spot, since it's fundamentally not interactive. Render to html string and ship it. And if I was doing that, I probably would not choose to use javascript or observables/signals.
Knockout was designed in the heyday of the "progressive enhancement" era so it seems hard for me to claim a Knockout influence/inspiration if I'm not at least contemplating "progressive enhancement" of some sort. SSR isn't really my goal on that front but progressive enhancement/SSG (static site generation) certainly is a side goal for me (that's what I would like to have to self-host my own documentation site in something resembling the framework itself, rather than Jekyll or Docusaurus or whatever), but again not a main priority. It feels like the case for me where there is a lot of bleedover between SSR, SSG, and progressive enhancement and solving one basically solves all of them.
> I probably would not choose to use javascript or observables/signals.
This seems to be a case where we differ. In one obvious part because I don't tend to like signals and think they are very different from observables (because they are harder to encapsulate and offer fewer operators and tend to bleed too many accidental imperative escape hatches). Observables, to me, are just as useful to describe "open this file, read its contents, convert it from Markdown to HTML, then bind it to innerHTML here" on the server side as "fetch this URL, read its contents, convert it from Markdown to HTML, then bind it to innerHTML here" on the client side. Very different forms of interactivity, but there is still an interactivity there that a good observable pipeline can describe. Especially when you start to get into the idea that the difference between "open this file" and "fetch this URL" is tiny and can be dependency injected. Same component, slightly different inputs, slightly different expected outputs (you expect the server side binding to complete, whereas you expect the client side one to live for some time and continue to respond to different URLs from input).
I don't know much about the state of the art SSR/SSG, but in my mind, a whole document can be built synchronously, with a depth-first traversal of the templates/components. From that perspective the power and the constraints of reactive UI seem like overkill and limiting at the same time.
But anyway, the more UI frameworks, the more ideas get out there, the better. I'm hoping that some day in my lifetime, web UI gets "solved" and I'm not willing to believe that React is the answer. Does your project have a name yet? I'll keep an eye out.
Just because on most modern hardware file I/O has millisecond latency and feels synchronous doesn't mean it is synchronous. It might feel like overkill to use Observables instead of Promises and I/O event loops or even thread-blocking faux synchronous file system calls, but there is still an asynchronous world there where it can be nice to have the full power of Observables. To be fair, my love affair with Observables started in C# in "backend" applications, so that's always been the natural fit for me and frontend and UI work has been the "side hustle" of taking stuff that I love in the backend side of the house and putting it to even more use.
I'm calling my view engine Butterfloat, and I only just finished the first documentation pass, so be gentle, but feedback is very welcome: https://github.com/WorldMaker/butterfloat
It is possible with React to write an application where components have no internal state, every component is "read only," and all UI changes are state transitions in (something like) a redux store.
This is rarely done, because there are pragmatic reasons (e.g., animations) not to, but it is possible.
The other mistake alternatives make is to try to make components having internal state "easier." It should not be easier! Every single useX() is a statement that "I am violating the proper design pattern of this application," and it's a feature not a bug of React that you have to be obvious and intentional about it.
useEffect should have been named useDangerousSideEffectAndThisIsNotALifecycleHook and the js influencers should have never compared useEffect to component lifecycles and the React team should have updated their docs and not wait 4.5 years to do so and the dependency array should absolutely not be optional.
It’s a misremembering of history. The point of all the “pure functional” discussion was that rendering the UI now shouldn’t depend on how the UI was rendered earlier. The idea was to move away from the “create then update” paradigm to just “render”. React would be responsible for which elements need to be created and which can be updated in place.
To achieve that, it doesn’t matter whether the state is local to a component or global across the application.
> React would be responsible for which elements need to be created and which can be updated in place.
That works for simple, read-only components. The moment the component starts managing its own interactivity you end up needing state, and at that point things break down. If you need to change props, you have to essentially recreate the component by changing key [1], and at that point, what is the benefit of React?
The idea of a reactive framework is that every interface component is either an event creator with no representation and that can update your application state, or an state viewer that has no inputs but can represent your state.
It's decoupling those two that brings all the power.
But the idea doesn't represent at all the web. So react is a mess of complex code trying to make the things you can create on the web behave like stateless pure components. Yet, it mostly works, and the react does indeed implement the idea that the interface is a pure functional transformation of the application state. (But I do disagree on claiming this the "entire idea", it's half of it at most.)
I too remember building interactive web sites with jQuery. It was never fun creating, for instance, an interactive list view where each item can be modified in client state and new items can be added. This was the problem for which React provided a major "Aha!" moment.
I would say SolidJS does everything better than React while keeping with the same general mindset. React spent way too much time worrying about DX to the point that now DX is really bad.
Fine grained granularity is such a breath of fresh air to work with after the very large and very heavy brush that is the React “render the world every time anything changes” method (yes they try to be smart about it, but so far haven’t succeeded, the next compiler might solve it, but then we’re back to a black box of incomprehensible code soup to debug).
Thank you. Finally someone mentions Solid, it got all the good part of React, and none of the bloated parts.
Personally, JSX is the mainly thing that makes React attractive. As JSX is just modern E4X. It really ought to be put into the ES standard again instead of this Web Component stuff.
> (B) Advocate a framework other than React that uses the same pattern as React, but improves the usability. I think the two places there is the most room for improvements are:
> 1. Animations
> 2. useEffect() in general
I'm not normally one to "shill" a web framework, and I still mainly use (and love) React, but I'm curious if you've tried Svelte, because it definitely manages animations better than React, and has a different idea of state that's more ergonomic for many use cases (though I won't go so far as to say it's definitively "better" than useEffect)
It can't be that that design pattern because React did not invent it. Every server-side templating library is a pure functional transformation of application state. I can tell you that many people also ported that design pattern to JS.
What tripped library writers up is once they applied that pattern to JS, there is no way to actually define the transformation because to do that, you either write a template or the code-equivalent (i.e. using DOM as your data model). And that's where JSX came in.
Also, I think you have patterns completely confused.
Backbone is NOT in the same class as jQuery or React. Backbone is more like Redux, mobx, or React hooks because it's a data model library. In Backbone, you define "models" and "collections" -- basically, you use Backbone to store your application data in memory.
Backbone did have a views component to it but it actually could not generate any HTML. Look at this example from their docs:
It literally has jQuery and underscore.js! Backbone had no templating/HTML generation ability so when you used Backbone, you combined the fat Backbone classes with whatever horrific HTML-generation method you used to create a huge monster.
You can actually use Backbone.js with React since they are not in the same class. You would not, of course, because mobx is basically the same style of data modeling as Backbone.js but with almost no boilerplate.
The reason React uses a virtual DOM is because when React started, there were no (advanced) HTML templates yet. And it made it easy to setup listeners on elements, instead of manually adding it with `addEventListener()` and possibly remove them again with `removeEventListener()`. So the virtual DOM was really a game changer.
But Lit templates solve these problems in a more browser integrated way, without the need of a virtual DOM. How you manage the state is free to your choice, that is also not something exclusive to React and your favorite pattern can also be used with Lit. I wrote a tiny state management library (LitState [0]) which makes it very easy for multiple components to share the same state and stay in sync. I personally find it much more convenient and cleaner than any other state library I've used before. And it integrates very nicely with Lit.
With modern browsers, "completely re-output the entire user interface on every state change" is kinda viable. I recently wrote a trebuchet simulator app (hastingsgreer.github.io/jstreb) without a framework. instead I wrote a "rebuild UI" function that I call on every new state, and the user experience is super snappy
Weirdly I see that changing the "Projectile" selection to "P3" and then back to the original "P4" made the range drop way down, even though the new value was identical to the old value. But changing the "Main Axel" value made it jump way back up: https://imgur.com/a/boo5Xw3
So maybe some kind of "non-functional"/reused state issue exists regardless?
Ah, global variables in modules have to be declared with var etc in chrome, but firefox and safari let it slide if you just assign. Fixed, but I guess I’m gonna have to set up a test suite
To add to that, one of the (largely justified) criticisms of React is that it, or at least the way it is commonly used, can have negative performance impact, and thus negatively impacts user experience. However, user experience is broader than just performance, and critically also includes that the application has as few bugs as possible and works well in the first place, and I feel that the model you describe greatly helps there, and it makes unit testing and strict static typing feasible to boot.
(Admittedly, these benefits haven't been thoroughly researched, as far as I'm aware, so it still mostly relies on gut feeling and experience.)
The server side style of MVC you describe is a far stretch from how MVC is practiced in retained-mode UI frameworks like UIKit, Cocoa, or Backbone. It’s possible to make this style work fine with careful design and planning; Apple built web versions of Pages and Keynote using SproutCore (which evolved into Ember?) in 2013-era.
In fact back then, everyone’s big app was MVC - usually Backbone. I worked on Airbnb’s host-side web app called “Manage Listing”, it had probably 30+ models, 150+ views, 100+ controllers in Backbone. There were many bugs in this scale of app around making sure the DOM reflected the latest change to some model. the engineering team regarded the more complicated screens as a nightmare to maintain in our fast paced environment with many teams touching the code.
Engineers at Airbnb started to adopt React as a solution to the problems we all experienced with MVC - not because it was a “hot new thing”. When React came out, it was widely regarded as weird - it was more like “eww, this smells of PHP and needs a weird compiler, but pure function of state is a lot better than fiddling DOM manually…”. Eventually we replaced Manage Listing backbone views with React components one by one until there was no backbone left.
React is still kinda weird but it does solve this problem the best out of the modern frameworks. It’s happy to over-render by default and prefers a correct DOM-for-state over everything else. It’s clear thought that the mental models popularized by React are worth it - now Apple and Google are switching to the React model in their own frameworks.
MVC is a proven and popular technology. It works very well, otherwise it wouldn't be so popular. I notice you allude to "problems we all experienced with MVC" without mentioning any. Surely if there are so many problems, you would be able to mention one?
I mentioned the main problem in the second paragraph:
> There were many bugs in this scale of app around making sure the DOM reflected the latest change to some model. The engineering team regarded the more complicated screens as a nightmare to maintain in our fast paced environment with many teams touching the code.
I've seen this same issue in Cocoa/UIKit/Android views. Older Cocoa in particular has a lot of hairy wiring up of signals and first responders and delegates. I think it's less of an issue there because the rate of change is typically lower; in web land we expect to deploy continuously and with a very high number of engineers, anything targetting the app store will usually deploy at most weekly (2 orders of magnitude fewer deploys) and with many less engineers (usually an order of magnitude at least. My hypothesis is the difference in change rate is why this kind of bug was more of an issue for web developers.
As parent pointed out, the MVC in server-side development only shares a name with the MVC in GUI development. Yes, MVC is a proven and popular name. But it means different things to different people.
Why would it be different? The concept of Models is the same whether it is client-side or server-side. These are objects that encapsulate business logic. The concept of Views is also the same. These are responsible for rendering the screen. The concept of controllers? That too is the same. Controllers determine application flow from one screen to the next.
The server is typically not a retained-mode kind of abstraction. Incremental view maintenance in retained-mode MVC systems is the main source of bugs. If you render the view from scratch on every request, it's more similar to React style immediate-mode UI than something like UIKit where you end up handling many UI events and keeping little bits of the UI up-to-date with model changes incrementally.
You can render the view from scratch on every user interaction, even in MVC. In fact, you can use React for that purpose. "Lots of people use React as the V in MVC." See that quote on this page: https://github.com/facebook/react/tree/015833e5942ce55cf31ae...
Personally, I have not run into large amounts of bugs of this type, and I have written plenty of MVC code using VanillaJS.
As I said, "MVC", model, view, controller - popular names. But if you've ever done MVC GUI programming, and MVC web programming, you find that the relationship is merely analogous. And even within both camps, there is such variety that I don't think you can fairly call MVC a single technology. It's a (very) loose pattern.
Fair, though you can find plenty of stuff on the internet using React, but where the app/page itself performs abysmally. Meaning maybe there is some merit in approaches that are easier for lesser skilled teams to deliver in.
There is always space for options for "fast and easy" vs "robust and maintainable."
Nothing will ever beat the following as tech demo for how easy it is to make interactive UIs, but anybody who ever tried to reason through a large Angular 1 application would seriously hesitate to want to use it for something much more complicated.
As someone who does remember why because they've been building sites since the 90s, it's because the React team created a preprocessor (JSX) to let you embed HTML tags in JavaScript. This fixed the problem that other languages like Java, Python, etc. don't have because those languages has assemblies/packages so they can put HTML templates in separate files and load them in your app. There is zero standard way to do that in JS and every custom way you invent looks like trash.
Doing something like this.shadow.innerHTML = `your HTML` with web components is terrible. document.createElement() is terrible. $('div').appendChild() is terrible. <script language="html" name="my-template"><!-- --></script> is terrible. HTML(Div(Strong(text))) is terrible*. Storing templates as JSON and writing a one-off loader is terrible. <div style="display:none">template</div> is terrible. I've done it every possible way and they are all terrible.
JSX fixed all that.
The biggest previous attempt at something like JSX was E4X where you could embed XML straight into JS, which was kinda nice except it added the entirety of XML and its complexity. I creamed when it came out but then I tried it and it was not it. (E4X ended up surviving a little longer in Adobe Flash though.)
Interesting. Yet I find that React HTML—that is not actually HTML, but a look-alike, a dialect if you want—to be exactly what I dislike about React. That is because it still encourages people to put JS in their HTML in their JS in their ... And we are almost back to crazy PHP land of "I treat HTML as a string and blend everything together into one big lump.", instead of using a templating engine, that treats HTML in separate files, or making use of a DSL, that treats HTML as structured data, say for example SXML. Also there are issues with that custom HTML-look-alike preprocessor, because you cannot write class="...", because then somehow it gets syntactically confused, because "class" is now a keyword in JS.
This all feels rather half-baked. Why can't the parser/prprocessor distinguish between that "class" and "class" in JS source code? We can have reusable HTML snippets (some may call components) with normal templating engines easily. Look at something like Jinja2 and how to reuse blocks and macros. Yes, some React component can encapsulate its own interactive behavior. That is only because we are already writing JS though, so we can already write frontend logic. But do we actually want that? Coupling state and behavior? I think we might not. Writing a script that gets served only on those rendered templates, where it is needed is not so hard either, when using a normal templating engine.
Except it's not half baked. Because guess what - now you need a new template language that supports constructs like conditionals, loops, etc... You basically end up implementing a half-baked version of javascript with an unfamiliar syntax. Even worse they need to interact with state. Many template engines introduce some sort of "data binding" abomination which is a complex way of saying how you want the state to interact with the view.
React is simple. Here is your data, and here is a function that transforms that data into a view.
Templates are terrible, and that is a hill I am willing to die on.
> React is simple. Here is your data, and here is a function that transforms that data into a view.
Is that aspect so much different from templating engines? In templating engines the rendering step is simply abstracted one step further: You get a generalized render function, that you pass data to and a template to render with that data. That is also a function to turn your data into a view. I don't see how React is better in that aspect.
Your criticism was the biggest one of React when it came out -- mixing view code with your controller code. Big no no. Everyone loved the MVC pattern (model-viewer-controller where you separate these things in different places) and what React did was a big no no.
But you know, if you are trying to put HTML templates in separate files, you have to now send extra HTTP requests. That's an even bigger no no.
In other languages, you can just put your template in a separate file and load it from your package/.jar/assembly. Super easy and most importantly, 100% standard and provided by the environment.
So people just settled with React because it worked and no successfully invented a standard bundle format for the web.
> But you know, if you are trying to put HTML templates in separate files, you have to now send extra HTTP requests. That's an even bigger no no.
It's not actually, with HTTP/2. The separate requests are all multiplexed over the same connection, often with prefetching, and compressed together so that there's little to no overhead vs. putting them in the same file.
This illustrates a common failure point for web frameworks though. They encode a lot of folk knowledge about how the web works, but that folk knowledge becomes obsolete as browsers change.
Another prominent React example fits into this category: the virtual DOM. React assumed that DOM manipulations were slow and Javascript manipulations were fast, and so they built up an internal representation of the DOM in Javascript so they could manipulate that one and diff the change to apply it to the real DOM. This was true from approximately 2008 (when V8 introduced JS JITting) to 2013 (when Blink/Webkit/Firefox all moved to a dirty-bit system for DOM manipulations), which not coincidentally is when React was designed. But since then, DOM manipulation has been just pointer swaps and a dirty bit flip, and if you're careful not to invoke any operation that triggers a reflow and repaint you can make your modifications directly in the DOM for roughly the same cost as making them in JS. Since React is declarative it could easily have enforced the no-reflow rules without the virtual DOM, but because DOM manipulations were expensive when its designers learned web programming, it introduces an unnecessary concept.
But HTTP/2 is not the right example. You're missing some things on the web timeline.
Long before HTTP/2 (time in web terms), and after React (and Angular, etc.) came about, people created actually-popular bundler toolchains that can bundle arbitrary files together and then incrementally load them as needed. This effectively fixed the multiple HTTP request problem long before HTTP/2 existed. Efficient template files have been possible for years. (Granted, not anything standard though.)
The issue right now is that someone has to make a full toolchain with strong developer support to make this a de-facto and popular way to distribute apps. Just because you have a bundler or HTTP/2 doesn't mean you have a nice way to make use of it. You need a nice library. Your usage examples need to look pretty. It needs to work with other toolchains. It needs to look like your library will be supported for a long time, just like how React was supported by Facebook.
You can't just write a blog post about how it's possible because you're basically asking your readers to invent and maintain a library or worse, roll their own internal library that will confound people at their company.
Multiplexing requests doesn't help when there is a logical dependency between them, e.g. some javascript code needs to download and then execute just to determine what template files it needs to subsequently download. That can't be parallelized.
If you're in a position where you could've written the template inline in your source file, this is a static dependency, independent of any page content, and can be handled through build systems and prefetching.
Short answer: anything that modifies the DOM, followed by a call which measures geometric properties of the DOM. Also you get an automatic reflow/repaint when control leaves the Javascript event handler that triggers a modification (this is how the browser's UI is updated). You can batch up a bunch of modifications without triggering a reflow and then have it account for all of them on next reflow, though, which is what React tries to achieve with the Virtual DOM and what you get for free after ~2013.
Also there's a bunch of exceptions where you can modify things without triggering a full reflow. Anything that takes elements out of normal flow (position: fixed, position: absolute, float:, overflow: hidden) creates a layout boundary where changes inside only reflow the containing element. Any element with a transform: or opacity: property gets rendered as a 2D texture on the GPU, and then you can do subsequent transform/opacity animations purely on the GPU without touching the CPU. Used to do this to make performant animations on mobile devices.
"Generally, all APIs that synchronously provide layout metrics will trigger forced reflow / layout."
> What forces layout/reflow. The comprehensive list.
> All of the below properties or methods, when requested/called in JavaScript, will trigger the browser to synchronously calculate the style and layout*. This is also called reflow or layout thrashing, and is common performance bottleneck.
>But you know, if you are trying to put HTML templates in separate files, you have to now send extra HTTP requests.
Most projects that I have been involved with have some kind of build system that does all sort of magic. It should be possible to include the template in the JS file during the build process
Yep, and that's what was being done before React existed. JSX took over because people (including me) prefer to have the full power of JavaScript for their templates rather than a half-based templating language.
> Also there are issues with that custom HTML-look-alike preprocessor, because you cannot write class="...", because then somehow it gets syntactically confused, because "class" is now a keyword in JS.
> This all feels rather half-baked. Why can't the parser/prprocessor distinguish between that "class" and "class" in JS source code?
Remember that React is "just JavaScript", JSX is a syntax transformation of JavaScript. When you use `className` in your JSX, you're using the standard DOM Attribute [1]. You wouldn't use `class` either in vanilla JS to set the CSS class, you'd use `className`.
However, that means, that now one has something, that is neither looking like HTML, nor is it looking like JS, even if it may be JS through some pre-processing (but then actually it is not really JS?). The result is, that one has to learn some different syntax that is specific to React. If there is already a preprocessing step, why not preprocess `class` instead of `className`, to get closer to normal HTML syntax?
In a usual templating engine valid HTML is also valid template. One does not have to use templating engine specific things. A HTML snippet can simply be HTML. No harm done. But in JSX one cannot use normal HTML, as shown by the `class` case.
I think you're hung up on JSX being HTML - it isn't HTML and doesn't try to be. The "JS" stands for "JavaScript" and the "X" stands for XML, not HTML.
> However, that means, that now one has something, that is neither looking like HTML, nor is it looking like JS, even if it may be JS through some pre-processing (but then actually it is not really JS?).
Yes, it's not HTML or JS, it is JSX. It's an XML-based syntax to declaratively write JavaScript. It's optional too - one can write the function calls directly in JS, and indeed that's what people did before JSX existed. `React.createElement("div", React.creatElement("span"),...)`. It could be worth using a REPL [1] to gain an intuition of the JavaScript that is produced from transforming different JSX examples.
> The result is, that one has to learn some different syntax that is specific to React.
JSX was originally created for React, but now is not specific to React, other libraries and frameworks use it as well. It's a general purpose XML-based syntax for writing JavaScript declaratively.
And yeah, if you want to use JSX you have to learn it. It's easy to learn if you know JavaScript and XML and shouldn't take very long. It's XML and then anything inside curly braces is a JavaScript expression.
If you're using TypeScript replace everything "JS" I'm saying with "TS", it's the same result. And obviously type checking works without issue because it's a syntactic transformation to TS, not a semantic transformation.
> In a usual templating engine valid HTML is also valid template. One does not have to use templating engine specific things.
JSX is not an HTML templating engine [2]. JSX is a way to write JavaScript declaratively using an XML-based syntax.
> But in JSX one cannot use normal HTML, as shown by the `class` case.
Yes, as expected. JSX is not an HTML templating engine, it's a way to write JavaScript declaratively using an XML-based syntax. In JavaScript, you use the DOM APIs [3], not HTML attributes [4].
100% agree. Like you I’ve been building sites since the mid 90s and always was pulling my hair out at all the convoluted ways we would attempt to handle HTML in these JS frameworks. As someone who knows HTML and CSS and vanilla JS, as soon as I saw React all I could think of when I saw JSX was “finally!”.
Yeah it’s another framework with its own quirks but it lets me think about the UI in the same way I’ve thought about it for 25 years. For someone like me that’s a godsend.
I remember using PHP and CodeIgniter in the mid-2000s. IIRC PHP had that template-interpolation thing solved since the first day: You populated your Views with PHP code.
Not saying that you can't. I'm just explaining why React won and how it was blatantly obvious that it was going to win when it came out (that is, if you were there in the before-times).
Agree with you on that. React was a breath of fresh air compared to what we had in the before-times, such as Angular, Ember and so on. The canonical demo of Ember.js was two-way data binding. React did away with two-way data binding and introduced JSX syntax. This was a major step forward. Code suddenly looked sane and readable. Then they took two steps backward when they introduced hooks. Code went back to being unreadable.
It's new and has no significance for the history. But I think it's relevant to point out that <template id="myhtml"><div></div></template> isn't horrible.
And that those articles about web components are doing a really bad job of using constant strings instead of this.shaddow.innerHTML = getElementById("myhtml").innerHTML.
The implementation is new but as far as the UX goes, it's very similar to <script language="html" name="my-template"><!-- --></script>. That said, the UX is going to be slightly better for <template> simply because it's is an official standard and so IDEs and tooling will be more likely to support it without additional extensions or plugins.
It's much more descriptive and obvious, and it's just plain HTML, so anything that assists you on writing HTML will assist you inside the templates.
It's bad because it's inline and your templates have no obvious place to go. You also can't import them on the fly (or rather, it's as idiomatic to import as any HTML). And obviously, because they have no effect on HTML and can only be used in javascript
Recent updates and other JSX frameworks simplified the name of `React.createElement` to just `jsx` or `h`. I've seen projects that manually write `h` calls like that everywhere, and it is indeed terrible.
(Source: I've just completed a bunch of crazy TSX work and got pretty familiar with the compiled forms.)
Yeah, you're right. I was kind of simplifying it. API-wise, it's more like document.createElement() but I didn't want to asterisk that because document.createElement() is actually a thing and I didn't want people to think it was a simple layer on top of document.createElement.
I liked the templates-as-JSON approach much more than JSX. HTML is terribly verbose, doesn't fit well with the rest of Javascript, doesn't let you use JS language features like destructuring or iteration on the component tree, and doesn't let you factor out common properties into their own data structure. Would much rather see:
The main reason I ended up settling for JSX was just convention: I don't want to be the one with my own unique format for UI trees unless I can convince everybody else to use my format.
Note that Jetpack Compose has a very similar declarative reactive paradigm as React, but represents components with Kotlin language mechanisms. IMHO I like it much better, because it's much more composeable.
Fascinating that React simultaneously receives criticism as being
1) boring, old technology that has been around for so long that no one even remember why it was chosen in the first place, and
2) extremely fast-churning, bleeding edge software that is constantly changing and breaking because the JS community is more interested in chasing trends than building robust stuff.
React “won” because Facebook spent three years flying devrel to every web conference on earth to persuade other people that Facebook’s problem space was applicable to small agencies.
Back in reality, React is slow and massively overbuilt for the majority of stuff that most people are building.
If you played around with Web Components a long time ago then you probably played with the v0 spec, which was somewhat different to the current version.
> React “won” because Facebook spent three years flying devrel to every web conference
You do know that Google sponsored and ran things like Polymer conf? That it builds lit? That Google's devs have literally overrun and overruled most web specs committees? That Google has spend hundreds of millions of dollars promoting Web Components?
Polymer was incredibly even slower that React and even more overbuilt, and it had the added negative that it tried to enforce a visual style as well, which was too much for most people. Google couldn’t spend its way out of that hole.
As for Web Component specs, we got v1 because of Apple and Mozilla: Google would happily have stayed with v0.
I'm glad to have read this today. I'm going to look into how I could use web components in my next side project. I'd really like something that worked easily with SSR and client-side, maybe using htmx.
In retrospect, I think I avoided web components because of Google and their aggressive dev relations pushing Polymer. It felt so one-sided that it didn't seem like a web standard. It felt more like a Google "standard" like NaCL. Having to ship Polymer to support non-Google browsers felt even more heavy weight than React.
I'm pretty sure that just shipping the HTML works. The nice thing if I use web components is that I can just have my backend create HTML that uses those components. I can create elements whatever way I want on the backend or the front-end so long as it is HTML.
Yes, if you stick to custom elements. If you want shadow dom encapsulation then you’ll need to wait for declarative shadow dom to turn up in all browsers.
React "won" I think because it trojan horsed itself as being "just the view" but then morphed into a hand-rolled kitchen-sink solution, and inertia kept people around.
I would not say that React won over svelte because of simplicity. Hate what you will about implicit behaviors in svelte, but the syntax is simple and intuitive.
React won by being early and different. Svelte came out three years after React and got (unfortunately) steamrolled.
As someone who just had to answer this for my startup, the value of React is that it's robust and immensely hire-able. If you're looking for frontend developers, the one thing you can always expect is at least passable React knowledge.
Everything else, even if it has a better technical fit for your project, is likely riskier for your organization.
Some of the most productive teams I've worked with (not as a dev) have been for tech stacks I personally don't enjoy using. Java, .NET/C#, React, etc. In practice, I'd rather quickly hire a local senior Java/C# dev for 1X than scour the interwebs to hire a Golang dev that requires relocation for 1.5-2X.
If I was going to learn a language though, I'd probably learn Golang. Their rate is so much higher.
I find this argument so absurd. If you know JavaScript and basic programming, you can use any front-end framework.
We're hyper-specializing people in a specific framework that then don't even understand the basics of JavaScript itself.
I already find the divide between frontend and backend developers unnecessary the majority of the time. This takes it a step further and in turn creates monstrosities like the leftpad debacle.
Can we stop with this nonsense? Hire good developers and let them spend 5 minutes to learn the god damn framework of the week. If your hire can't learn React in a week, I have some bad news for you.
Would anyone pick react these days, if they did not already use it/know it/think-it-is-what-they-should-use-because-everyone-else-does?
I think that is the point. The original "pitch" for react in my mind was that it was lightweight and simple. I don't think you can say that any more, and I think a lot of rough edges have been identified (e.g. hooks fiasco, app state management, dependency-hell etc to name just 3) after years of use.
It's the same cycle that always happens. Old thing ossifies and grows fat overtime trying to be all things to all people. Then some new thing appears that starts with a clean slate and no prior expectations that proves popular as a result
Web components are a bit verbose by themselves but used with a library like lit.js you can build a framework agnostic component library. Angular and Vue support WC out of the box and they have a wrapper for React.
I think the only thing missing(or not mature enough right) now is SSR. There are probably libraries other than lit.js that take the pain out of writing WC.
I was skeptical at first but I've seen in production a lit.js/WC component library used with React and Angular successfully in the banking sector and it works surprisingly well.
It sounds like the common thing that someone in the Frontend space would say, that a technology less than 5 years old says the technology is old.
I prefer the terms stable, mature, or hardened.
People use React/Angular because large products are forced to have a way to organize things across multiple developers and time. Now don't get me wrong I think these JS bloated websites are an abomination that have largely made the web worse and not better, especially since UX "engineers" feel a compulsive need to change the layout every 6 months and now even simply scrolling through a page involves 50 web requests, and takes a full 3 minutes to load the next page... but I digress.
As a full time JavaScript developer of 15 years it boils down to 2 reasons.
1. Eases candidate selection. There is no uniform baseline of competence in software generally and certainly nothing exists for web development. Its often the blind leading the blind, so outsource everything to a tool. At the very least, people that cannot use that tool are then not qualified to be there if you discount absolutely everything else. After all, it isn't as though employers are willing to train new developers to perform as required, so they need to turn this into a commodity as much as possible.
2. Composition. Most of the people who do web development cannot write original software, plan, or organize at the level required by modern applications. Employers still need people to do trivial things to get text to appear on screen. As the demand for these trivial tasks still exists employers still need to hire people to do this work, and so they attempt to outsource the parts that require higher intelligence.
These beg the obvious question: What will happen when employers realize they don't need to overpay developers to do this work when half of it can be pushed into content management systems and the other half can be pushed into AI?
Yes, I agree with him. What's the reason to use React? It is over-engineered and too complicated for no clear benefit. It takes longer to build an app using react just because you have to deal with things that are exclusive to react
Try next.js. We have seen massive improvements in code quality and development velocity using v13/14. Our codebase is a mix of typical server rendered crud web and client only logic (web3). It feels like php without the bad parts. In particular react actions proved to be a major quality of life improvement.
No, they just lock you into one framework per component. I don't know why people say obviously false stuff like this about web components besides they just really, really want it to be true. Yeah, if you're willing to have the same framework on the page ten times, you can just chuck them all in separate script tags using the custom element API. But if you care about making a performant page with progressive enhancement, etc. this is a bad strategy.
Even the name "web components" is basically just marketing fluff. When people say "web component", they mean using two particular DOM APIs: customElement and shadow DOM. Those are both pretty niche APIs. There are some cases where they are helpful, but 99% of the time, they don't add much to a project versus good old querySelectorAll and normal CSS.
Author here — I'm not sure what you mean by "lock you into one framework per component". The point is that you can encapsulate framework code within web components, not that every component you write should be a web component.
Let's say you're writing a Vue app and you really want to use a library that's only available as a React component. You can wrap that library in a web component and use it in your Vue app just like you would any other HTML element. The rest of your app can continue being Vue, using normal Vue components.
The biggest problem of web component is that it don't support most state injection(for things that rely on contexts, for example: tabs) and template instantiation(render function of react or scoped slot in vue for example), which literally every current popular web framework does. You may pass string or number as string to it. But anything more complicate that can't be easily serialized? Good luck.
You may add another layer of abstraction on the top of it. But that only make you another framework (like polymer) instead of actually using web components.
In other word. Web component is useful to encapsulate an 'app' (for example: a interactive map viewer that accept an address) inside another app. But is mostly useless to encapsulate anything other than a simple ui/input component. There is basically 0 functionality to inter-blend between parent and child components of different frameworks.
except you can't use it as a normal component, you can't adjust its CSS normally, you have to `&::part()` your way around and hope for the best. Accessing through refs is a complete blackbox. I work with web components daily and it is a hindrance to my daily work, it is very common for people at my org to just re-write a component instead of using its web component version.
I also wonder about this. The webcomponent make the style completely immutable unless you add part selector specifically… how on the earth this is even useful? Imagine using an ui library that you can't change the style at all. That sounds like a total joke to me. That isn't even a sane default that is useful to most web folks that make page base on layout that designers gave.
I find it very useful for embedding interactive demos on my blog that are mostly independent of the styles for the rest of the site (for example, the article here). But for what it’s worth, there is discussion of an “open-stylable” shadow DOM mode that addresses those concerns: https://github.com/WICG/webcomponents/issues/909
Shadow DOM was a mistake. It's a 0.1 version that was unfortunately pushed out as a completed standard. Basic stuff is missing like your link. The entire thing should be deprecated and we should start from scratch.
If you want to embed something that doesn't use your page's styles, we already have iframes. Shadow DOM is just a half-assed recreation of that.
You wouldn't, but shadowroot is bad design for that. What's wrong with bootstrap or any other number of of existing frameworks? I don't want to include a button and have it stick out like a sore thumb because it ignores my page's styles. ::part() is a stupid hack to make up for a bad approach.
If you want to include something "as-is" (i.e. the demos you mention), use iframes. If you want to include a component like a button, use any of the existing frameworks that work just fine. Trying to build a button that pretends to be a browser-native component but actually isn't is a terrible idea.
You could use srcdoc="..." to simulate a component, except that iframes don't have automatic height adjustment, which is the thing they should actually fix.
In any event, shadow DOM is just a worse version of scope selectors. There's not really a good use for it now that you can just do a style reset on a donut selector inside an import layer. It can all be done declaratively with CSS instead of using an imperative JS API that has a ton of gotchas.
There are a lot of things you can do with shadow DOM that you can’t with iframes or scope/donut selectors:
- transclude other elements (technically you can with iframes, but hopefully it’s clear why making something like this breadcrumb component would be extremely awkward [1])
- control and react to the display of child elements via <slot>s
- call methods on custom element objects
etc etc. It’s fine if it doesn’t solve any problems you personally have, but that doesn’t mean it’s not useful.
Transclusion can totally be done with CSS now. That’s a donut selector.
The other things are just plain old JavaScript and have nothing to do with Shadow DOM. Yes, they can be done with customElement, but they can also just be done without it.
I think I’m going to bow out because it’s clear this discussion isn’t going anywhere, but you should look up what transclusion means because it makes no sense to say that you can do it in CSS.
Transclusion means that .a in this can escape the Shadow DOM: <my-element><div class="a">Transcluded content</div></my-element>
To do the same thing in CSS you would do <div class="myelement"><div class="slot"><div class="a">Transcluded content</div></div></div> @scope (.myelement) to (.slot) { /* rules that apply to .myelement but not .a */ }).
I've been fought by people insisting that if we're using a framework, we should be using it for everything, if it has it, even when both agree that doing it natively is actually less cumbersome. All that in the name of consistency. I think middle ground is a good solution.
On topic: I don't think WebComponents are going to "make it" until someone builds a nice framework on top of them. React, Vue, Svelte, etc. solve a number of problems that are not directly solved by Web Components. State management, rendering, routing - right now, these are, imho, the high level areas that need solid solutions for an UI app to function in any sane way. How much of that is solved by going Web Components?
I work on Lit, which I would hesitate to call a framework, but gives a framework-like DX for building web components, while trying to keep opinions to a minimum and lock-in as low as possible.
It's got reactivity, declarative templates, great performance, SSR, TypeScript support, native CSS encapsulation, context, tasks, and more.
It's used to build Material Design, settings and devtools UIs for Chrome, some UI for Firefox, Reddit, Photoshop Web...
Lit's features are internal to each component (except context which is being developed as an open community protocol with the Web Components Community Group) and there is no coupling between components written in Lit. So you can port from Lit to something else component-by-component.
Lit is also modular. The template library, lit-html, is usable independently and used by other web component and non-web component libraries. The reactive custom element base class ReactiveElement can be used to build web components with a different template system like Preact.
This is just splitting hairs in an attempt to pretend that lit isn't a framework (or framework-like lib), or that it's somehow unopinionated, or that it somehow prevents you from lock-in.
Almost all of the things you listed are specific to lit, and lit only. So, people who will develop with lit will be locked in to lit. Because it's not like you can just pop the code you wrote with lit into stencil or ionic, and will just work.
> So you can port from Lit to something else component-by-component.
I personally saw a huge project ported from Angular to React basically doing the same. It's not a testament to lit. It's what people have been doing since time immemorial.
> I personally saw a huge project ported from Angular to React basically doing the same.
Do Angular and React components talk to each other? Lit and other Web component frameworks can share components. To refactor Lit components into other web component framework or raw web component is orders of magnitude easier than converting Angular <-> React.
> Do Angular and React components talk to each other?
You can make them talk to each other. Depends on what exactly you need, how components and projects are structured etc.
> Lit and other Web component frameworks can share components. To refactor Lit components into other web component framework or raw web component is orders of magnitude easier than converting Angular <-> React.
You're putting a false equivalency between "talking to each other" and "refactoring one code base into another".
Preact, Svelte, Vue, and Angular can all be compiled to web components. How easy do you think it would be to convert app code between each of these frameworks? Convert that code to and from lit?
you can make almost whatever you want with code but they weren't build for that. Besides that, both angular and react are bloated software, adding another layer to create web components version of their components is just more bloat. It took some time for chariots to be considered a legacy way of transport but you can't fight its obsolescence just by saying that chariots will also carry you from one place to another.
What a vendor lock-in basically means is that your integration with the vendor is so specific, that it's very hard to transfer to another vendor.
Lit is basically a library that makes use of the native Web Components APIs in modern browsers. If someone else would make a similar library, it would most probably have similar functionality.
So I don't really see the issue with vendor lock-in here. Most logic regarding your app is not gonna have anything to do with Lit. Only the way the templates are structured is a bit specific. But it is way less specific than JSX. Because it's just normal HTML with a few specific attributes to easily bind event listeners on HTML elements.
So Lit basically just gives you easy access to powerful browser APIs, making it really easy to build complex webapps without using a big framework.
> your integration with the vendor is so specific, that it's very hard to transfer to another vendor.
Indeed.
> Lit is basically a library that makes use of the native Web Components APIs in modern browsers. If someone else would make a similar library, it would most probably have similar functionality.
Maybe, similar, perhaps.
The meat of the matter is this. There are a lot of things in lit that are specific just to lit. They have nothig to do with web components. Custom DSL. Tasks. Reactivity. etc. etc.
So yes, when you're buying in to lit, you're locking yourself to lit, and the way lit does things.
For example, Stencil, another popular web component library, is completely different from lit: it uses a different templating mechanism, a different data binding mechanism etc. etc.
> So Lit basically just gives you easy access to powerful browser APIs
No, it doesn't give access to those APIs. It goes out of its way to hide those APIs and provide a different, ore ergonomic API on top.
Well, if Stencil is a Web Component framework using native Web Component technologies and strategies, transferring from Lit to Stencil will probably be a lot easier than from React to Angular or something.
And there are actually not that many things specific to Lit, and it's only things that would need to be solved in some kind of (opinionated) way anyway. But I think Lit does it in an elegant, intuitive and flexible way. You might like it or you might not.
I don't know Stencil, but looks nice. But their main npm package [0] is 47.8 MB, whereas Lit [1] is only 105 KB. So I would say that there are a lot more things specific in Stencil then there are in Lit. Which would probably make it harder to move from Stencil to Lit, than it is to move from Lit to Stencil.
> Well, if Stencil is a Web Component framework using native Web Component technologies and strategies, transferring from Lit to Stencil will probably be a lot easier than from React to Angular or something.
Literally everything that's on the web is using "native technologies and strategies". Because there's nothing else.
So, extraordinary claims require extraordinary proofs. I eagerly await a description, with examples, of how much work there is to convert a non-trivial lit component to Stencil.
Why non-trivial? Because trivial components are easy to convert from anything to anything. You could convert a trivial React component into knockout.js, then to Angular, and then to Lit, and back, in under half a day even if you've never worked with those technologies before.
> And there are actually not that many things specific to Lit
I've listed a few of them. They are opinionated enough that lit code and stencil code are completely different and incompatible.
Besides, there are a dozen or so libraries and frameworks that can, or do, compile to web components. Their code is also different from lit's.
> But their main npm package [0] is 47.8 MB
This is completely beside the point. We're not discussing Stencil, or the opinions its authors may or may not have taken.
Sorry but I think it is quite obvious that a large framework will create much more lock-in and dependency than a tiny library. The more specific stuff you use, the more you are locked in. And yeah Lit still does some things for you so there's always some lock-in, with any library that you use. So it's not about simply whether it is a lock-in or not, but the amount of lock-in.
Lit doesn't need JSX and a virtual DOM, which are React specific technologies. You have to design your React components with these technologies in mind. With Lit there are much less dependencies like that, so your code will be less designed for a specific framework, making it easier to move to another framework that doesn't impose a specific workflow.
So. So, extraordinary claims require extraordinary proofs. I eagerly await a description, with examples, of how much work there is to convert a non-trivial lit component to Stencil.
BTW. Claiming that Virtual DOM is somehow a react-specific technology (and that somehow apparently affects conversion from React to something else) really shows how much you understand about the topic at hand.
I: ask to show me how converting from lit to something else is easier as you claim
You: ignore everything completely and answer a question literally no on asked, and pretend that the only custom thing is the DSL.
Yup. My choice to completely ignore you in a sibling discussion was correct.
On the other hand, after a few years of engaging with web component defenders, propoenents and propagandists I'm not surprised in the least. This behaviour is on par with the rest of them.
From all our arguments I think it's obvious that Lit has less lock-in than any other framework we discussed. If you find it so important to prove your point, why don't you make an exstensive comparison of all the discussed frameworks?
I mean they have to be for now - you're just being semantic for the sake of it a bit. I will say as a team that utilizes Lit for our design system web components (which none of our users even need to know or care about no matter their framework btw). The Lit team are huge advocates of aligning with native standards (now or what they might be in the future) and working to establish or push them forward. The goal of the project for a lot of these issues truly seems to be to eventually not need them to be a part of Lit at all.
> you're just being semantic for the sake of it a bit.
No. I'm calling it as it is. I don't pretend that something isn't a framework when it has all the same things that the frameworks they so love to vilify do.
> The Lit team are huge advocates of aligning with native standards
Which of the things that lit provides are native standards current or future? Its template DSL? Its custom decorators? Its data binding system? Tasks? Directives?
Honestly, you don't. It's used for many Google projects like Chrome, parts of YouTube, Maps APIs, Collab, the Google Store, and a ton of internal things, so I think it's unlikely, but I understand Google's reputation.
This is one reason why we care so much about low coupling and lock-in, and a small, easy-to-understand codebase. You should be able to migrate away from Lit very easily, and fork or maintain it if necessary. We're also trying to build up our non-Google contributors.
> It's used for many Google projects like Chrome, parts of YouTube... so I think it's unlikely,
When Custom Components v0 was barely released Google re-wrote Youtube with Polymer. Where's Polymer now?
> You should be able to migrate away from Lit very easily
And that should comes from which part of lit? Custom DSL? Custom decorators? Custom data bindings? Custom tasks?
As I wrote elsewhere, Preact, Svelte, Vue, and Angular can all be compiled to web components. How easy do you think it would be to convert app code between each of these frameworks? Convert that code to and from lit?
I never used Polymer but as far as I understand it was always an experimental project for the then very young technology of Web Components. And it was a rather opinionated framework also. Lit is just a very lightweight layer on top of the now matured Web Component API. And you are not really dependend on a strong community releasing occational security updates and new features and bugfixes, because it's very small and simple, and it won't really need much new features, because Lit doesn't want to be a opinionated framework, but a simple tool for a single job: rendering a web component.
So because it's small and doesn't need much new features, it's also easy for the community to maintain it. I think not much has changed in the Lit library over the last few years. So it's also easy with upgrading.
> as far as I understand it was always an experimental project for the then very young technology of Web Components
So experimental that Google even had a Polymer Conference and was promoting it heavily, like it promotes lit now.
> because Lit doesn't want to be a opinionated framework
For a "non-opinionated" framework it sure does have a lot of opinions: custom DSL, custom directives, custom decorators, custom way of building elements...
Well, any popular framework has all these things, and most frameworks have a lot more. Lit is really the littlest amount of tools you would want. With less than that, you can just as well directly use the web component APIs, and not use a framework / library at all. I don't know what you imagine would be a less opinionated way without having to chip in on usability.
SSR, context and tasks are all separate packages, not in the Lit core package. The others are very basic functionalily for what you expect from a framework like Lit. It has to do something ultimately :D
> SSR, context and tasks are all separate packages, not in the Lit core package.
Splitting hairs
> The others are very basic functionalily for what you expect from a framework like Lit.
Indeed. Framework like Lit. These mental hoops and shenaningans lit defenders have to jump and go through to pretend lit is somehow not a framework and somehow different.
"Web Components" are the name for a dream, not an actual technology. The actual technologies involved -- customElement and shadow DOM -- are pretty crappy to use directly, and even when hidden behind a framework/library don't buy you that much. But people want it to be true that there is such a thing as a "Web Component" so the dream lives on.
Stencil does it, but the resulting web components are still not great to work with because of shadow dom and the missing standards you can't expect from custom elements. You want inline styles? hope your dev remember to drill those down.
That's good to know. I really liked what I saw last time I played with it but it's hard to find many job listings where people are using svelte. Almost everything is react and surprisingly, at from what I can tell, it's getting even bigger share in job postings I used to see. Hooray for uniformity, I guess.
In case anyone was wondering, JavaScript per se isn't replaced at all. All mentioned examples still use event listeners, querySelectorAll, ES modules, and what not. Most importantly, you need to subclass HTMLElement and register your custom element using JavaScript in the first place eg:
class MyElement
extends HTMLElement {
}
window.customElements
.register('my-element',
MyElement)
(the hyphen in the name is idiosyncratically required by the custom element spec).
As such, "HTML web components" (aka custom elements, which have be around for many years) are targeted at developers not hypothetical web users/authors. Then what is the point? When you're relying on JavaScript anyway, you have already much greater freedoms - syntactically and otherwise.
Custom element declarations and custom vocabularies can make sense as a means to organize and isolate authoring concerns when you're creating hypertext documents. The fact alone that you have to use JavaScript for registering custom elements make them a non-starter though (ie consider an authoring tool which surely doesn't want to execute arbitrary JavaScript in client docs).
It's not that there's no precedent either. SGML has a mechanism for parametric macro expansion where your element is syntactically replaced into an arbitrary markup fragment, with type-checked arguments (= attributes at the call site, just as with custom elements), and with type-checking the resultant expansion in context (ie. checking whether the expansion adheres to the content model at the expansion site), also having of course the capability to include JavaScript. Moreover, SGML actually can serialize/re-parse such markup whereas HTML's preliminary APIs for fragment parsing won't deal with contextual tag inference at all.
For me, being able to offer my library as a web component is kind of neat. Sure I can ask users of my library to import it then query select math inputs, then apply my library on these, and remember to apply it also on DOM change.
<script type="module">
import lib from "/path/to/my/lib.js";
for (const target of document.querySelectorAll(".target")) {
lib(target);
}
// TODO: Watch for DOM change and apply lib.
<script>
<span class="target">Some Input</span>
Or I can simply ask them to import my web component module and use the custom element:
It may just be me, but all of these seem a lot inferior API design then a simple web component. Particularly if I’m asking my users to setup a mutation observer.
Aside: Don’t you need to pass the library function into the callback while constructing the mutation observer?
import lib, { mutationObserverCallback } from "https://my-lib.example";
lib({
target: ".target",
observer: new MutationObserver(mutationObserverCallback),
});
Honestly, this feels like so much magic compared to a simple:
<my-lib>Some Input</my-lib>
where I handle update in my library by listening to the slotchange event.
I like the idea of web components, but really dislike html and js being intermingled (the reason I don't like React/JSX). In web components its even worse because its HTML as a string which means it has no validation and isn't syntax aware. I much prefer the angular approach where you have separate css,html,ts files, and would love a web component framework that could work similarly.
Searching for this I found some kinda hacky solutions on Stack Overflow which use fetch to load html/css at runtime.
Web Components are really just the minimal APIs required to allow the implementation of new HTML elements. This includes things like:
- Responding to being attached to the DOM
- Encapsulating DOM nodes (the Shadow DOM)
- Scoped styling (Shadow DOM + User defined stylesheets + CSS parts)
It is definitively not a templating engine. It doesn't provide any new APIs for creating DOM nodes, or mutating them a la React or handlebars or lit-html. Templating is basically the "next step up the stack". Using shadowDom.innerHTML = `...`; is basically a stand-in for having an actual templating engine.
I like React but I actually agree with you re: JSX, it helps me to remember that JSX is 'just javascript' - it's a syntactical shorthand for creating a component tree, which then happens to be rendered into HTML.
I was actually just looking at that after posting this (lit is new to me). That's a pretty cool solution. I'd still prefer an option to have the html in its own file, but that is just my taste. I know a lot of people feel exactly the opposite.
Maybe a bit pedantic - but I prefer using lit-html, not lit.
Lit is a bit too "frameworky" for my taste, I generally just use vanilla classes that extend HTMLElement and have a render function that renders the lit-element template to the light dom.
Perfect, and perfect timing. I was recently tasked with creating a small standalone web app and everything feels like overkill to me. This might be the perfect fit. Thanks for the explanation.
This is the example from the article, and pretty common practice for web components. As far as an IDE is concerned this is just a string of text (it doesn't know/care that it is html). This makes it more error prone as the IDE can't catch syntax errors in the html.
connectedCallback() {
this.shadow.innerHTML = `
<p>Hello from a web component!</p>
<style>
p {
color: pink;
font-weight: bold;
padding: 1rem;
border: 4px solid pink;
}
</style>
`;
}
Web components are a half-baked solution. It only becomes useful with another framework (even if it's very lightweight) like lit. At which point I might as well use vue/react/svelte since I am already brining in a library. Tech like preact is really lightweight as well, and given the popularity of react, is enough to offset any benefits web components have.
I would really like it if we reached a point where a web project only had a single dependency that's a bundler like vite that you point to an index file, and that's it.
I think we're going in the opposite direction though - everyone wants to hide what's going on and use some magic CLI that just takes care of everything for you, don't worry about how or when or what to do if it goes wrong, just run `flyctl deploy`, `wrangler publish` (Cloudflare), `npx wizzle wazzle` :sparkles: :tada: never `git commit -m '(chore): [...]'` again!
Oh and here's a readme example of how to set that up if you're using pnpm v42 with sveltekit v2 and webpack v99. For any other combination of the 5 packagers, 19 bundlers, and 56 frameworks commonly in use and giving examples like this recommending each other - have fun.
I use them for a basic website (no build step) for things like navigation components and page templates. They are great for that, but not much else in my experience. Once you have a complex UI or multiple devs on a project it’s probably better to just use a full framework
Can you elaborate further ? Anything that removes dependencies from external libraries is a huge plus for me so I am curious as someone who is not great at JS.
As you read the following, keep in mind that at this time Web Components have been in development for almost 12 years.
The core is just three standards, CustomElements, Shadow DOM and HTML Imports (already deprecated and removed in favor of JS-only imports). And people will go out of hteir way to sell you the idea that this is lightweight, all that you need etc.
However.
They've already spawned half a dozen new web standards just to deal with issues they inflicted on themselves. None of these issues are present in any other solution/lib/framework that exists.
They will need at least 20 more new web standards to fix other issues that, once again, are not a problem for literally every other framework, library, or hand-written code under the sun: https://w3c.github.io/webcomponents-cg/2022.html.
Among my favorite ones: a web component button cannot be a submit button in a form; you cannot reference an id inside a shadow root, and that breaks ARIA.
To call them half-baked is an understatement. They are badly thought-out, badly implemented APIs with no forethought or visible planning, and literally no end goal in sight. The people building this met to hash out what more is needed for them to be complete only last year, 11 years into development. All development before that looked like ad-hoc patches by people surprised that a yet another thing doesn't work, but is sorely needed.
I think you are trying to impose a React workflow on Web Components. Some things that work in React indeed don't work in Web Components / Lit, but that is usually for good reasons. There are a lot of quirks with React too, for example I find it very cumbersome the way you reference elements in React. That's a lot nicer with Lit. But in Lit, input fields can't communicate to a form in a different Shadow DOM. In React you have your ways of dealing with it, in Lit also. Overall I think Lit is generally a lot cleaner than React, feels more native, less opinionated. That's logical of course because Lit is made to work with modern Web Component APIs, and React already existed before these technologies, so they had to implement those features into React itself.
Literally none of the issues I listed have to anything with React.
> But in Lit, input fields can't communicate to a form in a different Shadow DOM
Indeed. They break the most basic functionality that exists in the browser. This issue doesn't exist in anything else. And they need a separate new web spec to barely fix it.
Does it have to do anything with React? No.
> That's logical of course because Lit is made to work with modern Web Component APIs
Yup, so modern that they creak basic browser functionality and need 20+ new web specs to fix issues that don't exist in literally anything else.
They don't break semantics, input fields work just fine within a single Shadow DOM. You have to understand that a different library has a different workflow. If you addopt the correct workflow, you won't have any of the issues you're having. But it takes some time to learn something new.
2. If you have an input in Shadow DOM, it cannot be referenced with a label from outside that shadow DOM. That breaks ARIA, and will be fixed god knows when with a new cross-root ARIA spec.
This has nothing to do with libraries, or React, or whatever you imagine. These are basic browser behaviours that everyone expects to work out of the box, and they are broken.
> that a different library has a different workflow.
This has nothing to do with libraries. This is basic browser functionality.
> If you addopt the correct workflow, you won't have any of the issues you're having.
No "correct workflow" can cover the fact that these behaviours are broken, and need 20+ new specifications to fix.
There's no correct workflow that will make cross-shadow ARIA work. There's no correct workflow that will make a custom component participate in forms if the author didn't add that functionality. There's no correct workflow that will make your custom button be able to work as a submit button. And so on, and so on, and so on, and so on.
Edit. Note: if you took the time to actually read the report from people who shove webcomponents into the browser, you will see that even they admit how much of an issue all this is, and it has nothing to do with React or libraries, and everything to do with self-inflicted wounds by a badly thought-out design: https://w3c.github.io/webcomponents-cg/2022.html (emphasis mine).
Note how none of these are issues for anything built for the browser. These are issues only for the half-baked, badly-designed web components.
--- start quote ---
This document tries to highlight the main features that are lacking from the web components spec that either block adoption for more developers and frameworks, or cause pain points for existing developers.
It's worth noting that many of these pain points are directly related to Shadow DOM's encapsulation. While there are many benefits to some types of widely shared components to strong encapsulation, the friction of strong encapsulation has prevented most developers from adopting Shadow DOM.
...
Shadow boundaries prevent content on either side of the boundary from referencing each other via ID references. ID references being the basis of the majority of the accessibility patterns outlines by aria attributes, this causes a major issue in developing accessible content with shadow DOM.
...
The form-associated APIs currently have no way for a developer to behave as a custom submit button.
It is currently unclear how form-associated custom elements should participate in the autocomplete lifecycle despite there being an API for that purpose.
...
Many web components could be implemented without JavaScript, taking advantage of encapsulated DOM and styles. However, web components cannot currently be rendered by users who have JavaScript disabled.
I will read those links you referenced later. But what I think about the Shadow DOM is that that is for me actually the killer feature. That prevents a lot of weird issues. But it also brings limitations to methods of how web developers are used to do things, like applying styles globally, or having some sort of dependency between deeply nested elements, crossing the Shadow DOM when using Web Components.
What people usually try to do is to somehow open up the Shadow DOM for certain things, to make some things allowed to pass, or global. But I think might be a bit holding on to an old familiar habit. And I think there are better ways of structuring a project with Web Component in mind.
For example, you can create a base class from which all your components extend, and put the base style in that base class, and have your components add style on top of that. I implemented this method in a tiny library which makes it easy to use [0].
But yeah it is hard for most developers to adopt a new way of thinking. And as long as the new way doesn't provide that much improvement over the old way, it won't get adopted. But I think the idea of Web Components still needs to be integrated more in the web dev community. And maybe they will manage to make some changes to make the adoption easier.
And besides that, of course Web Components still have lots of other issues. But for me it has reached a point where I don't feel the need for React anymore. I rather live with some quirks in Lit than doing things with React, which just feels clumsy to me now.
> But yeah it is hard for most developers to adopt a new way of thinking.
It's not "a new way of thinking". Things like functioning inputs, buttons, and ARIA are basic browser functionality.
> And as long as the new way doesn't provide that much improvement over the old way, it won't get adopted.
Not only it doesn't provide improvment, it needs 20+ new web standards to fix the issues that literally nothing else has. I've gone ahead and quoted directly from the report made by people who keep developing these specs.
And yet you've ignored literally everything I wrote and keep answering something entirely else.
> of course Web Components still have lots of other issues.
Indeed, they do. I listed a bunch of them. And yet you keep pretending that I'm talking about "React workflows" or something.
This is pointless until your read what I write, and not what you think that I write. Until then, adieu.
Any technology has issues and limitations. Many basic browser functionalties also don't work with the React workflow, and Lit brings those things back again, making it more native, and less need for framework code.
It seems you are only focussing and zooming in on the issues and limitations. And there are issues and limitations in any technology. I think it has to do with adopting a different way of thinking and structuring. All those issues you listed are either non-issues with the correct workflow, or are easy to work around.
And hey, I'm not saying you or anyone should use web components; if you like React better then just keep using that. But I don't see why you would critizice this technology so much. Remember that creating new web specs and standards takes a lot more time than to build an independent framework like React. So yeah the development and adoption is slow, and that might frustrate you. And as long as you think it's not good enough yet, you can just keep using React. But I personally find that it is mature enough for me to use it in combination with Lit instead of React. And I'm very satisfied about it. It does take some investment to learn a bit about how Web Components work.
> It seems you are only focussing and zooming in on the issues and limitations.
The question literally was: "Can you elaborate further on why web components are a half-baked solution".
Did I say anything about React? No. Did I say anything about lit? No.
Stop making up what you think people are saying and start reading and understanding what people are saying.
> And there are issues and limitations in any technology.
Yes. Yes they are. And web components are literally the only technology that after 12 years in development needs 20+ web specs to not break basic functionality that literally no other technology breaks.
This has nothing to do with react. This has nothing to do with lit. Read what I wrote and not what I think I wrote.
> if you like React
> framework like React.
> keep using React.
> combination with Lit instead of React.
Jesus Christ.
Literally nowhere was I talking about React or lit. Not a single one of my comments in this thread had anything to do with either.
And yet you keep arguing with the voices in your head that are telling you that I'm talking about React.
> It does take some investment to learn a bit about how Web Components work.
So go ahead and learn about how they work, why don't you? Or, rather, about how they don't work, and why after 12 years they still need 20+ new web specs to to the most basic things.
Edit: from now on I will disengage from this conversation and sibling ones, because it is useless and pointless.
I recently rebuild some parts of a large APM (application performance monitoring) solution to find out how much JavaScript is needed to have similar functionality (minus the backend, of course), e.g. faceted search.
It's interesting how much of a component system one can build only by using `<input>`, `<label>`, and `<form>`. For the remaining interactive elements that can't be build easily without JavaScript I plan to use Web Components.
For me this is a reasonable 80-percent solution. But for web applications with high requirements I would use React and React-Aria components/hooks.
I don't feel like web components and React should compete for most people. Web components feel pretty good at making leaf components, especially when they will be used with multiple technologies. I tried using React to only make a single component for use within a larger React app and within a Django site, and it was not as smooth as a web component. Also, I tried to make a web component app and there was way more friction and less tooling than a React app. As it stands now, I wouldn't use React for single component nor web components for an entire app.
As far as I can see, web components take only strings as arguments. That alone disqualifies them from being a serious component framework. I've looked at them only for a short time last month, because I was excited about a web native component framework, but they provide basically nothing I would expect from such a framework. They are not even in the same arena as React.
This is 100% correct. I think a lot of the disappointment about web components comes from a mismatch in expectation between the spec writers and what people when they think "components".
Web Components allow you to make new HTML elements. That is, you can make new kinds of DOM nodes out of other DOM nodes. This is powerful, but the resultant API is still a DOM-level API, and not a full templating system like React.
On the other hand, because all these templating systems (React, lit, svelte, etc.) ultimately boil down to a series of DOM manipulations, this allows you to create a kind of element that can be plugged into all of these systems.
Custom elements are a lot more akin to the C ABI. Than a fully featured framework.
Strings as _attributes_, yes. But that's par for the course when it comes to html (boolean attributes aside).
However, anything can be passed as a _property_. React operates on properties by default (hence `htmlFor` and `className`, not `for` and `class`). In fact, react's upcoming improved WC support will first do an `in` check on a property name before falling back to attribute. This is similar in vue etc.
So yes if you're only authoring plain html you're confined to primitives, but if you're using a framework or WC lib, they almost certainly support properties
I see, interesting. That's certainly helpful. Still, I don't see what problem web components solve. New custom html tags? Nice, but useless. And if I have to use a framework or WC lib on top of web components... Well. Nothing gained, it is just switching one framework for another. I am not against that at all, in fact I am writing my own framework for specific reasons. But let's not pretend that web components are a solution to anything, or that there are specific reasons why it needs to exist.
It's not all that shiny. Web components have global names (you should pretty much apply a prefix/namespace if you want to work with others) and managing multiple version of the same component in the same page is an issue in any non trivial codebase (either use a different name per version or fix all breaking changes at once during the upgrade, unless the draft about scoping web elements became standard https://github.com/WICG/webcomponents/blob/gh-pages/proposal... )
For folks looking for a lightweight JS class that manages the lifecycle of Web Components, I have this little Template class I use in many of my front-end projects. It's able to manage the application state by pushing the state down through the application and bubbling changes up.
It's a 161-line file that's easy to reason about and modify as needed.
The main problem with the Shadow DOM which makes people avoid it is the inability to use CSS externally to style the elements which are generated internally by the component...
This is unfortunate because the Shadow DOM is essential if you want to work with child components slotted into it from the outside. This opens up many use cases.
There is one alternative which is not being considered; it's possible for components with a shadow DOM to inject their elements into the Light DOM (where they can be styled/skinned externally with CSS), you just have to make the user slot a div (or other element) from the outside to act as a 'viewport' so that the component can inject its children into it (instead of injecting them into its Shadow DOM).
With this approach, you can still access slotted elements. It's an ideal pattern for situations where you want the component to generate child elements from a slotted template.
Thanks for pointing this out. I should probably mention this approach in my article for cases when you need to work with slotted elements but don't want to inherit all page styles.
Cool solution. I'm using Lit, and implemented a different approach to this problem. I created a way to easily apply a set of styles to particular components, by using a mixin class:
Is there a comparison between light and shadow dom for webcomponents? I kinda want the simplicity of applying light dom css. Svelte doesnt support slots in light dom, I want to know the other caveats of light dom.
I don't think there's a need to cause a stir and generate hate for either Web Components or React.
We should hate both equally.
Either approach is frankly an embarrassing way to build complex interactive applications. Web tech is just way too low level, batteries not included. We've added mountain of complexity to deal with it but it doesn't hide that the fundamentals are broken and that productivity is low.
I've been using Web Components in production for years with great success.
My guiding principles:
- Avoid shadow dom unless it's a library. Stick with the light DOM and css system of your choice.
- Use lit-html or similar for rendering
- Use class properties for reactivity (add a render() call to setters, as needed)
- Ignore attributes entirely. Just use properties.
- Don't bother with composable components and slots. You generally don't need them
- Use a nice router like vaadin or ionic or similar to hoist components and support deep linking
- Let components maintain their own state. Structure the dom so that it's easy to grab state from a component with querySelector. If this doesn't work, I have a little state lib called ApplicationState[1] that works great.
- Really think about what needs to be a component vs normal html. Don't overdo it with components.
- Structure the app with high level "scene" components that map to URL deep links, and app components that you use to build the scenes. Scenes are targets of the router.
I've seen the entire industry move towards React/Angular type frameworks and it's invariably been a really bad thing. Large projects end up with front end specialists and backend specialists and very few actual full stack devs. What ends up happening is that no one person can do an entire feature anymore.
GP didnt say that. They said lot of devs become "front end" or "back end" specialists which means that they cannot do full stack. Full stack devs knowing React is fine. The problem is that most "React devs" don't know full stack and most "backend devs" don't know full stack.
Why does being a front end or back end specialist mean you can’t do full stack? If I’m a full stack dev that’s a back end specialist I can still write a complete feature myself just fine, thank you very much. But of course, if I’m having trouble with some part on the front end I might ask a front end specialist colleague for help, and vice versa.
The concerns, constraints, and behavior of server-side headless software and a viewer that fetches and renders data from a remote backing store are entirely different.
Is it a bad thing that organizations specialize on those concerns? Seems like the most obvious place to slice responsibility, even if it means every feature is split across two teams. After all, the performance of the backing store is impacted not by neigbhoring logic in the UI infrastructure but by neighboring state in the backing store; it should be someone's job to be looking at the backing infrastructure holistically and not sliced as "frontend-backend feature A, frontend-backend feature B, etc."
In your opinion what is the “really bad thing” that React/Angular have resulted in? Is it just the fewer full stack devs? I mean I’m a full stack dev still while using Vue. But also specialization (at a certain scale) is nearly unavoidable.
Please remember that Web Components are much more akin to an ABI for web projects and not a full-featured framework.
Any web component easily plugs into React, svelte, lit, etc. Existing components written in those frameworks can pretty easily be wrapped in a web component. It's a common base-layer we can all use.
If you attempt to build a web app using just web components and no libraries, you'll quickly find that you're doing lots of manual DOM updates (no templating engine) and lots of manual state management (no data management API).
As an ABI, it's wildly successful. It does, in fact, just work. It's just very low level.
That is why we have a library to make it easier to work with these low level functions: Lit. And because Lit uses these functions, it can be a lot more lightweight compared to React & Angular etc.
My hair always bristles a bit when I see plans to "eliminate JavaScript Framework Lock-in."
For a backend service, it doesn't matter if you use no framework or one or five, other than pain for your developers having to learn the complexity; storage is so cheap it's nearly free, executable RAM slightly less so, and the end-user doesn't care how complex your server is.
Frontend code gets pushed over a wire to your end-user. If you're using three overlapping frameworks to build one web service frontend purely because someone in your team likes Svelte and someone else likes React... that's a problem. You'll be pushing more bytes than you should to your end-users, and that cost doesn't scale the right way; in fact, the more popular your app, the more redundant bytes you'll be passing.
We don't want to enable multiple frameworks in the UI. We should be settling on one and committing everyone on the frontend team to using it (ideally lock-stepped to the same version of it) within each app-shaped thing we create as a frontend team.
Author here — I feel like I addressed this point in the article, no? Obviously using a zillion frameworks in your app is a bad idea, but there are a bunch of actual reasons that encapsulating and/or mixing frameworks might be useful:
- Gradually migrating from one framework to another
- Including interactive "islands" within a static or server-side rendered page
- Using a dependency only available in one framework from within another (this works best if the dependency framework has a small footprint — e.g. using Svelte within React is better than vice versa)
I am a backend dev so I don't really want to get into the intricates of React or Angular. But if I need some reactivity for some complex element, I use lit. It's awesome
Web Components are not a replacement for React. They are a thing you would use to build React if you were to do so today. To use only Web Components, you will be writing a lot of low-level code using the browser's API, or you will have to use a framework built on Web Components
For me it's a perfect replacement for React. I've been using it for years, and I'm much more happy about it than React. And I was already very happy with React compared to before that. I think it's the logical next step, but you need to unlearn some React concepts and relearn some Web Component concepts before you are really comfortable with it. But when you know how to work with it it's really super nice, and you'll appreciate better understanding the powerful browser and DOM APIs.
i did this back in 2019 to make the transition smoother between angular.js and react
> there are ways to build a web app other than writing the entire thing with a single JavaScript framework
totally agree, and reducing rewrites or making converting them into "strangler" rewrites is a huge win
on the other hand, it reminds me of the microservices hype a few years back. Just because you can, doesn't mean you should. Uniform languages, frameworks, coded patterns make things SO much smoother for an organisation.
I would repeat the author's words of warning: "you should not build a real app like this!". you should seriously think hard before adding this level of complexity to any production app
> To prove it, we’re going to do something kinda crazy: build an app where every single component is written with a different framework.
Interesting exercise. But now I wish she/he would one-by-one replace each framework with web components, so that in the end, there are no frameworks, only web components. As in, "Oh shit! We're going to abandon Vue (or React, etc.) and replace it with web components" or "We've been taked to only use web componentst, and no frameworks." What does that migration / transformation look like? Isn't that a likely scenario?
When your tech needs 20 more web specs [1] to fix stuff that literally no one has issues with, it means that you will be locked in to frameworks that solve these issues.
Literally right now Web Component SSR is a framework-specific barely working non-solution. Even the most ardent web component proponents have given up and advocate a framework lock-in with lit-html and others.
No they don't eliminate anything. Framework never HAD to have a lock-in. They WANT to have a lock-in. They want to have a flashy site, with short sexy demos, and to give you slogans to repeat, and create in you a sense that all your struggles as a developer were caused by %PREVIOUS_TECH%, that you've been wronged and now you get to be a part of a revolution.
And they want to CAPTURE you. This is why 99% of frameworks have a deliberately monolithic and isolating architecture, where it's all in, or all out. You don't want to miss the revolution are you? Are you stupid? Of course you're not stupid. So now your apps are locked in.
And Web Components won't stop frameworks from finding highly specific ways to be "useful" in a way where you need to do everything in them.
The solution is to know how to architect your app and stop believing marketing BS. Otherwise you'll keep fleeting to the Next Big Thing (tm) and never realize why it always ends the same way.
People discussing writing Web Components by hand are missing the point.
Web Components, once adequately specced, will become a compile target for higher level frameworks like React and Vue. That way you still get the benefits of higher level frameworks but the components can interoperate with each other. Vue CLI already supports compiling down to a WebComponent, though not sure how first class it is.
There are far too many lacking ergonomics to expect writing Web Components by hand to become popularized/convention
I work at a big org and we use Stencil to produce UI kits using web components.
In my experience and the anecdotal experience of the people in adjacent orgs that work with web components too: Its still a shit show.
I'm mostly distracted by it. The cursive parts in particular are distracting me from the actual content, so, while it looks somewhat nice, it does a disservice. At least that's the case for me.
A good font should go out of my way in my opinion. When I don't notice it at all, the font is perfect. Android default fonts definitely fall in this category, for example.
I haven't been in the frontend world for many years now, but I come from the mid-90's world of GUI development / game engines / old school desktop stuff.
I look at this stuff, and just think how sad it is that we haven't progressed beyond the state of gluing together freakin low level divs and spans within some JS code with callbacks galore.
For some reason I thought we'd have made it beyond that by 2023, and we could talk declaratively at a high level about the kinds of interfaces we want to render and where the data lives. Hopefully I'm wrong and the magic is buried under some Elm tree or a React library or something.
Even in the old desktop world someone had to build the button widget (and all the others) that let you just throw stuff together in MFC or Swing or whatever.
Same today - someone has to build the web components in order for us to declaratively use them as high-level Lego.
Trouble is, there is no real high-level "general purpose" library of components beyond the core HTML elements (they'll get you a long way but there are notable things missing that we expect from apps, e.g. toolbars, menus, tab strips etc), and then the probably reason for their not being a general high-level library is that everyone wants something special for their websites (because historically websites have always allowed a lot of design flexibility, way more than your typical win32 app ever did for example).
I have several times really wished to have some solid "desktop style" components to use for things like menus, tool bars etc. That would make prototypes in electron/neutralino/tauri way way way faster to do.
> Trouble is, there is no real high-level "general purpose" library of components beyond the core HTML elements
This is why I hate making web UIs.
> then the probably reason for their not being a general high-level library is that everyone wants something special for their websites
This is why I hate using web UIs.
At this point it's hard not see this as a fully self-inflicted wound by the platform. I know there are component libraries, but the work always remains fragmented because someone decided that their buttons needed purple highlights while someone else's needed drop shadows.
And the devs seem to love staying at this low level of abstraction. Feels like they had to be dragged into the component model espoused by React et al over many years.
There are certainly lots of great component libraries out there for various frameworks that help with this, but I agree with the parent comment that it's still not the kind of progress we should have had by this point. I think it's unfortunate that we have to stick to HTML/CSS as the foundation for everything to maintain compatibility and accessibility, but that's how the web works I suppose. If we were to design the web from the ground up today based on what people use it for, it would look pretty different I think.
I am not sure it would look that different. It would be more consistent with terminology. Things like SwiftUI and Jetpack Compose look a lot more like HTML and CSS than their predecessors, and there is nothing forcing them to go in that direction.
The biggest difference between other major platforms and the web, is that the web doesn't come with a default UI framework. The primitives for building UI on the web are pretty good though.
Yeah maybe it's a grass-is-greener situation, but from a quick look at SwiftUI and Jetpack Compose, they both seem to have a lot more in common with React than HTML/CSS itself. They seem to encourage functional UI that combines state management, event handling, and view layout. They have primitives like `Text`, `Row`, `Column`, `Spacer`, etc.
I do think the web is a lot easier to learn and the on-ramp is so much faster compared to older mobile UI frameworks, so it makes sense that they're sort of evolving toward the same patterns.
Building a declarative UI that compiles to that sort of declaration means building that from scratch.
We do currently work like that though. React isn't that far and web components built into an element of that.
I wonder how different things would look if you could opt out of the cascade for CSS. It's great for documents but signifcantly less so for "apps", where the widget is the widget and by-and-large should not be affected by the other bits of interface it's inside.
I think that's why frameworks like Tailwind etc. have got so popular -- they're much closer to the traditional native application way of styling. You set all the appearance details on the component and then you reuse the component, styles and all.
This is talking declaratively at a high level about the kind of interface to render. Lots of component frameworks look like this example. Thinking "how sad it is that we haven't progressed beyond the state of gluing together low level divs and spans" sounds like a preconceived idea rather than a response to this article.
By the way, I come from mid-80's BASIC on 8-bit home computers. You get off my lawn.
Not OP but at the end of the day, custom components like this still have to be rendered down to primitive HTML and CSS, and are plagued by all sorts of browser-specific issues and conventions that make higher level abstraction way more difficult than they need to be.
As a random example, HTML specifies that clicking a `<button>` inside a `<form>` automatically submits a POST request to the current URL. We can't change that because it will break a lot of webpages that rely on this default behavior, so now every component system built on top of <form> or <button> needs to prevent the default browser behavior, and there are so many more examples of things like this.
You can make the calling interface look like that (that’s definitely good), but the implementations in the example were still very document centric inline html. It all just seems like it’s a lot more low level work than it ought to be. I feel much the same way when using a (bad) orm: there’s just a vague feeling that the solution isn’t quite an appropriate fit to the problem. Maybe this gets better when you’re composing from a library of core components, I don’t know. Again, I’m very much an outsider here.
I’m not saying that old GUI component frameworks are vastly superior either. I just imagined that we’d have progressed well past the kind of approach the article is mentioning.
It’s a side rant, but I don’t think it’s entirely without merit.
It's a very complex problem to solve and I think a lot of people need to accept that. There will never be a simple solution with a low learning curve that's actually performant for non-trivial applications without a fundamental shift in browser technology.
There is. I was frustrated by all of the chaos and built a solution [1]. Not too far off from an RC1 and then a 1.0 (which is being done slowly so I can freeze APIs and avoid the typical JS rug pulls).
I don't really do FE anymore, but I've worked in that realm long enough to see several frameworks come and go - as well as see the JS ecosystem scale far beyond the limits of its organizing principles.
In my opinion, the community is lacking foundations, structure, and principles - something that would otherwise be instilled by formal education. JS is fantastic for exploring how programming works, it makes it easy to stitch things together, and the barrier to entry is basically zero; all you need is a text editor and a browser.
The flipside is that people regularly reinvent things, same sets of ideas get formed and re-formed, fall into and out of vogue over and over again. It is true that there is great complexity to be dealt with in this domain, but it feels like whenever the current set of tools and practices matures enough to face some of the hard problems, the instinct in the community is to "start from scratch" and before long some new shiny exciting thing appears. It shows a lot of potential, it's nowhere near facing the hard problems, people jump on the bandwagon, time passes, and the new set of tools and practices arrives at precisely the same place.
Web components have been in the works for a long, long time. The inherent competition between the major frameworks divides people into camps, which doesn't help. But, seeing the slow but steady progress in the web components realm indicates to me that they're apart from the patterns I was ragging on in the previous paragraph. They increasingly seem to deliver on the promise of creating advanced building blocks - perhaps one day a developer won't have to choose between a React Table, a Vue Table, a Gobagool Table, etc, but use a plain vanilla standard issue web component table to display their CSVs.
I do front end stuff for a living and have been in the javascript space for several years. I do other backend development as well and I can't see why people think like you honestly.
Most other GUI libraries is in a much worse state than front end web dev. That is probably also the reason why people use front end tech to make native apps today, because you can customize and make apps much faster than in basically any other way.
I think front end gui development is very easy today and very powerful as well and we have progressed a lot. Making stuff with web components isn't event that hard and if you want you can just use one of the many available syntax sugar libraries that exist like Lit and others.
Devs use web frontend tech because it is installed on every machine, will never have anything less than the full backing of the browser devs for the next hundred years, and gets around corporate filters. No need to deal with IT security losers to get your app installed, no need to get ports opened, just everything down port 443 until the end of time.
> Most other GUI libraries is in a much worse state than front end web dev.
I'm certainly not going to suggest you're wrong. But I would like a sincere comparison between JavaFX (because I sorta know it) and "the web".
Maybe its unfair, since the Web is "just the DOM", an empty vessel many of the other techs are built upon, which is why there's so many options.
I'm not a front end person, by any means, and have been striving to make things work with FX. I mostly "get" FX, how it does things with its containers and layouts and properties and bindings and events and UI thread. It has CSS, I mostly don't use it (better living through gray!).
The web, honestly, intimidates me. It intimidates me with its vast variety, its complex build processes, the apparently galaxy of dependencies and tools and what not. Cross browser stuff terrifies me. And maybe that's the wrong reality, but that's the impression I get.
I'm managing to Forest Gump my way through FX, but I have a Java background.
Exactly. I'm starting to understand the push for web UI now that I've started to use qt for a small GUI. I'm sure qt is good for some type of apps. But for my smaller scale project where the graphic interface is not where we want to spend most of our dev time, I'd rather take javascript/react at this point.
I feel the same after playing with SwiftUI and UIKit on iOS and trying to make something simple like a text editor with a hideable keyboard. The whole platform feels half baked, with various overlapping features that each have serious, barely documented drawbacks and bugs. “I’m getting a warning about my constraints being defined badly” “oh just ignore that - you can’t make it work without that warning”. “Everything in my project looks the same as the example but mine doesn’t work” “Try deleting your constraints and re-adding them. Sometimes Xcode is just buggy like that”. “I tried but Xcode hard crashed”. Etc.
The web feels downright cohesive, stable and well documented in comparison.
And then you don't even have come to the real meat, the freedom the web gives you. Freedom to deploy whenever, freedom from app stores with arbitrary rules set by big boring corporate interests.
Why publish with restrictions when you can be free?
The problem with many front and backend web frameworks is they love the medium of the web too much. This might sound absurd, but they leak all sorts of web gunk through and then pile their own concepts on top.
A simple example of this is most backend frameworks let you signal an error by throwing an exception. Good choice! Except when you go to throw one, you often have to choose from a bunch of HTTP status codes to bundle with your exception. I want to tell the user that validation failed, that's all. I should throw a ValidationError, not a HttpResponseError. They're not really abstracting anything, just adding a layer of structure, usually via libraries that are glued together.
Similarly, I've started to be of the opinion that the ideal HTTP request handler has very few HTTP-specific details in it, as the framework can introspect the types and annotations to determine how to pass data in and out. This is very different from typical frameworks which are happy to hand you raw requests and responses and tell you to do it all. Nothing wrong with that for special cases, BTW, except for people's tendency to mix HTTP, infrastructure (DB/messaging/APIs), and business logic in the same handler.
There will always be cases where you need direct control, but I've been moving towards stacks that automate most of this to cut down on the gunky makework feeling I get when doing webdev, and it has been integral to me actually enjoying the tooling rather than feeling like I'm filling out TPS reports. Currently that's Spring Boot + Kotlin, despite the enterprise stigma the JVM and Spring have.
While I agree, this is what we're stuck with. I have 25+ years of experience. Before JavaScript and CSS existed.
Now? I'm on an Angular 16 (moving to 17 SPA).
Worked with almost everything else in between.
I had all the same feelings. "We're doing what with JavaScript now??".
It turns out, it's not all that bad. TypeScript is pleasant enough, for me Angular is logical, and sure at the end of the day it's all just HTML/JS/CSS but what can you do?
We're stuck with it, unless WASM totally up-ends the entire thing and we have JIT'd languages like .Net and Java running on the client ... which is ...
Well, I'm not even sure what that is anymore. It's not HTML, JS, and CSS!
I'm less cynical about web development. Lots of software engineers bemoan writing web interfaces and pine for the days of native GUI development, but web won because it's extremely accessible to people without CS degrees. There just isn't a good native framework that's as forgiving and easy to learn as HTML, JS, and CSS. I think gtk is pretty decent though
Hard disagree, web won because of the deploy story. Users don't have to install anything. Html and css is a terrible API for app layout, because it wasn't designed for that
> Html and css is a terrible API for app layout, because it wasn't designed for that
And yet it's so easy and forgiving that millions of 13 year olds learned it for their myspace and tumblr pages over the last 15 or so years.
Somehow, despite all the CS graduates and 20 year software engineering veterans bemoaning it, more and more people learn HTML, CSS, and Javascript every day while the number of people learning native GUI development struggles to keep up or outright fades away. I truly believe that most software engineers don't understand what ergonomic software or programming languages look like. They're blinded by their expertise
Given how important the web’s deploy story has been for its success, I’m surprised we haven’t seen more zero deployment application platforms / prototypes appear. Docker is an attempt at something similar on the server, but docker images are huge and docker still separates its docker fetch and docker run steps.
Maybe part of the problem is that the web is the only platform where people obsess over the size of deployed artefacts. Websites are certainly getting bigger, but they’re still an order of magnitude smaller than the average snap package or iOS app.
that's how it is if you're using high-level react components or web components, it's just an XML-like layout, user-friendly. What the article is showing is their low-level implementation, but as a consumer you can just import and use them
It would be nice for conversations to be kinder, less snarky, and more curious. Could even edit out any swipes and internet-style cross examination as well.
Specifically there are two type of components that really thrive as web components (as opposed to react):
1. Highly interactive components - Components that implement complex interaction management (but sort of agnostic to application state) are ideal web components. You don't need to mess around with `useEffect` or `useMemo`. You get really tight control of rendering and state updates.
2. Highly internally stateful components - Components that track a lot of state that doesn't escape the component, work great as web component. You get strong encapsulation without a framework requirement.
React conflates two concepts that I think are better when separated: templates, and components. Templates provide a "re-render the world" approach, and components encapsulate state and interaction patterns. Conflating these two things causes the standard useEffect and useMemo headaches. It also means that any consumer of your component, must also use your templating system (react's render function).
The `lit` library does this separation extremely well, allowing you to implement components using templates if you want, or not. And consumers do not care how the internals are implemented.