Page MenuHomePhabricator

Spike: Research JS UI libraries that can render in browser and server
Closed, ResolvedPublic

Description

Research the different alternatives for modern UIs in browsers that are capable of server rendering.

Initial research was started in a Gdoc in the wikimedia hackathon: https://docs.google.com/document/u/1/d/16oL-_166IvPNkVV0qQ3HJGtK9CynY5okygf0GdPRw60/pub

Things we know:

Outcomes

  • Fill a table with the following information:
LibrarySizeSize(gzip)Size(gzip) +router+state mgmtDom perf scoreServer render scoreMaintainedUsed byLicense

And mark on each column which is best ✅ and worst ❌

  • Schedule discussion on frontend standards group
  • Document on wiki the table, methods, and discussion outcomes

Event Timeline

Follow up to hackathon and Front-end-Standards-Group discussion.

Preact is favored because of size and good enough performance, the wikidata team have started experimenting with vue on certain parts.

Let's document things properly to make a sensible choice and for reference in the future.

Preact is favored because of size and good enough performance

An open question I have about Preact: How do they keep up with changes to the react API? I really like small and fast, but I felt a bit unsure about how sustainable their compatibility is.

Jdlrobson triaged this task as Medium priority.Jun 20 2017, 4:42 PM

@Jan_Dittrich There is this optional package [preact-compat](https://github.com/developit/preact-compat) that shims the React API if you need it.

First, I'm interested, are there any reasons you think it is important to use the React API?

How do they keep up with changes to the react API?

I'm not a maintainer of theirs but I guess by keeping an eye on React releases, having good tests, and users of the library? It has quite a good amount of react like tests on that library.

I felt a bit unsure about how sustainable their compatibility is.

React is widely used and they are committed to a stable API and migration paths for api changes. I'm guessing that gives things like this time to adapt. Other libraries like inferno are doing it too.

These are just guesses though. I'd welcome any help gathering more information.

any reasons you think it is important to use the React API?

As far as I understood this, preact says it is compatible with React. That "compatibility to react" is what I referred to with "react API" (but maybe, technically, this is not API)

React is widely used and they are committed to a stable API and migration paths for api changes.

My concern is the following:

  • Preact seems to have a smaller community then vue or react.
  • They seem to need to follow react with its developments to keep the advantage to be compatible to react

Which resulted in the concern: They may have less resources and in addition less flexibility because they can’t keep compatibility AND say "we only focus on bugfixes for some time", which is what I see as a possible point of failure. Thats why I voiced the question of preact being a sustainable solution.

As far as I understood this, preact says it is compatible with React. That "compatibility to react" is what I referred to with "react API" (but maybe, technically, this is not API)

To clarify, preact uses the same paradigm as React, but has some differences. It is compatible if you use preact-compat on top of it (as an extra).

My concern is the following:

  • Preact seems to have a smaller community then vue or react.

Preact itself is smaller, yes. Community size is something to consider which is why I added *Maintained* & *Used by* to the table headers to help inform any decision 👍

  • They seem to need to follow react with its developments to keep the advantage to be compatible to react

Which resulted in the concern: They may have less resources and in addition less flexibility because they can’t keep compatibility AND say "we only focus on bugfixes for some time", which is what I see as a possible point of failure. Thats why I voiced the question of preact being a sustainable solution.

Of course a valid concern to be taken into account generally.

Specifically I don't think you should worry about React compatibility unless we decide to use it. I don't think that would be necessarily our case.

I also think applies to every library. They all end up deprecated and superseeded. Like Backbone, like Angular 1, like the current famous ones like React and Vue will.

That's why there are other important factors to look at for choosing a solution.

If you ask specifically about preact, I can tell you why I think it is less of a risk in terms of sustainability:

  • It is focused on one thing: being the view layer between you and the DOM
    • Compared to other libraries that do more, it is easier to replace with some other view and keep the rest of your stack the same (less risk than all-in solutions)
  • It is very small
    • preact (master=) => cat src/**/*.js | wc -l
      • 1064
    • Small amount of code is easier to read, understand and contribute to, even to fork if it became necessary

These of course apply to other options, and I'm not advocating for preact necessarily.

If you have suggestions on other factors to look at let me know and we'll incorporate them to the task.

I've started work here. I'll bring the summary table back when I'm finished.

The doc definitely addresses the desired outcomes. Is there supposed to be a conclusion here or not?

On size alone, Preact seems like a good choice. Does that include jsx? React bundles this automatically right, so side by side it may not be the best comparison?

Any plans to measure Dom perf score for OOjs UI ? (maybe by forking https://github.com/krausest/js-framework-benchmark ?) While that information is not present it's definitely a negative point against OOui.

Possibly offtopic... but...
Being unfamiliar with Vue.js and the various other libraries could we get some side by side pseudo card examples of how to generate some kind of standard hello world widget ?
The size differences intrigue me as I wonder if this is because the libraries are more generic/versatile or bloated. For instance, if React is 150KB, when I build complicated things do I save myself writing additional bytes or do I find myself writing new code on top of it? A lot of bytes is not necessarily a bad thing if it makes the rest of the implementation less complicated and saves you writing additional code.

Nitpick: jQuery is not used by the whole internet. Many people are actively trying to move away from it (http://lea.verou.me/2015/04/jquery-considered-harmful/) :)

Only conclusions I can draw are that Inferno should probably be dropped from consideration, but all the other libraries seem like fair game...

Being unfamiliar with Vue.js and the various other libraries could we get some side by side pseudo card examples of how to generate some kind of standard hello world widget ?

Great idea. After brief googleing I did not find much, but maybe we can use snippets from TodoMVC or so?

The size differences intrigue me as I wonder if this is because the libraries are more generic/versatile or bloated.

Good question. I was told (and had the impression myself) that vue’s abstractions are meaningful and save lines of code ("Dev friendly"); as well, it does not recreate HTML, so it saves quite some time in working with not-knowing-the-framework people (e.g. Designers) (@Milimetric, @Aleksey_WMDE, does this make sense?)

Example component […] deleted, since below is a better example by @Jhernandez

The doc definitely addresses the desired outcomes. Is there supposed to be a conclusion here or not?

Not for now, the next steps are sharing the info with others in the frontend standards group and writing down the discussion notes. With all that we should be equipped to make some decisions.

On size alone, Preact seems like a good choice. Does that include jsx? React bundles this automatically right, so side by side it may not be the best comparison?

JSX is a compile time transformation, independent of React. It is syntax sugar over
plain function calls. For example:

<div>
  <button class="btn" onClick={console.log}>Banana</button>
</div>

Get's transformed to JS code:

h("div",null,
  h("button",
    { "class": "btn", onClick: console.log },
    "Banana"
  )
)

We can use or not use JSX, it is up to us.

Any plans to measure Dom perf score for OOjs UI? (maybe by forking https://github.com/krausest/js-framework-benchmark ?) While that information is not present it's definitely a negative point against OOui.

I had a look but it seems like too big of a task to tackle for the purposes of this information. Also OOJS is quite raw DOM manipulation, so basically depending on how dumb you make the implementation, or how much you micro-optimize it you could get widely different results. It would be great to see that information/experience though.

The size differences intrigue me as I wonder if this is because the libraries are more generic/versatile or bloated. For instance, if React is 150KB, when I build complicated things do I save myself writing additional bytes or do I find myself writing new code on top of it? A lot of bytes is not necessarily a bad thing if it makes the rest of the implementation less complicated and saves you writing additional code.

Agreed. Like including jQuery, besides its size, it is very useful and worth it if you are using most of it.

Only conclusions I can draw are that Inferno should probably be dropped from consideration, but all the other libraries seem like fair game...

Agreed. Sadly I believe that we also have to discard React because of license issues. IANAL, but that's what I've heard, until the license is OSI approved, we shouldn't use it in Wikimedia. Same goes for every other project with the facebook patents grant (Jest, Flow, etc)

JSX is a compile time transformation, independent of React. It is syntax sugar over plain function calls. … We can use or not use JSX, it is up to us.

At least for our context (Wikidata/Wikimedia Germany) I think it is important to collaborate easily with designers and/or new colleges. Thus I would like to evaluate it with JSX (or any other way to transform HTML-like to "reactive calls")

The examples from T167041#3394034 but reformatted and + preact and preact(no-jsx):

Vue

Example component (with user interaction) for vue (source+demo), assuming you use vue single-file-components

<div id="app-5">
  <p>{{ message }}</p>
  <button v-on:click="reverseMessage">Reverse Message</button>
</div>
var app5 = new Vue({
  el: '#app-5',
  data: {
    message: 'Hello Vue.js!'
  },
  methods: {
    reverseMessage: function () {
      this.message = this.message.split('').reverse().join('')
    }
  }
})

React

Similar example react (source and demo)

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

    // This binding is necessary to make `this` work in the callback
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}

ReactDOM.render(
  <Toggle />,
  document.getElementById('root')
);

Preact

Mostly the same as react. Demo and source

const { h, Component, render } = preact;  /** @jsx h */

class Toggle extends Component {
  constructor(props) {
    super(props);
    this.state = { isToggleOn: true };

    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }

  render(_, { isToggleOn }) {
    return (
      <button onClick={this.handleClick}>
        {isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}

render(<Toggle />, document.body);

Just JS (no JSX)

Just to see that react/preact is just plain javascript. (source)

const { h, Component, render } = preact; /** @jsx h */

class Toggle extends Component {
  constructor(props) {
    super(props);
    this.state = { isToggleOn: true };

    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }

  render(_, { isToggleOn }) {
    return h(
      'button',
      { onClick: this.handleClick },
      isToggleOn ? 'ON' : 'OFF'
    );
  }
}

render(h(Toggle, null), document.body);

What I've recently understood that size comparison React vs Vue was not totally fair. (It was in another ticket which I've failed to find.)
If we use React(Preact) with JSX we assume that templates will be precompiled on the back-end.
The same could be done with Vue and then we only need to load runtime part of the library which is significantly smaller:

vue.min.js 77.2 KB VS vue.runtime.min.js 55.2 KB

For what it's worth, we are just working on bundling our very minimal alpha build of wikistats so far (not the prototype, the real application with live data). And the total size for everything minified and gz is 200kB. That's including CSS, state manager, router, apis to grab data, logic and data manipulation, lodash modules, d3 components to visualize, semantic ui widgets, date and number formatting, etc. The only thing that's extra are the fonts for icons. And this is not slimmed down aggressively yet, it's just what we shaved off to have a decent first build. We can probably realistically get around 150kB, especially if we get rid of unused CSS.

I know this is slightly off-topic, but I figured you could use some real-world example of a functional app that wasn't just hello world.

This looks done to me.
@Jhernandez feel free to reopen if you think there is more to be done here.

For completion: In a somehow surprising step, Facebook – after seemingly facing strong opposition to it's BSD with patents license combination, like the latest announcement by Automattic to move away from React – has decided to move towards an MIT license, see https://code.facebook.com/posts/300798627056246/relicensing-react-jest-flow-and-immutable-js/

Also, React v16 has just been released and is smaller (33kB minified) and more performant.

I've updated the summary table with the new license https://github.com/joakin/frontend-libraries-comparison.

Will have a look at updating dom perf scores and file size at some point.