{"id":20573405,"url":"https://github.com/israel-nogueira/night-proxy","last_synced_at":"2026-06-24T06:34:50.012Z","repository":{"id":92819211,"uuid":"226431441","full_name":"israel-nogueira/night-proxy","owner":"israel-nogueira","description":"O night-proxy simplifica a aplicação de templates com o Proxy Recursivo, uma técnica inteligente que utiliza proxies do JavaScript para controle total sobre operações em objetos de modelo, oferecendo resultados impressionantes. Experimente e descubra uma nova abordagem intuitiva e poderosa para lidar com templates.","archived":false,"fork":false,"pushed_at":"2026-04-26T05:32:13.000Z","size":481,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"no-reflow","last_synced_at":"2026-04-26T07:22:34.553Z","etag":null,"topics":["mustache","mustache-js","mustache-templating","proxy","proxy-pattern","template","template-engine"],"latest_commit_sha":null,"homepage":"https://israel-nogueira.github.io/night-proxy","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/israel-nogueira.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2019-12-07T00:09:14.000Z","updated_at":"2026-04-26T05:32:18.000Z","dependencies_parsed_at":"2024-02-11T15:47:58.407Z","dependency_job_id":null,"html_url":"https://github.com/israel-nogueira/night-proxy","commit_stats":null,"previous_names":["israel-nogueira/proxy-update","israel-nogueira/night-proxy"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/israel-nogueira/night-proxy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/israel-nogueira%2Fnight-proxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/israel-nogueira%2Fnight-proxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/israel-nogueira%2Fnight-proxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/israel-nogueira%2Fnight-proxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/israel-nogueira","download_url":"https://codeload.github.com/israel-nogueira/night-proxy/tar.gz/refs/heads/no-reflow","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/israel-nogueira%2Fnight-proxy/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34720920,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-24T02:00:07.484Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["mustache","mustache-js","mustache-templating","proxy","proxy-pattern","template","template-engine"],"created_at":"2024-11-16T05:27:34.677Z","updated_at":"2026-06-24T06:34:49.981Z","avatar_url":"https://github.com/israel-nogueira.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n\n\n\n\n\n\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://raw.githubusercontent.com/israel-nogueira/night-proxy/master/assets/img/avatar.png\" width=\"650\"/\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/version-2.5.0-7c3aed?style=flat-square\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/zero%20dependencies-✓-22c55e?style=flat-square\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/no%20build%20tools-✓-06b6d4?style=flat-square\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/license-MIT-f59e0b?style=flat-square\" /\u003e\n\u003c/p\u003e\n\n\n# Feito para quem constrói, não para quem quer aprender um framework.\n\nSua página PHP/HTML está pronta! E agora você precisa que **uma lista atualize sozinha**, que **um contador mude em tempo real**.\u003cbr\u003e\nOu que **um formulário reaja ao que o usuário digita** _(tudo isso sem recarregar a página)_.\n\nNão temos nada contra os grandes frameworks, eles existem por boas razões, resolvem problemas reais e sustentam aplicações enormes. Mas existe um espaço enorme entre \"página HTML com PHP\" e \"SPA completa com React\".\n\n\n## É exatamente esse espaço que o night-proxy.js ocupa.\n\nA ideia é simples: um arquivo, uma tag script, e sua página passa a ser reativa. Sem npm. Sem build. Sem opinião sobre a sua stack. \n\nVocê escreve os atributos no HTML, popula os dados via JavaScript, e o DOM se atualiza sozinho de forma granular, eficiente, sem re-renders desnecessários com uma única linha:\n\n```html\n\u003cscript src=\"./assets/js/night-proxy.js\"\u003e\u003c/script\u003e\n```\n\nOu via CDN:\n```html\n\u003cscript src=\"https://cdn.jsdelivr.net/gh/israel-nogueira/night-proxy@no-reflow/assets/js/night-proxy.js\"\u003e\u003c/script\u003e\n```\n\n\nSem npm. Sem build. Sem configuração. Você escreve HTML normal, adiciona alguns atributos, e a página começa a reagir sozinha às mudanças de dados. Funciona em qualquer projeto, PHP, HTML puro, WordPress, Laravel, o que for.\n\n---\n\u003e ✅ Se você já sabe fazer uma página em HTML, você já sabe usar night-proxy.js.\n---\n\n## Para quem quer saber como funciona de verdade\n\nnight-proxy.js implementa **reatividade declarativa baseada em Proxy Recursivo** com dependency tracking granular, sem virtual DOM, sem dirty checking, sem re-renders desnecessários.\n\n### 🔥 O que isso significa na prática\n\nA maioria das soluções \"leves\" de reatividade usa uma de duas abordagens ruins: re-renderiza o componente inteiro a cada mudança, ou percorre o DOM em busca de diferenças (dirty checking). Ambas escalam mal.\n\nnight-proxy.js faz diferente. Durante o render de cada nó, qualquer leitura de propriedade registra automaticamente uma dependência via `WeakMap`. Quando um valor muda, **apenas os nós que dependem daquela propriedade específica são atualizados!** cirurgicamente, sem tocar no resto.\n\n### 🛡️ Garantias de performance\n\n- **1 dependente** → update síncrono imediato, sem microtask, sem overhead de scheduler\n- **N dependentes** → batching via `Promise.resolve()`, agrupa mudanças simultâneas em um único ciclo\n- **Mudanças estruturais** (push/splice/substituição de lista) → re-render do `x-for` via microtask\n\nEm testes com 5.000 itens renderizados, um update pontual (`lista[2500].nome = 'x'`) executa em menos de 1 frame (\u003c 16ms), porque toca **exatamente 1 nó**, independente do tamanho da lista.\n\n### ⚙️ Diferenciais técnicos\n\n- **Proxy Recursivo**, qualquer nível de aninhamento é rastreado automaticamente, sem necessidade de declarar observers manualmente\n- **Effects com auto-cleanup**, cada nó reativo tem seu próprio Effect que se desregistra e re-registra nas dependências a cada run, evitando memory leaks e renders obsoletos\n- **Lifecycle completo**, `$beforeRender`, `$afterRender`, `$beforeDestroy`, `$afterDestroy` com suporte a eventos DOM nativos (`before-render`, `after-destroy`...)\n- **Destroy real**, limpa effects, event listeners, watchers e store em cascata; essencial para SPAs que trocam conteúdo via fetch\n- **44 testes automatizados**, cobrindo reatividade, granularidade, stress (500 / 1k / 5k itens) e ciclo de vida completo, todos passando\n\n### 🤓 Para quem é indicado\n\nProjetos que precisam de reatividade pontual sem o custo de adotar um framework completo.\u003cbr\u003e\nAplicações PHP, páginas com conteúdo dinâmico via fetch, dashboards simples, formulários reativos \u003cbr\u003e\ne qualquer cenário onde **React ou Vue seria complexidade desnecessária**.\n\n**Um arquivo. Sem dependências. Sem opinião sobre sua stack.**\n\n---\n\n## 🛠️ Instalação\n\nUm único arquivo. Inclua no `\u003chead\u003e`:\n\n```html\n\u003cscript src=\"./assets/js/night-proxy.js\"\u003e\u003c/script\u003e\n```\n\nNenhuma dependência externa necessária.\n\n---\n\n## Conceito básico\n\nVocê define um container reativo no HTML com `x-data` e inicializa o proxy.  \nQualquer alteração em `proxy.template` atualiza o DOM automaticamente.\n\n```html\n\u003cdiv x-data=\"produto\"\u003e\n    \u003ch1 x-bind=\"nome\"\u003e\u003c/h1\u003e\n    \u003cp x-bind=\"Preço: R$ {preco}\"\u003e\u003c/p\u003e\n\u003c/div\u003e\n\n\u003cscript\u003e\n    proxy.initProxy();\n    proxy.template.produto.nome  = \"Coxinha Supreme\";\n    proxy.template.produto.preco = 9.90;\n\u003c/script\u003e\n```\n\n---\n\n## Diretivas\n\n### `x-data=\"chave\"`\n\nDefine o container reativo. As expressões internas não precisam de prefixo.\n\n```html\n\u003cdiv x-data=\"produto\"\u003e\n    \u003ch1 x-bind=\"nome\"\u003e\u003c/h1\u003e\n\u003c/div\u003e\n```\n\n```javascript\nproxy.initProxy();\nproxy.template.produto.nome = \"Coxinha Supreme\";\n```\n\n---\n\n### `x-bind=\"expr\"`\n\nRenderiza um valor reativo como texto. Suporta expressão direta ou interpolação com `{}`.\n\n```html\n\u003cdiv x-data=\"produto\"\u003e\n    \u003ch1 x-bind=\"nome\"\u003e\u003c/h1\u003e\n    \u003cp x-bind=\"Preço: R$ {preco}, Qtd: {qty}\"\u003e\u003c/p\u003e\n\u003c/div\u003e\n\n\u003cscript\u003e\n    proxy.initProxy();\n    proxy.template.produto.nome  = \"Coxinha Supreme\";\n    proxy.template.produto.preco = 9.90;\n    proxy.template.produto.qty   = 3;\n\n    // Qualquer alteração posterior atualiza o DOM automaticamente\n    proxy.template.produto.nome = \"Novo nome\";\n\u003c/script\u003e\n```\n\n---\n\n### `x-if=\"expr\"`\n\nOculta o elemento via `display: none` quando a expressão for falsa. O elemento permanece no DOM.\n\n```html\n\u003cp x-if=\"ativo\"\u003eProduto disponível\u003c/p\u003e\n\u003cp x-if=\"!ativo\"\u003eFora de estoque\u003c/p\u003e\n```\n\n```javascript\nproxy.initProxy();\nproxy.template.produto.ativo = true;\n\n// Alternar visibilidade reativamente\nproxy.template.produto.ativo = false;\n```\n\n---\n\n### `x-for=\"alias in lista\"`\n\nLoop reativo e aninhável. Suporta duas sintaxes para declarar o índice com nome:\n\n```html\n\u003c!-- sem índice nomeado, usa $i / $index como fallback --\u003e\n\u003cdiv x-for=\"item in itens\"\u003e\n\n\u003c!-- índice nomeado, sintaxe com vírgula --\u003e\n\u003cdiv x-for=\"item, k in itens\"\u003e\n\n\u003c!-- índice nomeado, sintaxe com as (estilo SQL) --\u003e\n\u003cdiv x-for=\"item in itens as k\"\u003e\n```\n\nExemplo com aninhamento e índices nomeados:\n\n```html\n\u003cdiv x-data=\"pedido\"\u003e\n    \u003cdiv x-for=\"item, k in itens\"\u003e\n        \u003cstrong x-bind=\"{item.nome}\"\u003e\u003c/strong\u003e\n        \u003cspan x-bind=\"Item {k}\"\u003e\u003c/span\u003e\n\n        \u003cdiv x-for=\"sub, b in item.subitens\"\u003e\n            \u003cspan x-bind=\"{sub.label}\"\u003e\u003c/span\u003e\n            \u003csmall x-bind=\"Item {k} › Sub {b}\"\u003e\u003c/small\u003e\n        \u003c/div\u003e\n    \u003c/div\u003e\n\u003c/div\u003e\n```\n\n```javascript\nproxy.initProxy();\nproxy.template.pedido.itens = [\n    {\n        nome: \"Salgados\",\n        subitens: [{ label: \"Coxinha\" }, { label: \"Pastel\" }]\n    },\n    {\n        nome: \"Bebidas\",\n        subitens: [{ label: \"Suco\" }, { label: \"Água\" }]\n    }\n];\n\n// Adicionar item, re-render automático do x-for\nproxy.template.pedido.itens.push({ nome: \"Doces\", subitens: [] });\n\n// Update cirúrgico, toca só o nó do item[0], não re-renderiza a lista\nproxy.template.pedido.itens[0].nome = \"Salgadinhos\";\n```\n\n---\n\n### `x-key=\"expr\"`\n\nChave única para otimização do `x-for`. O proxy reutiliza nós DOM existentes ao reordenar ou atualizar a lista. Sem `x-key`, um id interno é gerado automaticamente.\n\n```html\n\u003cdiv x-for=\"item in lista\" x-key=\"item.id\"\u003e\n    \u003cspan x-bind=\"{item.nome}\"\u003e\u003c/span\u003e\n\u003c/div\u003e\n```\n\n```javascript\nproxy.initProxy();\nproxy.template.catalogo.lista = [\n    { id: 1, nome: \"Item A\" },\n    { id: 2, nome: \"Item B\" },\n    { id: 3, nome: \"Item C\" },\n];\n\n// Com x-key, ao reordenar a lista o proxy reutiliza os nós DOM existentes\n// em vez de recriar tudo, mais eficiente e preserva estado de inputs internos\nproxy.template.catalogo.lista = [\n    { id: 3, nome: \"Item C\" },\n    { id: 1, nome: \"Item A\" },\n    { id: 2, nome: \"Item B\" },\n];\n```\n\n---\n\n### `x-model=\"caminho\"`\n\nTwo-way binding com inputs. Suporta `text`, `checkbox`, `radio`, `select` e caminhos profundos.\n\n```html\n\u003cinput type=\"text\"     x-model=\"produto.nome\"\u003e\n\u003cinput type=\"checkbox\" x-model=\"produto.ativo\"\u003e\n\u003cinput type=\"radio\"    x-model=\"produto.cor\" value=\"azul\"\u003e Azul\n\u003cinput type=\"radio\"    x-model=\"produto.cor\" value=\"verde\"\u003e Verde\n\u003cselect x-model=\"produto.categoria\"\u003e\n    \u003coption value=\"a\"\u003eCategoria A\u003c/option\u003e\n    \u003coption value=\"b\"\u003eCategoria B\u003c/option\u003e\n\u003c/select\u003e\n\n\u003c!-- Caminho profundo --\u003e\n\u003cinput type=\"text\" x-model=\"produto.lista[1].titulo\"\u003e\n```\n\n```javascript\nproxy.initProxy();\n\n// Valor inicial, já aparece nos inputs\nproxy.template.produto.nome      = \"Coxinha\";\nproxy.template.produto.ativo     = true;\nproxy.template.produto.cor       = \"azul\";\nproxy.template.produto.categoria = \"a\";\n\n// Alterar via JS também atualiza os inputs (two-way)\nproxy.template.produto.cor = \"verde\";\n\n// Alterar via input também atualiza o proxy (two-way)\n//, o usuário digita no campo e proxy.template.produto.nome é atualizado automaticamente\n```\n\n---\n\n### `x-on:evento=\"expr\"`\n\nEvent listener declarativo com acesso ao escopo do loop e às magic variables.\n\n```html\n\u003cdiv x-data=\"lista\"\u003e\n    \u003cdiv x-for=\"item, k in itens\"\u003e\n        \u003cspan x-bind=\"{item.nome}\"\u003e\u003c/span\u003e\n        \u003cbutton x-on:click=\"remover(k)\"\u003e✕\u003c/button\u003e\n        \u003cbutton x-on:click=\"$emit('selecionou', { index: k })\"\u003eSelecionar\u003c/button\u003e\n        \u003cbutton x-on:click=\"console.log(event.target)\"\u003eLog\u003c/button\u003e\n    \u003c/div\u003e\n\u003c/div\u003e\n```\n\n```javascript\nproxy.initProxy();\n\nproxy.template.lista.itens = [\n    { nome: \"Item A\" },\n    { nome: \"Item B\" },\n];\n\n// Função registrada no escopo, disponível no x-on sem depender de globais\nproxy.template.lista.remover = function(idx) {\n    proxy.template.lista.itens.splice(idx, 1);\n};\n\n// Ouvindo o evento emitido pelo $emit dentro do template\ndocument.querySelector('[x-data=\"lista\"]').addEventListener('selecionou', e =\u003e {\n    console.log('índice selecionado:', e.detail.index);\n});\n```\n\n---\n\n### `x-ref=\"nome\"`\n\nRegistra uma referência ao elemento, acessível via `$ref.nome` em qualquer `x-on` do mesmo componente.\n\n```html\n\u003cdiv x-data=\"busca\"\u003e\n    \u003cinput x-ref=\"campo\" type=\"text\"\u003e\n    \u003cbutton x-on:click=\"console.log($ref.campo.value)\"\u003eBuscar\u003c/button\u003e\n\u003c/div\u003e\n```\n\n```javascript\nproxy.initProxy();\n\n// $ref é resolvido dentro do x-on, não precisa de querySelector manual\n// O acesso ao DOM fica encapsulado no próprio componente\n```\n\n---\n\n## Magic Variables\n\nDisponíveis dentro de qualquer expressão `x-on`.\n\n### `$root`\nElemento DOM do container `x-data`. Útil para manipulação direta ou para saber em qual componente o evento ocorreu.\n\n```html\n\u003cbutton x-on:click=\"$root.classList.toggle('ativo')\"\u003eToggle classe\u003c/button\u003e\n```\n\n```javascript\nproxy.initProxy();\n\n// $root é o próprio elemento [x-data=\"...\"]\n// Equivale a document.querySelector('[x-data=\"meu-componente\"]')\n// mas sem precisar de querySelector, já está no escopo do x-on\n```\n\n---\n\n### `$ref`\nAcessa elementos marcados com `x-ref` dentro do mesmo componente.\n\n```html\n\u003cinput x-ref=\"campo\" type=\"text\"\u003e\n\u003cbutton x-on:click=\"console.log($ref.campo.value)\"\u003eBuscar\u003c/button\u003e\n```\n\n---\n\n### `$emit`\nDispara um `CustomEvent` no `$root`. Ideal para comunicar ações do template para o JS externo.\n\n```html\n\u003c!-- dentro do template, ação intencional --\u003e\n\u003cbutton x-on:click=\"$emit('item-selecionado', { id: item.id })\"\u003eSelecionar\u003c/button\u003e\n```\n\n```javascript\n// fora, no JS, quem quiser ouvir\ndocument.querySelector('[x-data=\"lista\"]').addEventListener('item-selecionado', e =\u003e {\n    console.log(e.detail.id);\n});\n```\n\n---\n\n### `$i` / `$index`\nÍndice do item atual no loop. Disponíveis quando nenhum alias de índice foi declarado. Quando um alias é declarado (`item, k in lista`), use o alias, `$i` e `$index` ficam como fallback.\n\n```html\n\u003c!-- sem alias, usa $i / $index --\u003e\n\u003cdiv x-for=\"item in itens\"\u003e\n    \u003cspan x-bind=\"Item {$index}: {item.nome}\"\u003e\u003c/span\u003e\n    \u003cbutton x-on:click=\"remover($i)\"\u003e✕\u003c/button\u003e\n\u003c/div\u003e\n```\n\n```javascript\nproxy.initProxy();\n\nproxy.template.lista.itens = [\n    { nome: \"Item A\" },\n    { nome: \"Item B\" },\n];\n\nproxy.template.lista.remover = function(idx) {\n    proxy.template.lista.itens.splice(idx, 1);\n};\n```\n\n---\n\n### `$this`\nObjeto rico com informações do item atual no loop.\n\n| Propriedade | Descrição |\n|---|---|\n| `$this.index` | Índice do item no loop |\n| `$this.dom` | Elemento DOM do item |\n| `$this.data` | Objeto de dados do item |\n| `$this.parent` | `$this` do loop pai (encadeável) |\n\n```html\n\u003cdiv x-for=\"item, k in itens\"\u003e\n    \u003cdiv x-for=\"sub, b in item.subitens\"\u003e\n        \u003cbutton x-on:click=\"console.log($this.index, $this.parent.index)\"\u003e\n            Log índices\n        \u003c/button\u003e\n    \u003c/div\u003e\n\u003c/div\u003e\n```\n\nEm loops profundamente aninhados, `$this.parent` é especialmente útil via JS:\n\n```javascript\ndocument.querySelector('[x-data=\"lista\"]').addEventListener('meu-evento', e =\u003e {\n    const ctx = e.target.__nightThis;\n    console.log(ctx.index, ctx.parent.index, ctx.parent.parent.index);\n});\n```\n\n---\n\n### `event`\nEvento DOM nativo, sempre disponível em `x-on`.\n\n```html\n\u003cbutton x-on:click=\"console.log(event.target)\"\u003eLog\u003c/button\u003e\n```\n\n---\n\n## Lifecycle Hooks\n\nExecutam antes e depois de cada ciclo de render do componente. Disponíveis via `proxy.template` ou `addEventListener` no container, ambas as formas funcionam simultaneamente e disparam em todo update, incluindo o render inicial.\n\n```javascript\n// via proxy.template\nproxy.template.produto.$beforeRender = function(el) {\n    console.log('vai renderizar', el);\n};\n\nproxy.template.produto.$afterRender = function(el) {\n    console.log('renderizou', el);\n};\n```\n\n```javascript\n// via addEventListener\nconst el = document.querySelector('[x-data=\"produto\"]');\n\nel.addEventListener('before-render', () =\u003e console.log('antes'));\nel.addEventListener('after-render',  () =\u003e console.log('depois'));\n```\n\n---\n\n---\n\n## Destroy\n\nLimpa completamente um componente antes de recarregar via fetch ou ao desmontar a página. O destroy remove todos os effects reativos, event listeners declarados com `x-on`, watchers registrados e a entrada no store interno.\n\n### Destruir um componente específico\n\n```javascript\n// via método direto\nproxy.destroy('produto');\n\n// via shortcut no template\nproxy.template.produto.destroy();\n```\n\n### Destruir tudo\n\n```javascript\nproxy.destroy();\n```\n\n### Hooks de destroy\n\nExecutam antes e depois do destroy. Disponíveis via `proxy.template` ou `addEventListener`, ambas as formas funcionam simultaneamente.\n\n```javascript\n// via proxy.template\nproxy.template.produto.$beforeDestroy = function(el) {\n    console.log('vai destruir', el);\n};\n\nproxy.template.produto.$afterDestroy = function(el) {\n    console.log('destruído', el);\n};\n```\n\n```javascript\n// via addEventListener\nconst el = document.querySelector('[x-data=\"produto\"]');\n\nel.addEventListener('before-destroy', () =\u003e console.log('antes do destroy'));\nel.addEventListener('after-destroy',  () =\u003e console.log('depois do destroy'));\n```\n\n### Padrão com fetch\n\nO destroy é o ponto de entrada natural antes de qualquer recarga de conteúdo dinâmico:\n\n```javascript\nasync function carregarProduto(id) {\n    // 1. Mata o componente atual\n    proxy.destroy('produto');\n\n    // 2. Busca novo conteúdo\n    const res  = await fetch(`/produto/${id}`);\n    const html = await res.text();\n\n    // 3. Injeta o HTML\n    document.querySelector('#container').innerHTML = html;\n\n    // 4. Reinicializa\n    proxy.initProxy();\n    proxy.template.produto.nome = \"Novo produto\";\n}\n```\n\n## Watchers\n\nObserva qualquer caminho do store e executa um callback quando o valor muda. Retorna uma função de cancelamento.\n\n```javascript\nconst unsubscribe = proxy.on('produto.preco', (novoValor, valorAnterior) =\u003e {\n    console.log(`preço: ${valorAnterior} → ${novoValor}`);\n});\n\n// Cancelar\nunsubscribe();\n```\n\nFunciona com caminhos profundos:\n\n```javascript\nproxy.on('pedido.itens.0.nome', (novo, velho) =\u003e {\n    console.log('nome do primeiro item mudou');\n});\n```\n\n---\n\n## Inicialização\n\n```javascript\nproxy.initProxy();\n```\n\nChame após o DOM estar pronto. Em seguida, popule os dados via `proxy.template`:\n\n```javascript\nproxy.initProxy();\n\nproxy.template.produto.nome  = \"Coxinha Supreme\";\nproxy.template.produto.ativo = true;\nproxy.template.produto.preco = 9.90;\nproxy.template.produto.lista = [\n    { titulo: \"Com catupiry\", subitens: [{ label: \"P\" }, { label: \"G\" }] },\n    { titulo: \"Com bacon\",    subitens: [{ label: \"Único\" }] },\n];\n```\n\n---\n\n## Atualizações reativas\n\n```javascript\n// Valor simples, síncrono, atualiza o DOM na hora\nproxy.template.produto.nome = \"Novo nome\";\n\n// Item específico da lista, cirúrgico, toca só o nó do item\nproxy.template.produto.lista[0].titulo = \"Titulo atualizado\";\n\n// Substituir lista inteira\nproxy.template.produto.lista = [{ titulo: \"Item novo\", subitens: [] }];\n\n// Adicionar item\nproxy.template.produto.lista.push({ titulo: \"Mais um\", subitens: [] });\n\n// Remover item\nproxy.template.produto.lista.splice(2, 1);\n```\n\n---\n\n## Funções no escopo\n\nRegistre funções diretamente no `proxy.template` para usá-las nos eventos sem depender de globais.\n\n```html\n\u003cdiv x-data=\"lista\"\u003e\n    \u003cdiv x-for=\"item, k in itens\"\u003e\n        \u003cspan x-bind=\"{item.nome}\"\u003e\u003c/span\u003e\n        \u003cbutton x-on:click=\"remover(k)\"\u003e✕\u003c/button\u003e\n    \u003c/div\u003e\n\u003c/div\u003e\n\n\u003cscript\u003e\n    proxy.initProxy();\n\n    proxy.template.lista.itens = [\n        { nome: \"Item A\" },\n        { nome: \"Item B\" },\n    ];\n\n    proxy.template.lista.remover = function(idx) {\n        proxy.template.lista.itens.splice(idx, 1);\n    };\n\u003c/\u003e\n```\n\n---\n\n## Exemplo completo\n\n```html\n\u003cinput type=\"text\"     x-model=\"pedido.cliente\" placeholder=\"Nome do cliente\"\u003e\n\u003cinput type=\"checkbox\" x-model=\"pedido.confirmado\"\u003e Confirmado\n\n\u003cdiv x-data=\"pedido\"\u003e\n    \u003ch2 x-bind=\"cliente\"\u003e\u003c/h2\u003e\n    \u003cp x-if=\"confirmado\"\u003e✅ Pedido confirmado\u003c/p\u003e\n\n    \u003cdiv x-for=\"item, k in itens\"\u003e\n        \u003cstrong x-bind=\"{item.nome}\"\u003e\u003c/strong\u003e\n        \u003cspan x-bind=\"Qtd: {item.qty}\"\u003e\u003c/span\u003e\n        \u003cbutton x-on:click=\"remover(k)\"\u003e✕\u003c/button\u003e\n        \u003cbutton x-on:click=\"$emit('selecionou', { index: k, nome: item.nome })\"\u003eSelecionar\u003c/button\u003e\n    \u003c/div\u003e\n\u003c/div\u003e\n\n\u003cscript\u003e\n    proxy.initProxy();\n\n    proxy.template.pedido.cliente    = \"João Silva\";\n    proxy.template.pedido.confirmado = true;\n    proxy.template.pedido.itens      = [\n        { nome: \"Coxinha\",  qty: 3 },\n        { nome: \"Pastel\",   qty: 2 },\n        { nome: \"Salgado\",  qty: 5 },\n    ];\n\n    proxy.template.pedido.remover = function(idx) {\n        proxy.template.pedido.itens.splice(idx, 1);\n    };\n\n    proxy.template.pedido.$afterRender = function() {\n        console.log('pedido renderizado');\n    };\n\n    document.querySelector('[x-data=\"pedido\"]').addEventListener('selecionou', e =\u003e {\n        console.log('selecionado:', e.detail.nome);\n    });\n\n    proxy.on('pedido.cliente', (novo, velho) =\u003e {\n        console.log(`cliente: ${velho} → ${novo}`);\n    });\n\u003c/script\u003e\n```\n\n---\n\n## Referência rápida\n\n### Diretivas\n\n| Diretiva | Descrição |\n|---|---|\n| `x-data=\"chave\"` | Container reativo, escopo sem prefixo |\n| `x-bind=\"expr\"` | Renderiza valor ou interpolação `{var}` como texto |\n| `x-if=\"expr\"` | Condicional, oculta via `display: none` |\n| `x-for=\"alias in lista\"` | Loop reativo (aninhável) |\n| `x-for=\"alias, k in lista\"` | Loop com índice nomeado |\n| `x-for=\"alias in lista as k\"` | Loop com índice nomeado (sintaxe alternativa) |\n| `x-key=\"expr\"` | Chave única para reuso de nós no `x-for` |\n| `x-model=\"caminho\"` | Two-way binding com inputs |\n| `x-on:evento=\"expr\"` | Event listener com escopo do loop |\n| `x-ref=\"nome\"` | Referência ao elemento via `$ref.nome` |\n\n### Magic Variables (em `x-on`)\n\n| Variable | Descrição |\n|---|---|\n| `$root` | Elemento DOM do container `x-data` |\n| `$ref.nome` | Elemento marcado com `x-ref=\"nome\"` |\n| `$emit(nome, detalhe)` | Dispara `CustomEvent` no `$root` |\n| `$i` / `$index` | Índice do item (fallback sem alias declarado) |\n| `$this.index` | Índice do item atual |\n| `$this.dom` | Elemento DOM do item atual |\n| `$this.data` | Objeto de dados do item atual |\n| `$this.parent` | `$this` do loop pai (encadeável) |\n| `event` | Evento DOM nativo |\n\n### API JavaScript\n\n| Método | Descrição |\n|---|---|\n| `proxy.initProxy()` | Inicializa o proxy |\n| `proxy.destroy('key')` | Destrói um componente específico |\n| `proxy.destroy()` | Destrói todos os componentes |\n| `proxy.template.key.destroy()` | Shortcut para destruir um componente |\n| `proxy.on(path, fn)` | Observa um caminho, retorna `unsubscribe()` |\n| `proxy.template.key.$beforeRender = fn` | Hook antes do render |\n| `proxy.template.key.$afterRender = fn` | Hook após o render |\n| `proxy.template.key.$beforeDestroy = fn` | Hook antes do destroy |\n| `proxy.template.key.$afterDestroy = fn` | Hook após o destroy |\n\n---\n\n## Como funciona internamente\n\nO proxy usa **dependency tracking** granular: durante o render de cada nó, qualquer leitura de propriedade registra uma dependência. Quando um valor muda:\n\n- **1 dependente** → render síncrono imediato, sem microtask\n- **Múltiplos dependentes** → batching via microtask (`Promise.resolve`)\n- **Mudanças estruturais** (push/splice/substituição de lista) → re-render do `x-for` via microtask\n\nIsso garante que `lista[250].nome = 'x'` toque **apenas o nó do item 250**, independente do tamanho da lista.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fisrael-nogueira%2Fnight-proxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fisrael-nogueira%2Fnight-proxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fisrael-nogueira%2Fnight-proxy/lists"}