@fluixi/dom

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

Reactive DOM runtime for Fluixi — surgical fine-grained updates, SSR and hydration.

原始使用文档
文档目录34 节
  1. Features
  2. Installation
  3. Quick Start
  4. Basic Usage
  5. With Signals
  6. Components
  7. Core API
  8. DOM Manipulation
  9. Attributes & Properties
  10. Dynamic Attributes & Properties
  11. Event Delegation
  12. Control Flow Components
  13. Show
  14. For
  15. Index
  16. Switch/Match
  17. Portal
  18. Dynamic
  19. ErrorBoundary
  20. Integration
  21. Templates
  22. Advanced Usage
  23. Memory Management
  24. Performance Tips
  25. TypeScript Support
  26. Browser Support
  27. Debugging
  28. Comparison with Other Libraries
  29. vs SolidJS
  30. vs React
  31. Contributing
  32. License
  33. Related Packages
  34. Resources

Fluixi

@fluixi/dom

The DOM runtime the compiler targets: surgical fine-grained updates, hydration and SSR.

License: MIT TypeScript npm


The runtime @fluixi/compiler emits calls into. It provides the low-level DOM operations: element creation, reactive attributes and properties, insertion, control flow, hydration: that make a change update exactly the binding depending on it. Usable directly, though most code reaches it through compiled JSX or html `` templates.

Features

  • 🎯 Fine-Grained Reactivity: Only updates the exact DOM nodes that need to change
  • 🔄 Signal & Store Integration: Works with any reactive system (signals, stores, observables)
  • 🔁 Hydration: adopts server-rendered nodes in place rather than rebuilding beside them
  • 🚀 Optimized Performance: Template caching, event delegation, and minimal re-renders
  • 🧩 Control Flow Components: Built-in Show, For, Switch, Portal, and more
  • 📦 Zero Dependencies: Core runtime has no external dependencies on reactive systems
  • 🔧 Flexible Integration: Use standalone or integrate with your reactive library

Installation

npm install @fluixi/dom
# or
pnpm add @fluixi/dom
# or
yarn add @fluixi/dom

Quick Start

Basic Usage

import { insert, createElement, setProperty } from '@fluixi/dom';

// Create an element
const div = createElement('div');

// Set properties
setProperty(div, 'className', 'container');
setProperty(div, 'textContent', 'Hello World');

// Insert into DOM
document.body.appendChild(div);

With Signals

import { insert, createElement } from '@fluixi/dom';
import { createSignal } from '@fluixi/reactive/signal';

const [count, setCount] = createSignal(0);

const div = createElement('div');

// Insert reactive text
insert(div, () => `Count: ${count()}`);

document.body.appendChild(div);

// Updates automatically!
setCount(1); // DOM updates to "Count: 1"

Components

Bindings work as soon as you import: the example above needs no setup. Rendering components needs one seam filled in, so a component call is owned and disposable:

import '@fluixi/core'; // wires it for you at import time

Using @fluixi/dom without @fluixi/core? Fill the seam yourself: see Integration.

Core API

DOM Manipulation

insert(parent, accessor, marker?, init?)

Insert dynamic content with automatic reactivity tracking.

import { insert } from '@fluixi/dom';
import { createSignal } from '@fluixi/reactive/signal';

const [text, setText] = createSignal('Hello');
const div = document.createElement('div');

// Insert reactive content
insert(div, () => text());

// Or insert static content
insert(div, 'Static text');

// With a marker for positioning
const marker = document.createTextNode('');
div.appendChild(marker);
insert(div, () => text(), marker);

spread(options)

Spread props onto an element with fine-grained updates.

import { spread, createElement } from '@fluixi/dom';

const element = createElement('div');
const props = {
  className: 'container',
  style: { color: 'red' },
  onClick: () => console.log('clicked'),
};

spread({ element, props });

Attributes & Properties

import { setAttribute, setProperty, setClassName, setStyle } from '@fluixi/dom';

const div = createElement('div');

// Set attribute
setAttribute(div, 'data-id', '123');

// Set property
setProperty(div, 'value', 'text');

// Set className (handles strings, arrays, objects)
setClassName(div, 'btn btn-primary');
setClassName(div, ['btn', 'btn-primary']);
setClassName(div, { btn: true, 'btn-primary': true });

// Set style (handles strings or objects)
setStyle(div, 'color: red; font-size: 16px');
setStyle(div, { color: 'red', fontSize: '16px' });

Dynamic Attributes & Properties

import { setDynamicAttribute, setDynamicProperty } from '@fluixi/dom';
import { createSignal } from '@fluixi/reactive/signal';

const [color, setColor] = createSignal('red');
const div = createElement('div');

// Reactive attribute
setDynamicAttribute(div, 'data-color', color);

// Reactive property
setDynamicProperty(div, 'className', () => `text-${color()}`);

Event Delegation

import { delegateEvents, addDelegatedEventListener } from '@fluixi/dom';

// Setup delegation for common events
delegateEvents(['click', 'input', 'change']);

// Add delegated listener
const button = createElement('button');
addDelegatedEventListener(button, 'click', (e) => {
  console.log('Button clicked!');
});

Control Flow Components

Show

Conditional rendering with optional fallback.

import { Show } from '@fluixi/dom';
import { createSignal } from '@fluixi/reactive/signal';

const [user, setUser] = createSignal(null);

// Basic usage
Show({
  when: user,
  children: (u) => `Hello, ${u.name}!`,
  fallback: 'Loading...',
});

// With reactive condition
Show({
  when: () => user() !== null,
  children: (u) => `Hello, ${u.name}!`,
});

For

Keyed list rendering with optimal updates.

import { For } from '@fluixi/dom';
import { createSignal } from '@fluixi/reactive/signal';

const [items, setItems] = createSignal([
  { id: 1, name: 'Item 1' },
  { id: 2, name: 'Item 2' },
]);

For({
  each: items,
  children: (item, index) => {
    const div = createElement('div');
    insert(div, () => `${index()}: ${item.name}`);
    return div;
  },
  fallback: 'No items',
});

Index

Index-based list rendering (use when items change but positions don't).

import { Index } from '@fluixi/dom';

Index({
  each: () => [1, 2, 3, 4, 5],
  children: (item, index) => {
    const div = createElement('div');
    insert(div, () => `Item ${index}: ${item()}`);
    return div;
  },
});

Switch/Match

Multi-way conditional rendering.

import { Switch, Match } from '@fluixi/dom';
import { createSignal } from '@fluixi/reactive/signal';

const [state, setState] = createSignal('loading');

Switch({
  fallback: 'Unknown state',
  children: [
    Match({
      when: () => state() === 'loading',
      children: 'Loading...',
    }),
    Match({
      when: () => state() === 'success',
      children: 'Success!',
    }),
    Match({
      when: () => state() === 'error',
      children: 'Error occurred',
    }),
  ],
});

Portal

Render content in a different DOM location.

import { Portal } from '@fluixi/dom';

Portal({
  mount: document.body,
  children: createElement('div', { textContent: 'Portal content' }),
});

Dynamic

Dynamically render components based on runtime conditions.

import { Dynamic } from '@fluixi/dom';
import { createSignal } from '@fluixi/reactive/signal';

const [component, setComponent] = createSignal('div');

Dynamic({
  component: component,
  className: 'dynamic-element',
  children: 'Dynamic content',
});

ErrorBoundary

Catch and handle errors in component trees.

import { ErrorBoundary } from '@fluixi/dom';

ErrorBoundary({
  fallback: (error, reset) => {
    const div = createElement('div');
    insert(div, `Error: ${error.message}`);
    
    const button = createElement('button');
    button.textContent = 'Retry';
    button.onclick = reset;
    
    div.appendChild(button);
    return div;
  },
  children: /* your components */,
});

Integration

This package renders; it doesn't own a reactive system. One seam connects the two: how a component call is wrapped, and it is a single function:

import { registerCreateComponent } from '@fluixi/dom';

registerCreateComponent((Comp, props) => myOwnedCall(Comp, props));

You almost never call this. Importing @fluixi/core wires @fluixi/reactive in for you at import time, so an app just imports and renders. It matters if you use @fluixi/dom on its own, or drive it with a different reactive library.

import { isIntegrationInitialized, resetIntegration } from '@fluixi/dom';

isIntegrationInitialized(); // has something claimed the seam?
resetIntegration();         // drop it again — tests

initializeIntegration({ signalSystem }) is the older entry point and still works; it picks createComponent off what you pass and ignores the rest.

Templates

html `` templates are compiled, not interpreted: @fluixi/compiler turns them into the same calls this package exposes, so they cost nothing at runtime and need no template library.

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

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

Advanced Usage

Memory Management

Bindings live and die with the owner they were created under, so tearing down a scope removes its listeners and effects with it:

import { createRoot, onCleanup } from '@fluixi/reactive';
import { insert } from '@fluixi/dom';

createRoot((dispose) => {
  insert(container, () => text());
  onCleanup(() => console.log('bindings gone'));

  dispose(); // runs the cleanups, drops the bindings
});

Performance Tips

  1. Use For for lists: The For component uses keyed reconciliation for optimal updates
  2. Delegate events: Use delegateEvents for better performance with many event listeners
  3. Batch updates: Wrap multiple updates in batch() to minimize re-renders
  4. Memoize expensive computations: Use createMemo from your signal system
  5. Untrack when needed: Use untrack() to read reactive values without creating dependencies
  6. Hoist static content: Move static elements outside reactive contexts
import { batch, createMemo, untrack } from '@fluixi/dom';

// Batch multiple updates
batch(() => {
  setSignal1(value1);
  setSignal2(value2);
  setSignal3(value3);
});

// Memoize expensive computations
const computed = createMemo(() => {
  return expensiveOperation(signal1(), signal2());
});

// Read without tracking
const value = untrack(() => signal());

TypeScript Support

Full TypeScript support with comprehensive type definitions.

import type {
  Children,
  InsertOptions,
  SpreadOptions,
  SignalSystem,
  StoreSystem,
  ShowProps,
  ForProps,
} from '@fluixi/dom';

// Use types in your code
const mySignalSystem: SignalSystem = {
  createEffect: (fn) => {
    // Implementation
    return () => {};
  },
  batch: (fn) => {
    // Implementation
  },
};

Browser Support

  • Modern browsers (Chrome, Firefox, Safari, Edge)
  • ES2020+ required
  • No polyfills needed for supported browsers

Debugging

import { isIntegrationInitialized } from '@fluixi/dom';

// A component rendering as a bare function usually means nothing claimed the seam
isIntegrationInitialized();

Comparison with Other Libraries

vs SolidJS

This package is heavily inspired by SolidJS's dom-expressions but:

  • Works as a standalone library
  • Can be driven by another reactive system through registerCreateComponent
  • Serves both JSX and html `` templates, which compile to the same calls

vs React

  • Fine-grained reactivity (no virtual DOM)
  • No reconciliation needed
  • Direct DOM manipulation
  • Smaller runtime size
  • Better performance for many use cases

Contributing

Contributions are welcome! Please see the main repository for guidelines.

License

MIT

  • @fluixi/jsx - JSX runtime using this DOM package
  • @fluixi/reactive - Signal and store implementations
  • @fluixi/compiler - Compiles JSX and html `` into these calls

Resources

版本与发布记录

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

版本发布日期距今
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/dom 的常见问题

@fluixi/dom 是什么?

Reactive DOM runtime for Fluixi — surgical fine-grained updates, SSR and hydration.

如何安装 @fluixi/dom?

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

@fluixi/dom 支持 TypeScript 吗?

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

@fluixi/dom 支持 ESM 还是 CommonJS?

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

@fluixi/dom 可以商用吗?

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

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

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

@fluixi/dom 还在维护吗?

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