🚐

VanJS

Ultra-lightweight reactive UI framework with under 1kB bundle size

Results Summary

Performance

100%
Lighthouse Score

Bundle Size

5.9KB
Gzipped

Build Time

0.7s
Average

Load Time

1.6s
LCP

Complexity

76
Cyclomatic

Performance Metrics

CLS
0.0001
FCP
1271ms
LCP
1581ms
TBT
0ms

Bundle Analysis

Compression
2.9x
File Count
1
JS %
97.0%
Total Size
16.8KB

Build Info

Build Time
0.7s
Output Size
2.2MB
HMR Time
105ms
Dev Startup
1.0s

About the VanJS Weather Front App

Status

  • Lint
  • Build
  • Test

Usage Instructions

First, follow the repo setup instructions.
Then cd into ./apps/vanjs/ and and use the following commands:

  • Dev Command npm run dev
  • Test Command npm run test
  • Lint Command npm run lint
  • Build Command npm run build
  • Start npm start
For troubleshooting, use npm run verify from the root of the project.

App Requirements

The purpose of this project, was to build the same identical app in every frontend framework, in order to benchmark and compare their performance. As such, each app is built to meet identical requirements, which are then verified with the test suite.

Technical Requirements

  • Binding user input and validation
  • Fetching external data asynchronously
  • Basic state management of components
  • Handling fallback views (loading, errors)
  • Using browser features (location, storage, etc)
  • Logic blocks, for iterative content and conditionals
  • Lifecycle methods (mounting, updating, unmounting)

Feature Requirements

  • 🌦️ Live weather conditions
  • πŸ“… 7-day weather forecast
  • πŸ” City search functionality
  • πŸ“ Geolocation support
  • πŸ’Ύ Persistent location storage
  • πŸ“± Responsive design
  • β™Ώ Accessible interface
  • 🎨 Multi-theme support
  • πŸ§ͺ Fully unit tested
  • 🌐 Internationalized

VanJS Implementation

Hyperscript DOM Creation

The main.js uses VanJS's hyperscript syntax with const { div, h1, p } = van.tags to create DOM elements functionally without JSX or templates.

Reactive State with van.state

VanJS provides reactive state through van.state('initial') which returns an object with a .val property. Changes to state.val automatically trigger re-renders of dependent DOM.

Functional Component Pattern

Components are plain JavaScript functions that return DOM elements. The WeatherApp class demonstrates organizing complex UI logic while maintaining VanJS's functional approach.

Direct DOM Manipulation

Unlike virtual DOM frameworks, VanJS directly manipulates the real DOM, making it extremely lightweight (~1KB) while maintaining reactivity through state bindings.

Template-less Architecture

No templates, JSX, or HTML strings - everything is created through JavaScript functions, providing full IDE support and type safety for DOM creation.

About VanJS

Real-world App

Since the weather app is very simple, and doesn't show of the full features of a framework, it may be helpful to see a more practical implementation of a VanJS app. So, checkout:
RAID Calculator Logo

RAID Calculator

RAID array capacity and fault tolerance

Intro to VanJS

About VanJS

VanJS is an ultra-tiny library for writing reactive UIs with plain functions. No build step, no virtual DOM, just direct DOM manipulation with reactivity built in. It’s surprisingly powerful for its size and is good for small apps or embedded widgets. Think of it as a modern alternative to jQuery that actually plays nice with modern JS.

My thoughts on VanJS

VanJS is impressively tiny - just 1KB of runtime with zero dependencies. It's basically "what if we took the reactive parts of modern frameworks and stripped away everything else?" The result is surprisingly elegant for simple applications, but you'll quickly bump into its limitations.

The functional approach is refreshing after dealing with classes and complex component lifecycles. van.state(initialValue) creates reactive state, van.tags.div() creates DOM elements, and everything just works. Our weather app's temperature display is literally van.tags.span(temperature) - when temperature changes, the DOM updates automatically.

But the simplicity comes with trade-offs. There's no component abstraction beyond functions, no templating system, no event system. You're essentially building a reactive version of vanilla DOM manipulation. It works for basic interactivity but gets unwieldy fast.

The DOM creation syntax is functional but verbose: van.tags.div({class: "weather-card"}, van.tags.h2("Weather")). Coming from JSX or template languages, it feels like writing assembly code. You'll miss the declarative nature of modern frameworks.

VanJS works well for simple enhancements where you need just a touch of reactivity without the framework overhead. I've used it for mini apps, like raid-calculator. But for anything substantial, you'll spend more time fighting the limitations than building features. It's an interesting experiment in minimalism, but modern frameworks exist for good reasons.

Choosing a Framework

Stack Match Stack Match

Not sure if VanJS is right for your project? Use Stack Match to select your preferences and get a tailored recommendation based on the benchmark data.

Stack Match Screenshot