How difficult is it to assemble the pieces you need
First of all, let’s be clear what we mean by a framework. For me a framework embodies some application architecture and, as long as you fill in the right pieces in the right way, it will call your code and make it run. But the framework is the thing in charge and you work in the way that it dictates. Frameworks can be great when you are getting started because they provide some of the structure that you may not know how to build yourself but if you don’t mind “some assembly required” then libraries provide a lot more flexibility and less lock-in. The theory is you can pick and chose the libraries you want to use and replace any of them as you need if something better comes along. You could consider a Framework to be a ready-assembled group of libraries but the framework makes the rules.
But times change. Just as jQuery made perfect sense and provided valuable abstractions to mask the myriad browser inconsistencies, but is less valuable now that things have become more standardized, so too many of the features that frameworks provide are no longer quite so necessary as increasingly the browsers have the capabilities built in directly.
Whatever framework you use, it’s easy to fall into the trap of assuming that it’s needed but the reasons it was needed some 2+ years ago, or whenever you started using it, may no longer apply or be as valid. The browser platform is developing all the time so it’s good to re-evaluate our choices from time to time to make sure we still need them and we’re not just using them because they have become a comfy blanket that we’re familiar with.
Instead, we can use the platform itself whenever possible and, where it makes sense, use libraries to make using that platform a little easier and more convenient, so long as they don’t cost too much in terms of performance and are stepping stones to what the platform may adopt in future.
There are still things we need and that make sense to re-use across projects rather than re-invent and re-implement for each one so I’m certainly not advocating no-dependencies whatsoever but it’s beneficial to treat them as libraries we need to do specific tasks. So let’s look at the main pieces and options we have for using libraries to provide the functionality we need and how we can put them together.
This is an opinionated list based on what I use for my development, you should be able to replace the pieces with what you need though.
If you have a web app, you have users and you need to authenticate them. If you don’t then you just have a static website so stop overcomplicating things and just use your favourite CMS or site generator such as Jekyll or Hugo or write your own.
I’m a big fan of Firebase Authentication because it’s “cheap as chips”, works great and is very easy to use. So I’m using that but you could plugin whatever other auth system you use instead.
The two-way data binding used to be all the rage but as an approach it’s really fallen out of favour and is dying out (like an evolutionary dead-end). Once you experience the benefits of one-way / immutable data flows using something like Redux you will never go back. So use Redux and learn to use it correctly - it’s well worth the investment.
Although there are alternatives, it’s worth remembering that there is a whole ecosystem of tools and libraries for Redux. We’ll use some of the common ones to make handling remote API calls and other async actions easier plus some associated libraries to efficiently create views of the data in our store.
The web is all about URLs, and mapping URLs to views in your app is what the router does. For a Single Page App it also prevents links to views re-loading the app each time and instead intercepts them and switches out the views so everything is super-fast.
The active view and the parameters for it are just state like any other and that state should be in the Redux store. If we use middleware to keep the Redux store in sync with the browser address-bar then our app can just work from that state.
We want our views to be encapsulated components and this requires two things - components, or classes, and some way to render them into HTML to show in the browser. Fortunately, the WebComponents standard now provides a component system natively built in to the browser complete with lifecycle methods we can hook into. So that just leaves the rendering of our state, via the components, into HTML. While we could code the DOM manipulation ourselves, this is one of those pieces that can be made generic and there is a new game in town for HTML view templating called Lit-Html.
TL;DR; Lit-Html lets you define the HTML template as a special type of ‘tagged’ string and can then replace the variables within it whenever those variables change but super-efficiently so it’s not wasting time updating any of the pieces that didn’t.
This used to mean a backend JSON REST API but the the cool kids will laugh at us if we’re not “serverless” and truth be told, serverless is really convenient and as we’re using Firebase for Authentication, we may as well use Firebase for the the Datastore as well.
You may have heard of, or already tried, the Firebase Realtime Database but there’s also a newer Firestore database that kind of merges the RTDB with the Google Cloud Platform Datastore and gives you nicer structure to your data (vs the “big JSON doc” of RTDB) while keeping the live data syncing capabilities and even adding some nice offline capabilities out of the box. It can be significantly cheaper as well and provides easier / richer querying (it will be very familiar if you’ve used Google Cloud Datastore)
Here’s the complete shopping list of libraries we’re going to use and what they deliver for us:
I’m still working on tidying a few things up (esp. the routing part) and will post more about how it works and how the pieces fit together plus some of the design decisions, but you can checkout the source code at:
Let me know what you think and if you have any specific questions or suggestions on what to cover in future.