https://github.com/airxjs/airx
☁️ Airx is a simple enough JSX web application framework.
https://github.com/airxjs/airx
airx framework jsx react reactive tsx vue
Last synced: about 15 hours ago
JSON representation
☁️ Airx is a simple enough JSX web application framework.
- Host: GitHub
- URL: https://github.com/airxjs/airx
- Owner: airxjs
- License: mit
- Created: 2023-06-08T12:01:20.000Z (almost 3 years ago)
- Default Branch: main
- Last Pushed: 2026-03-29T15:02:50.000Z (4 days ago)
- Last Synced: 2026-03-29T17:39:16.260Z (4 days ago)
- Topics: airx, framework, jsx, react, reactive, tsx, vue
- Language: TypeScript
- Homepage:
- Size: 530 KB
- Stars: 16
- Watchers: 0
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Airx ☁️
[](https://www.npmjs.com/package/airx)
[](https://github.com/airxjs/airx/actions/workflows/check.yml)
[](https://www.typescriptlang.org/)
[](https://opensource.org/licenses/MIT)
> A lightweight, Signal-driven JSX web application framework
[中文文档](./README_CN.md) • [English Documentation](./README.md)
Airx is a modern frontend framework built on **JSX** and **Signal** primitives, designed to provide a simple, performant, and intuitive solution for building reactive web applications.
## ✨ Features
- 🔄 **Signal-driven reactivity**: Seamlessly integrates with [TC39 Signal proposal](https://github.com/tc39/proposal-signals)
- 📝 **TypeScript-first**: Developed entirely in TypeScript with excellent type safety
- ⚡ **Functional components**: Define components using clean JSX functional syntax
- 🚫 **No hooks complexity**: Simple and straightforward API without React-style hooks
- 🪶 **Lightweight**: Minimal bundle size with zero dependencies
- 🔌 **Extensible**: Plugin system for advanced functionality
- 🌐 **Universal**: Works in both browser and server environments
## 🚀 Quick Start
### Installation
```bash
npm install airx
# or
yarn add airx
# or
pnpm add airx
```
### Basic Usage
```tsx
import * as airx from 'airx'
// Create reactive state using Signal
const count = new Signal.State(0)
const doubleCount = new Signal.Computed(() => count.get() * 2)
function Counter() {
const localState = new Signal.State(0)
const increment = () => {
count.set(count.get() + 1)
localState.set(localState.get() + 1)
}
// Return a render function
return () => (
Counter App
Global count: {count.get()}
Double count: {doubleCount.get()}
Local count: {localState.get()}
Click me!
)
}
// Create and mount the app
const app = airx.createApp()
app.mount(document.getElementById('app'))
```
## 🌐 Server-Side Rendering (SSR)
Airx supports server-side rendering (SSR) out of the box. SSR allows you to render your components to HTML strings on the server, which can improve initial page load performance and SEO.
### Quick Start
```tsx
import * as airx from 'airx'
// Create an SSR app
const app = airx.createSSRApp()
// Render to HTML string
const html = await app.renderToString()
// html === '
Hello World
'
```
### Full SSR Example
```tsx
import { createSSRApp } from 'airx'
// Define a component
function UserCard({ name, email }: { name: string; email: string }) {
return () => (
{name}
{email}
)
}
// Server-side rendering
async function renderPage() {
const app = createSSRApp(
)
const html = await app.renderToString()
console.log(html)
//
Alice
alice@example.com
return html
}
```
### Hydration (Client-Side Activation)
> ⚠️ **Note**: Hydration support is planned for 0.8.x release. Currently, `hydrate()` is available as a stub for future implementation.
```tsx
// Future: Activate SSR HTML on the client
import { createSSRApp, hydrate } from 'airx'
async function hydrateApp(ssrHtml: string) {
const app = createSSRApp()
const container = document.getElementById('app')
if (container) {
hydrate(ssrHtml, container, app)
}
}
```
### API Reference
#### `createSSRApp(element)`
Creates an SSR application instance for server-side rendering.
```tsx
const app = airx.createSSRApp()
```
#### `renderToString(app)`
Renders an SSR app to an HTML string (returns a Promise).
```tsx
const html = await airx.renderToString(app)
```
#### `hydrate(html, container, app)`
Activates server-rendered HTML on the client (planned for 0.8.x).
## 📖 Core Concepts
### Components
Components in Airx are simple functions that return a render function:
```tsx
function MyComponent() {
const state = new Signal.State('Hello')
return () => (
{state.get()} World!
)
}
```
### State Management
Airx leverages the Signal primitive for reactive state management:
```tsx
// State
const count = new Signal.State(0)
// Computed values
const isEven = new Signal.Computed(() => count.get() % 2 === 0)
// Effects
const effect = new Signal.Effect(() => {
console.log('Count changed:', count.get())
})
```
### Context & Dependency Injection
```tsx
const ThemeContext = Symbol('theme')
function App() {
// Provide values down the component tree
airx.provide(ThemeContext, 'dark')
return () =>
}
function Child() {
// Inject values from parent components
const theme = airx.inject(ThemeContext)
return () => (
Current theme: {theme}
)
}
```
### Lifecycle Hooks
```tsx
function Component() {
airx.onMounted(() => {
console.log('Component mounted')
// Return cleanup function
return () => {
console.log('Component unmounted')
}
})
airx.onUnmounted(() => {
console.log('Component will unmount')
})
return () =>
My Component
}
## 📚 API Reference
Airx follows a minimal API design philosophy. Here are the core APIs:
### `createApp(element)`
Creates an application instance.
```tsx
const app = airx.createApp()
app.mount(document.getElementById('root'))
```
### `provide(key, value): ProvideUpdater`
Provides a value down the component tree through context. Must be called synchronously within a component.
```tsx
function Parent() {
airx.provide('theme', 'dark')
return () =>
}
```
### `inject(key): T | undefined`
Retrieves a provided value from the component tree. Must be called synchronously within a component.
```tsx
function Child() {
const theme = airx.inject('theme')
return () =>
Theme: {theme}
}
```
### `onMounted(listener): void`
Registers a callback for when the component is mounted to the DOM.
```tsx
type MountedListener = () => (() => void) | void
airx.onMounted(() => {
console.log('Mounted!')
return () => console.log('Cleanup')
})
```
### `onUnmounted(listener): void`
Registers a callback for when the component is unmounted from the DOM.
```tsx
type UnmountedListener = () => void
airx.onUnmounted(() => {
console.log('Unmounted!')
})
```
### `createElement(type, props, ...children)`
Creates virtual DOM elements (usually handled by JSX transpiler).
### `Fragment`
A component for grouping multiple elements without adding extra DOM nodes.
```tsx
function App() {
return () => (
First
Second
)
}
```
## 🔧 Development
### Building from Source
```bash
# Clone the repository
git clone https://github.com/airxjs/airx.git
cd airx
# Install dependencies
npm install
# Build the project
npm run build
# Run tests
npm test
# Run tests with UI
npm run test:ui
# Run tests with coverage
npm run test:coverage
```
### Project Structure
```text
source/
├── app/ # Application creation and management
├── element/ # Virtual DOM and JSX handling
├── logger/ # Internal logging utilities
├── render/ # Rendering engine
│ ├── basic/ # Core rendering logic
│ ├── browser/ # Browser-specific rendering
│ └── server/ # Server-side rendering
├── signal/ # Signal integration
├── symbol/ # Internal symbols
└── types/ # TypeScript type definitions
```
## 🤝 Contributing
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
### Development Workflow
1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Make your changes
4. Add tests for your changes
5. Ensure all tests pass (`npm test`)
6. Commit your changes (`git commit -m 'Add amazing feature'`)
7. Push to the branch (`git push origin feature/amazing-feature`)
8. Open a Pull Request
## 📄 License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## 🙏 Acknowledgments
- Thanks to all contributors and supporters of the Airx project
- Inspired by the [TC39 Signal proposal](https://github.com/tc39/proposal-signals)
- Built with ❤️ by the Airx community
## 📞 Support
- 📖 [Documentation](https://github.com/airxjs/airx)
- 🐛 [Issue Tracker](https://github.com/airxjs/airx/issues)
- 💬 [Discussions](https://github.com/airxjs/airx/discussions)
---
Made with ☁️ by the Airx team