[{"data":1,"prerenderedAt":35},["ShallowReactive",2],{"3766292":3},{"type_of":4,"id":5,"title":6,"description":7,"readable_publish_date":8,"slug":9,"path":10,"url":11,"comments_count":12,"public_reactions_count":12,"collection_id":13,"published_timestamp":14,"language":15,"subforem_id":16,"positive_reactions_count":12,"cover_image":17,"social_image":18,"canonical_url":11,"created_at":14,"edited_at":13,"crossposted_at":13,"published_at":14,"last_comment_at":14,"reading_time_minutes":19,"tag_list":20,"tags":21,"body_html":26,"body_markdown":27,"user":28},"article",3766292,"Exo: Declarative Cross‑Section Coordination for Astro Without Components or Global Mutable State","lucianofedericopereira        /          exo                       ...","May 27","exo-declarative-cross-section-coordination-for-astro-without-components-or-global-mutable-state-52a","/lucianofedericopereira/exo-declarative-cross-section-coordination-for-astro-without-components-or-global-mutable-state-52a","https://dev.to/lucianofedericopereira/exo-declarative-cross-section-coordination-for-astro-without-components-or-global-mutable-state-52a",0,null,"2026-05-27T19:15:15Z","en",1,"https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv1t3botob59zfvnthsta.png","https://media2.dev.to/dynamic/image/width=1200,height=627,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv1t3botob59zfvnthsta.png",4,"astro, vue, javascript, vapor",[22,23,24,25],"astro","vue","javascript","vapor","\u003Cdiv class=\"ltag-github-readme-tag\">\n  \u003Cdiv class=\"readme-overview\">\n    \u003Ch2>\n      \u003Cimg src=\"https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg\" alt=\"GitHub logo\">\n      \u003Ca href=\"https://github.com/lucianofedericopereira\" target=\"_blank\" rel=\"noopener noreferrer\">\n        lucianofedericopereira\n      \u003C/a> / \u003Ca style=\"font-weight: 600;\" href=\"https://github.com/lucianofedericopereira/exo\" target=\"_blank\" rel=\"noopener noreferrer\">\n        exo\n      \u003C/a>\n    \u003C/h2>\n    \u003Ch3>\n      Coordinate interactive sections of an Astro page through declarative HTML attributes—with zero component trees and no shared mutable state\n    \u003C/h3>\n  \u003C/div>\n  \u003Cdiv class=\"ltag-github-body\">\n    \n\u003Cdiv id=\"readme\" class=\"md\" data-path=\"README.md\">\u003Carticle class=\"markdown-body entry-content container-lg\" itemprop=\"text\">\u003Cdiv class=\"markdown-heading\" dir=\"auto\">\n\u003Ch1 class=\"heading-element\" dir=\"auto\">EXO\u003C/h1>\n\u003C/div>\n\u003Cp dir=\"auto\">\u003Ca target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/lucianofedericopereira/exo/assets/exo.png\">\u003Cimg src=\"https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Flucianofedericopereira%2Fexo%2FHEAD%2Fassets%2Fexo.png\" alt=\"EXO\" style=\"max-width: 100%;\" loading=\"lazy\">\u003C/a>\u003C/p>\n\u003Cp dir=\"auto\">Coordinate interactive sections of an Astro page through declarative HTML attributes—with zero component trees and no shared mutable state.\u003C/p>\n\u003Cp dir=\"auto\">Exo is that event bus, engineered with a clean, declarative HTML flight deck on top.\u003C/p>\n\u003Cp dir=\"auto\">It deploys at a razor-thin ~11 kB bundled—loaded exactly once, regardless of how many sectors utilize it.\u003C/p>\n\u003Cdiv class=\"markdown-heading\" dir=\"auto\">\n\u003Ch2 class=\"heading-element\" dir=\"auto\">The Mission Brief: Overcoming Orbital Decay\u003C/h2>\n\u003C/div>\n\u003Cp dir=\"auto\">Astro launches content flawlessly. But the moment two isolated sectors need to coordinate—a product matrix and a payload summary, or a filter telemetry panel and a results grid—current architectural solutions compromise the integrity of the mission. You are forced to reach for heavy, multi-ton frameworks just to bridge a micro-gap.\u003C/p>\n\u003Cul dir=\"auto\">\n\u003Cli>\n\u003Cp dir=\"auto\">\u003Cstrong>The Alpine Drift\u003C/strong>: Alpine operates well for self-contained, isolated pods. But the moment those pods need to synchronize telemetry, you are forced to deploy $store—a chaotic, global, mutable void where any element can overwrite data at any time. It lacks named…\u003C/p>\n\u003C/li>\n\u003C/ul>\u003C/article>\u003C/div>\n  \u003C/div>\n  \u003Cdiv class=\"gh-btn-container\">\u003Ca class=\"gh-btn\" href=\"https://github.com/lucianofedericopereira/exo\" target=\"_blank\" rel=\"noopener noreferrer\">View on GitHub\u003C/a>\u003C/div>\n\u003C/div>\n\n\n\u003Cp>Modern Astro pages often contain multiple interactive sections that must react to each other: a product matrix updating a cart summary, a filter panel driving a results grid, or any pair of isolated DOM sectors that need to stay in sync.\u003C/p>\n\n\u003Cp>Most solutions force you into heavy component runtimes or fragile global stores. Exo takes a different path: a declarative HTML directive layer on top of a real event bus, with no component tree, no shared mutable state, and no cross‑imports between sections.\u003C/p>\n\n\u003Cp>Exo ships at ~11 kB bundled and loads exactly once, no matter how many sectors use it.\u003C/p>\n\n\u003Ch2>\n  \u003Ca name=\"what-exo-is\" href=\"#what-exo-is\">\n  \u003C/a>\n  🚀 What Exo Is\n\u003C/h2>\n\n\u003Cp>Exo is a thin directive layer that coordinates independent DOM sectors through a central vapor‑chamber bus.\u003C/p>\n\n\u003Cp>Each sector declares:\u003C/p>\n\n\u003Cp>commands it emits (v-command)\u003C/p>\n\n\u003Cp>state it reads (v-bind-text, v-show)\u003C/p>\n\n\u003Cp>initial scope (v-scope)\u003C/p>\n\n\u003Cp>There is no direct wiring between sectors. No component hierarchy. No global mutable object. All writes go through named commands; all reads come from reactive state.\u003C/p>\n\n\u003Ch2>\n  \u003Ca name=\"the-problem-crosssector-coordination-without-heavy-frameworks\" href=\"#the-problem-crosssector-coordination-without-heavy-frameworks\">\n  \u003C/a>\n  🛰️ The Problem: Cross‑Sector Coordination Without Heavy Frameworks\n\u003C/h2>\n\n\u003Cp>Astro excels at static delivery and isolated islands. The trouble begins when two isolated sections must coordinate.\u003C/p>\n\n\u003Ch3>\n  \u003Ca name=\"the-alpine-drift\" href=\"#the-alpine-drift\">\n  \u003C/a>\n  The Alpine Drift\n\u003C/h3>\n\n\u003Cp>Alpine is excellent for self‑contained widgets. But cross‑widget coordination collapses into $store: a global, mutable object with no named actions, no single home for side effects, and no deterministic write path.\u003C/p>\n\n\u003Ch3>\n  \u003Ca name=\"the-island-isolation-trap\" href=\"#the-island-isolation-trap\">\n  \u003C/a>\n  The Island Isolation Trap\n\u003C/h3>\n\n\u003Cp>Vue islands are intentionally isolated. Sharing state requires either: wrapping both islands in a parent island (destroying the isolation boundary), or wiring custom DOM events manually (scattering coordination logic everywhere).\u003C/p>\n\n\u003Cp>Both approaches reintroduce complexity that Astro was supposed to avoid.\u003C/p>\n\n\u003Ch3>\n  \u003Ca name=\"when-neither-fits\" href=\"#when-neither-fits\">\n  \u003C/a>\n  When neither fits\n\u003C/h3>\n\n\u003Cp>Developers end up writing ad‑hoc event buses, singletons, or brittle pub/sub modules. Exo replaces that with a clean, declarative, HTML‑first coordination model.\u003C/p>\n\n\u003Ch2>\n  \u003Ca name=\"what-it-looks-like\" href=\"#what-it-looks-like\">\n  \u003C/a>\n  🧩 What It Looks Like\n\u003C/h2>\n\n\u003Cp>Two sectors. Different DOM subtrees. Zero knowledge of each other.\u003Cbr>\n\u003C/p>\n\n\u003Cdiv class=\"highlight js-code-highlight\">\n\u003Cpre class=\"highlight html\">\u003Ccode>\u003Cspan class=\"c\">&lt;!-- Sector A: product list --&gt;\u003C/span>\n\u003Cspan class=\"nt\">&lt;button\u003C/span>\n  \u003Cspan class=\"na\">v-command=\u003C/span>\u003Cspan class=\"s\">\"cartAdd\"\u003C/span>\n  \u003Cspan class=\"na\">v-target=\u003C/span>\u003Cspan class=\"s\">'{\"id\": 1, \"name\": \"Coffee\", \"price\": 4}'\u003C/span>\n\u003Cspan class=\"nt\">&gt;\u003C/span>Add to cart\u003Cspan class=\"nt\">&lt;/button&gt;\u003C/span>\n\n\u003Cspan class=\"c\">&lt;!-- Sector B: cart summary --&gt;\u003C/span>\n\u003Cspan class=\"nt\">&lt;p\u003C/span> \u003Cspan class=\"na\">v-show=\u003C/span>\u003Cspan class=\"s\">\"empty\"\u003C/span>\u003Cspan class=\"nt\">&gt;\u003C/span>Your cart is empty.\u003Cspan class=\"nt\">&lt;/p&gt;\u003C/span>\n\n\u003Cspan class=\"nt\">&lt;span\u003C/span> \u003Cspan class=\"na\">v-bind-text=\u003C/span>\u003Cspan class=\"s\">\"count\"\u003C/span>\u003Cspan class=\"nt\">&gt;\u003C/span>0\u003Cspan class=\"nt\">&lt;/span&gt;\u003C/span> item(s) —\n$\u003Cspan class=\"nt\">&lt;span\u003C/span> \u003Cspan class=\"na\">v-bind-text=\u003C/span>\u003Cspan class=\"s\">\"total\"\u003C/span>\u003Cspan class=\"nt\">&gt;\u003C/span>0.00\u003Cspan class=\"nt\">&lt;/span&gt;\u003C/span>\n\u003C/code>\u003C/pre>\n\u003Cdiv class=\"highlight__panel js-actions-panel\">\n\u003Cdiv class=\"highlight__panel-action js-fullscreen-code-action\">\n    \u003Csvg xmlns=\"http://www.w3.org/2000/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-on\">\u003Ctitle>Enter fullscreen mode\u003C/title>\n    \u003Cpath d=\"M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z\">\u003C/path>\n\u003C/svg>\n\n    \u003Csvg xmlns=\"http://www.w3.org/2000/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-off\">\u003Ctitle>Exit fullscreen mode\u003C/title>\n    \u003Cpath d=\"M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z\">\u003C/path>\n\u003C/svg>\n\n\u003C/div>\n\u003C/div>\n\u003C/div>\n\n\n\n\n\n\u003Cdiv class=\"highlight js-code-highlight\">\n\u003Cpre class=\"highlight typescript\">\u003Ccode>\u003Cspan class=\"k\">import\u003C/span> \u003Cspan class=\"p\">{\u003C/span> \u003Cspan class=\"nx\">bus\u003C/span>\u003Cspan class=\"p\">,\u003C/span> \u003Cspan class=\"nx\">busState\u003C/span> \u003Cspan class=\"p\">}\u003C/span> \u003Cspan class=\"k\">from\u003C/span> \u003Cspan class=\"dl\">'\u003C/span>\u003Cspan class=\"s1\">./directives\u003C/span>\u003Cspan class=\"dl\">'\u003C/span>\u003Cspan class=\"p\">;\u003C/span>\n\n\u003Cspan class=\"nx\">busState\u003C/span>\u003Cspan class=\"p\">.\u003C/span>\u003Cspan class=\"nx\">count\u003C/span> \u003Cspan class=\"o\">=\u003C/span> \u003Cspan class=\"mi\">0\u003C/span>\u003Cspan class=\"p\">;\u003C/span>\n\u003Cspan class=\"nx\">busState\u003C/span>\u003Cspan class=\"p\">.\u003C/span>\u003Cspan class=\"nx\">total\u003C/span> \u003Cspan class=\"o\">=\u003C/span> \u003Cspan class=\"dl\">'\u003C/span>\u003Cspan class=\"s1\">0.00\u003C/span>\u003Cspan class=\"dl\">'\u003C/span>\u003Cspan class=\"p\">;\u003C/span>\n\u003Cspan class=\"nx\">busState\u003C/span>\u003Cspan class=\"p\">.\u003C/span>\u003Cspan class=\"nx\">empty\u003C/span> \u003Cspan class=\"o\">=\u003C/span> \u003Cspan class=\"kc\">true\u003C/span>\u003Cspan class=\"p\">;\u003C/span>\n\n\u003Cspan class=\"kd\">let\u003C/span> \u003Cspan class=\"nx\">runningTotal\u003C/span> \u003Cspan class=\"o\">=\u003C/span> \u003Cspan class=\"mi\">0\u003C/span>\u003Cspan class=\"p\">;\u003C/span>\n\n\u003Cspan class=\"nx\">bus\u003C/span>\u003Cspan class=\"p\">.\u003C/span>\u003Cspan class=\"nf\">register\u003C/span>\u003Cspan class=\"p\">(\u003C/span>\u003Cspan class=\"dl\">'\u003C/span>\u003Cspan class=\"s1\">cartAdd\u003C/span>\u003Cspan class=\"dl\">'\u003C/span>\u003Cspan class=\"p\">,\u003C/span> \u003Cspan class=\"p\">(\u003C/span>\u003Cspan class=\"nx\">cmd\u003C/span>\u003Cspan class=\"p\">)\u003C/span> \u003Cspan class=\"o\">=&gt;\u003C/span> \u003Cspan class=\"p\">{\u003C/span>\n  \u003Cspan class=\"nx\">busState\u003C/span>\u003Cspan class=\"p\">.\u003C/span>\u003Cspan class=\"nx\">count\u003C/span>  \u003Cspan class=\"o\">+=\u003C/span> \u003Cspan class=\"mi\">1\u003C/span>\u003Cspan class=\"p\">;\u003C/span>\n  \u003Cspan class=\"nx\">runningTotal\u003C/span>    \u003Cspan class=\"o\">+=\u003C/span> \u003Cspan class=\"nx\">cmd\u003C/span>\u003Cspan class=\"p\">.\u003C/span>\u003Cspan class=\"nx\">target\u003C/span>\u003Cspan class=\"p\">.\u003C/span>\u003Cspan class=\"nx\">price\u003C/span>\u003Cspan class=\"p\">;\u003C/span>\n  \u003Cspan class=\"nx\">busState\u003C/span>\u003Cspan class=\"p\">.\u003C/span>\u003Cspan class=\"nx\">total\u003C/span>   \u003Cspan class=\"o\">=\u003C/span> \u003Cspan class=\"nx\">runningTotal\u003C/span>\u003Cspan class=\"p\">.\u003C/span>\u003Cspan class=\"nf\">toFixed\u003C/span>\u003Cspan class=\"p\">(\u003C/span>\u003Cspan class=\"mi\">2\u003C/span>\u003Cspan class=\"p\">);\u003C/span>\n  \u003Cspan class=\"nx\">busState\u003C/span>\u003Cspan class=\"p\">.\u003C/span>\u003Cspan class=\"nx\">empty\u003C/span>   \u003Cspan class=\"o\">=\u003C/span> \u003Cspan class=\"kc\">false\u003C/span>\u003Cspan class=\"p\">;\u003C/span>\n\u003Cspan class=\"p\">});\u003C/span>\n\u003C/code>\u003C/pre>\n\u003Cdiv class=\"highlight__panel js-actions-panel\">\n\u003Cdiv class=\"highlight__panel-action js-fullscreen-code-action\">\n    \u003Csvg xmlns=\"http://www.w3.org/2000/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-on\">\u003Ctitle>Enter fullscreen mode\u003C/title>\n    \u003Cpath d=\"M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z\">\u003C/path>\n\u003C/svg>\n\n    \u003Csvg xmlns=\"http://www.w3.org/2000/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-off\">\u003Ctitle>Exit fullscreen mode\u003C/title>\n    \u003Cpath d=\"M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z\">\u003C/path>\n\u003C/svg>\n\n\u003C/div>\n\u003C/div>\n\u003C/div>\n\n\n\n\u003Cp>Sector A emits a named command.\u003Cbr>\nSector B reacts to state.\u003Cbr>\nExo is the only bridge.\u003C/p>\n\n\u003Ch2>\n  \u003Ca name=\"why-exo-works-the-cqrs-constraint\" href=\"#why-exo-works-the-cqrs-constraint\">\n  \u003C/a>\n  🧭 Why Exo Works: The CQRS Constraint\n\u003C/h2>\n\n\u003Cp>The core principle: read-only scopes and command-only writes.\u003C/p>\n\n\u003Cp>v-scope seeds reactive state but cannot be mutated directly.\u003C/p>\n\n\u003Cp>v-command is the only write path.\u003C/p>\n\n\u003Cp>Every mutation is a named command handled in one explicit place.\u003C/p>\n\n\u003Cp>Because Exo uses a real vapor‑chamber bus, you inherit its full middleware system:\u003C/p>\n\n\u003Cp>logging\u003C/p>\n\n\u003Cp>validation\u003C/p>\n\n\u003Cp>throttling\u003C/p>\n\n\u003Cp>undo callbacks\u003C/p>\n\n\u003Cp>cross‑tab sync\u003C/p>\n\n\u003Cp>WebSocket bridges\u003C/p>\n\n\u003Cp>Exo stays small because it delegates complexity to the bus.\u003C/p>\n\n\u003Cp>If you allow direct scope writes, the bus becomes decorative and the model collapses. CQRS is the mechanism that keeps the architecture coherent.\u003C/p>\n\n\u003Ch3>\n  \u003Ca name=\"why-not-alpine\" href=\"#why-not-alpine\">\n  \u003C/a>\n  🧱 Why Not Alpine\n\u003C/h3>\n\n\u003Cp>Alpine is perfect when:\u003C/p>\n\n\u003Cp>one widget owns its own state\u003C/p>\n\n\u003Cp>no other widget needs to read or write it\u003C/p>\n\n\u003Cp>The moment two sectors must coordinate, $store becomes a global mutable void. Exo keeps the ergonomics of HTML attributes but enforces a deterministic write path.\u003C/p>\n\n\u003Ch3>\n  \u003Ca name=\"why-not-vue-islands\" href=\"#why-not-vue-islands\">\n  \u003C/a>\n  🏝️ Why Not Vue Islands\n\u003C/h3>\n\n\u003Cp>Vue islands shine when the UI itself is complex.\u003Cbr>\nThey break down when coordination is the complex part.\u003C/p>\n\n\u003Cp>Sharing state between islands requires:\u003C/p>\n\n\u003Cp>a parent island (rebuilding a component tree), or\u003C/p>\n\n\u003Cp>custom DOM events (scattered coordination logic)\u003C/p>\n\n\u003Cp>Exo keeps HTML as HTML and centralizes coordination in one place.\u003C/p>\n\n\u003Ch2>\n  \u003Ca name=\"when-exo-stops-being-the-right-tool\" href=\"#when-exo-stops-being-the-right-tool\">\n  \u003C/a>\n  🧪 When Exo Stops Being the Right Tool\n\u003C/h2>\n\n\u003Cp>Exo is ideal for pages with:\u003C/p>\n\n\u003Cp>a bounded set of named user actions\u003C/p>\n\n\u003Cp>reactive sections listening to shared state\u003C/p>\n\n\u003Cp>no need for complex component lifecycles\u003C/p>\n\n\u003Cp>You’ve outgrown Exo when:\u003C/p>\n\n\u003Cp>handlers start dispatching other commands\u003C/p>\n\n\u003Cp>you need retry/circuit‑breaker middleware\u003C/p>\n\n\u003Cp>a single action must await network calls\u003C/p>\n\n\u003Cp>coordination logic becomes more complex than rendering\u003C/p>\n\n\u003Cp>At that point, work directly with vapor‑chamber or use a full state library like Pinia, Zustand, or XState.\u003C/p>\n\n\u003Ch2>\n  \u003Ca name=\"v01-specifications\" href=\"#v01-specifications\">\n  \u003C/a>\n  📦 v0.1 Specifications\n\u003C/h2>\n\n\u003Cp>Directives: v-scope, v-command, v-target / v-payload, v-bind-text, v-show\u003C/p>\n\n\u003Cp>Dot‑paths only\u003C/p>\n\n\u003Cp>No expression parser\u003C/p>\n\n\u003Cp>No v-if, v-for, v-model\u003C/p>\n\n\u003Cp>Click events only\u003C/p>\n\n\u003Cp>~150 lines of runtime\u003C/p>\n\n\u003Cp>~11 kB bundled including vapor‑chamber\u003C/p>\n\n\u003Cp>The npm package ships once two or three real projects validate the API without changes.\u003C/p>\n\n\u003Cp>🚀 Installation &amp; Launch Parameters\u003Cbr>\nv0.1 is a single-file drop‑in.\u003C/p>\n\n\u003Cp>bash\u003Cbr>\nnpm install vapor-chamber\u003Cbr>\nCopy src/directives/index.ts into your project.\u003C/p>\n\n\u003Cp>In your Astro page:\u003C/p>\n\n\u003Cp>ts\u003Cbr>\nimport { bus, busState } from '../directives/index.ts';\u003C/p>\n\n\u003Cp>busState.count = 0;\u003Cbr>\nbusState.empty = true;\u003C/p>\n\n\u003Cp>bus.register('cartAdd', (cmd) =&gt; {\u003Cbr>\n  busState.count += 1;\u003Cbr>\n  busState.empty  = false;\u003Cbr>\n});\u003Cbr>\nThe runtime binds all v-* attributes on DOMContentLoaded.\u003Cbr>\nNo configuration. No plugins.\u003C/p>\n\n\u003Cp>🧑‍🚀 Author\u003Cbr>\nLuciano Federico Pereira\u003C/p>\n\n","{% embed https://github.com/lucianofedericopereira/exo %}\n\nModern Astro pages often contain multiple interactive sections that must react to each other: a product matrix updating a cart summary, a filter panel driving a results grid, or any pair of isolated DOM sectors that need to stay in sync.\n\nMost solutions force you into heavy component runtimes or fragile global stores. Exo takes a different path: a declarative HTML directive layer on top of a real event bus, with no component tree, no shared mutable state, and no cross‑imports between sections.\n\nExo ships at ~11 kB bundled and loads exactly once, no matter how many sectors use it.\n\n## 🚀 What Exo Is\nExo is a thin directive layer that coordinates independent DOM sectors through a central vapor‑chamber bus.\n\nEach sector declares:\n\ncommands it emits (v-command)\n\nstate it reads (v-bind-text, v-show)\n\ninitial scope (v-scope)\n\nThere is no direct wiring between sectors. No component hierarchy. No global mutable object. All writes go through named commands; all reads come from reactive state.\n\n## 🛰️ The Problem: Cross‑Sector Coordination Without Heavy Frameworks\nAstro excels at static delivery and isolated islands. The trouble begins when two isolated sections must coordinate.\n\n### The Alpine Drift\nAlpine is excellent for self‑contained widgets. But cross‑widget coordination collapses into $store: a global, mutable object with no named actions, no single home for side effects, and no deterministic write path.\n\n### The Island Isolation Trap\nVue islands are intentionally isolated. Sharing state requires either: wrapping both islands in a parent island (destroying the isolation boundary), or wiring custom DOM events manually (scattering coordination logic everywhere).\n\nBoth approaches reintroduce complexity that Astro was supposed to avoid.\n\n### When neither fits\nDevelopers end up writing ad‑hoc event buses, singletons, or brittle pub/sub modules. Exo replaces that with a clean, declarative, HTML‑first coordination model.\n\n## 🧩 What It Looks Like\nTwo sectors. Different DOM subtrees. Zero knowledge of each other.\n\n```html\n\u003C!-- Sector A: product list -->\n\u003Cbutton\n  v-command=\"cartAdd\"\n  v-target='{\"id\": 1, \"name\": \"Coffee\", \"price\": 4}'\n>Add to cart\u003C/button>\n\n\u003C!-- Sector B: cart summary -->\n\u003Cp v-show=\"empty\">Your cart is empty.\u003C/p>\n\n\u003Cspan v-bind-text=\"count\">0\u003C/span> item(s) —\n$\u003Cspan v-bind-text=\"total\">0.00\u003C/span>\n```\n\n\n```ts\nimport { bus, busState } from './directives';\n\nbusState.count = 0;\nbusState.total = '0.00';\nbusState.empty = true;\n\nlet runningTotal = 0;\n\nbus.register('cartAdd', (cmd) => {\n  busState.count  += 1;\n  runningTotal    += cmd.target.price;\n  busState.total   = runningTotal.toFixed(2);\n  busState.empty   = false;\n});\n```\n\nSector A emits a named command.\nSector B reacts to state.\nExo is the only bridge.\n\n## 🧭 Why Exo Works: The CQRS Constraint\nThe core principle: read-only scopes and command-only writes.\n\nv-scope seeds reactive state but cannot be mutated directly.\n\nv-command is the only write path.\n\nEvery mutation is a named command handled in one explicit place.\n\nBecause Exo uses a real vapor‑chamber bus, you inherit its full middleware system:\n\nlogging\n\nvalidation\n\nthrottling\n\nundo callbacks\n\ncross‑tab sync\n\nWebSocket bridges\n\nExo stays small because it delegates complexity to the bus.\n\nIf you allow direct scope writes, the bus becomes decorative and the model collapses. CQRS is the mechanism that keeps the architecture coherent.\n\n### 🧱 Why Not Alpine\nAlpine is perfect when:\n\none widget owns its own state\n\nno other widget needs to read or write it\n\nThe moment two sectors must coordinate, $store becomes a global mutable void. Exo keeps the ergonomics of HTML attributes but enforces a deterministic write path.\n\n### 🏝️ Why Not Vue Islands\nVue islands shine when the UI itself is complex.\nThey break down when coordination is the complex part.\n\nSharing state between islands requires:\n\na parent island (rebuilding a component tree), or\n\ncustom DOM events (scattered coordination logic)\n\nExo keeps HTML as HTML and centralizes coordination in one place.\n\n## 🧪 When Exo Stops Being the Right Tool\nExo is ideal for pages with:\n\na bounded set of named user actions\n\nreactive sections listening to shared state\n\nno need for complex component lifecycles\n\nYou’ve outgrown Exo when:\n\nhandlers start dispatching other commands\n\nyou need retry/circuit‑breaker middleware\n\na single action must await network calls\n\ncoordination logic becomes more complex than rendering\n\nAt that point, work directly with vapor‑chamber or use a full state library like Pinia, Zustand, or XState.\n\n## 📦 v0.1 Specifications\nDirectives: v-scope, v-command, v-target / v-payload, v-bind-text, v-show\n\nDot‑paths only\n\nNo expression parser\n\nNo v-if, v-for, v-model\n\nClick events only\n\n~150 lines of runtime\n\n~11 kB bundled including vapor‑chamber\n\nThe npm package ships once two or three real projects validate the API without changes.\n\n🚀 Installation & Launch Parameters\nv0.1 is a single-file drop‑in.\n\nbash\nnpm install vapor-chamber\nCopy src/directives/index.ts into your project.\n\nIn your Astro page:\n\nts\nimport { bus, busState } from '../directives/index.ts';\n\nbusState.count = 0;\nbusState.empty = true;\n\nbus.register('cartAdd', (cmd) => {\n  busState.count += 1;\n  busState.empty  = false;\n});\nThe runtime binds all v-* attributes on DOMContentLoaded.\nNo configuration. No plugins.\n\n🧑‍🚀 Author\nLuciano Federico Pereira",{"name":29,"username":30,"twitter_username":13,"github_username":30,"user_id":31,"website_url":32,"profile_image":33,"profile_image_90":34},"Luciano Federico Pereira","lucianofedericopereira",3727055,"https://luciano-pereira.pages.dev/","https://media2.dev.to/dynamic/image/width=640,height=640,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3727055%2Fc21728ea-2492-4d86-84dc-40f44cafe8ec.png","https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3727055%2Fc21728ea-2492-4d86-84dc-40f44cafe8ec.png",1780059467458]