Even Next.js, for all that people are unhappy about its quirks, complexity, and random undocumented behavior and bugs (God help you if you ever want to try and actually use parallel routes as documented), can do all of this SPA stuff out of the box. Use `<Suspense>` appropriately on data loading, and everything static (including e.g. purely input-output components like editors) will load once and be re-used forever, and your Suspense-wrapped items will show a loading placeholder and only re-load when you intentionally re-trigger the data loading (which you can push down all the way to the level of individual buttons if you want).