# Understanding Mods

Mods (short for "modules") are the fundamental building blocks of Vellum, enabling you to create modular, extensible web applications. Each mod is a self-contained unit of functionality that Vellum loads, initializes, and manages. This document introduces mods, explains their structure and lifecycle, and provides guidance on dependency management and error handling.

For details on interacting with Vellum from within a mod, see [Toolkit API](./toolkit.md). For more on mod communication, check out [Action System](./actions.md).

---

## What is a Mod?

A mod is a JavaScript module defined by an HTML element (e.g., `<vellum-mod>`) with a `src` attribute pointing to its code. Mods are loaded dynamically by Vellum and initialized to perform tasks like registering layouts, rendering content, or handling actions. They work together to build complex applications, leveraging Vellum’s action system for loose coupling.

---

## Mod Structure

A mod is typically a JavaScript file exporting an `init` function, which Vellum calls during initialization. The `init` function receives a `toolkit` object as its first argument, providing access to Vellum’s API.

### Basic Structure
- **Required**: An exported `init` function (can be async).
- **Optional**: Additional exports or logic as needed.

Here’s a simple example:
```javascript
// simple-mod.mjs
export async function init(toolkit) {
  console.log('Mod initialized!');
}
```
Defined in HTML as:
```html
<vellum-mod src="/path/to/simple-mod.mjs"></vellum-mod>
```

### Real-World Example from `app-counter.mjs`
```javascript
import { html } from 'lit';

export async function init(toolkit) {
  let count = 0;
  const renderCounter = () => html`
    <div slot="workspace" id="counter-app">
      <h2>Counter</h2>
      <p>Count: ${count}</p>
      <button @click=${() => { count++; updateCounter(); }}>Increment</button>
    </div>
  `;

  const updateCounter = () => {
    toolkit.dispatchAction({
      type: 'layout:content:remove',
      detail: { id: 'app-content-counter' },
    });
    toolkit.dispatchAction({
      type: 'layout:content:append',
      detail: { content: renderCounter(), id: 'app-content-counter' },
    });
  };

  toolkit.dispatchAction({
    type: 'app:register',
    detail: { id: 'counter', name: 'Counter', content: renderCounter },
  });
}
```
- **Explanation**: This mod maintains a counter state, renders it using Lit, and registers itself with the `app-manager` mod via an action.

---

## Mod Lifecycle

Mods go through a well-defined lifecycle managed by Vellum:

1. **Loading**: Vellum discovers `<vellum-mod>` elements and imports their scripts using dynamic `import()`.
2. **Sorting**: Mods are ordered based on dependencies (`require` attribute) and priorities (`priority` attribute).
3. **Initialization**: The `init` function is called with the toolkit.
4. **Execution**: Mods perform their tasks (e.g., registering actions, rendering content).
5. **Dynamic Updates**: New mods added to the DOM are detected and processed via a `MutationObserver`.

### Lifecycle Diagram
```
[Discovery] --> [Loading] --> [Sorting] --> [Initialization] --> [Execution]
     |                                                         |
     +-------------------[Dynamic Updates]---------------------+
```

---

## Dependency Management

Mods can depend on others using the `require` attribute, ensuring proper load order.

### Example from `index.html`
```html
<vellum-app mod-tag="vellum-mod">
  <vellum-mod src="/mods/mod-layout-manager.mjs" name="layout-manager"></vellum-mod>
  <vellum-mod src="/mods/mod-app-manager.mjs" name="app-manager" require="layout-manager"></vellum-mod>
  <vellum-mod src="/mods/apps/app-counter.mjs" name="app-counter" require="app-manager"></vellum-mod>
</vellum-app>
```
- **Explanation**: `app-counter` depends on `app-manager`, which depends on `layout-manager`. Vellum ensures `layout-manager` loads first.

### Priority Attribute
The `priority` attribute (an integer) overrides dependency order when needed:
```html
<vellum-mod src="/mod1.mjs" priority="1"></vellum-mod>
<vellum-mod src="/mod2.mjs" priority="2"></vellum-mod>
```
- Lower numbers load first. If omitted, mods default to the DOM order.

### Handling Circular Dependencies
If circular dependencies occur (e.g., mod A requires mod B, and B requires A), Vellum logs a warning and falls back to priority and DOM order.

---

## Error Handling

Mods should handle errors gracefully, as Vellum captures and reports failures:

- **Load Errors**: If `import()` fails, Vellum emits `'vellum:mod-load-failed'` and notifies via `'system:errors'`.
- **Init Errors**: If `init` throws, Vellum emits `'vellum:mod-init-failed'` and dispatches an error action.

### Example from `mod-error-toast.mjs`
```javascript
import { html } from 'lit';

export async function init(toolkit) {
  const showErrorToast = (detail) => {
    const { failedMods } = detail;
    const errorContent = html`
      <div slot="panel" id="error-toast">
        <h3>Errors Detected</h3>
        <ul>
          ${failedMods.map(mod => html`<li>${mod.src}: ${mod.error.message}</li>`)}
        </ul>
        <button @click=${() => toolkit.dispatchAction({ type: 'layout:content:remove', detail: { id: 'error-toast' } })}>
          Dismiss
        </button>
      </div>
    `;
    toolkit.dispatchAction({
      type: 'layout:content:append',
      detail: { content: errorContent, id: 'error-toast' },
    });
  };

  toolkit.dispatchAction({
    type: 'action:register',
    detail: { actionType: 'system:errors', modName: 'error-toast', handler: showErrorToast },
  });
}
```
- **Explanation**: This mod listens for `'system:errors'` and displays a toast with failure details.

### Tips
- Wrap risky code in try-catch blocks within `init`.
- Use the toolkit to dispatch error notifications if needed.

---

## Example: Creating a Simple Mod

Here’s a complete mod that logs a message and renders content:

```javascript
// hello-mod.mjs
export async function init(toolkit) {
  const content = '<div>Hello from the mod!</div>';
  toolkit.dispatchAction({
    type: 'layout:content:append',
    detail: { content, id: 'hello-message' },
  });
  console.log('Hello mod initialized');
}
```
```html
<vellum-app>
  <vellum-mod src="/hello-mod.mjs" name="hello"></vellum-mod>
</vellum-app>
```

---

## Next Steps
- **Explore the Toolkit**: Learn how to use the toolkit in [Toolkit API](./toolkit.md).
- **Understand Actions**: See how mods communicate via [Action System](./actions.md).
- **Check Examples**: Dive into [Examples and Tutorials](./examples/) for more mod implementations.