Core Concepts - cynchro/OldSchoolFrontFrame GitHub Wiki

Core Concepts

OLS is built on four primitives that compose into a full frontend architecture.


1. Reactive State

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.


2. Declarative DOM Bindings

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.


3. Module = Route

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:

  1. Current module's destroyed() hook is called
  2. Current HTML is removed
  3. New module's HTML is injected
  4. New module's mounted() hook is called
  5. Bindings and events are attached

See Module System and Router for details.


4. Global Store

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.


Module context (ctx)

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

Data flow summary

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.

⚠️ **GitHub.com Fallback** ⚠️