A universal React-compatible render engine for building applications across multiple platforms
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Universal rendering engine that works across multiple platforms through pluggable driver system. Enables Rax applications to run on Web, Weex, Node.js, Alibaba MiniApp, WeChat MiniProgram, and other platforms.
Renders Rax elements to a container using the specified platform driver. This is the main entry point for displaying Rax applications.
/**
* Renders a Rax element tree to a container
* @param element - Root Rax element to render
* @param container - DOM container or platform-specific container
* @param options - Render options including driver and other settings
* @param callback - Optional callback executed after render completion
* @returns Component instance of the root element
*/
function render(element, container, options, callback);
/**
* Simplified render function (callback as third parameter)
* @param element - Root Rax element to render
* @param container - DOM container or platform-specific container
* @param callback - Optional callback executed after render completion
* @returns Component instance of the root element
*/
function render(element, container, callback);Usage Examples:
import { createElement, render, Component } from 'rax';
import * as DriverDOM from 'driver-dom'; // Web platform driver
// Basic functional component
function App() {
return createElement('div', null,
createElement('h1', null, 'Hello Rax!'),
createElement('p', null, 'Universal React-compatible rendering')
);
}
// Render to DOM (Web platform)
const appInstance = render(
createElement(App),
document.getElementById('root'),
{ driver: DriverDOM },
() => {
console.log('App rendered successfully');
}
);
// Simplified usage with callback
render(
createElement(App),
document.body,
() => {
console.log('Render complete');
}
);The render function accepts various options to customize rendering behavior:
interface RenderOptions {
/**
* Platform driver for rendering (required)
* Defines how elements are created and managed on the target platform
*/
driver: Driver;
/**
* Enable hydration mode for server-side rendered content
* When true, Rax will attach to existing DOM instead of creating new elements
*/
hydrate?: boolean;
/**
* Parent element context for nested rendering
* Used internally for component composition
*/
parent?: RaxElement;
}Rax uses drivers to abstract platform-specific rendering logic. Each platform has its own driver implementation:
Web Platform (driver-dom):
import { createElement, render } from 'rax';
import * as DriverDOM from 'driver-dom';
function WebApp() {
return createElement('div', null,
createElement('button', {
onClick: () => alert('Clicked!')
}, 'Click me')
);
}
render(createElement(WebApp), document.body, { driver: DriverDOM });Server-Side Rendering:
import { createElement, render } from 'rax';
import * as DriverServer from 'driver-server';
function ServerApp() {
return createElement('html', null,
createElement('head', null,
createElement('title', null, 'SSR App')
),
createElement('body', null,
createElement('h1', null, 'Server Rendered'),
createElement('p', null, 'This was rendered on the server')
)
);
}
// Server-side rendering
const htmlString = render(createElement(ServerApp), null, { driver: DriverServer });Weex Platform:
import { createElement, render } from 'rax';
import * as DriverWeex from 'driver-weex';
function WeexApp() {
return createElement('div', {
style: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}
},
createElement('text', {
style: { fontSize: 48, color: '#333' }
}, 'Weex App')
);
}
render(createElement(WeexApp), null, { driver: DriverWeex });Hydration allows Rax to attach to server-side rendered HTML instead of creating new DOM elements:
/**
* Hydrates server-side rendered content
* Attaches Rax to existing DOM elements instead of creating new ones
*/
function hydrate(element, container, options, callback);Hydration Usage Example:
import { createElement, render } from 'rax';
import * as DriverDOM from 'driver-dom';
function HydratedApp() {
return createElement('div', { id: 'app' },
createElement('h1', null, 'Hydrated App'),
createElement('button', {
onClick: () => console.log('Hydrated click!')
}, 'Interactive Button')
);
}
// Hydrate existing server-rendered HTML
render(
createElement(HydratedApp),
document.getElementById('app'),
{
driver: DriverDOM,
hydrate: true
},
() => {
console.log('Hydration complete - app is now interactive');
}
);Rax supports rendering multiple independent component trees:
Multiple Roots Example:
import { createElement, render } from 'rax';
import * as DriverDOM from 'driver-dom';
// Header component
function AppHeader() {
return createElement('header', null,
createElement('h1', null, 'My App'),
createElement('nav', null,
createElement('a', { href: '/' }, 'Home'),
createElement('a', { href: '/about' }, 'About')
)
);
}
// Sidebar component
function AppSidebar() {
return createElement('aside', null,
createElement('h2', null, 'Sidebar'),
createElement('ul', null,
createElement('li', null, 'Item 1'),
createElement('li', null, 'Item 2')
)
);
}
// Main content component
function AppMain() {
return createElement('main', null,
createElement('h2', null, 'Main Content'),
createElement('p', null, 'This is the main content area')
);
}
// Render to different containers
render(createElement(AppHeader), document.getElementById('header'), { driver: DriverDOM });
render(createElement(AppSidebar), document.getElementById('sidebar'), { driver: DriverDOM });
render(createElement(AppMain), document.getElementById('main'), { driver: DriverDOM });The rendering process follows these steps:
createElement creates virtual DOM elementsLifecycle Integration Example:
import { createElement, render, Component } from 'rax';
import * as DriverDOM from 'driver-dom';
class LifecycleDemo extends Component {
constructor(props) {
super(props);
console.log('1. Constructor called');
this.state = { mounted: false };
}
componentDidMount() {
console.log('3. componentDidMount called');
this.setState({ mounted: true });
}
componentDidUpdate() {
console.log('4. componentDidUpdate called');
}
render() {
console.log('2. render called');
return createElement('div', null,
createElement('p', null, `Mounted: ${this.state.mounted}`)
);
}
}
render(
createElement(LifecycleDemo),
document.body,
{ driver: DriverDOM },
() => {
console.log('5. Render callback executed');
}
);Rax provides error boundaries and error handling during rendering:
import { createElement, render, Component } from 'rax';
import * as DriverDOM from 'driver-dom';
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = { hasError: false, error: null };
}
componentDidCatch(error, errorInfo) {
console.error('Error caught by boundary:', error, errorInfo);
this.setState({ hasError: true, error });
}
render() {
if (this.state.hasError) {
return createElement('div', null,
createElement('h2', null, 'Something went wrong'),
createElement('p', null, this.state.error?.message || 'Unknown error')
);
}
return this.props.children;
}
}
function ProblematicComponent() {
throw new Error('This component has an error!');
}
function App() {
return createElement(ErrorBoundary, null,
createElement('h1', null, 'My App'),
createElement(ProblematicComponent)
);
}
render(createElement(App), document.body, { driver: DriverDOM });// Render function signatures
interface RenderFunction {
(element: RaxElement, container: any, options: RenderOptions, callback?: Function): any;
(element: RaxElement, container: any, callback?: Function): any;
}
// Render options interface
interface RenderOptions {
driver: Driver;
hydrate?: boolean;
parent?: RaxElement;
}
// Driver interface (platform-specific implementation)
interface Driver {
createElement(type: string, props?: Object): any;
createTextNode(text: string): any;
createBody(): any;
updateElement(element: any, props: Object, prevProps?: Object): void;
appendChild(parent: any, child: any): void;
removeChild(parent: any, child: any): void;
insertBefore(parent: any, child: any, beforeChild: any): void;
// Additional platform-specific methods...
}
// Container types (platform-specific)
type DOMContainer = Element | Document;
type WeexContainer = any; // Weex-specific container type
type ServerContainer = null; // Server rendering doesn't use container
// Render callback type
type RenderCallback = () => void;
// Component instance type (returned by render)
interface ComponentInstance {
setState?(partialState: any, callback?: Function): void;
forceUpdate?(callback?: Function): void;
// Additional component instance methods...
}Install with Tessl CLI
npx tessl i tessl/npm-rax