The compiler knows
what's reactive.
Every reactive framework asks you to remember which reads are tracked and what you may not destructure. Fluixi's compiler resolves that itself, by where a value came from, not by how it's named, and carries it through JSX, templates, the DOM it generates, SSR, hydration and routing as one model. You write ordinary TypeScript. And because the model is the compiler's own, you can read it back: from source, and from a running app in your editor or the browser.
npm create fluixi@latestfunction Counter() {
const count = $signal(0); // no import, the compiler resolves it
return (
<button onClick={() => count.set(c => c + 1)}>
{count()}
</button>
);
}Both syntaxes compile to the same calls. Switch to Compiled to see them.
Ordinary TypeScript, still reactive.
The compiler resolves a reactive value by the binding it came from, never by how the name reads, so an alias is recognised and a local function of the same name is not. Knowing that, it can rewrite what a runtime alone would lose.
- Destructure props and the bindings stay live reads
- What it can't prove safe is left as written, and reported
- JSX and
html``compile to one reactive model
function Card({ title, ...rest }) {
return <h2 {...rest}>{title}</h2>; // title still updates
}
import { signal as state } from '@fluixi/reactive/signal';
const count = state(0); // a signal, resolved through the import
function signal() { return 42; }
const value = signal(); // not a signal, a local functionThe rest of it
Everything a modern app needs
One framework, from the signal graph to the edge.
Fine-grained reactivity
A TC39-Signals graph updates exactly the DOM that changed, no virtual DOM, no diffing, no re-renders.
Compiled, not interpreted
JSX compiles straight to imperative DOM calls. You ship the work, not a runtime that re-discovers it.
SSR + streaming
Request-scoped server rendering with web-stream output and hydration, isolated per request.
Static generation
Set `prerender` and `fluixi build` crawls your routes to static HTML, this very page is SSG.
File-based routing
Routes from the filesystem, nested layouts, lazy loading, data loaders, with a framework-agnostic core.
Server functions & actions
`"use server"` turns a function into a typed RPC; forms get progressive-enhancement actions.
API routes & middleware
Drop a handler in `src/api/**` for `/api/*`; a middleware chain runs before every render.
DI, i18n, interceptors
Angular-style dependency injection, built-in typed i18n, and an HTTP interceptor pipeline.
Islands & edge
Partial hydration for mostly-static pages, and an edge-safe server that runs on Workers, Deno and Bun.
Start in seconds, JSX or html``.
One command scaffolds an SPA or an SSR app, in JSX or JSX-free html`` templates. Both compile to the same fine-grained DOM calls, so you can even mix them in one file.
--jsxor--html·--spaor--ssr- html`` needs no
jsxin tsconfig, plain.tsfiles - Editor support via
@fluixi/ts-plugin, wired in for you
npm create fluixi@latest my-app -- --html --ssrimport { html } from "@fluixi/core";
// No JSX, no tsconfig changes, plain .ts, same compiled output.
function Counter() {
const count = signal(0);
return html`
<button @click=${() => setCount(c => c + 1)}>
count: ${count()}
</button>
`;
}The server is just a function away.
Mark a function "use server" and the compiler strips its body from the browser, leaving a typed RPC stub. Secrets, database calls and your API keys never ship to the client.
- Request-scoped context, cookies and headers
- Form actions with progressive enhancement
- File-based API routes at
/api/*
// runs only on the server, the body is stripped from the client bundle
async function getUser(id: string) {
"use server";
return db.users.find(id); // secrets stay server-side
}
// call it from anywhere like a normal async function:
const user = await getUser("42");See your reactivity.
The Fluixi Playground compiles JSX in your browser and renders the live dependency graph, watch state, memos, stores and effects light up as they propagate.