@fluixi/core

中文文档
1.0.0-alpha.108发布于 2026/11/07MITTypeScriptESM + CJS近 30 天下载 5979

framework to build apps with DOM runtime, reactive core, router, and JSX runtime; components run once, reactivity updates DOM

原始使用文档
文档目录21 节
  1. Features
  2. Installation
  3. Quick Start
  4. Creating a New Project
  5. Basic Example
  6. Core Concepts
  7. Signals
  8. Components
  9. Control Flow
  10. Load strategies
  11. html `` templates
  12. Resources & Suspense
  13. Context
  14. Router
  15. Lifecycle Hooks
  16. Derived State & Batching
  17. SSR
  18. TypeScript
  19. Ecosystem
  20. License
  21. Links

Fluixi

fluixi

A compiler-native reactive framework. The compiler knows what's reactive, so you write ordinary TypeScript.

License: MIT TypeScript npm


Most reactive frameworks ask you to keep a model in your head that the language doesn't share: which reads are tracked, what you may not destructure, where a value has to stay a function. The compiler can't help, because it doesn't know what your values are: so the burden is yours, and the failures are quiet ones.

Fluixi's compiler knows. It resolves a reactive primitive by the binding it came from, not by how the name reads, and carries that through JSX and html `` templates, the DOM it generates, SSR, hydration and routing as one model.

Features

  • 🧠 The compiler understands reactivity - resolves primitives by binding, not by name; an alias is recognised, a same-named local function is not
  • ✂️ Destructure your props - function Card({ title }) keeps updating; ...rest becomes the splitProps call you'd have written
  • ✍️ Two syntaxes, one model - JSX and html `` templates compile to the same reactive representation
  • 🚀 Direct DOM - a change runs the binding that depends on it; no component re-render, no diff, no virtual tree
  • ⏳ Load strategies - load:visible, load:idle, load:interaction, load:media split a component into its own chunk
  • 🛣️ Router, SSR and hydration - the same reactive graph end to end, not agreed at the edges
  • 📡 Resources + Suspense - async data with loading/error state, awaited and seeded during SSR
  • 🏗️ TypeScript first - full types, and a language-service plugin for html `` templates

Installation

npm install @fluixi/core @fluixi/reactive
# or
pnpm add @fluixi/core @fluixi/reactive
# or
yarn add @fluixi/core @fluixi/reactive

Quick Start

Creating a New Project

npm create fluixi my-app
# or: pnpm create fluixi my-app

Basic Example

import { render } from '@fluixi/core';

const Counter = () => {
  const count = $signal(0);

  return (
    <div>
      <h1>Count: {count()}</h1>
      <button onClick={() => count.set(count() + 1)}>Increment</button>
      <button onClick={() => count.set(count() - 1)}>Decrement</button>
      <button onClick={() => count.set(0)}>Reset</button>
    </div>
  );
};

render(() => <Counter />, document.getElementById('app')!);

$signal needs no import: the compiler resolves it and adds what it needs. signal(0) from @fluixi/reactive/signal is the same primitive when you'd rather import it, and works in a package that never runs this compiler.

JSX is compiled by @fluixi/vite-plugin. Scaffold a ready-to-run app with npm create fluixi.

Core Concepts

Signals

Signals are reactive state. Reading one inside an effect or JSX subscribes to it; setting it updates only what depends on it.

const count = $signal(0);
const name = $signal('Alice');

$effect(() => {
  console.log(`${name()} counted to ${count()}`);
});

count.set(5);      // "Alice counted to 5"
name.set('Bob');   // "Bob counted to 5"

Call it to read, .set() to write. $memo derives, $store holds an object you read properties off, $resource wraps async data. Each has an importable twin: signal, memo, effect, store, resource from @fluixi/reactive/signal: and they are the same primitives, so the two spellings mix freely in one file.

createSignal and its [read, write] pair are unchanged, and plenty of code is written against them.

Components

Components are plain functions that return JSX. A component runs once; props are live reads rather than values handed over at call time.

function Greeting(props: { name: string }) {
  return <h1>Hello, {props.name}!</h1>;
}

Destructuring them is fine: the compiler rewrites the bindings into reads, so they keep updating, and ...rest becomes the splitProps call you would have written:

function Card({ title, tone = 'calm', ...rest }) {
  return <article data-tone={tone} {...rest}><h2>{title}</h2></article>;
}

Where it can't prove a rewrite is safe: a reassigned binding, a computed key, a default it would have to re-run on every read: it leaves your code exactly as written and says why at build time.

Control Flow

Use control-flow components instead of ternaries and .map() so updates stay fine-grained.

import { Show, For, Switch, Match } from '@fluixi/core';

// Show — conditional rendering (child callback receives the narrowed value)
<Show when={() => user()} fallback={<p>Please log in</p>}>
  {(u) => <p>Welcome, {u.name}!</p>}
</Show>

// For — keyed list rendering (index is an accessor)
<For each={todos()}>
  {(todo, i) => <li>{i() + 1}. {todo.text}</li>}
</For>

// Switch / Match — multi-branch
<Switch fallback={<p>Idle</p>}>
  <Match when={() => status() === 'loading'}><p>Loading…</p></Match>
  <Match when={() => status() === 'success'}><p>Done!</p></Match>
  <Match when={() => status() === 'error'}><p>Error</p></Match>
</Switch>

Portal, Dynamic, Index, and ErrorBoundary are also exported.

Load strategies

A load: directive decides when a component's module is fetched, and moves it into its own chunk:

import { RevenueChart } from './RevenueChart';

<RevenueChart load:visible="200px" />   // when it scrolls near the viewport
<ExportDialog load:interaction />       // on first pointer, focus or key
<AuditLog load:media="(min-width: 1024px)" />
<Panel load:idle />

Deferring replaces your static import with a dynamic one, so it applies when the name is used only as a tag. Reference it as a value too and the import stays: the build says so rather than silently shipping the chunk eagerly.

html `` templates

The same reactive model without configuring JSX: useful in a library, a script, or a plain-TypeScript codebase:

import { html } from '@fluixi/core';

function Counter() {
  const n = $signal(0);
  return html`<button @click=${() => n.set(n() + 1)}>${n()}</button>`;
}

Both syntaxes compile to the same representation; @fluixi/ts-plugin gives templates hover, completion and type-checking in the editor.

Resources & Suspense

createResource fetches async data and tracks loading/error. <Suspense> shows a fallback while it's pending (works on the client and during SSR).

import { Suspense } from '@fluixi/core';

function UserCard() {
  const id = $signal(1);
  const user = $resource(id, (id) =>
    fetch(`/api/users/${id}`).then((r) => r.json())
  );

  return (
    <Suspense fallback={<p>Loading…</p>}>
      <p>{user()?.name}</p>
    </Suspense>
  );
}

Context

Share state down the tree without prop drilling.

import { createContext, useContext } from '@fluixi/core';

const ThemeContext = createContext<'light' | 'dark'>('light');

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Toolbar />
    </ThemeContext.Provider>
  );
}

function Toolbar() {
  const theme = useContext(ThemeContext);
  return <div class={theme}>…</div>;
}

Router

The router takes a routes config; nested routes render through <Outlet />, and lazy() code-splits.

import { render } from '@fluixi/core';
import { Router, Outlet, lazy } from '@fluixi/core/router';

const routes = [
  {
    path: '/',
    component: () => (
      <div class="app">
        <nav>…</nav>
        <Outlet />
      </div>
    ),
    children: [
      { path: '', component: () => <h1>Home</h1> },
      { path: 'about', component: lazy(() => import('./About')) },
    ],
  },
];

render(() => <Router routes={routes} />, document.getElementById('app')!);

Lifecycle Hooks

import { onMount, onCleanup } from '@fluixi/core';

function Clock() {
  const now = $signal(Date.now());

  onMount(() => {
    const id = setInterval(() => now.set(Date.now()), 1000);
    onCleanup(() => clearInterval(id));
  });

  return <time>{new Date(now()).toLocaleTimeString()}</time>;
}

Derived State & Batching

import { batch } from '@fluixi/core';

const first = $signal('Ada');
const last = $signal('Lovelace');

// Memo — cached, recomputes only when a dependency changes
const fullName = $memo(() => `${first()} ${last()}`);

// Batch — coalesce multiple writes into one update
batch(() => {
  first.set('Grace');
  last.set('Hopper');
});

SSR

Server rendering, hydration, file-based routing and the dev/build tooling live in @fluixi/start. Scaffold an SSR app with npm create fluixi and pick the SSR template.

TypeScript

Fluixi is written in TypeScript and ships full types. Configure JSX in your tsconfig.json:

{
  "compilerOptions": {
    "jsx": "preserve",
    "jsxImportSource": "@fluixi/jsx"
  }
}

Ecosystem

PackagePurpose
@fluixi/coreFramework façade: components, control flow, router, render
@fluixi/reactiveSignals, memos, effects, store: usable on its own
@fluixi/domThe DOM rendering runtime
@fluixi/compilerJSX and html `` → IR → direct DOM calls
@fluixi/vite-pluginThe compiler as a Vite plugin (rollup, esbuild and webpack adapters too)
@fluixi/startSSR, streaming, SSG, file routing, server functions, deploy adapters
@fluixi/routerThe routing core
@fluixi/serverServer rendering
@fluixi/headDocument head and SEO
@fluixi/ts-pluginEditor support for html `` templates
@fluixi/template-parserThe html `` parser, standalone
@fluixi/auth · @fluixi/sessionAuth bindings and sessions
@fluixi/testing · @fluixi/devtoolsTest helpers, reactive-graph devtools
@fluixi/cli · create-fluixiGenerators and the app scaffolder

License

MIT

版本与发布记录

@fluixi/core 共发布 55 个版本,首次发布于 2026/07/10;过去 12 个月发布了 55 个版本。

版本发布日期距今
1.0.0-alpha.108latest2026/11/078 天前
1.0.0-alpha.1072026/11/0511 天前
1.0.0-alpha.1062026/11/0213 天前
1.0.0-alpha.1052026/11/0115 天前
1.0.0-alpha.1042026/11/0115 天前
1.0.0-alpha.1032026/10/2620 天前

关于 @fluixi/core 的常见问题

@fluixi/core 是什么?

framework to build apps with DOM runtime, reactive core, router, and JSX runtime; components run once, reactivity updates DOM

如何安装 @fluixi/core?

在项目目录运行 npm install @fluixi/core,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:@fluixi/dom(^1.0.0-alpha.108)、@fluixi/jsx(^1.0.0-alpha.108)、@fluixi/head(^1.0.0-alpha.108)、@fluixi/router(^1.0.0-alpha.108)、@fluixi/server(^1.0.0-alpha.108)、@fluixi/storage(^1.0.0-alpha.108)、@fluixi/reactive(^1.0.0-alpha.108)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@fluixi/core 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@fluixi/core 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@fluixi/core 可以商用吗?

@fluixi/core 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@fluixi/core 的下载量有多少?

根据 npm 官方下载统计,@fluixi/core 在 2026/10/15 – 2026/11/13 这 30 天内被下载 5,979 次,日均约 199 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@fluixi/core 还在维护吗?

最新版本 1.0.0-alpha.108 发布于 2026/11/07(8 天前);至今共发布 55 个版本,其中过去 12 个月发布了 55 个;首次发布于 2026/07/10。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。