The Next Generation of Front-end Development

Experience the Speed and Efficiency of neo.mjs Version 5

Tobias Uhlig
ITNEXT

--

Web development is constantly evolving, and new tools and frameworks are emerging to help developers create faster and more efficient web applications. One such tool that has recently caught the attention of several big companies is neo.mjs, a JavaScript framework for building high-performance, responsive, and scalable web applications. With its recent version 5 release, neo.mjs offers developers a unique approach to front-end development by utilizing the “off the main thread” paradigm and making use of web workers to improve the performance of web applications.

The “an application worker being the main actor” paradigm:

One of the main goals of a front-end framework is to provide a robust and easy to use abstraction layer that allows developers to focus on the business logic of their applications. Other solutions try to push the main thread to the maximum, but neo.mjs takes a different approach by utilizing the “off the main thread” paradigm. This approach allows for tasks such as data processing and heavy computation to be handled by a separate thread, freeing up the main thread to focus on the crucial tasks such as rendering and handling user interactions. This can result in significant performance improvements and a more responsive and smooth user interface.

Multithreaded UIs:

In addition to its unique approach to front-end development, neo.mjs also allows for the creation of multithreaded UIs. This is achieved by making use of web workers and allowing the framework, apps, and components to live within a dedicated worker or a shared worker, which is called the application worker. This leaves the main thread as idle as possible and ensures super smooth transitions.

Content

  1. Goals of a frontend framework
  2. The version 5 release
  3. Global framework overrides
  4. How can I learn it?
  5. Integrating Figma design tokens
  6. JetBrains IDE plugin
  7. All major browsers are ready, are you?
  8. Short-term Roadmap
  9. Final thoughts

1. Goals of a frontend framework

The current trend seems to be to focus on providing a Container → an easy way to nest components. Ideally using Web Components to reduce the JavaScript related logic close to zero. Developers often end up with “supercharging” HTML and getting a rough time with creating complex apps. This already starts with submitting forms and manually writing massive (not maintainable) form services.

In my opinion, a framework should provide a declarative, robust and easy to use abstraction layer instead. Programmers can easily focus on the business logic and get useful tools like state management (view models), which we can nest as needed, view controllers and focus on app related bindings and events to create meaningful architectures which are extensible and scalable.

Our weapon of choice is JavaScript. That this is creating HTML related output is a nice coincidence, but nothing we want to deal with on a daily basis.

If we then get access to the latest Web APIs like OffscreenCanvas, we can create next generation user interfaces with an incredible speed.

A development mode which runs without any builds or transpilations while supporting lazy loading and the latest ECMAScript features once the browser support is in place further boosts this.

2. The version 5 release

The class config system, which is incredibly powerful, was created before static class fields were supported in all browsers and webpack.

The result was that neo.mjs did use functions which enhanced class prototypes at run-time.

This code does feel odd and can off course get written nicer:

The static config Object will still get merged throughout the class hierarchy and enables you to handle states super easily.

However, this is a breaking change, so a new major version was required.

Welcome to version 5 :)

All you need to do is to replace

static getConfig() {return { with

static config = {

and remove the one additional } . This can be done via “Replace in Files” within your IDE of choice and should not take longer than a couple of minutes.

In case you did use getStaticConfig() as well, you can just move the content object properties into static class fields and this is already it. No other changes are required.

Since neo.mjs has grown and evolved a lot, I had to change 550+ files with more than 2000 lines of code. Obviously I did not do that manually either, but adjusting the core logic to honor the changes was far from trivial.

The several 1000s of commits since version 4 were used to enhance the developer experience, getting neo.mjs more mature and adding a lot more features into the ecosystem.

A Google Maps wrapper component got added:

All unit tests are of course passing:

3. Global framework overrides

Prior to version 5, it was non-trivial to apply framework related config overrides. Use case: form.field.Text defaults to labelPosition: ‘inline’ , but I would like to change the value to top for all spots where I use TextFields.

In version 5, this got pretty easy:

You need to create an overrides file and stick to the className structure. Then you need to import it at the top of your app.mjs file and you are done.

It feels important to know, that it will only affect other modules / classes which did not get parsed yet by Neo.applyClassConfig() . Meaning: you can not override the core or worker files, but it does work for all Components.

4. How can I learn it?

The biggest downside of neo.mjs so far was the missing learning section. We did listen to your feedback and are on it :)

As a framework developer it most likely is the biggest honor you can receive when a massive corporation hires a world class software trainer to teach a group of 20 front-end developers for several weeks.

Max Rahder created all training materials and labs for Sencha Ext JS back in the days and is now working with an inspiring engery to do the same for neo.mjs:

https://www.linkedin.com/in/maxrahder/

We are closely incorporating the feedback of our students and are already working on an amazing learning platform for you.

While we do not want to put the content publicly online before it is fully polished, you are invited to get access to our current state. Just give us a heads up inside the project Slack channel:

5. Integrating Figma design tokens

Inside a massive client project, we are using a powerful Figma based design system which is based on design tokens.

Core, semantic and component based tokens can get exported as JSON and directly get pushed into the project git repository. We are using a custom converter, which will include these tokens as CSS variables into the neo.mjs theming engine.

It feels important to highlight that the converter also supports mappings from tokens to other tokens (e.g. semantic and component based tokens use references to core tokens).

Now we can simply connect the component design tokens to the neo.mjs based theming variables.

The result is incredibly powerful: we can either change tokens on all levels directly inside the console or programmatically (even from within the application worker). The user interface will update in real time at run-time.

Our design rockstar Max Mertens will hopefully write a blog post from a designer perspective after the go-live:

https://www.linkedin.com/in/mxmrtns/

6. JetBrains IDE plugin

To give you yet another spoiler: Torsten Dinkheller started working on a JetBrains IDE plugin to offer more convenient ways to create apps, classes and view packages.

He would love to get more feedback about which features you care the most:

https://www.linkedin.com/in/dinkheller/

Torsten also contributed animated toast messages into version 5:

7. All major browsers are ready, are you?

Inside neo.mjs, we are working with 3 different environments:

  1. development mode (run code as it is → no builds or transpilations)
  2. dist/development
  3. dist/production

While both dist modes run fine within all major browsers for quite a while, the real development mode was limited to Chromium (Chrome & Edge) as well as Safari.

The last missing player was Mozilla Firefox, since the support for JS modules was not given inside the worker scope.

The related ticket finally got resolved after 7 years:

Most likely in version 111, we can use the neo.mjs dev modes in Firefox too.

At this point, all major browsers are ready for all environments as well as single & multi-window versions.

neo.mjs will hit its prime time.

8. Short-term Roadmap

While the framework reached the maturity to be ready for enterprise grade applications, a framework is a never ending story → it is never finished.

For a current project we will need full accessibility support very soon, so this becomes a priority. Using the power of the config system, we could even make it optional and toggle aria roles and keyboard navigation on and off at run-time. E.g. for a mobile app you will most likely not need keynav.

We will also polish and enhance the forms engine a lot more. forms already work like view models, so we don’t need to save the state of a form inside a view model or create field related bindings. Neither do we need form services.

I am planning to create nested forms, where we can validate sub-views on their own, get & set their field values, but also do the same for the entire form. As you know, browsers do not support nesting form tags. However, we can map a neo.mjs form container to a div tag. This will be a mind-blowing blog post.

Max Rahder would love to see selection models to get more config driven to enable bindings to selections.

The data package also needs a refactoring and more features.

Thorsten Suckow-Homberg wants to help out on the buffered grid, but it is not clear yet when he will find the time:
https://www.linkedin.com/in/thorstensuckow/

9. Final thoughts

While the workers-setup is still unique:

it is just the tip of the iceberg about what neo.mjs has to offer. In case you want to multiply the productivity and throughput of your development teams, I can strongly recommend to take a closer look at what else the framework & ecosystem have to offer.

One of my favorites is the ability to jump back and forth between lazy loaded parts of your app in real time. While inactive views get kicked out of the DOM, you can still modify their state and the latest state will get rendered with zero backend requests.

The project is still looking for active contributors. In case you want to join a professional and welcoming open source community, you are very welcome to join the Slack channel:

Sharing is caring!

Best regards & happy coding,
Tobias

--

--