-
Notifications
You must be signed in to change notification settings - Fork 1
API Reference
Comprehensive API documentation for LARC (Lightweight Autonomous Reactive Components)
- Getting Started
- Core Package (@larcjs/core)
- Configuration
- Events Reference
- TypeScript Support
- Best Practices
- Common Pitfalls
LARC can be used in two ways:
1. Local Development (Zero Build)
<!DOCTYPE html>
<html>
<head>
<title>My LARC App</title>
</head>
<body>
<!-- Load autoloader -->
<script type="module" src="/core/pan.mjs"></script>
<!-- Use components - they load automatically -->
<my-widget></my-widget>
<pan-card>Hello World</pan-card>
</body>
</html>2. CDN Usage
<!DOCTYPE html>
<html>
<head>
<title>My LARC App</title>
</head>
<body>
<!-- Configure for CDN -->
<script type="module">
window.panAutoload = {
baseUrl: 'https://unpkg.com/@larcjs/core@latest/',
extension: '.js'
};
</script>
<!-- Load autoloader from CDN -->
<script type="module" src="https://unpkg.com/@larcjs/core@latest/src/pan.mjs"></script>
<!-- Components load from CDN -->
<my-widget></my-widget>
</body>
</html><!DOCTYPE html>
<html>
<head>
<title>Counter Demo</title>
</head>
<body>
<script type="module" src="/core/pan.mjs"></script>
<!-- Create a simple counter component -->
<script type="module">
import { PanClient } from '/core/pan-client.mjs';
class CounterElement extends HTMLElement {
constructor() {
super();
this.count = 0;
this.client = new PanClient(this);
}
async connectedCallback() {
await this.client.ready();
// Subscribe to counter updates
this.client.subscribe('counter.value', (msg) => {
this.count = msg.data;
this.render();
}, { retained: true });
this.render();
// Publish initial value
this.client.publish({
topic: 'counter.value',
data: this.count,
retain: true
});
}
increment() {
this.count++;
this.client.publish({
topic: 'counter.value',
data: this.count,
retain: true
});
}
render() {
this.innerHTML = `
<div>
<h2>Count: ${this.count}</h2>
<button onclick="this.parentElement.parentElement.increment()">
Increment
</button>
</div>
`;
}
}
customElements.define('x-counter', CounterElement);
</script>
<x-counter></x-counter>
</body>
</html>The core package provides three main APIs:
- PAN Autoloader - Automatic component loading
- PAN Bus - Message bus for pub/sub communication
- PAN Client - Simplified API for components
The autoloader automatically discovers and loads Web Components as they appear in the DOM, eliminating manual imports and customElements.define() calls.
- Progressive loading with IntersectionObserver
- Automatic component discovery via MutationObserver
- Configurable paths and file extensions
- Support for custom component resolvers
- Zero-build development workflow
interface AutoloadConfig {
baseUrl?: string | null; // Full CDN URL (e.g., 'https://unpkg.com/pan@latest/')
componentsPath?: string; // Relative path from baseUrl (default: './')
extension?: string; // File extension (default: '.mjs')
rootMargin?: number; // IntersectionObserver margin in px (default: 600)
resolvedComponentsPath?: string; // Computed full path (readonly)
}Local Development
// Default configuration works out of the box
// Components loaded from ./components/ relative to pan.mjsCDN Usage
<script type="module">
window.panAutoload = {
baseUrl: 'https://unpkg.com/@larcjs/core@2.0.0/',
componentsPath: 'src/components/',
extension: '.js'
};
</script>
<script type="module" src="https://unpkg.com/@larcjs/core@2.0.0/src/pan.mjs"></script>Custom Component Resolver
window.panAutoload = {
resolveComponent(tagName) {
// Custom logic to resolve component paths
if (tagName.startsWith('my-')) {
return `/custom/${tagName}.mjs`;
}
return null; // Use default resolution
}
};Manually loads a component module for a specific element.
import { maybeLoadFor } from '/core/pan.mjs';
const widget = document.createElement('my-widget');
document.body.appendChild(widget);
await maybeLoadFor(widget);Observes a DOM tree for undefined custom elements and sets up progressive loading.
import { observeTree } from '/core/pan.mjs';
// Observe entire document (default)
observeTree();
// Observe specific subtree
const container = document.querySelector('#dynamic-content');
observeTree(container);The central message bus for publish/subscribe communication between components.
Note: As of v1.1.1, the PAN bus is automatically instantiated when you load
pan.mjs. You no longer need to include a<pan-bus>element in your HTML.
| Attribute | Type | Default | Description |
|---|---|---|---|
max-retained |
number | 1000 | Maximum retained messages |
max-message-size |
number | 1048576 | Max total message size (1MB) |
max-payload-size |
number | 524288 | Max data payload size (512KB) |
cleanup-interval |
number | 30000 | Cleanup interval in ms (30s) |
rate-limit |
number | 1000 | Max messages per client per second |
allow-global-wildcard |
boolean | true | Allow '*' subscriptions |
debug |
boolean | false | Enable debug logging |
interface PanMessage<T = any> {
topic: string; // Topic name (required)
data: T; // Message payload (required)
id?: string; // Unique message ID (auto-generated)
ts?: number; // Timestamp in ms (auto-generated)
retain?: boolean; // Retain for late subscribers
replyTo?: string; // Topic for replies
correlationId?: string; // Correlation ID for request/reply
headers?: Record<string, string>; // Optional metadata
}Exact Match
subscribe(['users.updated'], handler);Wildcard Match
// Matches users.created, users.updated, users.deleted
subscribe(['users.*'], handler);
// Matches all messages
subscribe(['*'], handler); // Only if allow-global-wildcard=true| Event | Direction | Purpose |
|---|---|---|
pan:publish |
Component → Bus | Publish a message |
pan:subscribe |
Component → Bus | Subscribe to topics |
pan:unsubscribe |
Component → Bus | Unsubscribe from topics |
pan:deliver |
Bus → Component | Deliver message to subscriber |
pan:request |
Component → Bus | Send request (expects reply) |
pan:reply |
Component → Bus | Send reply to request |
pan:sys.ready |
Bus → Document | Bus is ready |
pan:sys.error |
Bus → Document | Error occurred |
A simplified, promise-based API for interacting with the PAN bus.
new PanClient(host?: HTMLElement | Document, busSelector?: string)const client = new PanClient();
await client.ready();
// Bus is ready, safe to publish/subscribeclient.publish({
topic: 'user.updated',
data: { id: 123, name: 'Alice' },
retain: true // Optional: retain for late subscribers
});const unsub = client.subscribe('users.*', (msg) => {
console.log('Received:', msg.topic, msg.data);
}, { retained: true });
// Later: unsub();const response = await client.request('users.get', { id: 123 }, {
timeoutMs: 5000
});
console.log('User:', response.data);import { PanClient } from '/core/pan-client.mjs';
class UserListComponent extends HTMLElement {
constructor() {
super();
this.client = new PanClient(this);
this.users = [];
}
async connectedCallback() {
await this.client.ready();
this.unsubscribe = this.client.subscribe(
['users.*'],
(msg) => this.handleUserEvent(msg),
{ retained: true }
);
this.render();
}
disconnectedCallback() {
this.unsubscribe?.();
}
handleUserEvent(msg) {
// Handle user events...
}
}
customElements.define('user-list-component', UserListComponent);LARC includes comprehensive TypeScript definitions.
import {
PanClient,
PanMessage,
SubscribeOptions,
RequestOptions
} from '/core/pan-client.mjs';interface User {
id: number;
name: string;
}
// Typed publish
client.publish<User>({
topic: 'users.created',
data: { id: 123, name: 'Alice' }
});
// Typed subscribe
client.subscribe<User>('users.*', (msg) => {
console.log(msg.data.name); // Type safe
});- Always wait for bus ready before publishing/subscribing
-
Clean up subscriptions in
disconnectedCallback - Use retained messages for state
-
Namespace your topics (e.g.,
app.users.created) - Use request/reply for RPC-style operations
- Validate message data in handlers
- Handle request timeouts gracefully
- Use debug mode during development
- Forgetting to wait for bus ready - Messages may fail
- Memory leaks from uncleared subscriptions
- Publishing non-serializable data - DOM nodes, functions fail
- Exceeding message size limits - Chunk large data
- Rate limiting issues - Batch or throttle messages
- Circular message loops - Don't publish to subscribed topics
- Incorrect topic patterns - Test pattern matching
- Quick-Start-Guide - Get started quickly
- State-Management - Advanced state features
- Troubleshooting - Common issues and solutions
- Examples - Code examples