Skip to content

Latest commit

 

History

9 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SandJS

Mini React-like engine: JSX, virtual DOM, diffing, and hooks.

Overview

SandJS is a lightweight educational rendering engine written in vanilla JavaScript. It helps you understand how modern UI frameworks work internally by implementing:

  • JSX to virtual DOM transformation
  • Initial DOM mount
  • Tree diffing and patching
  • Local state with a basic useState hook
  • Simple hot reload workflow

The project is intentionally minimal and readable, so each core concept is easy to inspect.

Features

  • Sand.createElement(type, props, ...children) for JSX runtime support
  • Recursive DOM creation (createDom) for first render
  • Incremental updates via patch(oldVNode, newVNode)
  • Component function support
  • Hook state storage per component path
  • Event and prop syncing to real DOM

Project Structure

  • sand/sand.js: core rendering engine
  • app/App.js: demo app and test components
  • hotReload.js: development hot-reload helper
  • index.html: runtime entry and page shell

Getting Started

Prerequisites

  • A modern browser
  • No build tool required

Run

Open index.html directly in your browser.

If you use a local server (recommended for smoother development), run for example:

cd sandjs
python3 -m http.server 8080

Then open http://localhost:8080.

Example

/** @jsx Sand.createElement */

function App() {
  const [count, setCount] = Sand.useState(0);

  return (
    <div>
      <h1>Count: {count}</h1>
      <button onClick={() => setCount(count + 1)}>+1</button>
    </div>
  );
}

Sand.render(<App />, document.getElementById("root"));

Testing

Unit tests cover the core engine (createElement, initial mount, useState and DOM updates on re-render), running with Vitest in a jsdom environment:

npm install
npm test

The test suite also exposed that the global hook store is shared across roots — tests reset it between runs via a small test-only helper, so the engine file itself stays untouched.

Current Limitations

  • Child reconciliation is index-based (no robust keyed diff yet)
  • No useEffect/lifecycle hooks
  • No batching/scheduler for state updates
  • Full root render trigger on each state update

Learning Roadmap

Suggested next improvements:

  1. Add keyed reconciliation for list stability.
  2. Improve prop/style cleanup on updates.
  3. Implement update batching with microtasks.
  4. Add hook extensions (useEffect, useMemo).
  5. Add keyed reconciliation for list stability (tests already cover mount/patch/hook).

Contributing

Contributions are welcome. Keep changes small, focused, and documented so the educational value remains high.

License

MIT — see LICENSE.

About

A minimal React-like rendering engine built from scratch — JSX, virtual DOM, diffing & hooks in vanilla JavaScript.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages