Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/docs/apps.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Framework Applications

This project contains the same weather application built using 12 different JavaScript frameworks. Each implementation provides identical functionality but uses the specific patterns and approaches of its framework.
This project contains the same weather application built using 14 different JavaScript frameworks. Each implementation provides identical functionality but uses the specific patterns and approaches of its framework.

## Available Frameworks

Expand All @@ -17,6 +17,8 @@ The project includes implementations for:
**Alpine.js** - Minimal framework with HTML-first approach
**Lit** - Web Components with efficient updates
**VanJS** - Ultra-small vanilla framework
**Lume.js** - Minimal reactive state library with no build step
**Gea** - Compiler-first reactive framework with surgical DOM updates
**Vanilla** - Pure JavaScript without any framework

Each app lives in its own directory under `apps/{framework}/` and can be developed, built, and tested independently.
Expand Down
65 changes: 65 additions & 0 deletions apps/geajs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Weather App — Gea

A weather application built with [Gea](https://geajs.com/) — a compiler-first reactive UI framework that compiles JSX into surgical DOM updates at build time (a hello-world app ships ~121 B of brotli JavaScript).

## Usage

```bash
# Install dependencies
npm install

# Dev server (Vite + @geajs/vite-plugin)
npm run dev

# Production build
npm run build

# Run tests (from repo root)
npm run test:geajs

# Lint (from repo root)
npm run lint:geajs
```

## Implementation

Gea doesn't use signals, hooks, dependency arrays, or a virtual DOM. You write ordinary JavaScript — classes with state and methods, getters for computed values — and the Vite plugin (`@geajs/vite-plugin`) analyzes the JSX at build time, works out which DOM nodes depend on which state paths, and generates the reactive wiring. At runtime only the affected nodes are patched.

The implementation uses:

- **`Store`** — [`weather-store.js`](src/weather-store.js) is a singleton class extending `Store`. Its fields (`searchQuery`, `isLoading`, `hasError`, `weatherData`, `activeForecastIndex`) are made reactive through a deep Proxy; mutations are plain assignments like `this.isLoading = true`.
- **Getters as computed values** — derived state such as `showContent`, `locationLabel`, `currentTemperature`, and `forecastDays` are ordinary JavaScript getters on the store. The compiler tracks which state paths they read and re-evaluates the dependent DOM bindings when those paths change.
- **Class components** — each UI piece ([`SearchForm`](src/components/SearchForm.jsx), [`CurrentWeather`](src/components/CurrentWeather.jsx), [`ForecastItem`](src/components/ForecastItem.jsx), …) extends `Component` and returns JSX from `template()`. JSX uses HTML-style attributes (`class`, `for`) and native-style event bindings (`click={...}`, `input={...}`, `submit={...}`) wired through document-level event delegation.
- **Function components** — stateless UI like [`LoadingState`](src/components/LoadingState.jsx) is a plain function; the compiler converts it to a class component at build time.
- **Conditional rendering** — `{condition && <X />}` in [`WeatherDisplay`](src/components/WeatherDisplay.jsx) compiles into `<template>` markers with swap logic, so hidden branches cost no DOM nodes.
- **Keyed lists** — the 7-day forecast maps `weatherStore.forecastDays` to `<ForecastItem key={day.date} day={day} />`; list changes are reconciled per-item rather than re-rendered.

```jsx
// Components read the store singleton directly — mutations patch the DOM surgically
export default class SearchForm extends Component {
handleSubmit(e) {
e.preventDefault();
weatherStore.search();
}

template() {
return (
<form submit={this.handleSubmit}>
<input value={weatherStore.searchQuery} input={this.handleInput} />
<button disabled={weatherStore.isLoading}>
{weatherStore.isLoading ? 'Loading...' : 'Get Weather'}
</button>
</form>
);
}
}
```

## About Gea

Gea's runtime and compiler are vertically integrated: JSX becomes HTML string templates, state tracking happens through deep proxies, and the generated `observe()` calls patch only the DOM nodes that depend on changed data — no diffing or reconciliation overhead. The framework can also run [without a build step](https://geajs.com/docs/browser-usage.html) from a CDN global (~4.1 kB gzipped), where the reactivity glue is written by hand instead of the compiler.

- 🌐 Website: [geajs.com](https://geajs.com/)
- 📚 Docs: [geajs.com/docs](https://geajs.com/docs/getting-started.html)
- 🐙 GitHub: [dashersw/gea](https://github.com/dashersw/gea)
- 📦 npm: [`@geajs/core`](https://www.npmjs.com/package/@geajs/core)
17 changes: 17 additions & 0 deletions apps/geajs/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Weather App - Gea</title>
<link rel="stylesheet" href="/styles/design-system.css">
<link rel="stylesheet" href="/styles/variables.css">
<link rel="stylesheet" href="/styles/base.css">
<link rel="stylesheet" href="/styles/components.css">
<link rel="stylesheet" href="styles.css">
<script type="module" src="./src/main.js"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
Loading