This commit is contained in:
@@ -1,85 +1,148 @@
|
||||
# Application Mounter: `Mount( )`
|
||||
# Application Mounter: `mount( )`
|
||||
|
||||
The `Mount` function is the entry point of your reactive world. It bridges the gap between your SigPro logic and the browser's Real DOM by injecting a component into the document and initializing its reactive lifecycle.
|
||||
The `mount` function is the entry point of your reactive world. It bridges the gap between your SigPro logic and the browser's real DOM by rendering a component into a target element and managing its full reactive lifecycle.
|
||||
|
||||
## Function Signature
|
||||
|
||||
```typescript
|
||||
Mount(node: Function | HTMLElement, target?: string | HTMLElement): RuntimeObject
|
||||
mount(component: Function | Node, target: string | HTMLElement): RuntimeObject
|
||||
```
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
| Parameter | Type | Required | Description |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **`node`** | `Function` or `Node` | **Required** | The component function or DOM element to render. |
|
||||
| **`target`** | `string` or `Node` | `document.body` | CSS selector or DOM element where the app will live. |
|
||||
| **`component`** | `Function` or `Node` | Yes | A component function (returns a Node) or a direct DOM node. |
|
||||
| **`target`** | `string` or `HTMLElement` | Yes | CSS selector (e.g., `"#app"`) or DOM element where the app will be mounted. |
|
||||
|
||||
**Returns:** A `Runtime` object containing the `container` and a `destroy()` method to wipe all reactivity and DOM nodes.
|
||||
**Returns:** A `Runtime` object with:
|
||||
- `container`: The actual DOM element created by the renderer.
|
||||
- `destroy()`: A method to completely unmount and clean up the application.
|
||||
|
||||
---
|
||||
|
||||
## Common Usage Scenarios
|
||||
## Usage Patterns
|
||||
|
||||
### 1. The SPA Entry Point
|
||||
In a Single Page Application, you typically mount your main component to the body or a root div. SigPro manages the entire view from that point.
|
||||
### 1. Main Application Entry Point
|
||||
|
||||
```javascript
|
||||
import SigPro from 'sigpro';
|
||||
import App from './App.js';
|
||||
import { mount } from 'sigpro';
|
||||
|
||||
// Mounts your main App component
|
||||
Mount(App, '#app-root');
|
||||
const App = () => div({ class: "app" }, [
|
||||
h1("Hello SigPro"),
|
||||
button("Click me")
|
||||
]);
|
||||
|
||||
mount(App, '#app');
|
||||
```
|
||||
|
||||
### 2. Reactive "Islands"
|
||||
SigPro is perfect for adding reactivity to static pages. You can mount small widgets into specific parts of an existing HTML layout.
|
||||
### 2. Reactive Widget (Island Architecture)
|
||||
|
||||
Mount small reactive components into static HTML pages.
|
||||
|
||||
```javascript
|
||||
const Counter = () => {
|
||||
const count = $(0);
|
||||
return Button({ onclick: () => count(c => c + 1) }, [
|
||||
"Clicks: ", count
|
||||
]);
|
||||
return button({ onclick: () => count(count() + 1) }, () => `Clicks: ${count()}`);
|
||||
};
|
||||
|
||||
// Mount only the counter into a specific sidebar div
|
||||
Mount(Counter, '#sidebar-widget');
|
||||
mount(Counter, '#sidebar-widget');
|
||||
```
|
||||
|
||||
### 3. Direct Node Mounting
|
||||
|
||||
You can also mount an already existing DOM node.
|
||||
|
||||
```javascript
|
||||
const myDiv = div("I am already a node");
|
||||
mount(myDiv, '#container');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## How it Works (Lifecycle & Cleanup)
|
||||
## How It Works (Lifecycle & Cleanup)
|
||||
|
||||
When `Mount` is executed, it performs these critical steps to ensure a leak-free environment:
|
||||
When you call `mount`, SigPro performs these steps:
|
||||
|
||||
1. **Duplicate Detection**: If you call `Mount` on a target that already has a SigPro instance, it automatically calls `.destroy()` on the previous instance. This prevents "Zombie Effects" from stacking in memory.
|
||||
2. **Internal Scoping**: It executes the component function inside an internal **Reactive Owner**. This captures every `Watch` and event listener created during the render.
|
||||
3. **Target Injection**: It clears the target using `replaceChildren()` and appends the new component.
|
||||
4. **Runtime Creation**: It returns a control object:
|
||||
* `container`: The actual DOM element created.
|
||||
* `destroy()`: The "kill switch" that runs all cleanups, stops all watchers, and removes the element from the DOM.
|
||||
1. **Duplicate Detection**
|
||||
SigPro keeps a `WeakMap` (`MOUNTED_NODES`) that tracks which DOM target already has a mounted runtime. If you mount a new component to the same target, the previous instance is **automatically destroyed** before the new one is rendered. This prevents memory leaks and “zombie effects”.
|
||||
|
||||
2. **Render Phase**
|
||||
The `render` function creates a **cleanup container** (a `div` with `style="display: contents"`), and executes the component inside a fresh reactive owner. All effects (`watch`), event listeners, and child components created during this render are captured.
|
||||
|
||||
3. **DOM Injection**
|
||||
The target element is cleared using `replaceChildren()`, and the container (which holds the rendered content) is appended.
|
||||
|
||||
4. **Runtime Object**
|
||||
Returns an object `{ _isRuntime: true, container, destroy }`. The `destroy` function recursively disposes all effects, cleans up DOM nodes, and removes the container from the parent.
|
||||
|
||||
---
|
||||
|
||||
## Manual Unmounting
|
||||
|
||||
While SigPro handles most cleanups automatically (via `If`, `For`, and `Router`), you can manually destroy any mounted instance. This is vital for imperatively managed UI like **Toasts** or **Modals**.
|
||||
You can call `destroy()` at any time to tear down the application. This is essential for imperatively managed UI like **modals**, **toasts**, or **dynamic panels**.
|
||||
|
||||
```javascript
|
||||
const instance = Mount(MyToast, '#toast-container');
|
||||
const widget = mount(MyToast, '#toast-container');
|
||||
|
||||
// Later, to remove the toast and kill its reactivity:
|
||||
instance.destroy();
|
||||
// Later, remove it completely:
|
||||
widget.destroy();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Automatic Re‑mount on Same Target
|
||||
|
||||
If you call `mount` a second time on the same target, SigPro automatically destroys the previous instance and replaces it with the new one. No manual cleanup required.
|
||||
|
||||
```javascript
|
||||
mount(LoginScreen, '#app');
|
||||
// ... later, after login
|
||||
mount(Dashboard, '#app'); // LoginScreen is destroyed automatically
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## What is Automatically Cleaned Up
|
||||
|
||||
When `destroy()` is called (or when a new mount replaces an old one), everything is purged:
|
||||
|
||||
- All `watch` effects
|
||||
- All event listeners added via SigPro (`onClick`, `onInput`, etc.)
|
||||
- All child components created with `when`, `each`, or nested `mount` calls
|
||||
- Any custom cleanups registered with `onUnmount`
|
||||
|
||||
> **You only need manual cleanup** for external resources not managed by SigPro (e.g., `setInterval`, third‑party libraries, WebSocket connections). Use `onUnmount` for that.
|
||||
|
||||
---
|
||||
|
||||
## Complete Example
|
||||
|
||||
```javascript
|
||||
import { $, mount, div, h1, button } from 'sigpro';
|
||||
|
||||
const App = () => {
|
||||
const count = $(0);
|
||||
return div({ class: "demo" }, [
|
||||
h1(() => `Count: ${count()}`),
|
||||
button({ onClick: () => count(count() + 1) }, "Increment")
|
||||
]);
|
||||
};
|
||||
|
||||
const runtime = mount(App, '#app');
|
||||
|
||||
// Destroy after 10 seconds
|
||||
setTimeout(() => runtime.destroy(), 10000);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Summary Cheat Sheet
|
||||
|
||||
| Goal | Code Pattern |
|
||||
| Goal | Code |
|
||||
| :--- | :--- |
|
||||
| **Mount to body** | `Mount(App)` |
|
||||
| **Mount to CSS Selector** | `Mount(App, '#root')` |
|
||||
| **Mount to DOM Node** | `Mount(App, myElement)` |
|
||||
| **Clean & Re-mount** | Calling `Mount` again on the same target |
|
||||
| **Total Cleanup** | `const app = Mount(App); app.destroy();` |
|
||||
| Mount to a CSS selector | `mount(App, '#root')` |
|
||||
| Mount to a DOM element | `mount(App, document.getElementById('root'))` |
|
||||
| Mount a static node | `mount(div("Hello"), '#target')` |
|
||||
| Manual destruction | `const app = mount(App, '#app'); app.destroy();` |
|
||||
| Auto‑replace on same target | Just call `mount` again – SigPro handles cleanup. |
|
||||
|
||||
> **Note:** The function name is `mount` (lowercase). It is exported from SigPro and also available globally after importing the library. The target must exist in the DOM at the time of mounting.
|
||||
Reference in New Issue
Block a user