TL;DR Modern JS app-building frameworks & libs share one quality - they are component-based. Why not use this (high) granularity to bundle components into small, user journey-focused micro-apps instead of building humongous, complex SPAs. Such model, if applied properly, may bring certain qualities usually associated to microservices into UI layer.
But in fact, does making SPAs out of every client-facing app make any sense? Many teams keep over-engineering their stuff (virtual component models, multi-version parallel framework, advanced cross-module communication, dynamic module life-cycle mgmt, ...) for the sake of being "future-proof" (meeting anticipated future requirements & growth), but they inevitably end-up fighting excessive technical complexity, instead of business domain-related challenges.
Here be ... micro-apps?
Don't get me wrong here, I'm not suggesting you to get back straight into server-side templating (yikes), server-side stateful controls (yikes x 2) or "RIA" plugins (yikes x 3). The model I find optimal is a hybrid of:
- server-side: routing + Web API + separate static scaffold as an anchor for each future area (FA)
- client-side: small trees of a few lightweight components as separate (independent) micro-apps (fully reloaded when you're navigating between them, only 1 loaded in particular time)
Before we dive into the details of what micro-app is & what does it matter, one clarification: the general purpose of introducing this concept is not to provide new feature capabilities, it's all about maintainability, delivery process agility & overall simplicity.
What we're losing & why it is (or isn't) a problem
The goal is to take what's best from the both worlds (client-side web apps & server-side web apps), but it's just not possible without inheritance of some drawbacks ...
- navigating between FAs means full-page reloads - it may impede UX (full re-renders), but also reduce the impact of potential memory leaks, loose event handlers, etc.
- each navigation between FAs causes re-initialization of a new micro-app - fortunately its impact may be reduced if you cache static content (ETags linked with versioning) & use lightweight frameworks (like Vue, Flight, Inferno or React)
- sharing a state via store manager (like Vuex or Redux) is more troublesome, but e.g. one can use web workers to contain state between reloads if needed
- cross-component communication gets more tricky as you can't just use basic event bus (components are not loaded in memory in the same time), but this can be solved via routing or pipelining custom events via web workers
What we're getting
Fortunately all the cons mentioned above are at least counterbalanced by some significant pros:
- hereby introduced "micro-apps" are more light-weight & have clearer boundaries - so e.g. there are supposedly more testable
- what is more - development dependencies of such micro-apps (e.g. libraries & their particular version) can vary among themselves (so their delivery cycle doesn't have to be synchronized): that actually means that you're getting a lot of benefits usually associated with microservices (e.g. loose coupling, separate deployment, openness to partial re-writes, etc.)
- this model is revamp-friendly, i.e. it can be used to gradually migrate old applications from legacy platform (e.g. ASP.NET or JSP/JSF) to new, lightweight one - due to barely any restrictions on scaffold, old "modules" can easily co-exist with new ones in parallel
Obviously there are some pre-requisites for this model to work:
- inter-Feature Area boundaries can't be random - they have to match user journeys as the UX during such a serie of interactions has to be as fluent & convenient as possible
- there are some application paradigms that just don't match such a composition model: e.g. dashboard-alike, highly configurable, complex "control panels"
- framework/library you're gonna use to build you micro-apps have to be really lightweight: initialization time matters, so does size of bundled development dependencies for each micro-app
- scaffolding & navigation scheme has to be well thought-through as it will be a main, common convention shared by all the present & future micro-apps; changing it at some point may be tricky
Still, even keeping this constraints in mind, I find the micro-app approach a very sensible compromise between pure-JS app potential & server-side app simplicity.
Pic: © deeaf - Fotolia.com