veliom
v0.3.5
Published
Ultra-fast, minimal frontend framework with API-agnostic design
Maintainers
Readme
Veliom 🚀
Ultra-fast, minimal frontend framework with API-agnostic design
Why Veliom?
- Performance First — Every feature justifies its cost
- Minimal Core — No bloat, just what you need
- API-Agnostic — Use fetch, axios, GraphQL — your choice
- TypeScript Native — Full type safety out of the box
- Security-Aware — Built-in XSS protection (10 security fixes in v0.3.5)
- Production Ready — 322 tests, strict-mode clean (v0.3.5)
Quick Start
npm install veliomimport { createComponent, createSignal, h } from 'veliom';
const Counter = createComponent(() => {
const count = createSignal(0);
return () => h('div', null,
h('span', null, String(count.get())),
h('button', { onClick: () => count.update(n => n + 1) }, '+')
);
});
const App = createComponent(() => {
return () => h('div', null, Counter({}));
});
// Mount to DOM
import { mount } from 'veliom';
mount(App, document.getElementById('app')!);Features
⚡ High-Performance Rendering
- Virtual DOM with efficient diffing & LIS-based keyed reconciliation (O(n log n) minimal DOM moves)
- RAF-batched DOM update queue (
scheduleDOMUpdate/flushDOMUpdates) - Event delegation — O(n) instead of O(n×m)
- Batched updates with
batch() - Style object support,
classList(string/array/object) dangerouslySetInnerHTML,ATTR_ALIAS(htmlFor→for, className→class, etc.)
🔄 Reactive State Management
const count = createSignal(0);
count.set(5);
count.update(n => n + 1);
const store = createStore({ user: null, loading: false });
store.set('loading', true);
// Computed (auto-tracking)
const fullName = createComputed(() => `${firstName.get()} ${lastName.get()}`);
// Memo (cached)
const doubled = createMemo(() => count.get() * 2);
// Deep reactive store
const deep = createDeepStore({ nested: { value: 1 } });
deep.nested.value; // tracks automatically
deep.subscribe((newVal) => console.log(newVal));
// Media query
const isLarge = createMediaQuery('(min-width: 768px)');
// Combine signals
const sum = combineSignals([a, b], () => a.get() + b.get());🪝 Hooks (25+)
const App = createComponent(() => {
const [getCount, setCount] = useState(0);
const [getItems, setItems] = useState<string[]>([]);
const ref = useRef<HTMLDivElement>(null);
const [state, dispatch] = useReducer(reducer, initialState);
useEffect(() => { document.title = `Count: ${getCount()}`; }, [getCount]);
const doubled = useMemo(() => getCount() * 2, [getCount]);
// Additional hooks
const isOnline = useOnlineStatus();
const scheme = usePreferredColorScheme(); // 'light' | 'dark'
const size = useWindowSize();
const scroll = useScrollPosition();
const isIdle = useIdleTimer(30000);
const isPressed = useKeyPress('Enter');
return () => h('div', null, ...);
});🧩 Component System
const Button = createComponent((props) => {
return () => h('button', { class: props.class }, props.children);
});
// Memo (shallow prop comparison)
const Expensive = memo((props) => {
return () => h('div', null, props.data);
});🎯 Control Flow
// Conditional
Show({ when: isLoggedIn, children: () => h('div', null, 'Welcome!') });
// Switch/Match (SolidJS-like)
Switch({
children: [
Match({ when: status === 'loading', children: () => h('div', null, '...') }),
Match({ when: status === 'error', children: () => h('div', null, 'Error!') }),
Match({ when: true, children: () => h('div', null, 'Ready') }),
]
});
// Lists with optional keys
For({ each: items, key: 'id', children: (item) => h('li', null, item.name) });
// Index (index-based rendering)
Index({ each: items, children: (item, idx) => h('li', null, `${idx}: ${item}`) });🌐 Router
const router = createRouter([
{ path: '/', component: Home },
{ path: '/users/:id', component: UserProfile },
], { mode: 'hash' });
// In JSX:
h(Route, { path: '/', router, component: Home, fallback: NotFound });
h(Link, { to: '/users/1', router }, h('span', null, 'User 1'));
// Access router state
const { path, params, navigate } = useRouter(router);📦 Lazy Loading & Suspense
const LazyComponent = lazy(() => import('./Heavy'));
Suspense({ children: LazyComponent, fallback: h('div', null, 'Loading...') });⏳ Async & Resources
// createAsync — general promise/sync-to-signal
const { data, loading, error, refetch } = createAsync(() => fetch('/api/data').then(r => r.json()));
// createResource — reactive data fetching
const [resource, { mutate, refetch }] = createResource((id) => fetch(`/api/users/${id}`).then(r => r.json()), { initial: null });Await Component
Await({ promise: fetchUser(), loading: () => h('div', null, '...'), children: (user) => h('div', null, user.name) });ErrorBoundary
ErrorBoundary({ fallback: () => h('div', null, 'Something went wrong'), children: () => h(MyComponent) });Portal / Teleport
// Portal
createPortal(h('div', null, 'Overlay'), document.getElementById('portal-root')!);
// Teleport JSX
h(Teleport, { to: '#portal-root' }, h('div', null, 'Teleported content'));Dynamic Component
Dynamic({ component: isDiv ? 'div' : MyComponent, props: { class: 'dynamic' } });🧩 Plugin System
import { usePlugin, Plugin } from 'veliom';
const logger: Plugin = {
name: 'logger',
hooks: {
beforeCreate: (vnode) => console.log('creating', vnode.type),
mounted: (vnode) => console.log('mounted', vnode.type),
beforeUnmount: (vnode) => console.log('unmounting', vnode.type),
},
};
usePlugin(logger);Available hooks: beforeCreate, created, beforeMount, mounted, beforeUpdate, updated, beforeUnmount, unmounted.
🔁 KeepAlive
import { KeepAlive, clearKeepAliveCache } from 'veliom';
// Caches DOM + VNode by key on first render
h(KeepAlive, { key: 'tab-1' }, h(TabContent));
// Clear single or all cache entries
clearKeepAliveCache('tab-1');
clearKeepAliveCache(); // all🎬 Transition (Enter/Leave)
import { Transition, createTransitionClasses, leaveTransition } from 'veliom';
// CSS class-based enter/leave
h(Transition, { show: isVisible, name: 'fade' }, h('div', null, 'Content'));
// Manual enter animation
createTransitionClasses(el, 'fade', () => console.log('enter done'));
// Manual leave animation
leaveTransition(el, 'fade', () => console.log('leave done'));Applies classes: {name}-enter-from, {name}-enter-active, {name}-enter-to / {name}-leave-from, {name}-leave-active, {name}-leave-to.
🌐 Server-Side Rendering
import { renderToString, renderToStringWithData, h } from 'veliom';
const html = renderToString(h('div', { class: 'app' }, 'Hello SSR'));
// '<div class="app">Hello SSR</div>'
const withData = renderToStringWithData(appVNode, { user: { id: 1 } });
// Appends script with window.__INITIAL_DATA__🔧 DevTools Hook
import { enableDevTools } from 'veliom';
enableDevTools(); // registers window.__VELIOM_DEVTOOLS__
const devtools = (window as any).__VELIOM_DEVTOOLS__;
console.log(devtools.getState());
// { components: [...], signals: [...] }Context
const Theme = createContext('light');
// JSX Provider
h(Theme.Provider, { value: 'dark' }, h(Child));
// Consume
const theme = useContext(Theme);Children Utilities
Children.toArray(children); // Flattens nested fragments
Children.map(children, fn); // Map + flatten
Children.forEach(children, fn); // ForEach + flatten
Children.only(children); // Throw if ≠ 1 child
Children.count(children); // Total child count🔒 Security
- Built-in XSS protection
- Sanitizes dangerous protocols (
javascript:,data:,vbscript:) - Blocks malicious attributes during create and patch
- State isolation between components
Full Hook API
| Hook | Returns | Description |
|------|---------|-------------|
| useState | [get, set] | Reactive state |
| useReducer | [state, dispatch] | Reducer pattern |
| useRef | { current } | Mutable ref |
| useEffect | — | Side effects with cleanup |
| useMemo | value | Memoized computation |
| useCallback | fn | Memoized callback |
| useTransition | [isPending, startTransition] | Non-urgent updates |
| usePrevious | prev value | Track previous value |
| useDebouncedValue | derived signal | Debounced reactive value |
| useEventListener | — | Auto-cleaned event listener |
| useInterval | — | Interval (pause with null) |
| useTimeout | — | Timeout (pause with null) |
| useMediaQuery | () => boolean | CSS media query |
| useLocalStorage | [get, set] | localStorage-backed signal |
| useForm | form object | Form state + validation |
| useIntersectionObserver | entry | Element visibility |
| useResizeObserver | rect | Element size tracking |
| useClipboard | { copy, copied } | Clipboard API |
| useDocumentTitle | — | Dynamic page title |
| useOnlineStatus | () => boolean | Online/offline |
| usePreferredColorScheme | 'light' \| 'dark' | Color scheme |
| useGeolocation | { coords, error, loading } | Geolocation |
| useWindowSize | { width, height } | Window dimensions |
| useKeyPress | () => boolean | Key press state |
| useHover | () => boolean | Element hover |
| useScrollPosition | { x, y } | Scroll position |
| useIdleTimer | () => boolean | User idle detection |
| useVirtualList | { visibleItems, totalHeight, scrollTo } | Virtual scrolling |
Events
// onClickOutside — detect clicks outside an element
onClickOutside(elementRef, () => console.log('clicked outside'));
onClickOutside(elementRef, handler, { enabled: isOpen }); // conditionalAPI-Agnostic Design
Veliom intentionally does NOT include HTTP clients or data fetching. You're free to use whatever you want:
const DataComponent = createComponent(() => {
const data = createSignal<Data[]>([]);
const loading = createSignal(false);
const fetchData = async () => {
loading.set(true);
const res = await fetch('/api/data');
data.set(await res.json());
loading.set(false);
};
return () => h('div', null, ...);
});Performance Benchmarks
| Feature | Impact | |---------|--------| | Event Delegation | O(n) instead of O(n×m) | | LIS Keyed Reconciliation | Minimal DOM moves (O(n log n)) | | RAF-Batched Updates | Single DOM write per frame | | VNode Pooling | Reduced GC pressure |
Project Structure
src/
├── core/
│ ├── renderer.ts # Virtual DOM & rendering
│ ├── component.ts # Component system (mount/update/unmount, memo)
│ ├── control.ts # Show, For, Index, Switch, Match, Fragment
│ ├── router.ts # Hash/history router, Route, Link
│ ├── error.ts # ErrorBoundary, global error handler
│ ├── await.ts # Await component (promise rendering)
│ ├── dynamic.ts # Dynamic component
│ ├── portal.ts # Portal rendering
│ ├── teleport.ts # Teleport JSX component
│ ├── lazy.ts # Lazy loading
│ ├── suspense.ts # Suspense component
│ └── refs.ts # Ref system
├── state/
│ ├── store.ts # Signals, Store, DeepStore, Memo, Computed, batch
│ ├── hooks.ts # 25+ hooks (useState, useEffect, useForm, etc.)
│ ├── async.ts # createAsync primitive
│ ├── context.ts # createContext, useContext, provideContext
│ ├── resource.ts # createResource data fetching
│ └── lifecycle.ts # onMount, onUpdate, onUnmount
├── utils/
│ ├── children.ts # Children.toArray, map, forEach, only, count
│ ├── events.ts # onClickOutside
│ └── benchmark.ts # Performance tools
└── veliom.ts # Main entry — re-exports all public APIInstallation
npm install veliomDevelopment
npm install
npm run dev # Start dev server
npm run test # Run tests (322+)
npm run typecheck # TypeScript check (strict mode)
npm run lint # ESLint (0 warnings)
npm run build # Build for productionBrowser Support
| Browser | Version | |---------|---------| | Chrome/Edge | 88+ | | Firefox | 78+ | | Safari | 14+ |
License
MIT © 2026 DerStr1k3r
Contributing
Contributions welcome! See CONTRIBUTING.md for guidelines.
⭐ Star this repo if you find it useful!
