1. Returning new JSX elements from every render
2. Building key indexes for every subdiff
The first issue can be solved with application-specified memoization in render. The second issue is pretty hard to avoid if you want to avoid matching elements based on indexes (naive subdiffs). Implicit and explicit keys are there for a reason, namely that moving elements is assumed to be a much less expensive operation than unmounting and re-mounting them. The O(N) trash memory overhead per subdiff incurred due to key indexes is justified, in my opinion. If using an algorithm like LCS, you'll incur more time/space cost, but you will even further minimize the edit path. <ul>
{this.state.bigList.map(i => <li>${i}</li>)}
</ul>
I don't think Imba would perform much better than these other libraries for templates which are 99% dynamic (like this one), and so the dominating term here is the subdiff term, where you will end up either: 1. Creating at least O(N) trash memory (e.g. key indexes)
2. Doing unnecessary mounts and unmounts
The cool thing is you could diff two different DAGs against each other and listen to the delta, like `diff(<App1/>, <App2/>, consoleLogPlugin)`. The base library could be used to generate application frameworks as long as your application framework can be thought of as a DAG operating on data. React is an example of such a framework, but so is something like Airflow, so you could write a plugin that lets you build your own kind of Airflow. That was the motivation behind my DAG abstraction -- to make it easy to create DAG frameworks for frontend and backend. Let the base library do all the hard reconciliation work, and you can build application frameworks on top.
Anyway that was all mostly an exercise. I didn't end up using my framework for anything more than a state management solution for React. It handles global data perfectly, although these days React context or hook management is usually enough.