Hacker News new | past | comments | ask | show | jobs | submit login
UI frameworks are stuck in the last decade (moonthought.github.io)
66 points by Pijng on Sept 26, 2023 | hide | past | favorite | 81 comments



I am not embracing the point of the author, it is overly focused on rendering, but not updating and re-rendering which are the real issues.

It also misses how the critical factor is generally time to market and maintainability cost and how these DSLs significantly lower those coupled with their huge ecosystems.

While, in general, I think there's an abuse of those DSLs in way too many use cases that do not really need those, the technologies move at such speed that you can develop a static website with the performance of a static website with some JS sprinkled on it using those DSLs.


Except UI frameworks are meant to be decidedly non-static.


Really a complaint of nothing, and the proposed solution is not any better than existing frameworks in practice. In fact the solution already exists, but I still see templates everywhere. People stick to existing, mature technology for a reason, and I really would rather use Vue/React/whatever that is "stuck", stable but actually useful. In web development, it is actually rare that we have something that sticks for a while.


Thank you for your reply. As far as I can see from the responses, people didn't quite get what I was trying to say right (purely my fault, of course). Probably due to several factors: my tone, presentation of information, English is not my first language and so on. But these are all excuses and I admit it.

I would like to note in advance once again - I am not trying to offer any specific solution. The text is not written for marketing purposes. Also, I am not suggesting to throw away all modern technologies, as it may seem. I am not a fan of such revolutions :)

Current technologies, for the most part, offer a balanced solution to the problems faced by web developers. Yes, with its own peculiarities and limits, but nothing is perfect. And that's perfectly fine. Moreover, every such technology throughout the years has been literally necessary for the overall development of the sphere. And despite everything I have said, none of them can be thrown out or said to be useless.

Also, as some may have mistakenly noted, I'm not from the mobile development field, so I don't seem to be trying to pull approaches specifically from that field. Well, at least consciously.

In general my main message is that maybe to solve the problems at hand in web development we don't necessarily need technologies that bring their own syntaxes, transpilers, modified html and so on? I'm not suggesting that custom syntax is a bad thing.

All I'm saying is that maybe it's time to look beyond the introduction of unique snowflake-like technologies? And start using what our own platform offers us and develop its usability. Perhaps not in the form that was presented, but in some other form. But, at least for me, it looks potentially possible.

We've already hit enough bumps in the road with current solutions and I believe that smart engineers (not me, haha) will be able to offer us something better.


I totally got your message and agree that people should learn the platform they are working on. It is painful to me every day to see Next.js and similar tooling that has half the volume of special knowledge that browsers’ web platform offers.


reposting this because it is a response from the author that for some reason is marked [dead]:

https://news.ycombinator.com/item?id=37657780

Pijng 3 hours ago [dead] | parent | prev | next [–]

Thank you for your reply. As far as I can see from the responses, people didn't quite get what I was trying to say right (purely my fault, of course). Probably due to several factors: my tone, presentation of information, English is not my first language and so on. But these are all excuses and I admit it.

I would like to note in advance once again - I am not trying to offer any specific solution. The text is not written for marketing purposes. Also, I am not suggesting to throw away all modern technologies, as it may seem. I am not a fan of such revolutions :)

Current technologies, for the most part, offer a balanced solution to the problems faced by web developers. Yes, with its own peculiarities and limits, but nothing is perfect. And that's perfectly fine. Moreover, every such technology throughout the years has been literally necessary for the overall development of the sphere. And despite everything I have said, none of them can be thrown out or said to be useless.

Also, as some may have mistakenly noted, I'm not from the mobile development field, so I don't seem to be trying to pull approaches specifically from that field. Well, at least consciously.

In general my main message is that maybe to solve the problems at hand in web development we don't necessarily need technologies that bring their own syntaxes, transpilers, modified html and so on? I'm not suggesting that custom syntax is a bad thing.

All I'm saying is that maybe it's time to look beyond the introduction of unique snowflake-like technologies? And start using what our own platform offers us and develop its usability. Perhaps not in the form that was presented, but in some other form. But, at least for me, it looks potentially possible.

We've already hit enough bumps in the road with current solutions and I believe that smart engineers (not me, haha) will be able to offer us something better.


> I really would rather use Vue/React/whatever that is "stuck", stable

I wouldn't call Vue stable. It's actually one of the points of the article (not necessarily agreeing); the frameworks tend to make breaking changes, especially Vue.


The author proposes this API:

  function Component({ showMessage }) {
    h('div', () => {
      h('h1', {
        text: 'Hey there',
        visible: showMessage
      })
    })
  }
I don't think it is better than the current React API `r = React.createElement`

  const Component = ({ showMessage }) => 
      r('div', null,
        showMessage && r('h1', null, 'Hey there'))


imo the readability of the proposed solution is not the best, especially for more complex things... it isn't clear to me if he is proposing that to be "under the hood" (like react's createElement), but if not i don't think it's a better solution (even though i understand the problem of using "custom syntax" but it's pretty normal when you are building "on top" of APIs.


I am getting through the same phase of rewriting my OSS [1] in vanilla JS [2], the solution I settled down on is to write components in pure es6 like this:

  export default function(render) {
      const $page = createElement(`
          <div class="component_helloworld">
              whatever here
          </div>
      `);
       render($page);

       $page.addEventListener("xxxx");
       onDestroy(/* remove listeners */);
  }

Yes I sort of had to write my own mini framework but it's well under 100 lines of codes [0] with the idea that maintaining that 100 lines of codes is gonna be a massive win compared to keeping up with any "modern framework" npm hell

The core idea is that instead of trying to pretend some cool ideas like HOC or render props, we call a dog a dog and say "decorator pattern" and just use the pattern directly [3] and when we need to compose things we do so as well [4]

ref:

- [0] the skeleton I started to settle on a nice API before starting the full rewrite https://mickael-kerjean.github.io/skeleton/example/index.htm...

- [1] original oss project which I'm migrating: https://github.com/mickael-kerjean/filestash

- [2] current state of the rewrite where you can see this pattern in action https://github.com/mickael-kerjean/filestash-rewrite/tree/ma...

- [3] https://github.com/mickael-kerjean/filestash-rewrite/blob/ma...

- [4] https://github.com/mickael-kerjean/filestash-rewrite/blob/ma...


what is this giving you more than using svelte or something like lit-html?

https://mickael-kerjean.github.io/example/counter

looking at this example (i personally don't like the template string for dom because it's a bit of a pain to read and you need a lot of manual work later, separated from the definition of the markup, to add eventhandlers etc) you rely a lot on rxjs to handle state and IMO it's a bit hard to follow what is going on, compared to https://svelte.dev/repl/f5acc8113ec14bc7946eff9687916fa1 for example


> what is this giving you more than using svelte or something like lit-html?

1. that's a trade off. From my point of view most framework provide short term win at the cost of the long run, this short term win is what we call "nice dev experience" and the long term cost is on the maintenance side when your dependencies will be rotten or someone will realise a dependency of your dependency of your dependency was disguised as a trojan. I don't get paid to upgrade my OSS project, if I can make that part much simpler, that's a BIG win for me even if the code doesn't look as nice as in svelte

2. The end goal is to enable people to change the end product by pushing patch of the frontend without having to recompile anything. I have many people contacting me to make changes to the UI and I can't make it because it doesn't make sense for 99% of the users, with this approach I can make a plugin for 1 dude without affecting anyone else and by just shoving a diff of what I need to change to enable that use case

3. I can actually read the code of 100% of my dependencies and yes I've had situation where I was asked this question

> you rely a lot on rxjs to handle state and IMO

yeah I'm a rxjs fanboy, can't help it but this is just a example you could use whatever rock your boat, my boat is definitly on the rxjs camp


Looks like Vue's render function:

https://vuejs.org/api/render-function.html

And let's be real, nobody likes writing code this way.


Sometimes you kind of need render functions but it definitely isn't the most handy way of building a template.

Many, many people struggle with this, including FE guys. In my experience, html is a pretty good abstraction of html.

Many have tried making it easy to do this programmatically but, at least imho, no js syntax beats good old html. No a huge fan of react but jsx templates are better than r(node, props). Even jquery allows you to do this.


Does anyone else wonder why the author doesn't go all the way but stops at HTML and DOM? How does "div", "h1" help here to "convey meaning" or attach "behavior", or serve any other purpose usually associated with HTML that may make sense for responsive/accessible documents but not apps? AFAICS the DOM is a crappy scene graph for apps, made barely tolerable through lots and lots of CSS ad absurdum, thereby complicating if not outright sabotaging text reading for generations to come. SVG would be a much more rational choice (with parts where typography and text flow/flow layout actually play a role still in an essential HTML subset). Or even pure JS-based immediate mode rendering, possibly with offloading of new layout model computations into JS libs portable across JS-enabled browsers, like the Houdini API is proposing? The proposed syntax merely seems like it's opportunistically driven by what's present in the JS language but isn't really pushing the limit despite the tone.


Frameworks have chosen to add abstraction layers that “simplify” writing code because it makes it easier for the not so great programmers to write code.

This has been desirable for one main reason: making writing code easier for the surge of new programmers entering the field. It’s the reason Facebook made React — the people they were hiring out of college were smart and capable but we’re not nerds about the technology.

The biggest proof of that is how many devs are still scared of CSS and don’t feel comfortable writing it, and why the adoption of Tailwind has surged.


I don't consider myself smart or a tech nerd, and certainly don't consider myself a real programner. I did rubbish at school, but ain't doing to bad in university (at 40).

All that being said I am massively confused by react and tailwind. I much prefer CSS and plain JavaScript. All be it I am not writing massive distributed billion-user applications.


The point of react is to let you manipulate the DOM with less effort than manually doing it while providing some additional controls through things like hooks. Tailwind is similar, you get standardized css styles that you can use without thinking too hard.


it makes it easier for the not so great programmer, but also for the average programmer, and the good programmer too.

being a good programmer is not about using more difficult or less accessible technologies.


No, you don't understand. I'm the greatest programmer in the world because I program only in raw bitstreams that I hotwire into the uop decoder. So what if it takes five years to get the machine up and running before I start my first task and everything only works on my machine? My (former) boss is just an imbecile who doesn't understand the first thing about true programming.


A given frameworks may be incredibly useful given the right project, but they also involve massive trade offs.

Being a good programmer is about being capable of using less accessible technologies. A limited toolkit eventually means using the wrong tool for the job. A competent programmer should know how to leverage a least one ORM, but they should also know raw SQL etc.


The adoption of Tailwind is its own phenomenon. The whole point was to come at CSS at a different angle that circumvented the pain points of regular CSS, not really aimed at being a crutch for those who don't know CSS. You still gotta know that p-8 adds padding and what it does within the box model, and using the grid or flexbox doesn't really make anything simpler.


lol what? i feel like you're jumping to the wrong conclusions here. i'm sure there is a subset of users that thought tailwind was "easier", but before tailwind there were a ton of other CSS frameworks like bootstrap, bulma, etc. that purported to make CSS easier and those never took off like tailwind did among devs.

people use tailwind because it's better to stand up something and maintain it when you're doing component based stuff without having to think of clever names on the fly or figure out what class does what and how did it fit into the hierarchy you created months ago. plus you get all the magic that you can't get with inline CSS. "Raw" css is in fact the easiest thing you can use, just style tags and have at it. Tailwind without that knowledge is nothing.


I hope we can have something better than tailwind because having to preprocess/add a build step is very meh. That locks people into the js ecosystem.

Also, CSS should ideally be enough if it's simply about destructuring classes and composing them.


> because it makes it easier for the not so great programmers to write code

A truly elite HN take.


That's an uncharitable reading. Genius doesn't scale, so you need processes and technologies that average people (or maybe above average, but definitely not top 0.1%) can use efficiently. Take literate programming, for example: it may be working great for Knuth but most programmers are not Knuth, and I don't even mean it as "not as smart", just "have different mentality and composition of mind".


Sir, watch out! Your monocle is about to drop into the scotch!


One of the primary reasons a company I worked for decided to use Vue was simply that the developers found it familiar. If you've been working with HTML and CSS already then Vue templates really just an extension to something you're already proficient with.

This was important where I worked because we had frontend developers who built the components and pages, and content developers who didn't really touch much JS, but were responsible for small content and design contents around the website. They were able to work with Vue quite quickly because Vue templates are basically just HTML.

All of these frameworks are really just making different tradeoffs in their approach. I don't think the author makes a bad point, but they are advocating for a very extreme position here without much concern for the trade-offs that are generally required to give a framework mass appeal and adoption.

What they're suggesting would have simply been unworkable in the place I worked, for example. The hassle of reskilling just wouldn't have worth it simply so we could be content with the purism of our framework.

JSX is ugly as hell. I like many hated it when it was first presented, but honestly, it works. It's not perfect, but that's actually a feature. It's why both new developers and senior developers and love and hate it for different reasons while still using it.


So, new framework-specific syntax is bad (for some reason), so the solution is a new framework-specific JS DSL? As much as I like DSLs, this is hardly a great revelation that justifies the tone of the article. There's plenty of prior work here, including in the frameworks the author criticises. And there are good reasons why HTML-constructing DSLs haven't caught on in JavaScript.


To me, all of the code examples in this article look terrible.

Is there any public website out there (not behind a login) which actually benefits from using these types of components with "magic data binding"?

Every time I see examples, I say "Hey, I could build that in a more readable and more performant way just using plain JS or using a template library like Handlebars".

And the answer I get is "Yes, but not for big enterprise SPAs." And I ask: Ok, where are those? And the answer is "Uuh, well, somewhere behind logins there are some, trust me!".

I tend to not believe it.

When I write real world code, I do not change some data value and expect all kinds of components in the interface to change magically. Instead, I write an event handler, which changes some data and then calls the parts of the UI that need an update. Like when a user changes a slider to change the x-axis range of a chart, then I set the data, call the update function of the chart and that's it. No need for components with data-to-ui-bindings.


I work on a large SPA: https://notion.so

It’s a document editing application. A document title might occur in the browser’s titlebar, in the header of the main editor, in a “mention” (a link to the document) - in another document title, or in the text of a document, and in multiple places in the user’s sidebar - like in both their “Favorites” section and in the the contents of their team.

When the user edits the document title, we need to update all those UI bits to render the new title. I have a hard time imagining some imperative code that iterates over all the possible views that may render a title to mutate them. Without binding/data subscription I can’t imagine Notion working at all.


Can you show the code of the "Favorites section"? Because to me it does not sound like it is as simple to update as "Just put a reference in the template". Because what is in the users favorites is probably defined in some other data structure.

Which is what I witness in real life: In theory it sounds cool to just use data in the template and everything gets updated automatically. But in reality it is a mess with a million edge cases. Worse then just calling a list of update functions when the title changes.


Here's pseudocode of the favorite section. The "SpaceView" is a database record that represents a specific user's "view" of a shared workspace. It has a few UUID[] list columns, one of which is the "bookmarked pages" list of Block UUIDs. Methods like `.getBookedmarkedPagesStore()` get a reference "RecordStore" object to a specific column inside the record. Reading the data from a RecordStore in a component implicitly subscribes the component to changes to that column. To render lists in general, we use a <List> component. It manages drag-and-drop behavior and efficient updates, react keys, etc.

    export function SidebarUserContent(props: {
      spaceViewStore: SpaceViewStore
    }) {
      const { spaceViewStore } = props
      const environment = useEnvironment()
      const sharedPages = useComputedStore(
        () =>
          getUserSharedPages({
            spaceViewStore,
            user: environment.currentUser,
          }),
        [environment.currentUser, spaceViewStore]
      )
    
      return (
        <>
          <SidebarSection
            canCreatePage={false}
            title={<FavoritesTitle />}
            list={spaceViewStore.getBookmarkedPagesStore()}
          />
          <SidebarTeamsSection
            list={spaceViewStore.getJoinedTeamsStore()}
          />
          <SidebarSection
            canCreatePage={false}
            title={<SharedTitle />}
            orderByList={spaceViwStore.getSharedPagesOrderStore()}
            orderByItems={sharedPages}
          />
          <SidebarSection
            title={<PrivatePagesTitle />}
            canCreatePage={true}
            list={spaceViewStore.getPrivatePagesStore()}
          />
        </>
      )
    }
    
    function SidebarSection(props: {
      list?: RecordStore<Array<RecordId<BlockTable>>>
      orderByList?: RecordStore<Array<RecordId<BlockTable>>>
      orderByItems: Array<BlockStore>
      title: React.ReactNode
      canCreatePage: boolean
    }) {
      const { title, canCreatePage, ...listProps } = props
      return (
        <div style={SidebarSectionStyle}>
          <SidebarTitle
            actions={canCreatePage ? <CreatePageButton /> : undefined}
          >
            {title}
          </SidebarTitle>
          <List {...listProps}>
            {blockStore => <SidebarPageItem store={blockStore} />}
          </List>
        </div>
      )
    }
Here's the pseudocode for the main editor view. The document itself is a "Page" block database record. We render editable text with the <Text> component. We listen to contentEditable document changes, and reconcile the mutations with the rendered <Text> components to understand where the user typed and how to update our database records in response to that activity.

All updates to database records happen inside a call to `transactionActions.createAndCommit`. Under the hood, this:

1. Builds a list of commands to send to our server, to persist the user's edit to the database. Once the edits are applied on the server, we notify collaborators those records have changed, so the collaborators can pull new data and re-render their own views.

2. Optimistically updates the local, in-memory version of the database records to reflect the change commands.

3. Schedule rendering views and recomputing derivations of the views/derivations that read from the changed records.

    function PageViewBlock(props: { store: BlockStore }) {
      const handleFavoritePage = useCallback(() => {
        transactionActions.createAndCommit(transaction => {
          const spaceViewStore = GlobalAppStore.state.currentSpaceViewStore
          listActions.append(
            transaction,
            spaceViewStore.getBookmarkedPagesStore(),
            props.store.id,
          )
        })
      }, [props.store])
      
      return (
        <ContentEditableRoot>
          <Text
            style={PageVieBlockTitleStyle}
            store={props.store.getTitleStore()}
          />
          <FavoritePageButton onClick={handleFavoritePage} />
          <List list={props.store.getContentStore()}>
            {blockStore => <DraggableBlockListItem store={blockStore} />}
          </List>
        </ContentEditableRoot>
      )
    }
    
    function ContentEditableRoot(props: { children: React.ReactNode }) {
      const [element, setElement] = React.useState<HTMLDivElement | null>(null)
    
      useMutationObserver(element, mutations => {
        transactionActions.createAndCommit(transaction => {
          const edits = getEditsToBlocks(mutations)
          textActions.applyEdits(transaction, edits)
        })
      })
    
      return <div contentEditable={true} ref={setElement}>
        {props.children}
      </div>
    }
Our React components "just" render the state of our database rows, but because we use a generic auto-tracking state system and publish change events, our views respond in near-real-time to both local and remote data changes. A new hire engineer at Notion can create a new collaborative feature on their first day with end-to-end reactivity "just" by a) rendering part of the record in a React component, and b) updating that data in the record with transactionActions.createAndCommit.

If you're still curious about our data model, I wrote a blog post about it: https://www.notion.so/blog/data-model-behind-notion


Well, this isn't really going to help the case, but yes, behind logins there really are some, trust me. Tongue in cheek aside, where I used to see this a lot as a contractor was on projects where multiple companies were hired and each was responsible for some small part of the system that had to interface with the rest of it. The core problem is that you might not even know which parts of the UI need to update when your data changes, so what you advise is not always possible.


> When I write real world code, ..., I write an event handler, which changes some data and then calls the parts of the UI that need an update.

That's your choice, and I'd argue you're creating messier code slower than someone who uses a UI framework that deals with reactivity in a principled manner. Having to synchronize the UI and data manually creates room for subtle desync errors which just can't happen in, say, Vue.


On the flip side with reactive programming it is very easy to just connect up all the data to UI components and have a bunch of unnecessary redraws.

It can encourage a set it and forget it mindset.

In iOS programming, there are many articles about how easy it is to cause too many redraws with SwiftUI, leading to performance issues and a bad UX.


I would love to see you post source code like this, for any sufficiently complex frontend. Theres a reason people don't do this.


Can you give an example of a "sufficiently complex frontend" which is not behind a login wall, so we can actually all look at and discuss it?


Someone already linked Notion.so and you didn't seem to find it complex enough?

The reality is there's a continuum between what is fluff and what is providing value you don't see.

I agree a lot of web development ceremony is misguided and of dubious benefit, but you're seemingly against even basic state propagation.

But you also seem biased in thinking of systems where you can hold the whole thing in your head.

When a site like Facebook shows you a chat message, there are is the an iceberg of functionality that you don't see and can't imagine with that bias.

You think "I'd just use JS and add a div styled like X", and Facebook probably has more JS to enable defining what X looks like because that div can have anything from a text message, to a video, to a chess move from a FB game, than you can picture for an entire site.

The analytics and tapbacks and a million little features that would make for hundreds of listeners on some seemingly simple component

At the end of the day not everyone is making Facebook, so I agree people are complicating things for dubious benefit, but not so much that basic React is problematic: even for small applications it's a cheap way to support the "combinatorial explosion of edge cases" problem of product development.

You add one edge case to a state change you wired with plain JS and things are fine. But then you add an edge case to that edge case, and so on, and eventually you'll either just have a worse version of what React offers, or an unapproachable mess of code.


Notion is behind a login.

So not easy for everybody here to look at and discuss.

If there is not a single public website out there which benefits from frontend frameworks with data-biding components, that probably tells us something.


You're not familiar with Facebook? Google Docs?

I mean it does tell us something they have logins: it's expensive to build complex single page applications

There's no incentive to do that for free and in the open.

I started my comment by explaining why you're not going to find the golden case you're digging for: even when provided you'll haughtily share how jQuery could do everything shown, and as I explained you don't see most of what is being done.

Everything is easy until it's not. Maybe you should share examples of things you worked on with a larger team and show us that we're overestimating the limitations of manual state updates.


That's an interesting position. Could you explain in more detail what you mean? What is the correlation? Asking without sarcasm.


The open web is enormous. Billions of pages.

If in this gigantic sample of websites, not a single one benefits from the techniques which people here describe as essential to build complex UIs - that would tell us that this is either false or that there are not complex UIs on the open web. The latter being unlikely, given the size and variety of sites out there.


Your logic doesn't track.

"

If a V12 is so powerful, show me an economy car with a V12.

If in all of the economy cars in existence, none has a V12, then either it's a false statement, or there are not V12s in economy cars. The latter being unlikely, given the size of the economy car market and the variety of models out there

"


It's a good writeup but I dislike the tone. The entire thing can be summarized by saying the author dislikes custom syntax and compiler when js and the Dom api are technically enough to potentially make a good dev experience without any syntactic fluff.

In any case. It's an interesting thought but I disagree with the fact that transpiling is so last decade.


I mean, this really isn't any different than the existing solutions, is it? Unless I'm missing some fundamental revelation, this is just decompiled JSX with a desire for Lisp-like syntax. Who can blame him though, Lisp is great in many ways.


Haha, the alternative the author proposes looks like either Mithril or jQuery-over-JSON. Those patterns (done like that, not jQuery) have a very concrete problem of failing 90% of the rendering in case of errors ("Don't have errors in your page then." "There weren't errors in my page prior to this breaking change in ES/DOM API."), and they aren't ergonomic (matter of taste maybe...) if they aren't transpiled from something more palatable.

I'm not really sure about why "that" would be more modern than "this" (reactive frameworks), too.


Personally I don't like JSX or "code generated html" and I prefer to quickly see (and visually parse) HTML to get what it does, so I'll keep my templates thank you.

I'm not sure how "v-if" is a monstrosity compared to the proposed solution.

Actually, based on the title, I thought it would be a novel approach to web UIs.


Let's face it, HTML is a markup language and that's the presentation layer. It allows for anyone to inspect a page and find a component or UI element.

What Reactive frameworks got right is to respect that. Separate presentation (HTML) from the logic (JavaScript: props, derived, methods, etc). Directives à la Vue are easy to understand and inject in the HTML markup.

What they also got right is to modularize UI elements into components.

This makes for any developer that master HTML to rapidly understand the code of any front-end code base.


What the author is suggesting is something very similar to hyper-dom-expressions[1] as they are used in Solid.js. I've tried using those because they look like a nice vanilla JS solution. What might not be obvious from the start is that all the "reactive" parts of the UI will need to be wrapped with an extra closure, ala `()=>h(...)` sometimes multiple levels deep, otherwise parts of the UI will not get updated when needed. Maybe this is a implementation specific thing to SolidJS but it makes the code look ugly and it was hard to figure out when and where to put the closures. I ended up just using JSX for SolidJS, sometimes you just need to compromise.

[1] https://github.com/ryansolid/dom-expressions/tree/main/packa...


Wow, this article really struck a chord with me. I totally get the frustration with mainstream UI frameworks, but let's not throw the baby out with the bathwater. These frameworks have their limitations, sure, but they've also pushed web development forward in a big way. The author suggests going back to the DOM API and creating a custom JS API, but that's just asking for more complexity and manual work. Mainstream UI frameworks have abstracted away a lot of that complexity and given us convenient tools for building interfaces.

And yeah, I know everyone loves to hate on the syntax and approach of frameworks like React, Vue, Svelte, and Angular. But guess what? They've been widely adopted and proven effective in real-world scenarios. They provide a familiar syntax and conventions that make collaboration and code maintenance easier. Instead of completely dismissing these frameworks, let's focus on improving them while staying open to new ideas.

I get it, some folks prefer alternatives like XAML/Silverlight/WPF or Android with Jetpack Compose. And hey, those technologies may have their advantages too. But before we jump ship, let's carefully evaluate the pros and cons of each option. Consider community support, learning curve, performance, and scalability.

At the end of the day, there's no one-size-fits-all solution in web development. We need to understand our project requirements and make informed choices. Let's keep learning and adapting to new technologies while respecting the merits of existing solutions.

What about frameworks like htmx though?

While they may not be as widely known as React or Angular, they offer a different approach to building dynamic web applications. htmx focuses on enhancing server-rendered HTML with minimal JavaScript, allowing for a more progressive enhancement approach.

By leveraging existing HTML and server-side logic, htmx can provide a simpler and more lightweight solution for certain use cases. It's definitely worth exploring and considering htmx as an alternative when evaluating framework options.

However, it's important to note that the adoption and community support for htmx might not be as extensive as some of the more mainstream frameworks. This can impact factors such as available resources, documentation, and community-driven improvements.

Ultimately, it all comes down to understanding the specific needs and goals of your project. Consider the trade-offs involved, evaluate the resources and community support available, and make an informed decision based on what aligns best with your requirements.


Maybe I'm just getting old but every time I see yet another shiny new thing that uses Javascript I just eyeroll massively. I can't fathom how frontend devs are ok with the pure madness that goes on in their sector.

Give me a plane old copy of Tailwind + Laravel Blade Components + Livewire any day, it's infinately quicker to work with and the end result is far more maintainable.


Things have slowed down a lot compared to 5 or 10 years ago. The recent shiny new things are all quite similar to each other. The amount of churn is overstated at this point. For beginners I’m sure it’s still tough because there’s a lot of noise.


> I can't fathom how frontend devs are ok with the pure madness that goes on in their sector.

It’s interesting madness and good stuff comes from it. You’re not obliged to use every library you see in a production project, you can just read about it and think about why it’s doing what it’s doing. Or you can ignore it totally!


This might be really good satire.


Isn't this basically how Mithril works?


Been a while since I did UI work but what happened to xaml/silverlight/wpf?

I had the easiest time with with some complicated UIs when .Net came out with that stuff. Dealing with all other frameworks for the web, andriod, apple, gtk etc always felt clunky after that.


WPF was left to wither about the time .NET Core came out. In typical Microsoft fashion, they "deprecated without deprecating" it. They instead worked on the successor, MAUI, but were beaten to the punch by Avalonia. MAUI also took a "mobile-first" approach; There's tons of documentation about making mobile apps for it, but not as much for desktop apps. It's like they're trying to upset React Native. Avalonia, instead, focused on desktop apps, and seems to have won out in that space.


Well ... XAML and friends did not fly into the web. That is what happened.

And the reason why the web feels clumsy, is because HTML is a document object model (for a floating and not paged document) and not a UI toolkit. And that will not really change. HTML made some moves to improve (like the flex display model) but still has not reached some of the core attributes of the WinForms or WPF layout models.


> HTML made some moves to improve (like the flex display model)...

Except that was CSS, not HTML. HTML is still just a representation of the DOM. Even the attempt at "semantic" elements (<section>, <article>, etc.) has basically failed, and been relegated to ARIA attributes. The "web" has settled on the trifecta of HTML for markup, CSS for layout, and JS for interactivity.


Articles that develop a "change everything I dislike instead of changing my own mindset" mindset are always interesting reads, because while I can agree with them I can also disagree and from there I want to propose something else. We have tools that allow us to develop UIs, we tend to be tired of their fake or true differences, but I honestly fail to design and implement something better.

In the end, one could ultimately say "DOM is the wrong abstraction" but that's kind of weird to me; a tree is almost the perfect representation of a document and even when I dislike xml like representations I often implement stuff that allow me to express documents under the form of a forest and in the end I have a tree-like representation of a document written in whatever "language" I want (an object, an array of objects, JSON, org-mode) and a tool to translate this representation into components and ultimately into html.

TL;DR : Tree like representation is a good way to describe a document, if you don't like html, you still can implement a medium that allow you to express it via another set of abstractions.


I am sympathetic for the bold title but not the content. Starting with "Who says HTML is the right abstraction?" I would say that, two strong abstractions for UI/UX are:

1/ If people around the world are doing the almost exactly the same web page in terms of behaviour, create a declarative way to launch a web app with zillion used behaviour.

2/ Create a designer for the UI.

IMHO UI/UX frameworks require a lot of innecesary knowledge. They seem more complex that writing the logic of the app itself.


> Using display: none in 2023?

As someone who hasn't built a website for ten years, what's wrong with `display: none`?


Why web+js is assumed as containing all UI frameworks? I am sure the reason is to get clicks.


My framework is little different :-) it was launched couple weeks ago, here we go: https://realm.codes


Hey... UI framework where I can actually read and understand the examples.

Brilliant idea here, I like.


For me, that link only shows a page with a nicely rendered script and link tag.

Safari 14.1.2


Can't see the examples on mobile unfortunately.


ctrl-f Elm yields no results. It seems Elm is not even part of the discussion anymore.

I get it, it didn't get a release in 4 years, but the path it showed was pleasant and robust. Why did nobody pursue it further, or did someone, and I just don't know about it?


I used Elm for a while (even gave a conference talk about it in 2015) but I don’t really know what Elm would add to the discussion. Elm’s template syntax is only superficially different from JSX. It’s nested function calls, which is exactly what the JSX transform turns JSX into.

And Elm overall is really not very different from React. What happened is that TypeScript got really good and took over. You don’t need a different language to get great static typing.


I don't think thats the reason Elm went away.

Typescript's type system isn't sound and it's overly complicated. Elm's type system is by far more robust, sound, and much much easier to learn and reason about.

Elm went away because:

    1.) It doesn't have a "Microsoft" behind it to champion it. 
    2.) It's a functional languages with "weird syntax" (I happen to think the ML style langs are beautiful, but to each their own)
    3.) Probably most important, the maintainers and the community around Elm imploded.


IMO TypeScript’s unsoundness is a red herring. It’s a wise pragmatic design choice, and the alternatives have tradeoffs that were judged to be worse. Whether people run into the particular problems caused by TypeScript’s particular sources of unsoundness is an empirical question. I can’t remember a time it caused me an issue.


any, any, any, any, etc.


I think author should do some android with jetpack compose and find peace.


I started building an app using plain Web Components (HTMLElement subclasses) and I've been blown away by how simple, fast, lightweight and versatile it is. Some lessons I learned:

- You don't need reactivity when you have good encapsulation.

- You don't need bundling for your main app (though some of the modules you use may benefit from bundling if they have a lot of small dependencies). You can preload dependencies using the link tag with rel="modulepreload" to remove latency for nested sub-dependencies so your app loads really fast and it gives you a lot of control.

- Building an app controller to handle front-end routing and instantiating your page components is actually very easy. It doesn't require much code.

I think the first one was the most surprising for me. I remember a core problem with jQuery was that the imperative approach didn't seem to work for single page apps; for example the user would change to a different page but some callback from an earlier request would be called a few milliseconds later and jQuery would try to update an element which no longer existed from the previous page...

What I found with Web Components is that because each page is its own HTMLElement and all its logic is confined to a single component, it naturally garbage-collects after itself. You can add event listeners all over the place inside your page component and when you change page, it becomes detached from the DOM and so they are all cleaned up automatically once the page component instance is no longer referenced. There is no DOM timing issue because changes to the component's internal DOM can happen independently from the main HTML DOM, even when the component is detached from the main DOM.

Also, you can have a render() method which clears the page components' DOM and creates it from scratch every time just like in React... Works very well with sub-components having their own render methods too. You can call it as many times as you like and don't need to worry about cleaning up event handlers because when child components are removed, their handlers are also automatically marked for garbage collection. Also, it gives you a lot more control as you don't necessarily need to re-render the entire component every time some data changes; sometimes you just want to update the value inside a single child element; it's a lot more efficient. You can mix and match; when there is a substantial change to the page, you re-render the whole component, if it's just a single attribute change, you just select and change that single child component.

I learned that the real game changer of React was probably not reactivity, it was the ability to fully encapsulate logic and markup inside components. I find that I actually like the additional control and flexibility provided by the imperative approach and it doesn't add much more code (and the code is a lot easier to follow/more readable). With React and others, there are often challenges related to fine-grained control; like when data is loading, it's a little bit messy if you want to show a loading indicator instead of rendering the value as the number 0 for example. Also, I find that many React apps suffer from multi-rendering issues where some heavy components are rendered much more frequently than they need to because several small pieces of data change in quick succession.

Reactivity is a euphemism for 'giving up control over how your app is rendered' but it doesn't add as much value as people think.


What if javascript and css frameworks are here just to push the limits of what a browser can do natively ? :-)


If js had trailing closure syntax like swift this would be a no brainer.


the author should write a wrapper for React's createElement (it should be easy enough to do) and then use it for a whole project


Arguing over syntax is a bit sad. It mostly just doesn't matter. The author like so many is judging surface level matters more than anything else, and there's just not really big importance to it.

They try to stage a huge freak out over conditional rendering. This feels so low stakes. Personally the React solution of just using a ternary & passing null makes all the sense in the world, leverages the language well IMHO. But we get:

> Pardon my British, but what the schlocky-donkey rubbish is that? If-statements inside a view tree with fallback to null?

Without real explanation, just loaded unexplained opining.

And again, oh no, we made some system to handle dynamic cases, when talking about lists, but this time the author tries to scare us with it being invented, maybe gasp not stable!

> Fictitious syntax, templating, directives. And where is the guarantee that none of this will change in the future? There’s no such guarantee. And it has happened before, am I right mr. React and mr. Vue?

I'm less familiar with the others but Reacts solution has been the for-loop we see here for forever. These tools are respectably stable. Yes they invent ways of doing things but the author is freaking out because that's insufficient for them; the idea seemingly has to be agreed to by everyone then encased in concrete such that it will forever be exactly the same. Personally I love that the web can progress, that it's not a singular fixed platform like that.

And then a lot of their DOM solution looks like a more componentful React might, with some renderprops.

> Because you need to have a lot of time to experiment and be able to accept new realities and the failure of current approaches.

Agreed. And I do think the frameworks are stuck. But it's not the question of hacking out some html; anything will do for that. The real question is architecture. It's what do our data stores or signal lling systems look like, how do we figure out what to render well (or do we just vdom forever, and even that was greatly speed up & shaped by redux & other stores)? These at least also have good pokers in the fire.

But most web frameworks work almost totally on the main thread. Most don't do a good job with incremental loading. These are the real structural matters, are the depth we need to be exploring. But which this debate over how-do-we-rasterize-some-DOM debates, which have been going for so long, gloss over. We keep rehashing something that doesn't matter much, that hasn't changed all that significantly since mod_perl. The real question of how web UIs work, how they are made fast, off main, has barely been delved into.


but ... the last decade was less than 3 years ago!

Are we all supposed to be using tech stacks newer than 3 years old?


I am so glad I read that. I feel like I stumbled upon a blog post that perfectly encapsulates many of my own thoughts on web frameworks. The author has managed to articulate criticisms that I’ve long held but struggled to express. I felt compelled to share my own experiences and viewpoints, as someone deeply committed to building user interfaces that are rooted in the foundational elements of the web—HTML, JavaScript, and CSS.

The Pitfalls of React and Other Frameworks

What I’ve disliked about frameworks like React is that they don’t fully respect HTML syntax. React offers something that looks like HTML but isn’t quite it. This forces you to juggle two parallel but distinct systems in your mind—HTML and JSX. This dissonance disrupts what could be an organic understanding of the operational principles of HTML.

Philosophy of Building User Interfaces

My approach to building UI is deeply influenced by a philosophy that leans toward artistic or sculptural expression. I believe in cleaving close to the ‘material,’ by which I mean HTML, JavaScript, and CSS—the core components of the web platform. I reject the use of domain-specific languages and avoid CSS processors. I strive for an approach that harmonizes with the given components rather than complicates them, even as I stay up-to-date with new features like async-await.

Ergonomics and Developer Experience

Of course, developer experience is highly subjective. What feels right for me won’t necessarily be right for you. But my goal goes beyond creating a tool that is merely comfortable; I believe there is a right and a wrong way to build frameworks. That’s why it was refreshing to read a perspective that aligns so closely with my own.

Key Takeaways from the Blog Post

The author mentions two vital points that resonate with me:

1. Respect the platform: This is a core tenet I’ve followed throughout my career. I utilize HTML syntax for templating and JavaScript template syntax. For scoped styles, I leverage the encapsulation provided by the Shadow DOM.

2. Minimize introduced complexity while embracing inherent complexity: This point beautifully encapsulates the essence of what it means to build ergonomic tools for UI development. We should aim to write minimal ‘glue code’ that ties the given web platform features into a coherent whole.

Final Thoughts and My Work

Although I think my own framework (good.html) has room for improvement, I’m happy enough to use it daily. I’ve shared my code for anyone interested in a different approach to web UI development. Check it out on GitHub: https://github.com/00000o1/good.html

Also if you want to see lots of code that utilizes this in real production, see: https://github.com/BrowserBox/BrowserBox/tree/boss/src/publi...




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: