The best frontend development strategies in 2022
This article is challenging, polarising and thought provoking on purpose. It covers a lot of fresh content and ideas which you are most likely not aware of.
Content
- Introduction
- How many cores are on a computer or smartphone?
- How many cores does a browser use?
- Web Workers API
- The “an application worker being the main actor” paradigm
- Can a worker access the DOM?
- Is there an exception where workers can access the DOM?
- How to create virtual DOM in a smart way?
- Can UI development happen directly inside the browser?
- Is there a future for TypeScript?
- What is wrong with React?
- Multi window apps
- Do we need to implement the workers setup on our own?
- Final thoughts
- [Update] How to get started?
1. Introduction
I will try my best to create a chain of connected logical arguments, which you can follow to get the idea of how frontend development should work.
I will also try to keep this blog post as simple as possible so that “non devs” can mostly follow it.
2. How many cores are on a computer or smartphone?
You have all seen pictures of a CPU like this one:

E.g. in case you are using a Mac, you can click on the top left Apple icon, then on “About This Mac” and it will show you something like:
Processor 3,2 GHz 8-Core Intel Xeon W
An iPhone has 6 Cores.
TL-BR: Every computer or smartphone has several Cores available.
This means that you can run multiple threads in parallel.
Would you build a car using just one engine cylinder?
If your answer is: “Of course not! It would be way slower!”, then you should read this article carefully.
3. How many cores does a browser use?
On its own, a browser will use just one core per tab / window.
Meaning: your Angular or React apps look like this:

The more JavaScript tasks are running inside your app, the slower it will get. The worst scenario is a complete UI freeze where your one core is at 100% and all other cores are completely idle.
This is not scalable at all.
[Side note] In case you are creating simple, small and rather static websites or apps, this setup can be sufficient.
4. Web Workers API
Web Workers makes it possible to run a script operation in a background thread separate from the main execution thread of a web application. The advantage of this is that laborious processing can be performed in a separate thread, allowing the main (usually the UI) thread to run without being blocked/slowed down.
The W3C and WHATWG envision web workers as long-running scripts that are not interrupted by scripts that respond to clicks or other user interactions. Keeping such workers from being interrupted by user activities should allow Web pages to remain responsive at the same time as they are running long tasks in the background.
The simplest use of workers is for performing a computationally expensive task without interrupting the user interface.
So, using workers we can actually use multiple cores in parallel and end this scalability nightmare.
Let the following quote really sink in:
The simplest use of workers is for performing a computationally expensive task without interrupting the user interface.
It leads to the question:
“What is the most expensive task?”
The answer is simple: an UI framework or library itself as well as the apps we build with it.
This is leading to the idea: Let us move everything we can out of the main thread, so that this one can purely focus on what it is intended to do: manipulating the DOM.
In case your apps are no longer running in main, there is nothing left which can slow down or block your UI or create memory leaks.
This thought is leading to the following concept:
5. The an application worker being the main actor paradigm
To resolve this performance bottleneck, we want to get main threads as idle as possible, so that they can fully focus on rendering / dynamically manipulating the DOM:

The worst case that could happen now is that your app worker will slow down and this core runs at 100%. However, this will not affect your UI (rendering thread → main).
The probably best solution for single page apps (SPAs) looks like this:

To prevent the app worker from handling too much logic, we can optionally use the virtual DOM worker and calculate the delta updates between state transitions there. For apps with a pretty idle app worker, you can alternatively run the virtual DOM engine directly inside the app worker instead.
We can also use a data worker. In case we have a remote data store and want to sort / group / filter our data locally, these computations could happen there.
This blog post covers how to make the use of a worker optional while keeping the same API:
6. Can a worker access the DOM?
Inside the WorkerGlobalScope, window
and window.document
are undefined.
Meaning: you simply can not access the real DOM directly.
So, we basically have 2 options here.
Option 1 would be to recreate the entire DOM API inside a worker. In my opinion this is a bad idea. Workers are not aware of the DOM for a reason and there is a massive amount of logic which is frequently changing. DOM OPs become async and in case you trigger many in sequence, it will lead to a lot of worker postMessages. The only benefit is that you can keep writing your apps like before, which is questionable. I will cover how to do it better later on.
There is actually one project doing exactly this:
The smarter approach is option 2: sticking to the concept that a worker should not be aware of the real DOM.
This makes using virtual DOM absolutely mandatory.
Reading on social media, I see posts like “vdom is bad!” quite frequently.
This is simply not true. It strongly depends on how it does get implemented.
The main show stopper inside Angular and React are xml or JSX based templates. These guys need to get transpiled into data structures that we can work with.
JavaScript is simply neither fast nor made for parsing strings.
Parsing templates is so expensive that even server side rendering (SSR) became popular again. I have been there 20 years ago, creating a PHP based CMS which generated html output files.
You could argue that today there is the cloud which can handle more client connections, but the concept of rich / fat / thick clients still makes total sense.
7. Is there an exception where workers can access the DOM?
There is actually one:
Workers can receive the ownership of canvas DOM nodes.
This already works very well in Chromium, Safari (Webkit) and Firefox are actively implementing it. It will probably take 6 more months, so this is a topic for 2022.
You probably noticed the yellow box inside the final workers setup
→ Canvas worker. In case you want to dive into this one:
8. How to create virtual DOM in a smart way?
While JavaScript is not good at parsing strings, it excels at working with nested Object / Array structures. There is a name for this format which you are most definitely familiar with: JSON.
In case we stick to a JSON based vdom syntax, there is no need for the expensive template parsing over and over again inside your UI or for even moving this part into a build step.
It is definitely in a way similar to working with JSX output directly.
Done right, there are no variables, if/else statements, bindings, methods, loops or any kind of logic inside the virtual DOM. You will never see templates with 1000+ lines of code (looking at Angular).
With a programmatic approach, you will use logic where it belongs: inside JavaScript. E.g. when creating a list, you can create a skeleton vdom first and once a data store gets loaded, iterate over the records and create new virtual DOM nodes on the fly.
This concept allows us to radically change your vdom for a component at run time. Yes, changing the vdom of a component before and after it got mounted can work exactly the same way.
Implementing infinite scrolling or other advanced features becomes easy.
You can find a lot more input here:
While a programmatic approach makes sense for low level vdom OPs, we definitely prefer a declarative approach for creating our apps.
To achieve both, the only thing we need to do is adding a declarative abstraction layer on top of the vdom: a component tree.
Meaning: you will only work with vdom when creating your component classes. For creating apps, you can just stick to the component tree.
9. Can UI development happen directly inside the browser?
When React became popular 5 to 8 years ago, browsers were in a bad shape when it came to supporting the latest ECMAScript features.
E.g. there was no support for classes (ES6) or JS modules.
At this point it made total sense to move UI development into node.
Meaning: you could use the latest language features and at the cost of a build step compile / transpile your code into Javascript which browsers understand.
Browsers vendors did a great job at catching up. Today, many shiny new features are directly available and most stage3 proposals do get implemented right away.
Inside the worker scope, JS modules work fine inside Chromium. Webkit (Safari) finished the implementation as well, but it is still limited to the Safari Technology Preview version. Mozilla (Firefox) is actively pushing it.
We can definitely assume that the full support is ready in 2022.
Build steps are expensive and should no longer be needed for the development mode of UI libs or frameworks.
The advantages are obvious:
- JavaScript is meant to be the only programming language which is understood by browser engines.
- Writing JS in a way that browsers can not understand feels just wrong.
- With bringing UI development back into the browser, we can debug our real code without any kind of builds / transpilations or using source maps.
- We do not need hot module replacements.
Especially creating and debugging code will be fun again, since we can ensure there are no external factors causing bugs.
Tools like webpack are definitely still needed for creating the dist/production
output. However, they will be build tools, not runtime environments.
The switch from node to deno will further boost this. CommonJS will die out rather sooner than later. Once deno has a package manager in place, more and more packages will use a syntax which can run inside browsers (e.g. not using bare module specifiers → imports with invalid paths and no file name extensions).
10. Is there a future for TypeScript?
This one is probably the most controversial section of this article. The JS community is split in half: some love using TS, while others refuse to touch it. Looking forward to the discussions.
My opinion:
Right now, when developing UIs in node and having a required build / transpilation step anyway, using TS is fine.
This will radically change once UI development does get back into browsers.
Would you set up an entire build step just for using TS?
At this point, it is getting way too expensive.
The thing is: TS is not a Web Standard. There are no plans to ever implement it into browsers.
History has definitely told us several times what happens to web based technology which is not based on Web Standards: they just vanish at some point. MS Silverlight is a perfect example.
Type checking in general is a good thing. The main problem is that Angular and React just don’t use JSDoc based comments, which enable IDEs to give you warnings while writing code.
It is actually even possible to “fake” TS using JSDoc based comments:
This is definitely an option and something we can discuss.
In case you really want to have type checking directly inside your programming language and don’t care about a build step, would Dart2 not be the way better fit?
Dart2 has full support for workers, so we could get the workers setup running there as well. The advantages for mobile include AOT compilations.
11. What is wrong with React?
To be fair: before React there was JQuery. When React became popular this was a big improvement and React was the first library which made using virtual DOM popular.
So, why should we not use React in 2022?
- React runs inside the main thread.
- The React code base is based on CommonJS → it can not run inside a browser without a build step.
- No JSDoc comments.
- JSX templates are very expensive to parse. There are even compilers like Svelte out there to move it to the server side.
- React does not expose a core. Everything extends Component and this makes no sense at all.
- State management is way too difficult for no reason.
- The
render()
method is definitely questionable.
Let me explain this one more in depth: it is definitely complicated to prevent state changes from triggering render
. In case a React component contains child components (custom tags inside render()
), new instances will get created in case you are not carefully using keys
.
Recreating Component instances made functional programming popular, since creating class instances more often than necessary is not performant and memory leaks inside your own Component implementations can hurt.
In case you have a lot of state props which e.g. affect the positions of items, you will need to add quite some logic into your JSX.
React is just a library, not a framework. Meaning: Component is pretty much all what is in there. There are no logical hierarchy chains like:
core.Base -> component.Base -> button.Base -> tab.header.Button
Once the render()
madness is resolved, you can pick the best fitting base class for whatever you want to create. E.g. a Container has a vdom object which contains references to the vdom objects of their child items. We can then change the vdom of child component without recreating their JS based instances.
At this point, state management becomes trivial and we don’t even need hooks. Especially changing many configs in parallel with ensuring that there is max 1 call to the vdom engine is key.
12. Multi window apps
Switching the workers setup to use SharedWorkers optionally enhances the concept even more:

This enables us to move entire Component trees across different browser windows, while keeping their JS instances in place.
Multi window state management without the need for a backend.
Cross window drag & drop is possible.
There are several articles inside the blog covering the details.
13. Do we need to implement the workers setup on our own?
Implementing all mentioned ideas on your own can literally take years.
You are in luck, I already did it for you. More than 12,000 commits inside the ecosystem, completely MIT licensed:
This includes a remote method access API which enables you to call methods in different workers or main directly via promises (an abstraction layer on top of the messaging).
A huge amount of components is already in place, as well as controllers, view models, apps and other utility classes.
You don’t need any 3rd party libs to support architecture design patterns like MVVM, Observable and many others.
Especially state management is extremely easy (hint: a class config system).
Many demo apps and examples are waiting for you to get explored, 40+ blog posts: https://neomjs.github.io/pages/
The CLI is advanced: you can create a new app (workspace) with a 1-liner: npx neo-app
. We even get cross app split chunks, so there is close to no overhead when putting multiple apps on one page.
14. Final thoughts
You actually don’t have to wait until 2022 and you can use these ideas right now to get your frontend development to the next level. Some companies and developers are already doing it and are using their head start to turn the new technology into a business advantage:
Most devs are still not aware that the neo.mjs project exists, which is a bummer.
I would love to see someone proving me wrong on these concepts!
To do this, you will need to create your first neo based PoC app.
I would enjoy to review your code in this case.
For dynamic DOM manipulations at run time, neo is the fastest option out there. Especially when it comes to big and complex apps.
You are welcome to join the project Slack Channel:
Best regards and happy coding,
Tobias
P.S.: There are some big changes incoming this September, which also affect my personal situation in a good way.
15. [Update] How to get started?
I just created a tutorial on how to actually build an app using this technology:
Preview Image
The idea is: “act” VS “react” and angular is out of scope anyway.
