Hacker News new | ask | show | jobs
by _heimdall 83 days ago
I'd argue that it was all downhill after we moved away from using HTML as the state representation.

Moving state out of HTML and into JS means we now have to walk this ridiculous tightrope walk trying to force state changes back into the DOM and our styles to keep everything in sync.

Given that problem, reactivity isn't the worst solution in my opinion. It tries to automate that syncing problem with tooling and convention, usually declaratively.

If I had to do it all again though, DOM would still be the source of truth and any custom components in JS would always be working with DOM directly. Custom elements are a great fit for that approach if you stick to using them for basic lifecycle hooks, events, and attribute getters/setters.

3 comments

Wasn’t that the Lit framework? It was okay. Like a slightly more irritating version of React.

I recall the property passing model being a nasty abstraction breaker. HTML attributes are all strings, so if you wanted to pass objects or functions to children you had to do that via “props” instead of “attributes.”

I also recall the tag names of web components being a pain. Always need a dash, always need to be registered.

None of these problems broke it; they just made it irritating by comparison. There wasn’t really much upside either. No real performance gain or superior feature, and you got fewer features and a smaller ecosystem.

The point of Lit is not to compete with React itself, but to build interoperable web components. If your app (Hi Beaker!) is only using one library/framework, and will only ever one one in eternity, then interoperability might not be a big concern. But if you're building components for multiple teams, mixing components from multiple teams, or ever deal with migrations, then interoperability might be hugely important.

Even so, Lit is widely used to build very complex apps (Beaker, as you know, Photoshop, Reddit, Home Assistant, Microsoft App Store, SpaceX things, ...).

Property bindings are just as ergonomic as attributes with the .foo= syntax, and tag name declaration has rarely come up as a big friction point, especially with the declarative @customElement() decorator. The rest is indeed like a faster less proprietary React in many ways.

Kind of? Lit does add some of the types of patterns I'm talking about but they add a lot more as well. I always avoided it due to the heavy use of typescript decorators required to get a decent DX, the framework is pretty opinionated on your build system in my experience.

I also didn't often see Lit being used in a way that stuck to the idea that the DOM should be your state. That could very well be because most web devs are coming to it with a background in react or similar, but when I did see Lit used it often involved a heavy use of in-memory state tracked inside of components and never making it into the DOM.

Lit is not opinionated about your build system You can write Lit components in plain JS, going back to ES2015.

Our decorators aren't required - you can use the static properties block. If you think the DX is better with decorators... that's why we support them!

And we support TypeScript's "experimental" decorators and standard TC39 decorators, which are supported in TypeScript, Babel, esbuild, and recently SWC and probably more.

Regarding state: Lit makes it easier to write web components. How you architect those web components and where they store their state is up to you. You can stick to attributes and DOM if that's what you want. Some component sets out there make heavy use of data-only elements: something of a DSL in the DOM, like XML.

It just turns out that most developer and most apps have an easier time of presenting state in JS, since JS has much richer facilities for that.

Dont get me wrong, I'm a pretty big believer in interop, but in practice I've rarely run into a situation where I need to mix components from multiple frameworks. Especially because React is so dominant.
HTML simply can't represent the complex state of real apps. Moving state to HTML actually means keeping the state on the server and not representing it very well on the client.

That's an ok choice in some cases, but the web clearly moved on from that to be able to have richer interaction, and in a lot of cases, much easier development.

I'm sure you could find examples to prove me wrong here so I'm definitely not saying this is a hard line, but I've always found that if app state is too complex to represent in the UI or isn't needed in the UI at all, that's state that belongs on the back end rather than the frontend.

My usual go-to rule is that business logic belongs where the state lives - almost always on the back end for state of any real complexity.

With true web apps like Figma I consider those entirely different use cases. They're really building what amounts to a native app that leverage the web as a distribution platform, it has nothing to do with HTML at all really.

State in HTML is a horrible mistake. Now everything has to be constantly serialized/deserialized into strings.
It's a bit more nuanced than that. State in Qite is held both in HTML and in JS Component. The html serialization is sort of consequence of changing a field (like when you want to update textarea content, for example). You can completely ignore it or you can also use it for CSS, for example. Another usecase is when user interacts with the pages, changes text in said textarea and it also automatically updates the JS Component field. Finally, there are also flags, which aren't stored in DOM. I'd like to point out this architecture isn't random, it came from building apps and realizing how everything interacts.
If the state can't, or shouldn't, be serialized in the client I question whether that state belongs in the client at all.

I'm sure you could find counterexamples so that isn't a hard line I'm proposing, but it is my opinion that nearly all website or web app built today over uses client state.