Lego.init()
Boots the engine. Until you call init(), reactivity, routing, and auto-discovery do not run, and any <template b-id> declared in HTML is not registered.
Lego.init(root?: HTMLElement, options?: InitOptions): Promise<void>Parameters
root
- Type:
HTMLElement - Default:
document.body
The element under which to scan for <template b-id> definitions and run loader auto-discovery. If you pass anything that isn't an element, init falls back to document.body.
options
interface InitOptions {
styles?: Record<string, (string | CSSStyleSheet)[]>;
loader?: (tagName: string) => string | Promise<string> | void;
manifest?: ManifestGroup | ManifestGroup[] | string | { url: string; headers?: Headers; credentials?: RequestCredentials };
studio?: boolean;
debug?: boolean;
}options.styles
Map of stylesheet keys to either URLs (fetched and converted to CSSStyleSheet) or pre-constructed CSSStyleSheet instances. Each key becomes addressable through b-stylesheets="key" and b-cascade="key".
await Lego.init(document.body, {
styles: {
base: ['/styles/reset.css', '/styles/typography.css'],
forms: ['/styles/forms.css']
}
});<template b-id="signup-form" b-stylesheets="base forms">
<form>…</form>
</template>Stylesheets are pre-loaded in parallel and adopted via Document.adoptedStyleSheets. After loading, every block already on the page that names one of these keys is reapplied, order-of-init doesn't matter.
options.loader
Auto-discovery hook for unknown hyphenated tags. Whenever the runtime sees a custom-element tag with no registered template, it calls loader(tagName).
await Lego.init(document.body, {
loader: (tag) => `/blocks/${tag}.lego` // shorthand: return a URL
});The loader can return:
string, treated as a URL; the runtime fetches it and parses the response body as a.legoSFC.Promise<string>, the resolved string is parsed as a.legoSFC. Use this when you need custom headers, credentials, or auth.null/undefined, no fetch is attempted for that tag.
Lock the loader down
A loader without an allowlist will fetch any unknown hyphenated tag a third party can inject. Always set Lego.config.loaderAllowlist in production. See config.loaderAllowlist.
options.manifest
Pre-register a batch of remote .lego blocks before users navigate. Three shapes are accepted:
// 1. Array form (most common)
manifest: [
{
base: '/blocks/',
suffix: true, // appends '.lego'
legos: ['user-card', 'app-nav'] // -> /blocks/user-card.lego
},
{
base: '/widgets/',
map: { 'date-picker': 'pickers/date.lego' }
}
]
// 2. URL form, manifest fetched from a public endpoint
manifest: '/blocks/manifest.json'
// 3. Authenticated form
manifest: {
url: '/api/manifest',
credentials: 'include',
headers: { Authorization: () => `Bearer ${token}` } // function or static
}For each entry the runtime registers a custom element that, on first connect, fetches the file, parses it via Lego.defineLegoFile(), and snaps the live element. While the fetch is in-flight, additional instances are queued and snapped when the response lands, so a list of 50 <user-card> elements triggers exactly one network round-trip.
Header values may be functions (called per-fetch) or strings. Strings prefixed $db. resolve through the persistence layer; strings prefixed $globals. read from Lego.globals.
options.studio
When true, side-loads @legodom/studio from the unpkg CDN and registers /_/studio and /_/studio/:block routes. Useful for in-app component browsing during development.
options.debug
Enables verbose [Lego Trace] logging. Equivalent to Lego.config.debug = true.
What init() actually does
In order:
- Stamps
config.loader,config.debug, and the styles map. - Awaits stylesheet preload (parallel
fetch+CSSStyleSheet.replace). - If routes are registered, performs an initial route match against
window.locationso$routeis correct on first paint. - Registers every
<template b-id>underrootas a custom element. - Resolves and registers the manifest, if any.
- If a
loaderis provided, walksrootfor unknown hyphenated tags and starts aMutationObserverto catch later insertions. - Wires up
popstate,<a b-link|b-target>click delegation, and<form b-action>submit prevention. - Calls
initCrossTabSync()to bind a singlestoragelistener for$dbcross-tab updates.
Step 4 means inline templates are upgraded after routes are matched, useful when you want a route to render before declarations are scanned.
Examples
Plain CDN
<template b-id="hello-world">
<h1>Hello [[ name ]]!</h1>
</template>
<hello-world b-logic="{ name: 'World' }"></hello-world>
<script src="https://unpkg.com/lego-dom"></script>
<script>Lego.init();</script>Vite app with stylesheets and routing
// src/app.js
import { Lego } from 'lego-dom';
import registerBlocks from 'virtual:lego-blocks';
registerBlocks();
Lego.route('/', 'home-page');
Lego.route('/users/:id', 'user-page');
Lego.route('*', 'not-found');
await Lego.init(document.body, {
styles: {
base: ['/styles/reset.css', '/styles/theme.css']
}
});Authenticated lazy-loading
await Lego.init(document.body, {
loader: async (tag) => {
const res = await fetch(`/api/blocks/${tag}.lego`, {
credentials: 'include',
headers: { Authorization: `Bearer ${getToken()}` }
});
if (!res.ok) return; // skip this tag
return res.text();
}
});
Lego.config.loaderAllowlist = /^app-/; // only fetch app-* tags