Skip to content

Runtime System ​

TachUI's runtime system provides direct DOM manipulation without virtual DOM overhead, complete component lifecycle management, and seamless integration with the reactive system.

Overview ​

The runtime system is the foundation that executes the code generated by TachUI's compiler. It provides:

  • Component Lifecycle: Mount, update, and unmount components with proper cleanup
  • Direct DOM Rendering: Efficient DOM manipulation without virtual DOM overhead
  • Reactive Integration: Seamless connection between signals/effects and DOM updates
  • Memory Management: Automatic cleanup and leak prevention
  • Performance Monitoring: Built-in performance tracking and optimization

Core Concepts ​

Component Lifecycle ​

Every TachUI component follows a predictable lifecycle:

typescript
import { createComponent } from '@tachui/core'

const MyComponent = createComponent((props) => {
  // Component render function
  return h('div', { className: 'my-component' },
    `Hello, ${props.name}!`
  )
}, {
  displayName: 'MyComponent',
  lifecycle: {
    onMount: () => {
      console.log('Component mounted')
      // Return cleanup function
      return () => console.log('Component cleanup')
    },
    onUnmount: () => {
      console.log('Component unmounted')
    },
    onError: (error) => {
      console.error('Component error:', error)
    }
  }
})

Direct DOM Rendering ​

TachUI renders directly to the DOM for maximum performance:

typescript
import { h, text, DOMRenderer } from '@tachui/core'

const renderer = new DOMRenderer()

// Create DOM structure
const element = h('div', { className: 'container' },
  h('h1', null, 'Welcome'),
  h('p', null, text(() => `Dynamic content: ${signal()}`)),
  h('button', {
    onClick: () => handleClick()
  }, 'Click me')
)

// Render to DOM
const container = document.getElementById('app')!
renderer.render(element, container)

Reactive Integration ​

The runtime system automatically connects reactive signals to DOM updates:

typescript
import { createSignal, createEffect } from '@tachui/core'

const [count, setCount] = createSignal(0)
const [message, setMessage] = createSignal('Hello')

// Reactive text content
const counterText = text(() => `Count: ${count()}`)

// Reactive styles
const styledElement = h('div', {
  style: () => ({
    color: count() > 5 ? 'red' : 'blue',
    fontSize: `${12 + count()}px`
  })
}, counterText)

Component Creation ​

Basic Components ​

typescript
const SimpleComponent = createComponent((props) => {
  return h('div', null, `Hello, ${props.name}!`)
})

// Usage
const instance = SimpleComponent({ name: 'World' })

Reactive Components ​

typescript
const ReactiveComponent = createReactiveComponent((props) => {
  const [count, setCount] = createSignal(props.initialCount || 0)
  
  return h('div', { className: 'counter' },
    h('p', null, text(() => `Count: ${count()}`)),
    h('button', {
      onClick: () => setCount(c => c + 1)
    }, 'Increment')
  )
})

Components with Default Props ​

typescript
interface GreetingProps {
  name: string
  greeting?: string
}

const Greeting = createComponent<GreetingProps>((props) => {
  return h('div', null, `${props.greeting}, ${props.name}!`)
}, {
  displayName: 'Greeting',
  defaultProps: {
    greeting: 'Hello'
  }
})

Enhanced Lifecycle ​

Adding Lifecycle Hooks ​

typescript
const EnhancedComponent = withLifecycle(BaseComponent, {
  onMount: () => {
    // Setup code
    const subscription = subscribe()
    
    // Return cleanup function
    return () => subscription.unsubscribe()
  },
  onUnmount: () => {
    // Cleanup code
  }
})

Error Boundaries ​

typescript
const ErrorBoundary = createErrorBoundary((error) => {
  return h('div', { className: 'error' },
    h('h2', null, 'Something went wrong'),
    h('p', null, error.message)
  )
})

// Usage
const SafeApp = ErrorBoundary({ 
  children: RiskyComponent({})
})

Component Management ​

Component Manager ​

The ComponentManager tracks all component instances:

typescript
import { ComponentManager } from '@tachui/core'

const manager = ComponentManager.getInstance()

// Register components
manager.registerComponent(instance)

// Schedule updates
manager.scheduleUpdate(instance.id)

// Get component info
const component = manager.getComponent(instance.id)
const allComponents = manager.getAllComponents()

// Cleanup
manager.unregisterComponent(instance.id)
manager.cleanup() // Clean up all components

Component Registry ​

typescript
// Components are automatically registered when created
const component = createComponent(() => h('div', null, 'Hello'))
const instance = component({})

// Instance has unique ID and tracking
console.log(instance.id) // "component_1640995200000_abc123def"
console.log(instance.type) // "component"

DOM Manipulation ​

Element Creation ​

typescript
// Simple element
const div = h('div', { className: 'container' }, 'Content')

// Element with props and children
const complex = h('section', {
  id: 'main',
  className: 'main-section',
  'data-testid': 'main'
}, 
  h('h1', null, 'Title'),
  h('p', null, 'Paragraph'),
  h('button', { onClick: handleClick }, 'Click me')
)

// Nested structure
const app = h('div', { className: 'app' },
  h('header', null, 'Header'),
  h('main', null, 'Main content'),
  h('footer', null, 'Footer')
)

Text Nodes ​

typescript
// Static text
const staticText = text('Hello, World!')

// Reactive text
const [name, setName] = createSignal('TachUI')
const reactiveText = text(() => `Hello, ${name()}!`)

// Text in elements
const element = h('p', null, text(() => `Count: ${count()}`))

Event Handling ​

typescript
const button = h('button', {
  onClick: (event) => {
    console.log('Button clicked!', event)
    setCount(c => c + 1)
  },
  onMouseOver: () => console.log('Mouse over'),
  onMouseOut: () => console.log('Mouse out')
}, 'Interactive Button')

Styling ​

typescript
// Static styles
const styledDiv = h('div', {
  style: {
    color: 'blue',
    fontSize: '16px',
    padding: '10px'
  }
}, 'Styled content')

// Reactive styles
const reactiveStyled = h('div', {
  style: () => ({
    color: isActive() ? 'green' : 'gray',
    transform: `scale(${scale()})`,
    opacity: visible() ? 1 : 0
  })
}, 'Reactive styles')

// CSS classes
const withClasses = h('div', {
  className: () => `
    base-class
    ${isActive() ? 'active' : ''}
    ${hasError() ? 'error' : ''}
  `.trim()
}, 'Dynamic classes')

DOM Bridge System ​

Application Root Mounting ​

TachUI uses a DOM bridge system to connect component instances to actual browser DOM elements. The primary entry point is mountRoot():

typescript
import { mountRoot } from '@tachui/core'

// Create your application component
const App = createComponent(() => {
  return h('div', { className: 'app' },
    h('h1', null, 'Welcome to TachUI'),
    h('p', null, 'This text is rendered to the DOM!')
  )
})

// Mount your app to the DOM (requires element with id="app")
mountRoot(() => App({}))

Component Tree Mounting ​

The DOM bridge automatically handles nested component structures:

typescript
const Header = createComponent(() => h('header', null, 'Site Header'))
const Main = createComponent(() => h('main', null, 'Main Content'))
const Footer = createComponent(() => h('footer', null, 'Site Footer'))

const App = createComponent(() => {
  return h('div', { className: 'app-layout' },
    Header({}),
    Main({}),
    Footer({})
  )
})

mountRoot(() => App({}))

Modifier Integration ​

The DOM bridge automatically applies TachUI modifiers to DOM elements:

typescript
const StyledComponent = createComponent(() => {
  return Text('Styled Text')
    .fontSize(24)
    .backgroundColor('#f0f0f0')
    .padding(16)
    .cornerRadius(8)
})

// All modifiers are automatically applied to the DOM element
mountRoot(() => StyledComponent({}))

Event Handler Binding ​

Component events are automatically connected to DOM event listeners:

typescript
const InteractiveButton = createComponent(() => {
  const [count, setCount] = createSignal(0)
  
  return Button(`Clicked ${count()} times`)
    .onTap(() => setCount(c => c + 1))
    .backgroundColor(count() > 5 ? '#ff4444' : '#4444ff')
})

mountRoot(() => InteractiveButton({}))

Reactive Updates ​

The DOM bridge maintains reactive connections between signals and DOM:

typescript
const ReactiveDemo = createComponent(() => {
  const [message, setMessage] = createSignal('Hello, TachUI!')
  const [count, setCount] = createSignal(0)
  
  return VStack([
    Text(message)
      .fontSize(18)
      .foregroundColor('#333'),
    
    Text(() => `Count: ${count()}`)
      .fontSize(16)
      .foregroundColor('#666'),
    
    Button('Update')
      .onTap(() => {
        setCount(c => c + 1)
        setMessage(`Updated ${count() + 1} times`)
      })
  ])
})

mountRoot(() => ReactiveDemo({}))

Rendering and Mounting ​

Basic Rendering ​

typescript
import { renderComponent } from '@tachui/core'

const App = createComponent(() => {
  return h('div', null, 'My App')
})

const instance = App({})
const container = document.getElementById('app')!

// Render and get cleanup function
const cleanup = renderComponent(instance, container)

// Later, cleanup when needed
cleanup()

Multiple Components ​

typescript
const Header = createComponent(() => h('header', null, 'Header'))
const Main = createComponent(() => h('main', null, 'Main'))
const Footer = createComponent(() => h('footer', null, 'Footer'))

const App = createComponent(() => {
  const headerInstance = Header({})
  const mainInstance = Main({})
  const footerInstance = Footer({})
  
  return h('div', { className: 'app' },
    headerInstance.render(),
    mainInstance.render(),
    footerInstance.render()
  )
})

Memory Management ​

Automatic Cleanup ​

typescript
const ComponentWithCleanup = createComponent(() => {
  const [data, setData] = createSignal(null)
  
  // Setup subscription
  const unsubscribe = dataService.subscribe(setData)
  
  // Cleanup is handled automatically when component unmounts
  onCleanup(unsubscribe)
  
  return h('div', null, text(() => data() || 'Loading...'))
})

Manual Cleanup ​

typescript
const manager = ComponentManager.getInstance()

// Clean up specific component
manager.unregisterComponent(componentId)

// Clean up all components
manager.cleanup()

// Clean up renderer resources
const renderer = new DOMRenderer()
renderer.cleanup()

Performance ​

Efficient Updates ​

typescript
// Only the changed parts of the DOM are updated
const OptimizedComponent = createComponent(() => {
  const [count, setCount] = createSignal(0)
  const [name, setName] = createSignal('User')
  
  return h('div', null,
    // This text node only updates when count changes
    h('p', null, text(() => `Count: ${count()}`)),
    
    // This text node only updates when name changes  
    h('p', null, text(() => `Name: ${name()}`)),
    
    // Static content never updates
    h('p', null, 'This never changes')
  )
})

Batched Updates ​

typescript
import { batch } from '@tachui/core'

// Multiple updates are batched automatically
const updateMultiple = () => {
  batch(() => {
    setCount(c => c + 1)
    setName('New Name')
    setVisible(true)
    // Only one DOM update occurs
  })
}

Development Tools ​

Component Tree Inspection ​

typescript
import { getComponentTree } from '@tachui/core'

// Get component hierarchy for debugging
const tree = getComponentTree()
console.log('Component tree:', tree)

Performance Monitoring ​

typescript
import { enablePerformanceTracking } from '@tachui/core'

// Enable performance tracking in development
if (process.env.NODE_ENV === 'development') {
  enablePerformanceTracking()
}

Integration Examples ​

With SwiftUI Syntax ​

When using TachUI's SwiftUI syntax, the runtime system handles the execution:

typescript
// SwiftUI syntax (compiled by TachUI)
VStack {
  Text("Hello, World!")
    .font("24px")
    .foregroundColor("blue")
  
  Button("Click me")
    .onTapGesture(() => handleClick())
}

// Compiles to runtime calls:
const container1 = document.createElement('div')
container1.className = 'tachui-v flex flex-col'

const textElement2 = document.createElement('span')
textElement2.className = 'tachui-text'
textElement2.textContent = "Hello, World!"
Object.assign(textElement2.style, {
  fontSize: "24px",
  color: "blue"
})

const buttonElement3 = document.createElement('button')
buttonElement3.textContent = "Click me"
buttonElement3.addEventListener('click', () => handleClick())

container1.appendChild(textElement2)
container1.appendChild(buttonElement3)

With Reactive State ​

typescript
// Reactive state integration
@State count = 0
@Computed doubled = count * 2

VStack {
  Text(`Count: ${count}`)
  Text(`Doubled: ${doubled}`)
  
  Button("Increment")
    .onTapGesture(() => count++)
}

// Runtime handles reactive updates automatically

Performance Benchmarks ​

TachUI includes comprehensive performance benchmarks aligned with industry standards:

Running Benchmarks ​

bash
# Quick performance check
npm run benchmark:quick

# Full benchmark suite with framework comparison
npm run benchmark:compare

# Individual benchmark tests
npm run benchmark

Benchmark Coverage ​

TachUI benchmarks cover all critical performance scenarios:

  • Component Creation - Creating 1,000 components
  • Mass Updates - Replacing all data at once
  • Partial Updates - Updating every 10th row (most important for UX)
  • User Interactions - Row selection and manipulation
  • Memory Efficiency - Heap usage and cleanup
  • Bundle Size - Framework overhead impact

Framework Comparisons ​

Benchmarks compare TachUI against major frameworks:

  • React 18.2.0 (most popular)
  • Vue 3.3.0 (progressive framework)
  • SolidJS 1.7.0 (closest architecture)
  • Svelte 4.0.0 (compile-time optimized)
  • Angular 16.0.0 (enterprise framework)
  • Preact 10.15.0 (lightweight alternative)

Performance Targets ​

TachUI aims for industry-leading performance:

  • ✅ Sub-30ms component creation
  • ✅ Sub-15ms reactive updates
  • ✅ <8MB memory usage
  • ✅ <20KB bundle size

Results are automatically scored on a 0-100 scale for easy tracking.

Next Steps ​

Released under the MPL-2.0 License.