What differentiates front-end frameworks
themer.dev
themer.dev
I radically disagree with this statement. Angular Signals (and signals in general, as in SolidJS) could not be more different from React's change detection model, and they are not particularly similar to Svelte stores either.
In React, your component function is a render function, which reruns. React diffs the state object when `setState` is called, determining which part of the DOM to update.
Signals-based solutions are generally much more fine-grained: the framework knows which portion of the DOM was affected by the signal, and does not need to diff the entire state object. This "surgical" approach requires more explicit state management on the part of the developer, through the use of Signals to wrap the application state. However, DOM nodes can be updated without doing a large, expensive diff. (As a corollary, the component function is typically a create function, not a render function.)
The developer experience is quite different as a result.
How does Svelte differ? I’m somewhat familiar with SolidJS, and had always assumed Svelte was somewhat similar.
> True to its de-facto tagline, change detection in React is “just JavaScript.”
Then in the example, the author updates a variable with `setCount(count - 1)`. That's not "just JavaScript". Just JavaScript would be `count = count + 1`.
This isn't to make any kind of judgement on either approach though, I personally really enjoy the DX that Svelte offers.
Signals as a concept existed well before React and I think part of the genius of React is actually not using them. In a way a signal is just a very simple version of RxJS that Angular is moving away from, with a lot of the same downsides, just without all the pipe/abstraction mess.
Except that with the introduction of hooks (aka "OCaml 5.0 effects, but in JS, as a UI framework") you get some of the same interesting issues cropping up in React codebases as well, just spelled differently (stale closures, implicit dependencies, weird debugging issues)
The proxy stuff I don't trust. Burned me once, never again.
I believe this to be generally pointless. Diffs are not that expensive, DOM changes are. The only case where this would help is you have a very large diff but a small amount of actual changes. React offers tools to handle this without changing the entire state management paradigm.
Er, what? That's not true at all, even for class-based components. `setState` merely queues up another render of the function and its children. There is no diffing, except for the new DOM returned against what is currently rendered.
Change detection is nothing but a hack to get around the fact that interacting directly with the browser DOM is very slow and blinky.
Imagine a world where interacting directly with the browser DOM didn't suck, then none of these libraries would exist.
The crux of the problem is that the browser immediately reflects changes to the DOM to the screen. And when you make a bunch of changes to the DOM you immediately see a bunch of changes happen, with portions of the screen being blanked out, and layout changes happening, and a whole bunch of other nasty stuff happening immediately, which all sucks. And updating a physical screen is slow too, double sucky. Change detection is a technique for minimizing updates to the DOM to avoid the suckiness.
I implemented word processors, and I've used a technique called 'double buffering' to rerender complete pages off-screen, fast. And then update the screen smoothly. If we used a proper word processor engine to display our UIs instead of a browser engine then we'd have no need for React etc... After decades, Chrome finally has a rational equivalent to this technique called the View Transitions API.
My hope is that the days of doing change detection are numbered and we can finally leave all this change detection crap behind us.
A performant big pile of mud is still a big ball of mud.
Web components are objects and they have properties that can be set. The entire web components community - which includes the developers of apps like Photoshop, Reddit, Chrome, Firefox, and a lot more - passes properties down through trees of web components _all the time_.
You can declaratively pass objects between web components in every web components library out there like Lit or Stencil.
Now, you may claim that that doesn't count because the declarative part is implemented in non-standard userland libraries, to which I would reply:
1) So what? React is a non-standard userland library. You can't pass data declaratively between React components without React. At least with web components there's a standard _interface_ for the components so that many different libraries can implement the declarative parts in a completely interoperable way.
2) Yes, you can't pass objects around in plain HTML because plain HTML doesn't have references to the objects in the first place. Even if you did add a way to set properties in HTML, what would you set them to?
2b) This is actually likely changing as the Template Instantiation proposal moves along and possibly gets the ability to make property bindings. This will be useful for declaring custom elements that accept properties. But the question remains: where do those properties originate from? Most likely JavaScript, because HTML doesn't have any.
They capitalized Web Components, I think they're talking about what browsers natively support and not a library or framework.
This makes it a non-standard library-specific method of passing things.
I have no idea what you're arguing against.
There's literally no way to pass objects as attributes to web components. Web components had a great opportunity to get rid of attributes/properties dichotomy, but they doubled down on them.
> At least with web components there's a standard _interface_ for the components so that many different libraries can implement the declarative parts in a completely interoperable way.
Of course there's nothing standardised, and nothing interoperable. Because if one web component exposes its API through attributes, and the other one through properties, and a third one through both, never the three shall meet. Without library-specific hacks.
There's a reason the "standardized" lit uses a custom DSL to distinguish between things:
`<some-component
attribute="string only"
?boolean=${boolean}
.property=${any_js_variable}
@event_name=${callback_function}
>`
So much standardization.Edit:
Stencil uses JSX (non-standard), so it doesn't care and probably sets properties directly, skipping attributes. For object props and HTML it says it explicitly that you cannot set them (of course): https://stenciljs.com/docs/properties#object-props
> But the question remains: where do those properties originate from? Most likely JavaScript, because HTML doesn't have any.
Indeed. That is another issue with anything web-component-related. Moar Javascript. As if we don't have enough. There are now dozens of more JS APIs existing just because of web components, and even more are incoming: https://w3c.github.io/webcomponents-cg/2022.html
This is so very much not true. On what basis do you even claim this?
Web components are JavaScript objects that extend from HTMLElement. They all share a common interface of attributes, children, events and properties.
You can get a reference to any web components any set a property on it:
document.querySelector('my-element').someProp = {};
This works on all web components. It's interoperable because there's no special React, or Angular, or Vue version of an API to set properties.> There's literally no way to pass objects as attributes to web components
How do you even get a reference to an object in HTML to pass as an attribute, if you could?
And who cares? You can pass objects as properties to web components. Attributes are string-valued, why would you want to pass an object to them?
I worte the basis, and you completely ignored it.
> And who cares?
Ah yes. The mantra of all web-component zealots. "Who cares".
How it started [1]: "we have too much Javascript, we rely on too much Javascript for all our functionality, empty body tag is the bane of web sites" etc.
How it's going: Who cares? Dozens of new JS APIs! More JS APIs coming every month. Why would you want to do anything with web components outside of Javascript? Declarative? Oh, in any of the Javascript libraries. Javascript Javascript Javascript Javascript Javascript.
> Attributes are string-valued, why would you want to pass an object to them?
That is not what anyone wrote. Literally not a single person.
Anyway, this is hopeless. Web Component zealots are absolutely deaf and blind to anything outside of their world where goals shift faster than grains of sand in a hurricane.
[1] The original pitch for Web Components: https://fronteers.nl/congres/2011/sessions/web-components-an...
Maybe a bit verbose, but here is an example https://jsfiddle.net/8kvucm9f/5/ in the context of the blog post (and with my preferences of doing things; there are just many different ways of "writing web components", and can adapt many use cases).
Also, by using their HTML attributes (id="", name=""), it is possible to make really nice features with CSS.
Finally, they can offer a clear API (just like the <img/> or <video/> or <input/> elements), to the users of these elements.
They can be inserted, to give "markdown" documents (or .org mode etc. if it is converted to HTML), JSX like features, by being "just embedded HTML text".
It is super powerful, maybe feels a bit scary at first, but all problems seems to get solvable with clean patterns.
If you start with such a statement, it would be best to follow up with proof instead of something unrelated.
someWebComponent.data = { foo: "bar" }I’d like to see a new mode introduced ala “use strict”. I know the big brains at the top hate this but we need a way to shake off some legacy especially in the DOM. A few changes to its semantics could dramatically speed it up. And then the second part would be a way to share events and DOM across workers so we can put React essentially off the main thread. These two changes together would make websites able to feel like native apps.
It's my observation that React and similar frameworks really help to bloat the DOM.
Now someone will say it is how people misuse React and similar frameworks.
and then I will say if large parts of the population using a technology make the same misuse of it, even people who know better, it seems like the technology supports that misuse and is to blame somehow.
But with JQuery I was able to create adaptive UIs by applying 'transforms' to the DOM, I really miss that. Think of the way that 'tag helpers' can apply cross-cutting transforms to Razor Page applications, I used to do things like that with JQuery.
React et al cuts me off from both the browser DOM and it's own virtual DOM, so this I can no longer do this. I have to do everything the React way. Developing with React is far less powerful than JQuery. I still find modern frameworks to be a kind of straight-jacket. I hope to have my transforms back in a rational way someday.
While I personally like React, it's pretty tricky to use in reality. I have found that its idiosyncrasies make it less resilient to suboptimal contributions from engineers that are still early in their careers.
Broadly, the projects I have entered using React tend to be pretty wild, messy and unreliable.
There is cross over though, Angular projects using Redux (ngrx) are horrific. The criticism of Angular for me is the lack of control you have over the compiler, dependency versions and testing strategy.
Svelte and Vue are both interesting, but they use custom file formats (.vue, .svelte) which can add an extra layer of unreliability to projects using TypeScript and testing frameworks.
The advantage of Angular is that it's an ergonomic abstraction that allows optimisations to occur at the engine level. It's more like an ORM, where React is more like writing SQL queries directly.
If you haven't I recommend having a look. If found it amazing for maintainability.
You have to be carful to structure everything well. If not you blow up the number of messages in one file. But once you get past that it's really amazing.
> You have to be carful to structure everything well.
This essentially sums it up. I can be careful, but it's impractical to review code to ensure it's also structured correctly when working on a team with lots of contributors with varying experience levels.
In my experience, It's also more difficult to teach MVU than it is to teach templating with automatic reactivity.
For simple use cases templating is much better as well. It's only in complex state management that I find MVU is worth it.
That said, it was a nightmare. I think we had state managed by vuex, and I just needed to add a new data point to the component and display it. But the data needed to be added to state…so I think I touched 6-7 files, adding mutators and updating definitions etc.
The experience put me off of React, though I do imagine a lot of that comes down to how the code is initially structured and maintained. It’s clear that whatever they were doing was more “make it work now” and it so much worrying about the future.
I kinda doubt it.
So then you'd have to store some state in JS, and some in the DOM, and again you get a syncing problem, since you lost your single source of truth.
Or did I misunderstand your comment?
The thing I have run into over and over again is that when we try to pretend the system is Y when it is in fact X, inevitably the impedance mismatch results in 1) bugs that should be easy to reason about but are difficult to fix, and 2) a form of pulling the ladder up behind you.
If I want to continue to work on interesting things I have to be able to carve out chunks of my code to gift to #3 on the bus number list, so I have the bandwidth to double down on some other topic or expand into another.
I know which side my bread is buttered on. Many don’t. Which is why I have a more consistent supply of mentees than many of my peers.
Who did you convince?
The DOM API sucks, so React et al went all in with state-as-objects. IMO it was the right call.
Talk about impedance mismatches.
But the funny thing with fractions is that if go above a threshold and come back from the brink, the path back is a smaller number than the path out. So if you go from 8 to 10 steps that's 25% worse and if you undo that bad decision you are getting 20% better. So you want to be careful to compare sustainable to unsustainable and not the other way around, if you follow me.
Well, I can see now that while I expressed my dislike for change detection I didn't paint a good picture of why I think we'd be better off without it :-).
While I appreciate React's declarative programming style I dislike the fact that React (and all the change-detecting alternatives) force me to interact with the DOM through their APIs.
JQuery allowed me to do whatever the hell I wanted to the DOM, but the resulting screens updates were very ugly. And yes, JQuery resulted in ugly and unmaintainable code but that's not on JQuery, there are rational ways to apply transforms to a DOM.
I want to "do whatever the hell I want" to the DOM because I want to apply cross-cutting, adaptive transforms to my application, like I could with JQuery. And I think that we'd all be better off for it. In the transition to React-like frameworks we have lost that ability
The view transition API lets me start a transition, do whatever the hell I want to the DOM, and then update the browser smoothly.
So what I'm imagining is a component-oriented framework like React that doesn't lock me into a component-only API. A framework that, when rendering occurs, starts a transition, let's me do whatever the hell I want to the DOM, and then updates the browser smoothly without doing change detection.
And the reason I would like that is because, while React's declarative, component-oriented development approach is nice and all, it's also very restrictive.
Reacts prevents me from directly traversing and mutating the DOM, and it's own virtual DOM, because if it did then it can't efficiently do change detection.
If we replace change detection with transitions then we can "do whatever the hell we want" (hopefully not in an unmaintainable JQuery way) and still have smoothly updating displays. We'd have a framework with all the benefits of React and without the restrictions.
Anyway, that's my best shot at explaining myself :-).
I needed to do calculations and reading bounding boxes from the DOM initially and on resize. Basically a hack to get around CSS limitations.
It was crucial that this is fast enough to avoid flickering.
I wouldn’t have attempted this with react. I think it would still be possible with useEffect, but I tried the most lightweight and fast by default approach that was feasible.
Have a look at lithtml.
Aside:
That’s why I‘ve been gravitating towards approaches that have much simpler execution models.
You can still do declarative and functional. But you have more control when needed, create _much_ smaller bundles, have fewer dependencies, better default performance, allocate less garbage and you can reason about your code in more fundamental ways.
In cljs this would mean to not use a react wrapper.
However I personally try to avoid using any deps for frontend, and that includes cljs. Any dep needs a justification IMO.
That justification is often not good enough, since I’m mostly writing „interactive documents with some fancy parts“.
If you’re writing something like nextjournal, roam, data rabbit or similar then it’s a different story.
I know there have been earlier tricks to pop elements off the DOM, modify them heavily and then pop them back on. I wonder if it would be better to a) provide a way to mark a node and it’s children as suspended reflow, or b) provide a virtual view where you can do operations on off-DOM nodes including ones that typically trigger reflow. c) something else entirely
This is not really true, or at least hasn't been for many years.
Change detection's primary purpose is to let other code know when something has changed, and what changed. You could theoretically re-render all your DOM based on that information, and in many cases that works much better than people expect. But the DOM is stateful, and truly large trees of 1000s of nodes are too slow to update, so frameworks try to also do minimal DOM updates.
> The crux of the problem is that the browser immediately reflects changes to the DOM to the screen. And when you make a bunch of changes to the DOM you immediately see a bunch of changes happen, with portions of the screen being blanked out, and layout changes happening, and a whole bunch of other nasty stuff happening immediately, which all sucks
This is also not really true. The browser doesn't update the screen until an animation frame. Anything you do synchronously is not rendered to the screen until code yields to the event loop. Even many async things, done on the microtask queue, block the next animation frame giving us visually atomic updates.
Lit, for instance, uses this to get async, batching rendering without unintended partial renders of the screen.
Time for a new state-ful GUI markup standard so we don't have to rely on the whacky DOM to get expected and common GUI idioms.
Maybe build the "engine" on top of the Tk or Qt kits to avoid starting from scratch.
I'm absolutely not a web dev (as this comment will make clear), but I'm very surprised that browsers haven't been doing this all along. I just assumed that they did.
If you were to go in this direction, you would eventually make the DOM less DOM-ish, and the painting mechanism more DOM-ish, effectively shifting everything one place and going full circle back to the frameworks.
Node trees can be created without attaching them to a document. Then the whole tree can be attached with one call,
There’s no need to attach nodes individually. I don’t know why anyone would want to do that.
Without it all app paints had a noticeable lag.
Change detection remains a common UI issue, even in native UIs. While rerendering everything on each UI loop is possible, as complexity increases, optimizations involve detecting changes. Smalltalk introduced MVC to identify changes and update the UI. Java Swing and Qt also adopted similar mechanisms with different names (observers, signals, and slots). Apple's Cocoa employs a variant of MVC as well. Change detection has historically been a common problem even in Win APIs.
I'd still have to use a framework for componentizing my components, scoping CSS, a namespaced store, etc
So, going with the themes of attention seeking hyperbole, I would say the 'single biggest factor', is the ability to find and keep skilled developers in any of these top 10 frameworks. The differences mean nothing when the bigger picture is considered.
Funny example, in Blazor, if you have a mouse move event, by default it will decide that your entire component including children needs to be rerendered whenever the mouse moves by a single pixel. Unless you change state management to manual or whatever.
- had a 3 year head start on Svetle (2013 vs. 2016)
- has major engineering orgs behind it. Facebook started it. Microsoft makes it work with Typescript.
- is easier to get started with. While JS-compilation is common, it's required for Svetle.
Svelte isn't free of pain points. Like any form of magic, it has edge cases. It's better but not "better enough" to de-throne React.
The automatic handling of dependencies and recomputing means you have less control over how updates work.
Also I think it is important to understand the mutations going on in your ui. Having them explicit like in Vue makes it easier to understand what is gonna happen by looking at the code versus the implicit way that Svelte uses.
Svelte trades off runtime size for component size. It was created in the context of infographics for the New York Times online and for projects that roughly line up with that it's pretty much the technically best option.
I like the Svelte authoring experience and introduced it for a few components in a React based low-code platform. The reason I phased it out was a chat component that was ~600 LoC and 50-something reactive variables in a moderately complex chain blew up into ~5k LoC of output. I also ran into what seemed to be some transient invalidation issues. I was short on time to debug this and engage with the Svelte community so I rewrote it in React to match the rest of the system. It's possible I was doing something wrong but I don't have enough confidence to bet on 3.x again. I'll take another look when 4.x comes around.
> Presumably if Svelte were the be-all-end-all of front-end frameworks, it would dominate soon enough?
There's significant network effects around the established frameworks. Nobody gets fired for picking React. I personally think Solid is the best overall technically but the ecosystem and mindshare is smaller and that matters to a company making a business and not necessarily technical decision.
Also, your component sounds cumbersome.
I also do a lot of code generation, and my absolute goal is to have it write code that I’d write if I were doing it by hand. That’s pretty key for me. If the output is better, then good. If the output is doing a bunch of stuff it doesn’t need to be doing because it’s taking my specific use case and making it conform with its own model for doing generic things, I don’t like it.
I was a web developer back when tables for layout, HTML attribute soup for styling, and applets for interactivity were going out of fashion. Semantic HTML and CSS for layout and styling and JS for interactivity were coming into fashion. Divs for layout, class soup for styling, and JS frameworks for interactivity hadn’t yet become mainstream when I stopped.
So my default is lean HTML, lean CSS, raw JS. Maybe JQuery if needs be. It’s an outdated default, but it’s mine. The thing is, I get great load times and performance for what I need. What I need is normal dashboard stuff - though because of the nature of the field I work in, it condenses a lot of information onto a page and that information is updating many times per second.
I don’t seem to get enough performance from the frontend frameworks I’ve tried. I don’t know if it comes from code bloat, or deep call stacks through god knows how many levels of indirection, the way DOM updates are issued, or something else - but it has just never seemed worth the learning curve to end up with something I can’t do myself with admittedly a lot of work.
As such, I find this review helpful. Svelte has caught my attention and I want to give it a go, but if the output is bloaty then that’s a red flag for me. If it’s bloaty because it isn’t doing backflips through the call stack, but is inlining code - that’s familiar territory and certainly something I can deal with.
Svelte's whole shtick is using ASTs from the compiler to stuff at compile time where possible, to reduce bundle size and complexity.
This is fine but having spent a decade of my career doing this, I would never advocate for it in an app with any kind of frontend complexity or a chance to grow into it. The frameworks mostly obviate the need to understand layout thrashing, resource cleanup, and retained state conflicts in the DOM. If you're doing simple stuff these don't matter but they're challenging to fix and more challenging to stay fixed when a group is contributing.
> Svelte has caught my attention and I want to give it a go, but if the output is bloaty then that’s a red flag for me
Your use case is a pretty good fit for Svelte and you're likely to get output you'd find acceptable and given your preferences I think you're more likely to prefer its sensibilities over other frameworks that could provide the perf you're looking for. The tradeoff is kind of like the tradeoff between monomorphization vs virtual dispatch. The Svelte compiler is basically inlining the update code instead of using shared code in a runtime.
This one, id wager. There isn’t necessarily anything wrong with your approach but Id agree that you should try svelte for this reason.
I was advocating/piloting a new framework in the app and was unhappy with the output versus the input and perceived complexity. I spend a significant fraction of my time cleaning up performance issues. A good chunk of that is download size so I care in general about what I'm sending across the wire.
> Also, your component sounds cumbersome.
Sure. It was the classic feature creep scenario.
It sounds to me like you didn’t understand the details of Svelte’s reactivity model, which are very important, and fairly straightforward to learn, but different from what people are commonly used to—and so even if you theoretically learn the model, it may take time in more complex cases for it to come naturally. The crux of these sorts of problems tends to be that reactivity is a property of bindings, not data; and as a secondary effect, mutation is therefore rather hazardous.
> 50-something reactive variables in a moderately complex chain
It sounds also like you’re fighting the framework. I’ve seen stuff like what you describe in some React libraries (e.g. mirroring something DOMmy in React—common, but I hate it because it’s so much mindless duplication, among other faults), but in Svelte at this scale you’re likely to get better results from seeing if you can bag things together (e.g. let x = {a, b, c} rather than let a, b, c), or passing through components rather than reactive variables. But these are vague concepts which may not actually be relevant or applicable.
Svelte is a framework that definitely requires that you work with it, or you’ll have a miserable time, whereas with React you can, to a much greater extent, do awful things and get away with it.
And when you speak of 3.x and 4.x and such—there’s basically no chance any of this stuff will ever change in Svelte, it’s too fundamental. In some cases you might end up with better compiler warnings, but that’ll likely be the extent of it.
This is a reasonable assumption given what I've described. It's been almost two years but from what I remember the problem was updating what should have been the same reactive binding in two different locations. When trying to debug a problem I was stepping through the code and noticed that the indicies passed to `$$invalidate` were different. Checked for typos and shadowed declarations and found none. Rolled back to checkout and found the indicies matched. In the process of undoing/redoing my conclusion was that the introduction of an unrelated reactive binding was the difference. I could have been wrong; I was pretty exhausted at that point.
> It sounds also like you’re fighting the framework.
Sure. In this case it was getting a big chunk of JSON back from an endpoint I didn't control and trying to use a number of reactive variables to select out pieces for display. I've done similar things in a half dozen other reactive/FRP libraries without issue but I assumed I was off the beaten path in Svelte.
I realize that this is empty complaining about other peoples' hard work. I don't have the code any more and I don't have a reproducible test case so I have no problem with anybody waving this off.
Implicit 2 way data binding which makes logic hard to follow in larger projects, same with their reactivity model.
Is the 2 way data binding implicit? As I understood, you need the "bind:" keyword for 2 way data binding.
JSX is the best templating language.
Svelte hides complexity and this can bite you in tracking down issues.
React just feels better to me for a professional project, though I like Svelte.
Instead of easy-to-trace functional logic and pure functions you have a thing more like an electrical circuit, or like a highly advanced jQuery contraption. It's fine and even great for smaller bits of interactivity. It becomes increasingly unwieldy as the scope grows.
(And for tiny bits of interactivity there is HTMX, wonderful in its own way.)
For example:
const cells: Record<string, ReactNode> = { a: "hello world", b: <>hello <b>world</b></>, c: <Icon src="world.png" />}
The closest you could get in Svelte, is creating three new components (3 entire files), which are then rendered using `<svelte.component this={HelloWorldComponent} />`.This becomes a problem, when you build composed components that decide their layout based on logic thats too complex to express in CSS or Sveltes templating system.
For example:
- A component for tabbed navigation that automatically becomes a sidebar on desktop.
- React Router defining its entire navigation tree [1]
- Ant.Design defining the columns of the table, where you can trivially supply a short callback to render a cell [2]
[1]: https://reactrouter.com/en/main/routers/create-browser-route... [2]: https://ant.design/components/table
Some types of errors cause your application to halt (which might feel like a UI freeze). There's no way to catch these errors and show an error page, show an error message, or report the error to an error tracking service like Sentry. I'm subbed to the github issue for this and never saw a fix.
Poor composability of components. Components in svelte are awesome in the general sense, they're just missing this higher-level code organization possibility that react, solidjs, and vuejs users have cozy versions of.
The docs claimed a specific function worked like nuxt's asyncData function. Whoever wrote that has no idea what nuxt's asyncData function does, because that function worked very very very differently.
This is completely wrong. The "naive" approach is the one you should always use, with the onpush strategy reserved for breaking certain cascading situations manually. But the default approach works perfectly fine, it is performant enough, and even more when compiled for production, as it runs only once (as compared to twice in the debug mode). The author is incorrectly assuming that the change detection is slow because it is automatic. That's the entire point of the framework btw.
* API calls
* Templates
* CSS
* Controllers, etc.
My usual technique of finding some text content, looking for an i18n file and working my way backwards is tedious.
also with react dev tools you can click somewhere on the page and see the react component, it's props, etc. similar tools are available for other frameworks
1) Provides a common externally defined abstraction, so that developers require less training and are more disposable.
2) Supplement skills of unskilled developers
The reason frameworks do not primarily solve for change detection, is because the browsers already provide that. Frameworks provide an additional solution riding on the browser's solution as an abstraction. Framework don't even really solve for a common set of standards either, because the browser provides that too. I really want to say that major frameworks provide for a more narrowly construed set of APIs and design approaches, but the APIs on modern frameworks are absolutely massive, so I cannot say that either.
So... frameworks are really just an abstraction to achieve a particular design approach, whether good or bad.
If it is just about the knowledge then wouldn't it be valid to just gain that same knowledge about a framework?
* State management is merely a sum of few parts: a state artifact (a big object), a means to update that artifact, a place where that artifact is saved, and finally a function to apply state on page reload. Its an isolated system. If anything wishes to update state it just calls a function.
* GUI: A window system (a big function and a bunch of supporting functions for events), content, and events specific to types of content.
* File system: A call to the file system library from a user interaction, a library to recursively walk the file system on the back end, a messaging payload to communicate the requested file system details, a function to populate the file system data into DOM artifacts for user interaction.
And so on.
I prefer to work without frameworks because they execute far more slowly, get in the way of solving real problems (complexity), and they slow me down in writing/testing code. Writing applications isn't about how to write code. It's about organization, flow control, and just connecting the dots between a problem and a solution. Its the difference between repeating minimum literacy and writing an original inspiring novel. Why would I think some giant abstraction would save me time or improve my code?
https://pagespeed.web.dev/analysis/https-themer-dev-blog-the...
Pagespeed shows .6 for desktop, but locally I'm seeing frames loaded under 350ms. I would have guessed much faster, but I guess the devtools don't lie.
The natural state of a home is tidy. It was probably empty when the current resident moved in. The natural state of a website is fast. A tiny website can be delivered in one packet.
The home only becomes messy through action. Not intention, but action. Someone has to dirty a dish for there to be dirty dishes. And it's not like you can avoid these activities, that's what a home is for.
It requires a countering action to put things back as they were. So it's action on both sides. Action to make things messy, action to keep things tidy. It's the second action we admire in the tidy home, the fast website.
Modern computers are obnoxiously fast, and so are modern browsers. But modern websites overload them with a sickening amount of processing and network latencies before displaying the content.
```
property int count: 0
Button { onClicked: { count--; } }
Text { text: count.toString(); }
Button { onClicked: { count--; } }
Button { onClicked: { incrementLater.start(); } }
Timer { id:incrementLater interval: 1000 onTriggered: { count++; } }
```
Better in so many ways.
counter.html:
<template>
<div>${count}</div>
<input type="text" value.bind="count" />
<button click.delegate="inc()">add one</button>
<button click.delegate="counter--">subtract one</button>
</template>
counter.js: export class Counter {
constructor() {
this.counter = 0
}
inc() {
this.counter++
}
}1. It uses modern JavaScript and not some limited custom ES5-like JavaScript
2. Svelte can be used with TypeScript so your UI code can be statically typed
3. The integration with Svelte and VSCode is much better than QML and Qt Creator (the big thing is that IntelliSense is much better at analyzing JavaScript code than whatever Qt Creator uses)
4. Having an actual live reloading dev server is so much nicer than compiling and running for every change
5. Svelte has much better documentation than QML
These are just the first things that came to mind, but I could probably keep going for a while. Do you think I'm being unfair to QML? And/or have you used Svelte?
<script>
let count = 0
</script>
<button on:click={()=>count--}>decrement</button>
<span>{count}</span>
<button on:click={()=>count++}>increment</button>
<button on:click={()=>setTimeout(()=>count++, 1000)}>
increment later
</button>
Play with this in the Svelte REPL here: https://svelte.dev/repl/97d42ad98e4b4a929d3c5a3de880e6fc?ver...Doing this, I also realized rubymamis cheated a good bit on their QML version. It's missing the text for the buttons. It's not wrapped in `ApplicationWindow { }`. And there's a bug with their implementation: If you clicked their "increment later" button many times quickly then it would keep resetting the timer and only increment once.
Regarding the timer, so in your Svelte code a new timer is being created each time? I wonder how to implement the efficiently in QML. I don't think it's as straightforward.
EDIT: Probably the best way is to expose QTimer::singleShot (C++) in QML.
> Regarding the timer, so in your Svelte code a new timer is being created each time?
`setTimeout`[1] isn't even a Svelte thing, it's a JavaScript API that QML would have access to if it was real JavaScript ;).
[1] https://developer.mozilla.org/en-US/docs/Web/API/setTimeout
[1] https://stackoverflow.com/a/75288105/5865379
I also used his library to share ENUMs between QWidgets (C++) and QML.
2. True.
3. Yes, Qt Creator is very lacking in that department. There are many instances where it doesn't recognize certain commands and you need to guess if you're writing correctly or not.
4. Live reloading is possible in QML. See[1] (But this should definitely be the default in Qt Creator).
5. I agree that QML documentation is lacking. That's probably my biggest pain point. Some of the examples also use deprecated/bad-practice code which is annoying (eg, using that magic `index` property rather than defining it as a required property.
I think you have fair points. I actually have a doc with similar things that QML needs to improve in. I never tried Svelte but I'm familiar with React, and I must say that Qt/QML is a breath of fresh air after using React. Developing in React always felt hacky like using duct tape and glue compared to building something properly which QML/QT feels like.
Apart from the points above, I still think QML has been great for my productivity and I'm impressed how easy it is to develop with it complex UIs easily. I've been developing a feature in my Qt C++ app in QML that turns Markdown tasks into Kanban[2]. It worked out perfectly. The tasks processing is done in C++ which sends the data to QML.
[1] https://github.com/patrickelectric/qhot#integrate-in-qtcreat...
That reloading tool is cool, though its not quite as useful as modern dev servers. It seems like this simply restarts the app on every change, but modern dev servers remember your state too.
I'm curious to hear more about your React experiences. I don't love React, but I still prefer React+TypeScript over Qt+QML. With TypeScript on the strictest setting, programs are much safer than with QML or Qt. We both know QML is very unsafe. And after using TypeScript and Rust, I'm realizing C++ is a very unsafe language too. It has unexpected nulls, memory leaks, seg faults, etc. I find C++ such a rough language to use, and that could be it's own mega rant. Qt's crazy macro system makes things even worse and generates some crazy errors.
There are so many options for building great cross platform UIs now. Tauri, Flutter, React Native, etc. Those all seem to have a better dev experience than Qt/QML. If performance and safety are really important, then you can use Tauri and write your critical code in Rust. There are also UI frameworks for Rust popping up like Dioxus so you can write everything in Rust.
Your "Better Notes" app is amazing and that Kanban is looking amazing. Though, I feel like you're a great dev making great stuff albeit Qt/QML, not because of Qt/QML.
> Maybe I'm missing something or doing things wrong?
To be fair, I have many annoyances with Qt Quick. I think many of the components don't look and work native out of the box, requiring significant customization that is time-consuming compared to what you get out of the box by using many libraries alongside React. And there are these other annoyances that we already talked about. But in my view, the QML paradigm is extremely consistent, even migrating from Qt5 to Qt6 was quite straightforward. I just updated my website to a new NextJS version and so many things broke in React there were serious paradigm changes if I remember correctly. I also enjoy working with Qt's Model/View, I appreciate the native performance I get from compiled C++ code (Most QML code is compiled to C++)[1], the community is very helpful, etc.
> I'm realizing C++ is a very unsafe language too.
Yes, and I think programming languages like Rust are very cool. I know there are Qt bindings for Rust. But I'm not sure how QML is unsafe. Probably because it compiles to C++? Converting Qt Core itself to Rust is quite an initiative that I'm not sure is necessary. But what is cool is that you can write your UI in QML (compiled to C++ somewhat safely if you trust Qt) and write your app logic in Rust[2]. I hope to see more things like that.
Regarding my React experience, I developed a fully working online marketplace in React + NextJS (but discarded the idea), a React Native app that finds rhymes for words (but didn't publish because chatGPT does it better in a way), and my personal website[3] is in React + NextJS - I love this combo for developing websites, I find it so easy and the integration with Vercel is amazing.
I like React for small projects but as it gets bigger I find it quite cumbersome. Though if we're talking about websites I guess it's one of the best approaches (although Svelte looks good but I never tried it).
React Native is so good because they cracked it with components behaving and looking like native components (well, they are the native components I guess). But I prefer to work with Qt/QML. I thought it would take me a long time to learn it but I bought a good online course from Udemy and in a day I knew all the basics, the next day I had a working prototype for my Kanban.
I tried Tauri as well, it sounds good on paper but when I tried it I didn't really like it. I don't remember why but I remember wrestling too much with things not related to actually writing code.
I keep an eye on Rust GUI frameworks but haven't seen something promising yet. I never heard of Dioxus before so I'll check it out, thanks!
[1] https://www.qt.io/blog/the-new-qtquick-compiler-technology
But anyway, I'm also making Slint [0], a toolkit developed in Rust, inspired from QML. So that even the implementation of the toolkit is safer.
[0] https://slint.rs
Exactly, that's what I meant, if I trust QtCore/QtQuick, writing the UI QML and logic in Rust is a pretty good idea. Although I must say that the latest Qt versions Qt 6.5.0-6.5.1 came with two serious bugs for me causing me to revert to Qt 6.4.3. So even that comes with a grain of salt.
I have been keeping my eye on Slint! I must admit, the use cases shown on your website don't look attractive. First, the apps don't seem useful (some random analytic panel, printer demo, and widget gallery) and they don't look good. If I may suggest, put there a simple TODO app that everyone is been taguht these day how to develop one in all the new frameworks. Maybe another app similar to that. It's going to be much more practical and people can have a sense of what is possible to do in Slint. In any case, I have been coming to check Slint every few weeks to check the progress so it's very cool to speak with the author. I wish you the best with it! If you need more feedback on the website's UX or anything don't hestiate to reach out: ruby . mamistvalove at gmail . com
Totally fair points here. Though slight nitpicks, these breaking changes were probably entirely NextJS changes and not React changes. NextJS solves a much more complicated problem, full stack web apps. I think it's more fair to compare QML with React as they both focus on simply describing UI.
> I appreciate the native performance I get from compiled C++ code (Most QML code is compiled to C++)[1]
I read the article and I'm skeptical that most QML code is compiled to C++. My understanding from the article is that they are able to compile VERY basic QML code that you manually specify all the types for. The problem still remains that QMLScript is a very dynamic language. QML doesn't even allow you to type your list or object properties! How much of your QML code doesn't touch lists or objects?
> But I'm not sure how QML is unsafe.
QML is unsafe because it's a dynamically typed langauges. Many errors will not be discovered until runtime! I brought your example over to qmlonline[1] and modified it.
Rectangle {
property int count: 0
Button { onClicked: { count += "1"; } }
Text { text: count.toString(); }
}
This "compiles" fine, runs fine. In fact, it perceives this as fine behavior and continues on without even giving a runtime error when I click the button??Let's try something even more clearly bad. Let's do `count = "test"`. This "compiles" and starts just fine too?? Finally you get a runtime error when you actually press the button.
I'm really skeptical about how or what C++ this all compiles too, because this is all very much dynamic behavior, and it's not giving us any useful feedback at compile time. These are really simple errors that this "QML compiler" should be catching and presenting to the developer.
These kind of errors are impossible with TypeScript. TypeScript will tell you immediately in your editor when you type this mistake, so you will never get runtime type errors. Going from TypeScript to QMLScript or regular JavaScript is probably the biggest downgrade of all to me. C++ is statically typed thankfully, but what good is having only half of your code statically typed?
> I like React for small projects but as it gets bigger I find it quite cumbersome.
Reading this and "developing in React always felt hacky like using duct tape and glue", I wonder how much of this is actually React and how much is using dynamic JavaScript. If your whole app was dynamic QML code, you'd probably feel like that was hacky too, right? If you have specific examples of things that felt hacky and hard in bigger projects, I'd love to hear that. My hypothesis is that you'd feel like your React projects were much more "solid" and "proper" if you used TypeScript. The facts are that your users would run into much less runtime errors with TypeScript code than C++/QMLScript code. Also, TypeScript provides much more immediate feedback while developing.
I'm curious about what you think QML really excels at. It sounds like it was perfect for quickly making a Kanban prototype? What all did the prototype include? Maybe I should try recreating some portion of it with Svelte. I think it could be interesting to have a direct comparison. If QML has useful tools for building UI that Svelte doesn't, I'd find that really interesting. I'm constantly looking for the best way to build UIs, and right now Svelte seems like the best.
If you remember the specific problem with Tauri, I'd be interested in hearing that. I'm curious about the performance differences between Tauri and Qt apps. There are probably some pros and cons with Tauri's web view approach. I imagine OS native web views might be better at rendering certain UIs than Qt's rendering.
It's cool that you're looking into Rust things too. Rust gives even better compile time feedback than TypeScript which excites me. It's super interesting hearing all your thoughts, and would love to hear more.
Yes, you're right that's probably the case.
> I read the article and I'm skeptical that most QML code is compiled to C++.
Well, all the core Qt Quick components are written in C++[1]. Other components either reuses them in C++ or QML. So they're mostly C++ underneath.
> QML doesn't even allow you to type your list or object properties! How much of your QML code doesn't touch lists or objects?
What do you mean? JS object (like JSON?)? I'm quite sure QML supports object property. And JS list? There's this[2].
> QML is unsafe because it's a dynamically typed languages.
I get your point. Although there is qmllint that warns you of many such things before compilation even[3]. It's great. It's a shame they don't easily integrate it into Qt Creator by default. It saved me many errors. In your first example, I wonder why it does its behavior where it concatenates an int like a string. That's weird.
> The facts are that your users would run into much less runtime errors with TypeScript code than C++/QMLScript code. Also, TypeScript provides much more immediate feedback while developing.
I think that's a good take. And maybe something Qt should consider adding on top of QML.
> wonder how much of this is actually React and how much is using dynamic JavaScript.
I just remember handling state changes wasn't that natural to me (maybe it's the use of Hooks?). TypeScript does sound interesting, but I'm a QML convert for now.
> I'm curious about what you think QML really excels at
First - using Qt Quick - native performance. But talking about the language itself - I can't get over how amazing property bindings and signal and slots are for state changes. Just these alone would make me quit any web framework. They are so simple yet incredibly versatile and powerful. It just makes sense to work with them than any Hooks or whatever in React. Then the Model/View paradigm of Qt fits so well into QML is just awesome.
> What all did the prototype include?
Well, you can easily grab a binary from our GitHub Actions and try it out[4] or compile it from source. The basics for the Kanban were to 1. Process the markdown tasks in TextEdit 2. Beautiful interface 3. Beautiful drag and drop like `react-beautiful-dnd` 4. Markdown inside of tasks. 5. Rendering fast with even thousands of tasks.
> I'm constantly looking for the best way to build UIs, and right now Svelte seems like the best.
Me too. But I'm reluctant to non-native performance anymore. I had enough of Electron apps. That's why I was trying React Native (I had a good experience with it but I still prefer QML) and Tauri. I really can't remember why I disliked tauri (maybe i tried to create a custom window decoration but couldn't?). If you ever give it a shot let me know what you think about it. But then again, I'm sold on the flexibility of Qt C++ together with QML.
> I imagine OS native web views might be better at rendering certain UIs than Qt's rendering.
Why is that? Qt is using the underline accelerated graphics APIs to render its content[5]. Even if a component isn't native we say it's native-like because it still uses the native graphic API just not the native component.
> It's super interesting hearing all your thoughts, and would love to hear more.
Thanks! I learned a lot from what you're saying. I have plans to create an ecosystem of open-source cross-platform apps, so I've been deliberating for the longest time on which framework to choose. For now, I've settled on Qt/QML. It has its cons. But that's why I like talking about it with other people so I can document these, file the right reports and maybe improve it as time goes by. After releasing the next version of my note-taking app I plan to migrate the UI completely to QML and create an adaptable/responsive app that will share the same source for desktop and mobile, taking inspiration from MAUI apps[6] that our based on MAUIKit[7].
[1]https://code.qt.io/cgit/qt/qtdeclarative.git/tree/src/quick/...
[2] https://doc.qt.io/qt-6/qml-list.html
[3] https://doc.qt.io/qt-6/qtquick-tool-qmllint.html
[4]https://github.com/nuttyartist/notes/actions/runs/5565887776
Gotcha, this makes sense. To be fair, browsers write HTML elements like <input> and <textarea> using C++ too. Though I admit the core Qt Quick components cover more functionality use cases than HTML elements.
> And JS list? There's this[2].
Ooh whoops, good catch on the typed lists. I seen now you can do stuff like `property list<int> intList: [1, 2, 3, 4]`. Looks like I missed this because it was added sometime inbetween 6.2 and 6.4?
Still I'm a bit skeptical, what about lists of lists like `list<list<int>>`? And what about lists of objects? I wish I could quickly test Qt 6.5 myself without setting up the whole dev environment, but qmlonline only supports 5.15.
> JS object (like JSON?)? I'm quite sure QML supports object property.
Whoops, objects are a tricky overloaded word. But yeah, something like a struct in C. For example, TypeScript ensures this code will be totally typesafe at runtime:
type Person = {
age: number,
name: string
}
let people: Person[] = []
people.push({
age: 24,
name: "jeff"
})
In QML it seems you need to go to C++ to define a type like `Person` and expose that to QML?> Although there is qmllint that warns you of many such things before compilation even[3]. It's great.
Ohh, that would definitely be an improvement. It doesn't look like it does any type checking, but atleast checking for syntax and anti-patterns is something. If Qt gave QML good static typechecking like TypeScript, it would make my QML experience sooo much better. Then the big remaining problem is how unsafe C++ is lol.
> First - using Qt Quick - native performance.
I'm still a bit skeptical about all that QMLScript getting compiled to native code, and it's not like there's zero overhead in Qt's OOP code. It feels like native is a spectrum where C or Rust would be more native, right? If you use native components with C, that should be considered "true" native performance, right? I'm sure Qt/QML is more performant than something like TypeScript with Svelte. But I'm really curious to see by how much.
> But talking about the language itself - I can't get over how amazing property bindings and signal and slots are for state changes. Just these alone would make me quit any web framework.
I totally agree property bindings are great. In the same way properties are reactive by default in QML, any variable is reactive in Svelte. Signals and slots are interesting. I always thought its better to avoid them and find a better way to structure things. Signals and slots are component events[3] in Svelte, but people seem to rarely use them. I'm curious to see where you use signals and slots in QML. Maybe I'm missing out here.
Properties, signals, and slots exist in the C++ side too and I have some nightmares about these. The fact that this is all implemented using the Q_OBJECT macro means that when you make any mistakes you get some really gnarly errors. It feels like humans were never meant to see these errors. Maybe I'm just too spoiled by Rust and TypeScript error messages.
Callbacks are really useful in UI programming. They make it possible to do event driven programming. But it feels so rough using callbacks in C++ because functions aren't first class citiziens. In Rust or TypeScript callbacks feel much more sane to use. And when you make inevitably make mistakes, you get much more sane errors.
> They are so simple yet incredibly versatile and powerful. It just makes sense to work with them than any Hooks or whatever in React
I definitely agree that QML bindings are much nicer to work with than React hooks lol.
> Then the Model/View paradigm of Qt fits so well into QML is just awesome.
Ooh interesting. It seems older frameworks were more model/view oriented, but now new frameworks interconnect these more. It's interesting you enjoy this. I find the model and view rarely get changed seperately. New features tend to require changes to both the model and view, so it seems weird to seperate them.
> Well, you can easily grab a binary from our GitHub Actions and try it out[4] or compile it from source
Awesome thanks! I'm looking forward to trying this out and checking out the code. It will be interesting to see if Svelte can compete on any of these things.
> Why is that? Qt is using the underlying accelerated graphics APIs to render its content[5]. Even if a component isn't native we say it's native-like because it still uses the native graphic API just not the native component.
If we call QML/Qt components native-like, then we should also call HTML and CSS native-like. Browsers are built with C++ and render HTML+CSS with accelerated graphics APIs too. There are tons of powerful, interactive HTML elements[1] and when combined with CSS animations you can achieve a lot without ever touching JS.
Browsers just keep getting better. For example, the new View Transitions API[2] means that the browser is exposing hardware accelerated page change animations. Even with current CSS animations, there are lots of GPU accelerated animations that are either 1. not possible with Qt/QML or 2. less performant in Qt/QML.
Maybe you find some built in GPU accelerated feature QML has that browsers do not expose. No big deal, the web has a WebGL API, and the even more powerful WebGPU API is rolling out! We can write our own hardware acceleration using TypeScript!
However, I admit reality is messier than this. With QML its tempting to quickly hack together functionality with QMLScript that should have probably been done through different means. On the web it's the same, but TypeScript seems like a much more sane and safe language than QMLScript.
> I have plans to create an ecosystem of open-source cross-platform apps, so I've been deliberating for the longest time on which framework to choose.
This is so awesome, and I'm excited to see how your journey continues.
I'll definitely stay in touch and let you know how my experiments with Svelte, Tauri, and Rust go.
[1] https://developer.mozilla.org/en-US/docs/Web/HTML/Element
[2] https://developer.mozilla.org/en-US/docs/Web/API/View_Transi...
That's cool. I think QML is going in that direction.
"In addition, Qt 5.14 introduced the possibility to provide type information in function signatures, similar to how it is done in TypeScript:"[1] `function add(a: int, b: int) : int { return a + b }`
> I'm still a bit skeptical about all that QMLScript getting compiled to native code
"Additionally, in Qt 6.3, there will be another compiler: The QML type compiler, or qmltc. With the QML type compiler, you will be able to compile your object structure to C++. Each QML component becomes a C++ class this way. Instantiating those classes from C++ will be much faster than the usual detour through QQmlComponent. qmltc, like qmlsc, is built on the availability of complete type information at compile time. In contrast to qmlsc, though, qmltc has no graceful fallback in case the type information is lacking. In order to use qmltc, you will have to provide all the information it requires. qmltc will be available with all versions of Qt." [1]
I read your entire comment. It takes a lot of effort to respond here. You make some interesting points. I do think each should find the right tool for his job. I found QML very appealing. And I think it keeps improving and I hope they integrate some of the cool security features of typed languages etc. I might not be the best person to respond technically to your arguments, tho. In any case, I'd love to keep in touch. I saw you on Twitter so that's cool. I'm also (more available) on Discord. My username is "rubymamis" so feel free to send a DM (:
[1] https://www.qt.io/blog/the-new-qtquick-compiler-technology
One quite an advantage for QML is how easy it is to align elements to get started. Personally, I find it quite frustrating to get HTML to do what I want whereas in QML having only used for two months I already see how to model `Kanban` UI with QML.
Felgo is what I was hoping for, good find! That covers one pain point, but there's still many, many more. QML does have a simple and great list of components to get started with, where as HTML and CSS have accumulated many years of cruft. But, that being said, aligning elements into rows and columns is easy using CSS flexbox[1]. Flexbox has the benefit of being much more versatile than QMLs layout tools as well. I imagine using flexbox you could make the Kanban UI just as easily, and you'll probably run into less limitations.
[1] https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layou...
Text {
anchors.top : parent.top
anchors.bottom : parent.bottom
anchors.left : parent.horizontalCenter
anchors.right : parent.right
anchors.topMargin : 10
text : "Hello World"
}which does not reference any dimensions of the objects. It is easy to reference an anchor of a sibling and other parent elements when needed.
Also, making new components is easy; I can inherit properties of a parent element, add my properties and put them in a file for later reuse is something I use extensively. Building each component carelessly using whatever mockery to get the look I need and then isolating it with its own namespace is relieving.
> The flexbox does not seem to match the power of QML. For instance, I can have a two-pane view as simple as:
I'm a bit confused by this example. When you make the other pane wouldn't you need to define all of its anchors too? It seems like the more standard QML approach to a two-pane is using RowLayout[1].
RowLayout {
anchors.fill: parent
Rectangle {
Layout.fillWidth: true
Text {
text: "pane 1"
}
}
Rectangle {
Layout.fillWidth: true
Text {
text: "pane 2"
}
}
}
I agree this is pretty nice and intuitive, but flexbox makes this problem easy too. <div style="
width: 100%;
height: 100%;
display: flex;
">
<p style="flex: 1">pane 1</p>
<p style="flex: 1">pane 2</p>
</div>
Yes inline css has problems, but I didn't want to scare you away with Tailwind[2] and I think inlined CSS makes this example clearer.> It is easy to reference an anchor of a sibling and other parent elements when needed.
It seems like by composing layouts in QML you can avoid a lot of manual anchor setting. Though layouts do have their limits. Is that why you resort to setting anchors manually? Flexbox is much less limited and flexbox layouts compose really well.
Do you have examples of UI layouts you feel QML solves intuitively that flexbox can't solve intuitively?
> Also, making new components is easy; I can inherit properties of a parent element, add my properties and put them in a file for later reuse is something I use extensively
Svelte works the same exact way. Well, except for the part that new components do not inherit from existing components. Svelte and other modern UI frameworks prefer composition over inheritance[3]. Composition allows you to be just as expressive, but without the footguns of inheritance. If you have a specific UI problem you think inheritance solves well, I'd be happy to try and create a matching composition based solution.
> Building each component carelessly using whatever mockery to get the look I need and then isolating it with its own namespace is relieving.
Svelte uses file based components as well. Each file is its own module in TypeScript/JavaScript.
If you have rebuttals or other additional things to add I'd love to hear it!
[1] https://doc.qt.io/qt-6/qml-qtquick-layouts-rowlayout.html
[3] https://en.wikipedia.org/wiki/Composition_over_inheritance
I think your example on the flexbox use for two pane view illustrates that well. Although I have no experience of using it I get that the gist of it is the same of a RowLayout. It’s a good abstraction for listing many items of the same kind which need to respond dynamically with the change of window dimensions. But when I really need to place two panes 10px appart or put elements on top of it in the bottome left corner, bottom right corner and align margins of the content within the pane anchoring elements manually is so much easier. I remember when I started to learn QML my first instinct was to find where can I make a table and align elements within it where instead I just needed to use anchors.
The beauty of QML is that I can treat RowLayout and Row as elements written in QML itself. If I recall accurately it is possible to loop through child elements and assign properties to them such as anchors with respect to sibiling elements. The abstraction thus is more fundamental.
> Svelte and other modern UI frameworks prefer composition over inheritance
Inheritance is the right abstraction for the UI elements. For instance I don’t need to predict all properties in advance for my custom bottom implemntion when used in the code. Assuming that all of them are available is quite powerful and allows to experiment in place. This work exceptionally well in QML but not in OOP languages in general. Nevertheless, can you come up with `footguns of inheritance` to which QML is susceptible to?
> Svelte uses file based components as well. Each file is its own module in TypeScript/JavaScript.
This sounds interesting. I will give it a try on someday when I will need to make an UI in HTML.
`gap: 10px`
> put elements on top of it in the bottom left corner, bottom right corner and align margins of the content within the pane anchoring elements manually is so much easier
These instructions seem a bit more vague. If you make this visually or with QML I'm sure I can replicate it in an intuitive way with flexbox.
Flexbox has `align-items`, `justify-content`, `align-content` which covers all the needs of aligning to centers or corners. `padding` and `margin` work exactly like you'd expect. Unlike QML's layouts, you can also enable `flex-wrap` so content automatically wraps when it overflows the allocated space.
Maybe you're also wondering, how do I memorize all these flexbox properties? I don't! Chrome dev tools give you a GUI for editing a flexbox[1], isn't that really nice?
With all these tools, hopefully it becomes clear that you never need to manually define anchors. You can compose these layouts to build whatever complex layouts your heart desires. But, if you are still really attached to the anchor workflow, you can do that with CSS as well. For example, `position: absolute; bottom: 100%; right: 100%` would anchor a child element to the bottom right of its parent.
> The beauty of QML is that I can treat RowLayout and Row as elements written in QML itself.
I totally agree here. My Svelte example from above would become:
<RowLayout>
<p>pane 1</p>
<p>pane 2</p>
</RowLayout>
What if I told you it's totally trivial to make this RowLayout component yourself in Svelte? This could totally be valid Svelte code! If this sounds interesting, this example[2] is a great starting point. And it would be even more trivial to pull in a great component library like Skeleton UI[3] which does stuff like this for you.> If I recall accurately it is possible to loop through child elements and assign properties to them such as anchors with respect to sibiling elements. The abstraction thus is more fundamental.
Hopefully this RowLayout example makes it clear that Svelte can also loop through child elements and assign properties.
> Inheritance is the right abstraction for the UI elements
How are you so sure about this? React is one of the most popular and successful tools for building UI elements, and it avoids inheritance entirely. Do you think React's approach is totally offbase? Similarly, Rust and Go do not have inheritance at all. Do you disagree with their design?
> For instance I don’t need to predict all properties in advance for my custom bottom implemention when used in the code. Assuming that all of them are available is quite powerful and allows to experiment in place.
You can expose properties with composition based elements too! You don't need inheritance to support this workflow.
> Nevertheless, can you come up with `footguns of inheritance` to which QML is susceptible to?
I think the composition over inheritance wiki page[4] explains things much more elegantly than I ever could. Though I do think I made a mistake. Does inheritance actually exists in QML land? I don't think so.
It feels like you compose things very similarly to Svelte or React. Maybe it's a just a semantics thing, but imagine HelloText.qml:
Text {
text: "hello world!"
}
Does HelloText inherit from from "Text"? I'd say no. HelloText simply instantiates Text and sets its' text property to "hello world". Though I imagine you would say HelloText inherits from Text and overrides the text property?Compare this to the Qt Widget world where the difference between inheritance and composition are much more clear. Sometimes a Qt Widget doesn't expose the properties or functionality you want. The best scenario is when Qt Widgets do expose the properties you need. Then you can instantiate them and change those properties. Notice that even Qt Widgets sometimes expose properties without inheritance! When defining bigger fancier widgets, why require inheritance? Break them into smaller parts and expose useful properties. Then you and other programmers can compose custom behavior without going through the sludge of inheriting and overriding!
Perhaps we already agree on that part and it was just a semantics issue about whether QML is actually using composition or inheritance?
> This sounds interesting. I will give it a try on someday when I will need to make an UI in HTML.
Yay, I'm interested to hear what you think!
[1] https://developer.chrome.com/docs/devtools/css/flexbox/
[2] https://svelte.dev/examples/slots
[4] https://en.wikipedia.org/wiki/Composition_over_inheritance
This is quite nice indeed. I didn’t know that Chrome dev tools can be used that way.
> Does HelloText inherit from from "Text"? I'd say no. HelloText simply instantiates Text and sets its' text property to "hello world". Though I imagine you would say HelloText inherits from Text and overrides the text property?
Note that is also possible to create a new properties and signals for the Text which can be referenced by the children. Also it is possible to override the default method on how to treat it’s children for instance if you want to implement a CustomRowLayout. The HelloText thus has properties of the Text and the newly defined ones and it is possible to instantiate it at multiple places with different parameters and children. I don’t see why this is not inheritance…
> Perhaps we already agree on that part and it was just a semantics issue about whether QML is actually using composition or inheritance?
In QML composition is when one places children elements within a component and expose relevant properties and signals to the parent. So I disagree on this part. QML in my opinion is OOP done right.
This behavior exists without inheritance as well! Let's imagine we want to use our existing `HelloText` component. But like you suggested, let's subscribe to the `onclick` signal and add a `bolded` property. When the user clicks the text, it will toggle the bolded property. We will use React because it's famous for not using inheritance.
```jsx function HelloText(props) { return <Text {...props}>Hello World!</Text>; }
export default function App() { const [bolded, setBolded] = React.useState(false); return <HelloText onClick={() => setBolded(bold => !bold) bold={bolded}} /> } ```
And just like you wanted, even children of `<Text>` could reference `bold` and `onClick`. I'll assume you know what that would look like. If not, let me know and I'm happy to make examples for that too. You can provide default prop values that can be overridden. You can accept functions. You can expose signals.
If you are being attentive, you might have noticed the code that enables this behavior: `{...props}` is the explicit way to pass all the props from the parent `HelloText` to its child `Text`. Unlike React, exposing props is implicit and automatic in QML. Though its trivial to make every component expose all their props to their children, the docs argue that you should avoid this. They say that if you find yourself doing this a lot, you are probably designing things poorly [1].
Here's how I understand this: If you are going back and wishing you exposed more properties or methods all the time, then you are probably developing things top down instead of bottom up. When building UI, it's easier and better if you start by building the smallest possible pieces of your UI. Then you can compose them into bigger, more complex pieces. The other way around is dangerous because you would be designing inherently inflexible abstractions. Even the most elaborate and beautiful castle made of yarn will never be as flexible as a castle made of legos.
For example, when and why would you want this `CustomRowLayout` component? Instead, simply start with the smallest easiest parts of your app. Build the buttons inside that row. Maybe the row has a dropdown item, so you can build that. Compose those parts using `RowLayout`, `ColumnLayout`, `GridLayout`, and `Flow`. Maybe make yourself yourself a `Spacer`. While you build your apps' custom rows in this pattern, you will 1. naturally develop a great toolbox of composable components that are flexible and useful and 2. have a much easier time than reimplementing some method on a `CustonRowLayout` component! Previously you asked me for an example where inheritance is a footgun in UI development. A `CustomRowLayout` is an example as building new row layouts bottom up is clearly superior.
But also, React and other modern UI frameworks won't stop you from building `CustomRowLayout` if that's what you really want. Hopefully now it's clear that you can build something like this using React, Svelte, or any other modern UI framework without inheritance. And also, if you find yourself doing this often, maybe that's a sign you are approaching problems from the wrong direction.
> In QML composition is when one places children elements within a component and expose relevant properties and signals to the parent. So I disagree on this part
Honestly, I think this is a fair distinction and definition. Though, then things get a bit hairy on the other side. Clearly React and Svelte support the alternative behavior that you call inheritance in QML. What do you call that now? Did React and Svelte suddenly become OOP frameworks too?
I think the important conclusion is that building complex UI using composition in a bottom up fashion is 1. possible and 2. optimal. QML, Svelte, and React all allow developing top down and bottom up, which is great. Svelte and React simply make top down development explicit.
I will leave things with a message from React's composition vs inheritance page: "At Facebook, we use React in thousands of components, and we haven’t found any use cases where we would recommend creating component inheritance hierarchies.
Props and composition give you all the flexibility you need to customize a component’s look and behavior in an explicit and safe way. Remember that components may accept arbitrary props, including primitive values, React elements, or functions." [2]
[1] https://react.dev/learn/passing-props-to-a-component#forward... [2] https://legacy.reactjs.org/docs/composition-vs-inheritance.h...
However, wouldn't the performance for this be very optimal? Check out the `Flex.qml` code[1]. It's all very unoptimized and dynamic QMLScript. None of the function arguments are typed. There is no way the QML compiler is turning any of this into efficient, statically typed C++ code. The beauty of using flexbox in the browser is that all the layout calculations are done natively in the browser without ever touching JavaScript.
[1] https://github.com/tripolskypetr/qml-flexbox/blob/master/qml...
[1] https://github.com/tripolskypetr/qml-flexbox/blob/master/obj...
[2] https://github.com/tripolskypetr/qml-flexbox/tree/master/thi...
[3] https://github.com/facebook/yoga
[4] https://github.com/tripolskypetr/qml-flexbox/blob/677a1287df...
P.S. I'll answer your other reply very soon. I'm releasing a new version of my app so it takes its toll on me.
On the web it's common to animate the size of flexbox items with CSS animations. These animations are entirely implemented by the browser, and I imagine much of it is even GPU accelerated. No JavaScript is executed for this on the browser. But with this library, you would be running the `Flex.qml`'s `updatePositions` function every frame of the animation. Isn't that wasteful when compared to how flexbox works in the browser? It seems like a browser would be much faster at computing layout for flexbox elements than this, especially when that flexbox's size is being animated with CSS animations.
[1] https://github.com/tripolskypetr/qml-flexbox/blob/master/qml...
Yeahh, looks like you'd have to connect to all these signals and be able to access sizing/position from C++. Not sure how possible this is, you probably know better than me.
The entire framework is surprisingly simple and easy to understand. In benchmarks I've seen it perform well, even better than SolidJS.
The cursive italics are apparently a feature of the Victor Mono [1] font used for the full page. While it'd be amusing in Tumblr context (where cursive is used for hyperbolic emphasis), I can't fathom why one would consider it in a code context, but to each their own...
You can change it (at least on Safari) by going into developer tools, clicking any node, and removing "Victor Mono" from --font-family
However, I personally find the narrowness more tiring for the eyes to the point that it is even more distracting than the cursive.
This is why I ended up building Joystick [2]. The amount of time I was wasting trying to reason through how a framework wanted me to do something vs. actually building what I wanted was driving me nuts (not to mention, having to watch people I was mentoring who had less experience struggle even more).
[1] Meaning, beyond a trivial interface, any sort of complex UI is often (not always) burdened by the framework's lack of clear ergonomics. There's a lot of having to learn "why it did that" in the way of getting stuff done.
And it isn't actually very different from React or Vue anyway, and in fact quite a bit more limited than Vue (not necessarily bad).
Saying:
“I’ll figure it out for you at compile time.” —Svelte
is just a non-technical, basically non-meaningful statement.You need to know _what_ it figures out exactly. What state and what state changes are observable? These things matter more than whether it's done at compile time or runtime.
And I think the author is ascribing far more power "compile time" than what's actually happening. Svelte is not doing some kind of sound data flow analysis on your JS code to figure out what could change and rewriting your code to be observable (something not really possible anyway). It's using specific syntax conventions to make some variables into shallowly observable properties. And it adds "store" concept, which is more-or-less Signals as popularized in Solid, now Preact, and soon Lit and Angular.
These points weren't touched upon by the author. He compared the frameworks from one perspective and one perspective only.
Shared by the dev https://news.ycombinator.com/item?id=36403909
The FA actually doesn't do this, but a lot of things (including those that do very well on HN) do for exactly this reason.
There must be a browser plugin that offers the date a website was first indexed.
You can also just not pick one.
MDN is my anti-framework.
I disagree. Sure that's at the core of how a framework is written, but all the developers really care about are the interfaces. The user doesn't care at all unless it doesn't work or is annoying to use.
If your interfaces are dictated by the way the event loop is written, there's something wrong that needs to be decoupled. Events should be generic and interfaces should be arbitrary to what developers want.
Views subscribe with the model to get notifications about changes to different "aspects" of the model. When they get a change-notification they update themselves by asking the model for its latest data for a given aspect.
(googling 'thing mobx' where 'thing' is your preferred rendering system has results in quite a lot of cases)
The reason why solutions like React are so popular is because it radically simplifies state management: data flows in from the top of the component hierarchy down. When a component makes changes to state, those changes are queued up for the next consistent render loop, which ensures that nothing renders in an intermediate state. An entire class of bugs, gone.
I think it should be only the Controller which changes the Model. That can cause views which are dependent on the "aspect" of the model that was changed to update themselves.
But a view updating itself should NOT cause the model to change and thus not cause a cascade of other views causing other views to change.
So a change in how the view looks does not trigger anything, it is user-actions caught by the Controller which do. These are the basic principles of MVC.
I don't know if you are using React or what, where the terms like View and Controller might have a different meaning, than in classic MVC.
My question more is about does React et al. use the principles of MVC and if not why not, and if yes why is a basic MVC framework not all we need to do change-handling.
OK, and how does this work? The view is rendering the filter box, allowing the user to select an option. How does the Controller know what option was selected, if the view is not registering a click handler and communicating this up?
What ends up happening is that as your application grows, so does the number of controllers, models, and views. A user action in one view can cascade to many different controller updates, which can overlap and conflict in difficult-to-debug ways, and render inconsistent data states. Flux architecture solves this, which is roughly what React is based on.
ExpressionChangedAfterItHasBeenCheckedError
[1] https://krausest.github.io/js-framework-benchmark/current.ht...
Angular is “opinionated” in that you don’t need to add anything. It definitely has a higher learning curve, but from an enterprise perspective, it’s a safer tool.
And if you have so many things on a web page that performance is a problem, then I’d suggest you need a better user experience. You should never have a design that overwhelms the framework.
Well, IIRC, Elm is faster than all the examples given, and yet front-end developers find Elm to be weird and frightening.
So I’m not sure I agree with the premise of the article.
I also don’t agree that there can be so many valid answers to “Find a change detection paradigm that fits the needs of your application”. Surely everyone just needs the one that is most efficient and least broken.
I’m not sure how to answer this question. Any serious answer would spoil the joke.
Really dynamic apps can be really fast with canvas but I am not we have the tools to replace DOM websites just yet. Maybe in a decade.
I don't believe any of the other frameworks have this specific problem.
And I find manual render very usefull and once you do it, you can have a global state as simple as a global object, no need to use useState anymore.
In short, injecting a naive render function over the react virtual dom calculation is wildly inefficient.
If two unrelated components are consuming the same context, it will update when that context updates.
Using Zustand, there's virtually no overhead to this and it's extremely reactive
Well if you update a state, every children of your component is updated as well regardless of if they have a prop passed.
I know there are way to make react trully reactive like Valtio using proxy or maybe Zustand, but my point is that useState or useContext is not "reactive" at all, you must call a function to rerender the components.
I do not consider myself a front end person, but I’m slowly getting more adept with FX, more so as a hobbyist than professional, but have no experience with the browser systems.
You can argue over if you prefer React, Angular, Vue or Svelte but at the end of the day you're still shipping 1-3mb bundles instead of 1kb and resuming
Most other frameworks here (all? not sure about Vue) will invalidate and rebuild an entire component subtree if a piece of state in them changes. The solid runtime doesn't care about components so changing a piece of state high in a subtree will only update the piece of the DOM directly depending on that state and not any nodes that were authored as sub-components.
Use a local variable (not react state) if you need to store a value and read it back synchronously. Use a useEffect hook if you need side effects to run when react state changes, and finally useMemo if you need derived react state
It's very likely that you're using effects improperly.
The rest is nice to have.
That's basically what the article is about: keeping state in synch with the user interface. There are a bunch of different ways to do it. TFA compares a few of them.
A front end has to do a lot of other things, and it's kinda overstating it to say that state is "the single most important factor". But maybe not by much.