I started building an app using plain Web Components (HTMLElement subclasses) and I've been blown away by how simple, fast, lightweight and versatile it is.
Some lessons I learned:

- You don't need reactivity when you have good encapsulation.

- You don't need bundling for your main app (though some of the modules you use may benefit from bundling if they have a lot of small dependencies). You can preload dependencies using the link tag with rel="modulepreload" to remove latency for nested sub-dependencies so your app loads really fast and it gives you a lot of control.

- Building an app controller to handle front-end routing and instantiating your page components is actually very easy. It doesn't require much code.

I think the first one was the most surprising for me. I remember a core problem with jQuery was that the imperative approach didn't seem to work for single page apps; for example
the user would change to a different page but some callback from an earlier request would be called a few milliseconds later and jQuery would try to update an element which no longer existed from the previous page...

What I found with Web Components is that because each page is its own HTMLElement and all its logic is confined to a single component, it naturally garbage-collects after itself.
You can add event listeners all over the place inside your page component and when you change page, it becomes detached from the DOM and so they are all cleaned up automatically once the page component instance is no longer referenced. There is no DOM timing issue because changes to the component's internal DOM can happen independently from the main HTML DOM, even when the component is detached from the main DOM.

Also, you can have a render() method which clears the page components' DOM and creates it from scratch every time just like in React... Works very well with sub-components having their own render methods too.
You can call it as many times as you like and don't need to worry about cleaning up event handlers because when child components are removed, their handlers are also automatically marked for garbage collection.
Also, it gives you a lot more control as you don't necessarily need to re-render the entire component every time some data changes; sometimes you just want to update the value inside a single child element; it's a lot more efficient. You can mix and match; when there is a substantial change to the page, you re-render the whole component, if it's just a single attribute change, you just select and change that single child component.

I learned that the real game changer of React was probably not reactivity, it was the ability to fully encapsulate logic and markup inside components.
I find that I actually like the additional control and flexibility provided by the imperative approach and it doesn't add much more code (and the code is a lot easier to follow/more readable).
With React and others, there are often challenges related to fine-grained control; like when data is loading, it's a little bit messy if you want to show a loading indicator instead of rendering the value as the number 0 for example. Also, I find that many React apps suffer from multi-rendering issues where some heavy components are rendered much more frequently than they need to because several small pieces of data change in quick succession.

Reactivity is a euphemism for 'giving up control over how your app is rendered' but it doesn't add as much value as people think.