The amount of complexity I'm willing to accept is proportional to the the difficulty of the problem. In this case it's manipulating web pages, which shouldn't be too hard. This isn't a knock on React in particular, but it seems all the major vendors are competing on complexity. React has "fibers", Ember has a "virtual machine", Angular has their own overblown architecture (I don't know anything about it, and don't want to).
Now that the DOM API is implemented in a standards-compliant way across most browsers, it should be the perfect time to use it. I don't like the current mess that is front-end web development, and more of the status quo isn't going to get any simpler, quite the opposite.
Shameless plug for my own DOM utility: http://simulacra.js.org
1. To sidestep problems with the DOM. The virtual DOM helps with performance, and fibers help with responsiveness.
2. To implement reactive components. Virtual DOM makes rebuilding sub trees of the DOM cheap, making it possible to have clean components that don't need to constantly attempt to tweak the DOM. Doing this style of programming without DOM diffing is possible, but much slower.
There are other approaches, but this one is significantly nicer to code for than DOM binding and is significantly faster than any naive approach.
Yes, you can extract the essence of React into a several kb bundle. It's been done to death. But why? React is fast, mature, has a great ecosystem, and it's nice to code for. It does nice things like seamlessly support SVG and intelligently batching changes. If you're truly making a complex app, it's worth the bump in bundle size.
The largest part of any web app is the browser. If the DOM wasn't so bloated and ridiculous, maybe we wouldn't need to spend all of our time minimizing our interactions with it. But if you try to count all of the work the browser has to do to layout and render one DOM element, suddenly React feels very tiny.
What's missing is that you can make complex web apps without any of these things, or the abstractions used can be something completely different. The reasons you stated just sound like ex-post facto rationalizations of what they did after they built it.
I've been in same situation once with my OS project. I've did something small that I've been certain does what all those other heavier solutions do. But when users came I've learned that there's unimaginable number of edge cases and scenarios that are common enough to require annoying amount of work.
React.js is not "DOM utility". Its battletested view library running one of busiest social sites in the world. It's highly performant, capable of handling thousands of components at single time, and handles countless edge cases, like maintaining input state while user is typing in it and its moved around DOM, normalizing events between browsers, maintaining scroll between large redraws or jumping user to components #fragment.
Ember.js and Angular are complete app frameworks that implement view, layers, services, data, communications testing, tooling and more. Those are solid options for people writing dashboard applications (think intercom or Podio), even if they are losing ground in public-facing sites to more elastic stacks like React or Vue.
Nobody looks at objective benchmarks. My own DOM utility is faster than React.js, and in fact it is not such a difficult feat, there are a few DOM utilities which are faster, also authored by relative nobodies.
I don't worry about catering to IE8 users, neither do most websites, and that number is vanishingly small. I'm also not interested in competing on complexity, which is what happens when one preemptively builds for edge cases.
I will probably never work on a web app that has a wider reach than Facebook. Setting up arbitrary personal goals for success like working on "one of the busiest social sites in the world" and even achieving that won't make me any happier. How much is enough? I've already proven that I beat Facebook at the DOM performance game, and still I'm the Dunning-Kruger idiot.
In fact I refuse to market my pet project as if it is something to be bought and sold. or to assign it a valuation based on how many big companies are using it.
At Facebook 'most browsers' has a very different meaning compared to other websites. When Facebook deploys code that works for 99.5% of their users that means they're failing ~10,000,000 people. Consequently they have a lot of code to handle the cases where they can't just rely on 'most browsers'. It's entirely valid that they maintain a relatively large library, and pretty awesome that they share it publicly.
With React Native I re-use over 75% of code from the web version of my apps. An actual measurable leap in productivity. Or even just for the web version, React and other frameworks (inb4 "not a framework"), provide their own proven patterns and best practices for scaling a code base, a task that is out of scope of any DOM utility library. And if providing those patterns requires more complexity under the hood, well, you don't refuse a free Lamborghini because it's "more complex under the hood" than your current Toyota.
I even see it in your landing page marketing.
> MINIMAL
> One function
> Its entire API surface area is a single function
Then I scroll down. var bindObject = require('simulacra')
var bindEvents = bindObject.bindEvents
var animate = bindObject.animate
var retainElement = bindObject.retainElement var helpers = require('simulacra/helpers')
var bindEvents = helpers.bindEvents
var animate = helpers.animate
There is no practical difference. It is just for those who read code but lack reading comprehension skills.To demarcate this separation better I have considered moving the optional convenience functions into a separate module, which might help clear things up.
Edit: actually it seems that you were being dishonest when quoting me, this is what it says, you cut it off short:
>Its entire API surface area is a single function (with some optional helpers and symbols)
That makes it pretty clear that the core functionality is a single function.
Calling React "DOM utility" does not sound fair. While one of the major problems it solves—slow DOM operations, I'd say that unidirectional data flow is even more important.
Fancy selling points like "unidirectional data flow" don't actually mean anything. Each fanboy has their own variant of this, like "transclusions", "immutables", "dependency injection", etc. These are all phrases I've heard that don't translate to tangible results.
This is how projects end up with millions of lines of black box dependencies. This is why `node_modules` folders that are hundreds of megabytes exist.
Take a look at benchmarks [0] and tell me, if any framework performs faster than vanilla JS. They probably are faster than vanilla code that you'd be able to write on your own, but that says more about your abilities than the performance of frameworks.
[0] http://www.stefankrause.net/js-frameworks-benchmark6/webdriv...
From a quick look at your approach, I have one concern:
<template id="product">
<h1 class="name"></h1>
...
You seem to use classnames as variable names. What if some other template has a "name" variable too? What if a stylesheet uses it?I prefer simple placeholders. Instead of:
<h1 class="name"></h1>
I would use: <h1>{{NAME}}</h1> <h1 class="name" data-bind="name"></h1>
It was also a design goal not to introduce a templating syntax, so `{{}}` brackets are out of the question.It's not an UML diagram. Looks more like an ad-hoc flow chart (unless I forgot a specific type of UML diagram that looks like this).
Fantastic work and a great resource for people wanting to dive into React's internals.
Great work by the author nonetheless.
Incidentally, this complexity is what led me to build my own little vdom utility <https://github.com/hyperapp/hyperapp>.
I'll be drawing inspiration from this chart to explain it.
There are simpler ways to get reasonably fast re-usable components on your project that introduce less accidental complexity.
Carefully consider which thing you actually need:
- A view library that uses components as the main building block (this usually means you already have other concerns like data modeling and routing taken care of)
- A full SPA framework (which people often get from the react ecosystem, i.e. React + Reflux/Redux/etc + React-Router)
Based on which one you need, there are other simpler (in the case of view libraries), and more coherent (in the case of full framework) choices.
Other libraries don't have that problem (because they didn't accept that trade-off in that fashion).
IMO Libraries that beginners should be shown should not be ES2015-in-every-example, and introducing transpiled DSLs for generating DOM elements.
KO also has components now, and they work super great. Also, while bigger frameworks like Ember (which I love) are just starting to figure out and cement how they work with engines (dynamically loaded chunks of your ember app), KO supported async loading of components with RequireJS so long ago.
Here are some options:
Component libraries -------------------
1) KnockoutJS (just data-binding, quite possibly the simplest I've seen)
2) Vue.JS (More complex, but one of the best sets of docs I've seen, fits in with the DOM model extremely well, few hacks, though I would have loved a simpler data-binding system)
3) Mithril.JS (super small, super fast, very simple. Transpilation tradeoff, it makes you just write the DOM as a JS function with elements like `m('div',[...])`. Have yet to use this one for a large project, but will very soon. Also has a little bit more support for the other thing you might need for a Single Page App.
Full fledged frameworks -----------------------
1) Ember (has been around a super long time, changes fast which is good and bad, and is great for large projects because it has a solid set of conventions)
"Seriously dude, you're still using React? That slow, bloated pig that creates a call stack 75 frames deep to change the label text of a button? Sheesh, get with the times, and use _____.js! It rocks!"
> An instance of what should be created (03)? Component… right, but which one? Well, it’s a good point. No, not <ExampleApplication /> that’s 100% :) We actually should instantiate some internal class. Let’s check out the next scheme at first.