Core Concepts - cynchro/OldSchoolFrontFrame GitHub Wiki
OLS is built on four primitives that compose into a full frontend architecture.
State is a plain JavaScript object wrapped in a Proxy. When you mutate a property, the DOM updates automatically — no setState(), no $set, no manual re-renders.
defineModule({
state: () => ({
count: 0,
user: { name: 'Alice' },
}),
methods: {
increment(ctx) {
ctx.state.count++; // DOM updates automatically
},
rename(ctx) {
ctx.state.user.name = 'Bob'; // Nested paths also reactive
},
},
});The state returned by state() is scoped to the module instance and destroyed when the user navigates away.
You don't write DOM manipulation code. Instead, annotate your HTML with data-* attributes and the framework keeps the DOM in sync.
<!-- Read-only display -->
<span data-bind="count"></span>
<!-- Two-way input binding -->
<input data-model="user.name" />
<!-- List rendering -->
<ul>
<li data-for="items" data-template="item-tpl"></li>
</ul>
<!-- Events -->
<button data-click="increment">+1</button>
<input data-input="search" />
<form data-submit="save">...</form>See Declarative Bindings for the full reference.
Every URL route maps to a module folder. The router loads the module's HTML into the mount point, then runs its JavaScript to set up state and bindings.
// app.js
initApp({
routes: {
home: 'home', // #/home → modules/home/
clientes: 'clientes', // #/clientes → modules/clientes/
'clientes/:id': 'perfil', // #/clientes/42 → modules/perfil/
},
});When the user navigates:
- Current module's
destroyed()hook is called - Current HTML is removed
- New module's HTML is injected
- New module's
mounted()hook is called - Bindings and events are attached
See Module System and Router for details.
The store is shared reactive state that persists across navigation. Use it when two or more modules need the same data.
// In any module
defineModule({
mounted(ctx) {
ctx.store.state.currentUser = { name: 'Alice' };
},
methods: {
logout(ctx) {
ctx.store.state.currentUser = null;
},
},
});Any DOM element in any module can bind to store state using the store. prefix:
<span data-bind="store.currentUser.name"></span>See Global Store for details.
Every method, mounted, and destroyed callback receives ctx — the module's context object:
| Property | Type | Description |
|---|---|---|
ctx.state |
Proxy | Module's reactive state |
ctx.root |
Element | The module's DOM root element |
ctx.store |
Store | Global store (shared across modules) |
ctx.config |
object | Loaded app config |
ctx.props.params |
object | Route parameters from the URL |
User action (click, input, etc.)
→ method(ctx) runs
→ ctx.state.x = newValue
→ Proxy intercepts mutation
→ Subscribed DOM nodes update
→ User sees the change
No virtual DOM. No diffing. Direct DOM updates scoped to the exact bindings that depend on the changed path.