Complaints against the complexity of modern web development tooling setups have been ever increasing in recent years as the web platform continues to evolve and innovate. A recent iteration of this movement toward simplicity is called the “stackless” (or “framework-less”) approach, coined by Daniel Keyhoe of yax.com.
The core tenets of the stackless approach are:
The core sentiment of utilizing standards is an admirable one, and indeed it may suffice for very small projects or prototypes, but here are some reasons why this approach is infeasible in practice for professional web development or projects of material size.
Frameworks play a critical role in the frontend ecosystem. As the web platform advances, so do the frameworks that build on top of it. They serve as a critical space to innovate and inform the future direction of the web standards.
Frameworks are built to overcome the deficiencies of the standard features until new standard features are introduced to fill the gaps. They can move faster than standards do, and can experiment with features to fine-tune and validate them before they get proposed and adopted by the platform. An example of this was the revolutionary jQuery
function (commonly called $
) in the 2000s and 2010s that directly informed what we know today as document.querySelectorAll
.
To Keyhoe’s credit, the limitations of the stackless approach are clearly acknowledged in the introductory tutorials. Unfortunately, they are prohibitively severe for many types of modern web development projects.
Perhaps the largest omission in the stackless approach is that it doesn’t account for data persistence. The approach talks about abandoning Rails for standards-based JavaScript, HTML, and CSS, but Rails solves a different problem than the frontend browser technologies.
What about an API to hide sensitive or proprietary business logic from the frontend? What about centralized state persistence? What about user authentication? There are so many common problems and paradigms that the stackless approach simply doesn’t account for.
Using “functions” (meaning serverless or Lambda functions) is mentioned in passing, but if you are using serverless functions backed by a database or other storage, all of a sudden you have a “stack” again.
CSS is powerful and chock full of features, but in favor of flexibility, it lacks adequate constraints to guide engineers toward solutions that are maintainable or easy for team members to contribute to.
Even with powerful tools like CSS preprocessors, the topic of keeping CSS under control and well-documented is a common point of discussion for software teams. Even the stackless approach recommends using a CSS framework in the fine print. This is akin to titling an article “How to tour America on foot,” and then in the body paragraph write, “Until we figure out a way to walk faster, just use a car.”
Web components are ill-equipped to manage the complex state required to build an advanced frontend application. The stackless approach can work for simple informational sites, but for applications with complex user interfaces, the state management becomes unwieldy without the help of a framework or state management library.
This is the second time the answer to “how to build an app without a framework” is “actually, just use a framework.” There are very few classes of applications that are both useful and don’t require the management of complex state.
The core problem with the stackless approach is that it tries to abandon complexity without a proposal on where that complexity should go. Complexity, in general, cannot be eliminated — it can only be pushed around to different parts of the system. Here are a few examples:
Hypermedia APIs vs bespoke RESTful APIs. Hypermedia APIs return the relevant data for the resource, along with links to related API resources that the client must subsequently request. The complexity of assembling the full picture is pushed to the client.
A bespoke API, on the other hand, may handle the complexity of gathering all of the relevant data before returning it to the client in a single, neat package. The complexity of assembling the requisite data can be moved around but not eliminated.
create-react-app
and react-scripts
. The Facebook team behind React has tried to abstract away the complexity of maintaining webpack and other configuration to bootstrap a React application as quickly as possible. This allows engineers to create fully functional React application without having to worry about installing and configuring all the tooling; they only have to install the react-scripts
package.
The build tool complexity didn’t go away, its burden just moved into the application’s dependencies rather than on the shoulders of the engineer building the application.
Though using the stackless approach may not be feasible for projects larger than hobbies or prototypes, there are some excellent points in its philosophy that can benefit software projects regardless of which approach they use.
Like any other tool, the stackless approach can be useful philosophy when approaching a problem. If you need to build a simple app where the features of the raw web platform will suffice, go for it.
Using the least powerful technology capable of accomplishing the task or solving the problem is an excellent way to build solutions.
But when working on a team, or on a project with even moderate complexity, leveraging modern frameworks will likely yield dividends throughout the life of the project.
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowLearn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
Bypass anti-bot measures in Node.js with curl-impersonate. Learn how it mimics browsers to overcome bot detection for web scraping.
Handle frontend data discrepancies with eventual consistency using WebSockets, Docker Compose, and practical code examples.
Efficient initializing is crucial to smooth-running websites. One way to optimize that process is through lazy initialization in Rust 1.80.