The Good Ole Registry (Lego Basket)
Let's not keep our toys everywhere, let's be good citizens and put them in a basket.
PSS!!! Come here lemme tell you a secret - are you a frontend developer? "The DOM is not your enemy" we talk about Light DOM and Shadow DOM in a minute 😉.
Topic 2: The Registry & Internal Storage
LegoDOM uses three specialized collections to store the "DNA" of your application. This separation allows the framework to distinguish between what a block looks like versus how it behaves.
const registry = {};
const legoFileLogic = new Map();
const sharedStates = new Map();1. The HTML Blueprint Collection (registry)
const registry = {} is a plain object that stores references to <template> elements.
When LegoDOM initializes, it scans the DOM for any
<template b-id="my-block">and saves it here.The
b-idbecomes the key, and the DOM node itself is the value.Purpose: This is the "Light DOM" source used to populate the "Shadow DOM" later during the "snapping" process.
2. The Lego File Logic Collection (legoFileLogic)
const legoFileLogic = new Map(); stores the JavaScript objects passed into Lego.block().
While
registryholds the HTML/CSS,legoFileLogicholds the functions likemounted(),updated(), or custom methods.Why a Map? Unlike a plain object, a
Mapis more performant for frequent lookups by string keys (tag names) - I think!!! or maybe I read wrong (call me out).
3. The Singleton States Collection (sharedStates)
const sharedStates = new Map(); is one of the most powerful "hidden" features of LegoDOM.
Every time you define a block, Lego creates a reactive version of its logic and stores it here.
This allows other blocks to access a specific block's state globally via the
$registry('tag-name')helper. NOTE the block's (template/blueprint) state, not the instance state.Example: If you have 3
user-profileblocks, any other block on the page can peek at their (shared) state data by asking thesharedStatesmap.
Dissecting Registration
The registry doesn't just wait for you to type; it's fed by three distinct streams across 2 paradigms.
Paradigm 1: Explicitly
const legoFileLogic = new Map(); // Specifically for SFB script logic
// ...
block: (tagName, templateHTML, logic = {}) => {
const t = document.createElement('template');
// ... stores template in registry
legoFileLogic.set(tagName, logic); // Stores the JS part separately
}Paradigm 2: Implicitly
// vite-plugin.js
async buildStart() {
const root = config?.root || process.cwd();
legoFiles = await fg(include, { cwd: searchPath, absolute: true }); // Scans for .lego files
}
// ...
async load(id) {
if (id.endsWith('.lego')) {
const blockCall = generateBlockCall(parsed); // Converts .lego file to Lego.block()
return `import { Lego } from 'lego-dom/main.js';\n${blockCall}`;
}
}The Three Ways to Register:
The HTML Manual Method: You put
<template b-id="my-comp">directly in your*.htmlfiles. DuringLego.init(), LegoDOM scrapes these and populates the registry. This is great for "no-build" prototypes.The
Lego.block()JS Method: You callLego.block('my-comp', '<h1>Hi</h1>', { ... logic })in a standard JavaScript file.The Lego File Automatic Method (The "Vite Way"): * The Vite Plugin (as seen in
vite-plugin.js) acts as a build-time robot.It uses
fast-glob(fg) to scan your entiresrc/blocksdirectory for any file ending in.lego.It parses the
<template>and<script>inside that.legofile.It injects a
Lego.block()call into your JavaScript bundle automatically.Result: You just create a file named
user-card.lego, and suddenly<user-card>is a valid HTML tag in your app.
Paradigm 3: Runtime Block Definition (New in v2.0)
defineLegoFile: (content, filename) => {
// Regex parsing of <template>, <script>, <style>
const templateMatch = content.match(/<template([\s\S]*?)>([\s\S]*?)<\/template>/);
// ...
const logicObj = new Function(`return ${script}`)();
// ...
legoFileLogic.set(name, logicObj);
}This is the power behind the Server Loader. We can fetch a string from the server and "compile" it in the browser using new Function(). It populates registry and legoFileLogic just like the build-time tools, but on the fly.
4. Block Naming Conventions ("Explicit or Go Home")
When you define a block via a file (e.g. .lego), LegoDOM automatically derives the tag name. To keep the web platform happy, we enforce Custom Element Best Practices:
Automatic Conversion: All filenames are converted to
kebab-case.UserProfile.lego-><user-profile>navBar.lego-><nav-bar>data_table.lego-><data-table>
The Hyphen Rule: A custom element MUST contain a hyphen.
Button.lego-> ErrorAdidas.lego-> Error
TIP
Single Word Block? Namespace It! Custom Element specs require a hyphen to distinguish from native tags. To ensure forward compatibility, LegoDOM will throw an error if you try to define a single-word block. Simply add your app or product prefix to the filename:
fb-button.lego-><fb-button>shop-card.lego-><shop-card>mobile-button.lego-><mobile-button>