β‘ Quick Cheatsheet
Essential syntax and API mapping for quick reference:
| Feature |
Syntax |
Description |
Example |
| Reactive Binding |
vj.bind(target, model) |
Binds Real DOM and plain object with $O(1)$ reactivity |
vj.bind('#app', { count: 0 }); |
| Mustache Expression |
{{ expression }} |
Pinpoint text node update with expressions |
<span>{{ user.name }} ({{ count * 2 }})</span> |
| One-time Evaluation |
[[ expression ]] |
Renders once initially without creating reactive subscriptions |
<h1>[[ title ]]</h1> |
| Two-Way Form Input |
bind="prop:value" |
Bi-directional synchronization between input and state |
<input bind="userName:value"> |
| Text Content |
bind="text: prop" |
Binds textContent directly to model property |
<span bind="text: description"></span> |
| Repeat List |
bind="items:list" |
Efficient array list synchronization with $index |
<div bind="items:list"><p>{{ $index }}: {{ name }}</p></div>
|
| Component Tile |
bind="prop:tile" |
Mounts HTML tile fragment with native Scoped CSS |
<div bind="user:tile" vjTileSrc="tiles/userCard.html"></div>
|
| DOM Hydration |
vj.hydrate(el) |
Extracts existing Real DOM values into a reactive proxy |
const state = vj.hydrate('#orderForm'); |
| State Watcher |
state.$watch(path, cb) |
Observes changes on a property or wildcard ('*') |
state.$watch('count', (newVal, oldVal) => { ... }); |
| Global Store |
vj.store(initialData) |
Global reactive store broadcast across all components |
const store = vj.store({ theme: 'dark' }); |
| Network Direct Pipe |
vj.fetch(url).into(target) |
Pipes HTTP response directly into DOM or state |
vj.fetch('/api/user').into(state.user); |
| SPA Router |
new vj.PageManager(host) |
Mobile-grade SPA routing with lossless slot snapshots |
const router = new vj.PageManager('#routerHost'); |
π Quick Start & CDN Usage
VinylJS requires no build tools (npm, vite, webpack). Choose the
single bundle script tag that fits your project:
<!-- 1. Standard Production Reactive Engine (Full Core without DevTools) -->
<script src="https://vinyljs.com/vinyl.js"></script>
<!-- 2. Non-Reactive Lightweight Base Engine (Template, Router, HTTP only) -->
<script src="https://vinyljs.com/minivinyl.js"></script>
<!-- 3. Development Suite with DJ Time-Travel DevTools -->
<script src="https://vinyljs.com/vinyl.dev.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>VinylJS Quick Start</title>
<!-- Load VinylJS via CDN -->
<script src="https://vinyljs.com/vinyl.js"></script>
</head>
<body>
<div id="app">
<h1>{{ title }}</h1>
<input type="text" bind="title:value" placeholder="Type a title...">
<p>Count: <strong>{{ count }}</strong> (Double: {{ count * 2 }})</p>
<button onclick="state.count++">+1 Increment</button>
<button onclick="state.count = 0">Reset</button>
</div>
<script>
const state = vj.bind('#app', {
title: 'Welcome to VinylJS π§',
count: 0
});
</script>
</body>
</html>
Global Edge CDN: Import any of the 3 bundles globally via https://vinyljs.com/vinyl.js with 1-year immutable edge
caching.
πΊοΈ Template & DOM Mapping (vinyl.map.js)
The base template engine that declaratively binds DOM structures, attributes, and text nodes to
data using bind attributes and mustache expressions ({{ }}).
1. 4-Stage Pipeline bind Syntax
The 4-stage pipeline directly connects display formatting and input sanitization:
<!-- <element bind="[property]:[handlerType]:[getFn]:[setFn]"> -->
<!-- Formats display with getFn, sanitizes input with setFn -->
<input bind="price:value:formatWon:setWon"
formatWon="return Number($val).toLocaleString() + ' KRW';"
setWon="return Number(String(val).replaceAll(',', '').replace(' KRW', ''));">
<!-- Or using the pickup attribute for input sanitization -->
<input bind="price:value" pickup="cleanNumeric">
2. Repeat Lists (bind="items:list")
Synchronizes array data with DOM lists with built-in {{ $index }} support and $O(1)$ key tracking:
<div id="todoApp" bind="todos:list">
<div class="todoItem">
<span>#{{ $index + 1 }}</span>
<input type="checkbox" bind="done:checked">
<span bind="text: title" style="{{ done ? 'text-decoration:line-through' : '' }}"></span>
<button onclick="deleteTodo($index)">Delete</button>
</div>
</div>
<script>
const state = vj.bind('#todoApp', {
todos: [
{ title: 'Learn VinylJS', done: false },
{ title: 'Deploy to Cloudflare Pages', done: true }
]
});
// Standard array methods fully supported (push, pop, splice, sort, reverse)
state.todos.push({ title: 'Write tests', done: false });
</script>
3. Component Tiles (vjTileSrc) & Scoped CSS
Loads external HTML fragments as modular components with native @scope CSS isolation:
<!-- index.html -->
<div id="slot" bind="user:tile" vjTileSrc="tiles/userCard.html"></div>
<!-- tiles/userCard.html -->
<style scope>
.card { padding: 16px; border-radius: 8px; background: #f1f5f9; }
.name { color: #2563eb; font-weight: bold; }
</style>
<div class="card">
<h3 class="name">{{ name }}</h3>
<p>{{ bio }}</p>
</div>
<script>
function init(el, model) {
console.log('Tile mounted:', el, model);
}
function onDestroy(el) {
console.log('Tile unmounted & resources cleaned up');
}
</script>
4. DOM Hydration & Extraction
Hydrates server-side rendered (SSR) or existing static HTML forms into reactive proxies in one
line:
// Reads existing inputs and activates 2-way reactive proxy
const state = vj.hydrate('#orderForm');
π§ Reactive Engine (vinyl.bind.js)
Powered by native JavaScript Proxies, vinyl.bind.js avoids
full container re-renders and virtual DOM diffing. Only target DOM text nodes or form inputs are
updated via an $O(1)$ direct node pointer (Map<Path, Set<Updater>>).
const state = vj.bind('#userProfile', {
name: 'Alex',
age: 28,
skills: ['JavaScript', 'HTML']
});
// Mutating a property updates target Real DOM nodes instantly (1,876,173 Ops/sec)
state.name = 'Jordan';
// Watch specific property or wildcard '*'
const unwatch = state.$watch('user.profile.age', (newVal, oldVal) => {
console.log('Age changed:', oldVal, '->', newVal);
});
// Access plain raw object
const plain = state.$raw;
// Global reactive store broadcast across all components
const store = vj.store({
isLoggedIn: true,
currentUser: { name: 'Admin' }
});
π± SPA Page Router (vinyl.page.js)
Provides mobile-grade view transitions, lossless form state restoration (Slot Snapshots), and
AbortController-based concurrency protection (Latest-Wins).
const router = new vj.PageManager('#routerHost', {
pageParamName: 'page', // Sync with URL search params (?page=home)
maxStackSize: 20
});
// Register Class with Lifecycle Hooks
class ProfilePage {
init(element, state, navSignal) {
console.log('Page initialized with params:', state);
}
onFront(element) {
console.log('Page brought to front (including back navigation)');
}
onLeave(element) {
console.log('Navigating away from page');
}
onDestroy(element) {
console.log('Page destroyed and resources cleaned up');
}
}
router.register('profile', ProfilePage);
// Navigate & Back (losslessly restores scroll & form inputs)
router.go('profile', { id: 100 });
router.back();
π Network Layer & .into() (vinyl.http.js)
High-performance standalone HTTP client built on native Fetch.
// 1. Pipe HTML partial directly into a DOM container
vj.fetch('/partials/userSummary.html').into('#userSummaryBox');
// 2. Pipe JSON response directly into a reactive state object
vj.fetch('/api/currentUser').into(state.user);
// Rapid consecutive clicks are automatically cancelled by AbortController
// guaranteeing Latest-Wins consistency without race conditions.
π οΈ Built-in DevTools (devtools.js)
Floating developer tools overlay for real-time state inspection and time travel:
- DJ Time-Travel Deck: Drag the slider like scratching
a vinyl record to rollback and restore past component state snapshots losslessly.
- Real-time Binding Inspector: Inspect all active
subscriber maps and direct node pointers visually.
- DOM Highlighter: Clicking a state property
highlights its connected Real DOM element with a pulsating neon bounding box.
π‘ Best Practices & FAQ
01.
Write Standard JavaScript
No special setter functions like setState(), ref.value, or signal(). Directly mutate state objects and arrays: state.count++, state.user.name = 'Jordan'. The DOM reacts automatically.
02.
Full Array Mutation Support
Standard array methods (push, pop, shift, unshift, splice, sort, reverse) are
fully tracked. $O(1)$ key reconciliation ensures optimal DOM element reordering without
recreating nodes.
03.
Defend Against Race Conditions
Use vj.fetch(url).into(state.target). Built-in AbortController ensures stale in-flight requests are
cancelled when new ones fire, guaranteeing Latest-Wins consistency.
04.
Instant Hydration of Static / SSR Forms
If your page has pre-rendered HTML form markup, activate it with const state = vj.hydrate('#formId'); in one line instead
of creating separate models.
05.
Automatic Memory Cleanup (Auto-Disposer)
When tile components are detached, onDestroy hooks
trigger, and active timers (setInterval, setTimeout) and listeners are automatically garbage
collected. Call el.unmap() or state.$unbind() to manually clean up.