This post is a cross-post from my blog.
... to your browser like a concave lense will spread light rays. Keep this sentence in your mind and come back here after the post.
If you are now wondering what the hell I am talking about, you are absolute right. With this sentence I want to explain the main concept of my idea of building a Single Page Application with concave - a tiny JavaScript UI framework.
Another JavaScript UI framework?
Yes... feel free to leave this post before even reading it, because this is the main pattern in nowadays tech arguments. Everything nowadays must be build with one of the top leading UI frameworks / libraries. There is a lot of hype around the major ones and it's clear why: Generating money with complexity. There are courses, videos, tutorials, workshops, conferences, podcasts, youtube channels and so on. People earn money to explain the concepts behind because there are some times so many that not every employee can follow up. It's okay for me that this industry exists, but I'm not okay with blindly following or advertising one golden approach which will lead to complexity in the wrong field. What I'm seeing a lot on the web platform is that people first choose the tool and afterwards adapting the problem they are facing to fit it.
My motivation
I'm a person that is really into performance optimization and tries to get the most out of something. The funny thing is, that I ingored that deep motivation in me and was really surprised by the result at the end. I wanted to create something simple with just a few easy understandable concepts. The framework should be shipped with batteries, so that developers only need one dependency. It should be directly usable in modern browsers to allow prototyping in sandboxes. And the most important point was to just use the platform and keep a potential bundler build process as simple as possible.
"Okay okay... all this already exists!" Maybe yes, maybe not. What I wanted to build is a framework that has no dependencies and is implemented in modern vanilla JavaScript. It should have everything that I need to build a functional SPA - this means it need at least a router (builtin), eventually a store to manage you application state (builtin) and some architectural guide to structure the code in components.
I told you that I have a heart for performance on the web, so I set myself a goal to reach this in 1 KiB.
SPOILER: I missed the goal, but it's not far away.
Sometimes it's good to have an unrealistic goal because it forces you to think different and walk other ways. And isn't that exactly what I wanted to reach in the first place: Explorer new ideas to face a set of problems instead of blindly follow the mainstream.
The framework: concave
Here are some key facts about concave
- Declarative - Components are powered by a ES6 template tag function to easily define templates
- Reactive - Components will be updated & re-rendered automatically by state changes
- Batteries included - State management & router are builtin without any dependencies
- Minimal - < 1.5 KiB minimized & gzipped dependency free ESM module
Let's start with a boring Hello World:
If you want a pure browser experience try out this CodeSandbox which uses just the native ES module.
Concept
The main concept consists of a pipeline of functions which will be controlled with actions (plain JavaScript objects). If you are familiar with functional programming concepts, then you will recognize that a pipeline in concave is mostly the same as the result of a pipe
function in FP.
There are the following predefined factory functions which will return ready to use pipeline functions:
-
createStore
>> creates a store pipeline function -
createRouter
>> creates a router pipeline function -
createRenderer
>> creates a renderer pipeline function -
createComponent
>> creates a component pipeline function
They will be composed with createPipeline
which returns a pipeline of functions. You can also compose pipelines with createPipeline
if you want. This could be interesting if you want to compose different parts of your application.
With runPipeline
you start your pipeline and the first action (state) will flow through the functions.
Through all of these composed functions, actions will be passed to control your application.
E.g. the state
action - when a component receive this action, it will check if it need to update itself and will trigger a render action on the pipeline if neccessary.
This simple concept results in:
- Unidirectional action flow >> time traveling & easy debugging
- Pure components >> predictive rendering results
- Single source of truth store >> only a state reducer can modify the state
Internals
Concave uses a really naive rendering approach internally. If a component uses a property that is stored in the state and this prop changes, then your whole component will be replaced by the new one. This sounds like a terrible idea doesn't it? The truth is for every example I build so far this was no problem, but I'm not a fool: This rendering approach will not scale well for real big applications with a lot of data exchange. This is okay because it's not build for that case. It's build for really fast boot up and small footprints on your asset budgets. Keep in mind that you don't have to think about why, why not, when and when not your UI will update. It's always the same behavior - naive, simple and working.
When to use concave?
Valid use cases to try out concave:
- small to medium sized SPAs
- static SPAs (e.g. portfolios, blogs, side projects)
- Progressive Web Applications (PWAs)
- bootstraping a bigger sized web application
- small teams that can figure out their own architecture
Don't use concave:
- SPAs with a lot of reactive data
- applications with a lot of animations (re-rendering will trigger them eventually)
What's next
This post was a quick intro to concave. If you are interested in more details checkout the GitHub repository of concave where your find more information about internals.
I just started to build a portfolio of mine with concave, so feel free to check it out. I will fill more data soon, to have an idea of performance with concave.
For updates, follow-up posts or sarcastic Tweets follow me on Twitter!
Thanks for all who read the whole post till the end! It's my first post on dev.to so I will appreciate any feedback or comments :)
Links
- concave@GitHub
- me@GitHub
- me@Twitter
- Portfolio << build with concave
Top comments (0)