Why You May Not Need A Framework
This was a talk given at the 2017 Des Moines Web Geeks Social Event.
Recorded video of the event: facebook.com/DSMWebGeeks/videos/1423410991065489. My talk starts at around 2:14:30.
The talk’s slides are embedded below. Use the left/right arrow keys to navigate.
I’m going to talk about why you may not need a front-end framework for your next project.
Around 2004/2005, this started to change. Firefox was released to challenge Internet Explorer in the browser market. Google started creating some rich apps like Gmail and Google Maps. And then libraries like Prototype and jQuery came out to help smooth over these inconsistencies across the browsers. And so that helped bring us to the present day, which I’m calling the “Age of Frameworks,” where we have these application frameworks like Angular, React, and Vue. This slide kind of shows some of the libraries out there. It’s from a survey of web developers that was made recently. The far left bar is jQuery; 3 out of 4 developers have used jQuery in a project, and many other developers have used Angular or React or some type of library for their application. The far right bar shows that less than 3% of developers do not use any framework at all for their apps.
Another problem is that we have these compartmentalized ecosystems. This is a snippet from an email newsletter, that I received a couple weeks ago, that has links to these great tools and libraries that you can use for your apps. But if you look closely, you’ll notice that most of these are tied to specific frameworks. They’re designed to be used in these frameworks; they’re not really made to be used in a different framework. For example, if you’re using React, you can use these React libraries, but you can’t use the Angular ones really.
Where I work, at Jack Henry, we have a suite of enterprise apps designed for our financial institution customers. These were created about 3 to 4 years ago, and they’re written in Angular 1. Since then, as we’ve built these apps out, we’ve amassed this collection of libraries — whether it’s a routing library, or UI components — to work in these Angular apps, and they’re all tied to Angular because of the way that the framework works. So we have all of these pieces that are tightly coupled together, and now after a few years we’ve realized that we’ve become caged within this framework.
The problems that you run into if you’re using a framework: Like I mentioned, components that are written for one framework usually can’t be easily used inside another framework. If you write a component for your app, it has to fit within that framework. We’ve run into friction when trying to maintain the applications, or adding new features. New developers obviously have to learn the framework or know it before they join. These frameworks have extra weight that they add to your application, whether it’s just the payload that the users receive, with that extra layer of abstraction that the frameworks give you, or if it’s even just pieces of the framework that you don’t use — often that’s weighing down on the user. Also, this extra abstraction slows down the performance of your application. There’s a good video that some Google developers did that looked at mobile performance and the frameworks specifically, and it showed that they’re really not designed to work on mobile devices with the CPU and the network limitations that they have.
Also, with all the new frameworks that keep coming out, what if you want to move your application to the latest hotness — how do you migrate from one framework to another? It’s usually a non-trivial amount of work. And there’s no guarantee that the framework that you choose will still be around in a couple years, or even a few months.
The solution that we’ve come across is the web platform. What that means is that the browser itself is the framework.
HTMLElement with a new class and then calling
customElements.define() with your tag name and your class, and then you can use it in your app. It’s that easy.
Shadow DOM is the piece of the web that lets you encapsulate your components. It creates the boundaries between the DOM of your component and the DOM of the rest of the page. It keeps those separate. You can also separate your styles so that it doesn’t bleed into other parts of the app; it’s just used for your component. This code here puts it all together — We’ve got your
customElements.define() to create a
fancy-tabs tag. It extends
HTMLElement. And then in your constructor call
attachShadow() to create a new shadow root — that’s the shadow DOM. And then you can import your template there and attach it to your shadow DOM. That’s pretty much all you need to create your own components — your native web components.
Browser support currently for these 4 specs is pretty good. Templates are supported across all modern browsers. Custom elements and shadow DOM have pretty good support or they’re in progress of being added to browsers. Microsoft is thinking about adding support — don’t know when that will be. For most of these that don’t have support yet or are in progress, you can use polyfills to fill in the gaps there. They only real wrinkle is the imports — that specs is actually on hold now; browser vendors and the standards committee are discussing where that might go, since there are some argument about that and the whole ES6 modules stuff and how that will shake out. But you can still use polyfills or transpilers now, if you want to use that.
The nice thing about components, of course, especially native web components, is that you can easily share them. This is webcomponents.org. They have a collection of some components that you can search for, so for example if you’re searching for a calendar. Since they’re native components, you can basically use them in any application or any framework, since there’s very little required to import them into your app.
And then everything else that’s not built into the platform, you can still use libraries. For your routing or your application state, data binding — stuff like that — you can use your standard
npm install, and then import it into your app. So the idea is to have these reusable components and other small libraries, and then compose them into your app, so that you kind of make your own custom framework in a way.
So, about a year ago at work, we had a task to create an online banking white-label app for our customers. This was greenfield project, so we didn’t have any of the baggage from Angular 1 or anything; it was completely fresh. What we came up with for that was an application that used these web components. Here’s a screenshot of the app. Everything you see here is components; it’s components all the way down. It runs on all modern browsers. It’s written in ES6, compiled down to ES5.
There’s really only 3 polyfills that are used: there’s the web components polyfill that provides the custom elements and templates for those browsers that don’t support the native stuff. And then there’s 2 small polyfills; one for the
dialog element and one for the
closest() method on elements. We have a custom router that’s based on page.js. We don’t use any CSS compiler; it’s just pure CSS. But we do use CSS variables and of course the shadow DOM, which makes it pretty easy to work with; we don’t have to worry about it cascading into other parts of the app, it just stays inside the component there. And there’s still the core CSS that’s used for styling across the entire app. The components themselves and bundled using vulcanize and crisper, and we also created a couple of projects to fill gaps in the Polymer ecosystem; one’s for linting, the other’s a renaming utility for Closure Compiler.
If you haven’t guessed yet, for this we’re using the Polymer library to create our components — Polymer version 1. And there is a Polymer app framework out there that we don’t use — it’s more like a traditional framework, I think. The Polymer library itself, which was created and backed by Google, is a very small library. It’s mainly a polyfill for native web components, but there’s also a little bit of syntactic sugar to make it a little bit easier and more concise to write the components.
So, a few months ago, we had the opportunity to rewrite our enterprise apps from Angular 1, from scratch, using any tech stack or framework we chose. The only restriction was that we would have to research and come up with a tech stack that would have the best maintainability for 5 years or so. It doesn’t sound like much, but 5 years is a pretty long time in the tech world. So we had to look at the different frameworks, create some prototypes, and figure out what direction we wanted to go to rewrite these apps so that they would be easily maintained and looking future-forward. We looked at the banking app that we created, and we decided to continue in that direction.
Polymer 2 was released a couple of weeks ago. It’s a very small upgrade; we’re already in the process of migrating our banking app from 1 to 2, and there’s not much to migrate, since it’s a very small library. The direction that we’re looking at is, again, to have these components that we’ve already created for the banking app and can be reused across the new apps as well, write new components in Polymer probably — we’ve started doing that — and then use libraries for routing, application state, and all that on an as-needed basis — evaluate them as we go, and integrate them into our custom app framework. So that’s the idea, to reuse these components, and keep everything as loosely coupled as possible to give us the most flexibility going forward. In case Polymer suddenly dropped off the face of the Earth, we can plug in React or some other view layer for components. If the router turns out to not work, we can throw that out and put in a new router library.
It’s still early days. Like I said, it’s been a year since we’ve used Polymer for the banking app, and we’ve started rewriting our enterprise apps into Polymer 2. But it looks promising; I’m optimistic. I’ll quote one of my co-workers here, since he’s a smart guy. He said:
“These are the early days of web components. I think Polymer is going to help more developers start using components. And in the next several years we’ll see more contenders like Polymer staying close to native APIs but adding what developers claim is missing from the browser. Add 10 more years and nobody will know what we’re talking about.”
Sort of the goal of Polymer — this polyfill — is to eventually just disappear, because as the browsers add these native APIs, the polyfill will get smaller and smaller. Other than maybe a little bit of syntactic sugar, there’s not going to be much there other than that close-to-the-metal native layer.
Maybe frameworks won’t disappear completely, but they might fade into the background a little bit, and turn into the “age of the platform”, where the browser is the framework. I’d like to encourage all of you, the next project that you start, give this approach a try. Simplicity matters. It’s not easy. It’s very easy to install a framework, grab CLI tools or a boilerplate, and just start writing. But as we’ve discovered, it’s not always the best thing for the long term. If you’re building an app that’s going to last more than a few months and has multiple people working on it, you might want to try this: a simple set of libraries, coupled together and using the native web components underneath. You’ll get the flexibility, the performance, and the longevity without sacrificing a lot of the power that frameworks give you.
We had the backing of management to rewrite our apps from scratch, but I would not expect this to be a normal thing at all. It’s very rare to have the time and the resources to be able to take a mature app and rewrite it in a framework of your choosing. So don’t paint yourself into a corner. Look towards the future of where the platform is heading, and free yourself from the framework cage. Thank you.