close

DEV Community

Cover image for Splitting the Compiler from the Runtime in Levelo JS
Saiful Siam
Saiful Siam

Posted on

Splitting the Compiler from the Runtime in Levelo JS

Splitting the Compiler from the Runtime in Levelo JS

Yesterday was focused on improving the architecture of Levelo JS rather than adding flashy features.

One of the biggest changes was separating the Vite compiler from the core framework.

Previously, the compiler lived inside the main levelojs package. Now it has been extracted into its own package:

Installation:

npm install levelojs vite-plugin-levelojs
Enter fullscreen mode Exit fullscreen mode

or

pnpm add levelojs vite-plugin-levelojs
Enter fullscreen mode Exit fullscreen mode

This makes the runtime cleaner, easier to maintain, and allows the compiler to evolve independently.

What's New

Batch Updates

Levelo JS now includes a new batch() API.

batch(() => {
  setCount(v => v + 1);
  setUser("MotionMind");
  setCount(v => v + 1);
});
Enter fullscreen mode Exit fullscreen mode

Multiple state updates are grouped together, reducing unnecessary reactive executions and improving performance.

Reactive Input Tracking

Reactive value binding for form elements has been improved.

Previously, updating a signal didn't automatically synchronize the value of inputs in every case.

Now developers can simply write:

const [message, setMessage] = state("");

<input
  value={message()}
  onInput={(e) => setMessage(e.target.value)}
/>
Enter fullscreen mode Exit fullscreen mode

The input stays synchronized with the reactive state automatically.


Dedicated Vite Plugin

The compiler is now available as an official package:

  • vite-plugin-levelojs

It compiles JSX into optimized h() calls at build time, eliminating the need for a Virtual DOM.


Runtime Refactoring

The internal JSX runtime has also been reorganized.

The h() factory has been extracted into its own runtime module for better code organization and maintainability.


Verified in a Real Project

After publishing the new packages, everything was tested inside a real Vite application.

The compiler, runtime, JSX transformation, and reactivity all worked as expected.


This update isn't about adding new UI features.

It's about making the foundation stronger before building bigger things on top of it.

More improvements are coming soon.

GitHub: https://github.com/motionmind2007/levelojs

Documentation: https://levelojs.motionmind.me

Top comments (2)

Collapse
 
frank_signorini profile image
Frank

Interesting read! I'm curious if this split primarily aims at reducing the runtime footprint,

Collapse
 
motionmind2007 profile image
Saiful Siam

Thanks! Reducing the runtime footprint was definitely one of the benefits, but it wasn't the primary goal.

The main reason for splitting the compiler was to make LeveloJS bundler-independent. We don't want developers to be limited to Vite forever. In the future, we're planning to support other bundlers (such as Webpack) through dedicated compiler plugins, allowing developers to choose the tooling that best fits their workflow.

Another reason is that compiler features are growing independently from the runtime. For example, better compile-time error reporting, showing the exact source line, code highlighting, and other developer experience improvements require additional compiler logic. Keeping that in a separate package makes the runtime cleaner while allowing the compiler to evolve without affecting it.

So, a smaller runtime is a nice benefit—but the bigger goal is flexibility, scalability, and a better developer experience.