Module System - cynchro/OldSchoolFrontFrame GitHub Wiki
A module is the primary building block of an OLS application. Each route maps to exactly one module folder.
modules/clientes/
├── clientes.html # Template (required)
├── clientes.js # defineModule() call (required)
├── clientes.css # Scoped styles (optional)
└── services/ # Data/API functions (optional)
└── clientes.service.js
The folder name must match the value used in initApp({ routes }).
import { defineModule } from '../../framework/module/module.js';
defineModule({
state,
methods,
mounted,
destroyed,
css,
});A function (or object) that returns the module's initial reactive state.
state: () => ({
users: [],
loading: false,
query: '',
}),Use a function (not a plain object) so each module instance gets a fresh copy.
An object of functions available in the template as event handlers and callable within mounted/destroyed.
Each method receives ctx as the first argument.
methods: {
async loadUsers(ctx) {
ctx.state.loading = true;
ctx.state.users = await fetchUsers();
ctx.state.loading = false;
},
deleteUser(ctx, event) {
const id = event.target.dataset.id;
ctx.state.users = ctx.state.users.filter(u => u.id !== Number(id));
},
},Called after the module's HTML is injected and bindings are attached. Use this for initial data loading.
mounted(ctx) {
ctx.methods.loadUsers(ctx);
},ctx.methods gives you access to the module's own methods from inside lifecycle hooks.
Called before the module is removed from the DOM. Use this for cleanup (timers, subscriptions, etc.).
destroyed(ctx) {
clearInterval(ctx._pollInterval);
},Set to true to load <name>.css alongside the module. Styles are scoped to the module's root element.
defineModule({
css: true,
state: () => ({}),
});| Property | Description |
|---|---|
ctx.state |
Module's reactive state (Proxy) |
ctx.root |
The module's root DOM element |
ctx.store |
Global store — see Global Store |
ctx.config |
Loaded app configuration |
ctx.props.params |
URL route parameters (e.g. { id: '42' }) |
ctx.methods |
The module's methods object, for calling methods from hooks |
// modules/clientes/clientes.js
import { defineModule } from '../../framework/module/module.js';
import { getClientes, deleteCliente } from './services/clientes.service.js';
defineModule({
state: () => ({
clientes: [],
loading: false,
error: null,
}),
methods: {
async cargar(ctx) {
ctx.state.loading = true;
ctx.state.error = null;
try {
ctx.state.clientes = await getClientes();
} catch (e) {
ctx.state.error = e.message;
} finally {
ctx.state.loading = false;
}
},
async eliminar(ctx, event) {
const id = Number(event.target.dataset.id);
await deleteCliente(id);
ctx.state.clientes = ctx.state.clientes.filter(c => c.id !== id);
},
},
mounted(ctx) {
ctx.methods.cargar(ctx);
},
});<!-- modules/clientes/clientes.html -->
<div>
<h2>Clientes</h2>
<p data-bind="error" style="color:red"></p>
<ul data-for="clientes" data-template="cliente-tpl"></ul>
<template id="cliente-tpl">
<li>
<span data-bind="nombre"></span>
<button data-click="eliminar" data-id="">Eliminar</button>
</li>
</template>
</div>Route change detected
→ destroyed() on previous module
→ HTML removed from DOM
→ New HTML injected into mount point
→ Bindings attached
→ Events attached
→ mounted() on new module