krausest / js-framework-benchmark

A comparison of the performance of a few popular javascript frameworks
https://krausest.github.io/js-framework-benchmark/
Apache License 2.0
6.58k stars 814 forks source link

New contenders for the ring #441

Closed trusktr closed 3 years ago

trusktr commented 5 years ago

A few more contenders to throw into the ring!

I have a bunch more framework listed here: https://forums.meteor.com/t/alternative-view-layer-libraries-alternatives-to-blaze-angular-react/38092 (some of which are already in the benchmarks).

I'll update the list if I find any more.

ryansolid commented 5 years ago

HyperHTML is already in there. There is a keyed implementation for 2.13.0 where it is much more performant than it's lit-html counterpart.

trusktr commented 5 years ago

Ah okay, cool. Removed it. I was looking at the v7 table. I'll look here instead.

Another contender is StencilJS. (added)

CaptainCodeman commented 5 years ago

HyperHTML is already in there. There is a keyed implementation for 2.13.0 where it is much more performant than it's lit-html counterpart.

The repeat directive for lit-html has now been reworked so you should see significantly better results with the next update.

trusktr commented 5 years ago

Would it make sense to add SkateJS to the benchmark?

SkateJS uses your choice of renderer under the hood (React, Preact, snabdom, etc), so it is a tool for making web components that render with those libs. It also has a default simple innerHTML-based renderer in case you haven't chosen a renderer yet (which is obviously slow).

Would it make sense to add the following combos to the benchmark?

I like SkateJS because it allows us to take a lib like domc and use it as a renderer in SkateJS, and to add a reactivity layer on top that is easy to work with regardless of renderer. Each component written with SkateJS is a web component (custom element).

ryansolid commented 5 years ago

Possibly, I mean I go through this debate all the time. I have a webcomponent library that is very similar to SkateJS, called Component Register. The difference is it tries to not impose much convention on the underlying library by presenting itself as a Recompose-esque HOC so that everything is presented through props and you can write your component in pretty much pure Framework syntax. You could take any existing framework component and just wrap it. I've only bothered making versions for Knockout, React, and Solid, much like Skate though it takes about 30 lines to do a new implementation.

And the underpinnings of Solid are a renderer Babel Plugin JSX Dom Expressions that technically works with any fine grained change library although I've only made implementations for Solid, Knockout, MobX, and S.js. So I did submit 2 of those libraries here (Solid, and ko-jsx). But I sort of felt it would be extreme to just send in every combination. As you can see with how I've broken things down I'd have a dozen just off the handful I've done.

My thinking is that there really are 3 different things being looked at here (using the above examples):

  1. Containers - SkateJS Components, Component-Register etc..
  2. Change Management - SkateJS Update, SolidState, S.js, Knockout.js, MobX, etc..
  3. Renderer - Skatejs Renderers, DomC, StageO, Babel Plugin JSX DOM Expressions,

So where say React handles all 3 aspects, as do many Virtual DOM frameworks, things get tricky for these sort of libraries because they are designed to essentially mix and mash. And with certain libraries only sitting in in certain categories here it's hard to compare.

My thinking has been at minimal to play here you need to be a data driven renderer. And it is the renderer and overhead around rendering that is being tested here. So I guess the question is what is trying to be demonstrated through the benchmark for the implementation? The overhead of Skate on top of the renderers/libraries already in the benchmark vs the convenience of the generalized API and WebComponent Interop? That can be demonstrated by choosing one that feels the most authentic(or performant) for Skate. I mean I actually starting working on Solid because I wanted to have example implementation of my Rendering and Component Libraries. One that captured the essence of what those libraries were doing.

So a submission could be made for all of those although it probably is overkill. My final thought here is given that the container (the web component) boundary is arbitrary most webcomponent solutions seeking greater performance might just write most of the benchmark implementation in a single component anyway since it isn't that large (depending on the change detection mechanism/renderer), although that doesn't demonstrate how one could best utilize the library. I think this benchmark isn't the most flattering for demonstrating the ergonomics of a library like SkateJS. There is a VanillaJS Webcomponent implementation. Maybe an approach like that might best demonstrate.

Ultimately I'm still unsure so I'd love to hear other thoughts.

PS. I am a huge fan of SkateJS. I've used their polyfills in previous versions of my Component library. And
the idea there is so similar if their open renderer idea had been there back when I started on my library 4 years ago(they were Preact back then I believe) I wouldn't have even bothered.

trusktr commented 5 years ago

Maybe the test can be updated to have more depth, f.e. nesting components, and other things that people generally want to do in an app.

Although we know Skate on top of Preact/React/etc will be slower (well, at least in the case of having nested components), I would still find it useful to know exactly how much slower, and if some combination of Skate+lib is faster than some other standalone lib.

trusktr commented 5 years ago

I think it'd be sweet to add mobx-jsx to the bench. It's yet another combination, but I think it is useful.

trusktr commented 5 years ago

Some other contenders can be found here: https://wc-todo.firebaseapp.com/ (stencil and atomico)

espoal commented 5 years ago

Omi.js is a new library from the far east that looks promising

prasannavl commented 5 years ago

Just adding in: https://github.com/prasannavl/icomponent

Technically, it's render agnostic - it can be used with lit-html, hyperhtml, or vanilla js, or pretty much any render fn, that can take a view and renders to the dom, emphasizing on renderer and framework freedom. I think it'd be useful to port vanilla js, into the icomponent paradigm.

Edit: @trusktr, litecomponent is now icomponent

trusktr commented 5 years ago

Yet another one! https://github.com/hybridsjs/hybrids

(Updated the list with the last three new ones)

ryansolid commented 5 years ago

So I did end up adding mobx-jsx afterall. It isn't as mature as the others but it is still right up in there.

Yeah WebComponent wrappers are an interesting one. There are a handful of ones now that are renderer(or even framework component) agnostic. And since they are pretty lightweight to write there are new ones popping up weekly. I was thinking more about it, but it's almost like we need to figure out a good way to benchmark them. For those that handle the rendering they could submit here but this isn't really showcasing their webcomponent nature. Like this benchmark has lit-html not lit-element.

I'm a big fan of the BYOF (Bring/Build your own Framework) mentality. And Bring Your Own Renderer is the natural next step from Bring Your Own Component. But you come here to shop for Renderers. Where do you shop for Component Libraries?

doronaviguy commented 5 years ago

Thus one looks interesting https://github.com/DenisKolodin/yew

ryansolid commented 5 years ago

Thus one looks interesting https://github.com/DenisKolodin/yew

Yeah that one could probably use an update. There is a Yew implementation in non-keyed, but it'd be nice to see a newer version and a keyed version.

trusktr commented 4 years ago

Adding to the list: https://crank.js.org (thanks @ryansolid ). It'd be neat to add all of the frameworks to the benchmarks and release a new benchmark resultset.

trusktr commented 4 years ago

I also have a fairly long list here: https://forums.meteor.com/t/alternative-view-layer-libraries-alternatives-to-blaze-angular-react/38092

trusktr commented 4 years ago

My thinking has been at minimal to play here you need to be a data driven renderer. And it is the renderer and overhead around rendering that is being tested here. So I guess the question is what is trying to be demonstrated through the benchmark for the implementation?

Regarding that, I think some things in the benchmark are not necessarily useful for end developers, but moreso for library authors. So I believe that we should expand on the test cases to make them more representative of an end developer experience.

The current benchmarks are very limited in scope, only manipulating table rows, but there are other aspects of frameworks that are imports:

For example how components are distributed into other components (in React this.props.children and in Web Components ShadowDOM slots, etc).

The current benchmark doesn't test props going into components.

It would be a lot of work to update all the example to all implement a more realistic example that covers more features that developers expect from all frameworks (and if those feature don't exist, like component distribution, that's fine, the implementation for that particular library just has to achieve the same thing somehow in a way that separate the "components" into two different re-usable pieces of code, even if it means just template string interpolation or something, or passing content nodes in via methods calls, or etc).

trusktr commented 4 years ago

most webcomponent solutions seeking greater performance might just write most of the benchmark implementation in a single component anyway since it isn't that large

@ryansolid Exactly, they could, but it doesn't capture what we really want to represent.

Maybe some libs are fastest with the current benchmark, but what would happen when we have deeper trees with component boundaries and distribution, and props flowing (or function arguments flowing, for libs that don't have component distribution, etc).

Standalone jQuery isn't even in the benchmarks, but I think it should be if vanilla JS is, so that we can get even more understanding.

ryansolid commented 4 years ago

Standalone jQuery isn't even in the benchmarks, but I think it should be if vanilla JS is, so that we can get even more understanding.

Maybe.. I wasn't a fan of this originally, but we have gotten more reference builds the last few years. See I don't consider VanillaJS a competitor but a baseline. I think most library authors are interested in seeing how their list handling works here, reconciling, nested partial updates, appending/clear. Look at memory usage and bundle size etc. But I can see how it might be interesting to see if jQuery has not aged well enough that even a mostly vanilla implementation might be slower than some of the top declarative libraries. We've seen that for the Web Component reference build and the WASM ones. But that is more interesting to certain people who get it. I think a number of people didn't want to see people go.. look jQuery's faster than Inferno take your fancy framework and go home. It's just not even comparable.

As for Web Components a couple more I think got in like litElement(although it did the one component thing like I predicted). The unfortunate part about doing them in the table based benchmark is you need to use native extensions so that the TR remains correct. Not sure if that limits some libraries. What I want to see more than anything else is Stencil. It's consistently high performing on the web component side in other benchmarks.

trusktr commented 4 years ago

The unfortunate part about doing them in the table based benchmark is you need to use native extensions so that the TR remains correct. Not sure if that limits some libraries.

True, but if we were to fork the benchmark and make it be a table-like custom thing, that'd be fine, as long as every framework does it the same way, so that Custom Elements in Safari can have a fair ground (where is="" isn't supported).

I'm adding this to my wishlist of things todo. :D

I think most library authors are interested in seeing how their list handling works here, reconciling, nested partial updates, appending/clear

I understand that some people want to compare only declarative libs against declarative libs, but ultimately there's a target goal, and different way to achieve the goal.

Maybe an updated benchmark can have some check boxes for like "declarative libs", "imperative libs", etc, to show/filter the results.

leeoniya commented 4 years ago

Maybe an updated benchmark can have some check boxes for like "declarative libs", "imperative libs", etc, to show/filter the results.

this is probably an impossible distinction to make since most (all?) of the top libs use a hybrid approach.

trusktr commented 4 years ago

@leeoniya What do you mean by hybrid approach?

In my view, React/Angular/Vue/Svelte and similar libs all use a declarative approach for the DOM representation. They all have a markup "template" of sorts that is declarative, where we write HTML or HTML-like declarative syntax (even if under the hood the compiled version is imperative, but I'm talking about the end developer surface area where the dev writes declaratively). In this sense, I think most of the popular libs are declarative for representing the desired state of the DOM based in input parameters.

But when we (as an end developer) write an app purely with document.createElement, el.appendChild, etc, then we're writing imperative code. I think most "top" libs avoid that imperative code for DOM manipulation, and aren't hybrid.

Curious what you mean by hybrid though, so we can clarify. I think a "declarative" checkbox being unchecked would effectively remove React/Angular/Vue/Solid/etc from the list of results.

ryansolid commented 4 years ago

@trusktr I think he's talking about the "cheats".. Things like explicit event delegation or places where libraries side step the selection test by basically finding a way to cache the DOM node or storing the per row state on the data. It sort of breaks the illusion of declarative. Once could argue that any library that allows for custom directives falls into this category because it is designed to allow custom wrapped imperative DOM code. But as been illustrated a VDOM library could more or less do the same with Refs and Component wrapper. So it's less about the approach and more on what is seen as acceptable as declarative.

The line is pretty grey I feel. Since like is infernos linkEvent for explicit binding considered not declarative? I think even though it is directive like it still declaratively expresses the idea. Then it becomes a debate of what is shipped with the library. Still weak cause someone could choose to ship that stuff. Solid shipped selection delegation with the library for quite some time but that doesn't change the nature of it really. All libraries have escape hatches so they can go as vanilla as it makes sense for them. Some of the ones that live closer to the DOM do so without prejudice so it does call into the question of how pure the implementation is.

If you aren't clear what I"m talking about.. look at how many implementations that walk up from the event target to the TR to read the text or label on the row to identify the id for event delegation. Ie.. they bind in the view to the tbody element instead of the individual tds for selection and removal. Now most VDOM libraries do delegated events anyway behind the scenes so the other libraries not doing delegation is a huge disadvantage, but there is definitely DOM crawling in the implementation. Again this is sort of what is shipped versus not shipped with the library thing.

trusktr commented 4 years ago

Added Microsoft Blazor to the list of contenders

ryansolid commented 4 years ago

Added Microsoft Blazor to the list of contenders

It's already there..you just have to scroll really far right.

trusktr commented 3 years ago

Another one I stumbled on: diffhtml

trusktr commented 3 years ago

This one is interesting:

weswigham commented 3 years ago

Almost assuredly has the worst perf you can get, since it relies on both es6 Proxy and pre-es6 loose mode with in its implementation, neither of which are well-optimized by runtimes. :wink:

krausest commented 3 years ago

Closing all issues that ask for some implementation - but please feel free to submit a PR for it!