Repository navigation
Debug pt BR
🌐 Esta página em: English · Português
O eQuantic.UI oferece ferramentas de depuração profissionais parecidas com as do Next.js, com recursos exclusivos de desenvolvimento que ajudam a identificar e corrigir problemas rapidamente.
O framework detecta o ambiente automaticamente usando o IWebHostEnvironment.IsDevelopment() e o expõe ao browser por:
window.__EQ_DEV__; // true em desenvolvimento, false em produçãoTodas as ferramentas de desenvolvimento são carregadas condicionalmente com base nessa flag.
O logger fornece logs consistentes e com prefixo, que só saem em modo de desenvolvimento.
import { logger } from "@equantic/ui-runtime";
// Só em desenvolvimento (silenciado em produção)
logger.debug("Component state:", state);
logger.info("API call completed");
// Sempre loga (mesmo em produção)
logger.warn("Deprecated API used");
logger.error("Failed to load data:", error);| Método | Saída | Produção | Prefixo |
|---|---|---|---|
debug() |
Console debug | ❌ Silenciado | [eQuantic.UI] |
info() |
Console info | ❌ Silenciado | [eQuantic.UI] |
warn() |
Console warn | ✅ Sempre | [eQuantic.UI] |
error() |
Console error | ✅ Sempre | [eQuantic.UI] |
No DevTools do browser, você pode filtrar pelo prefixo:
[eQuantic.UI]
O logger está implementado em src/eQuantic.UI.Runtime/src/utils/logger.ts:
const isDev = typeof window !== "undefined" && window.__EQ_DEV__;
export const logger = {
debug(...args: any[]) {
if (isDev) console.debug("[eQuantic.UI]", ...args);
},
info(...args: any[]) {
if (isDev) console.info("[eQuantic.UI]", ...args);
},
warn(...args: any[]) {
console.warn("[eQuantic.UI]", ...args);
},
error(...args: any[]) {
console.error("[eQuantic.UI]", ...args);
},
};O overlay de erro fornece uma interface de erro em tela cheia, no estilo do Next.js, que aparece automaticamente quando ocorrem erros em tempo de execução.
- Captura automática: pega erros não tratados e rejeições de promise
-
Stack traces em C# ✨: o overlay é ciente de source map: ele busca o
.js.mapde cada bundle, decodifica (src/dev/source-map.ts+src/dev/stack-remapper.ts), e reescreve a pilha de chamadas como os frames C# originais, mais um trecho da linha do código C# que falhou. Cai para a visão em JS se não houver mapa disponível. (É isso que torna real a promessa de "0 conhecimento de JS" na hora de depurar: quem desenvolve em C# vê C#, não JavaScript transpilado.) -
Suporte a teclado: aperte
Escpara fechar -
Só em desenvolvimento: nunca aparece em produção (carregado por um
import()dinâmico em dev) - UX limpa: cabeçalho vermelho, fonte monoespaçada, conteúdo rolável
O overlay de erro aparece automaticamente para:
- Erros não tratados: qualquer exceção não capturada no JavaScript
- Rejeições de promise: erros assíncronos não tratados
// Isto dispara o overlay de erro em modo de desenvolvimento
throw new Error("Something went wrong");
Promise.reject("Async error");
await fetch("/api/data"); // Se o fetch falhar e não for capturado┌─────────────────────────────────────────────┐
│ ⚠️ Build Error Close (Esc)│
├─────────────────────────────────────────────┤
│ │
│ Mensagem de erro aqui │
│ │
│ ┌─────────────────────────────────────────┐ │
│ │ Stack trace: │ │
│ │ at MyComponent.render (page.js:42) │ │
│ │ at Reconciler.patch (reconciler.js:12)│ │
│ │ ... │ │
│ └─────────────────────────────────────────┘ │
│ │
├─────────────────────────────────────────────┤
│ Este overlay de erro só aparece em │
│ desenvolvimento. Corrija o erro para seguir.│
└─────────────────────────────────────────────┘
Você pode mostrar erros no overlay manualmente:
import { errorOverlay } from "@equantic/ui-runtime/dev";
if (window.__EQ_DEV__) {
errorOverlay.show({
message: "Custom error message",
stack: error.stack,
componentStack: "Component hierarchy...",
});
}// Limpeza programática
errorOverlay.clear();
// Ações do usuário
// - Apertar a tecla Esc
// - Clicar no botão "Close"O overlay de erro está implementado em src/eQuantic.UI.Runtime/src/dev/error-overlay.ts:
class ErrorOverlay {
private overlay: HTMLDivElement | null = null;
private errors: ErrorInfo[] = [];
show(error: ErrorInfo) {
if (!window.__EQ_DEV__) return; // Só em dev
this.errors.push(error);
this.render();
}
clear() {
this.errors = [];
if (this.overlay) {
this.overlay.remove();
this.overlay = null;
}
}
private render() {
// Cria o overlay de tela cheia com os detalhes do erro
}
}
export const errorOverlay = new ErrorOverlay();
// Captura automática de erros
if (window.__EQ_DEV__) {
window.addEventListener("error", (event) => {
errorOverlay.show({
message: event.message,
stack: event.error?.stack,
});
});
window.addEventListener("unhandledrejection", (event) => {
errorOverlay.show({
message: `Unhandled Promise Rejection: ${event.reason}`,
stack: event.reason?.stack,
});
});
}Um build Debug escreve um source map ao lado de cada módulo, linkado a partir dele e com o C# de onde o módulo veio, então o depurador do browser mostra o próprio C#.
Chrome DevTools:
- Abra o DevTools (F12)
- Vá para a aba Sources
- Encontre o arquivo C# na árvore, nomeado pelo caminho dele dentro do projeto (
Pages/Home.cs), nunca pelo da máquina de build - Ponha breakpoints direto no código C#
- Inspecione estado, props e variáveis locais
O que o mapa de um módulo carrega é a propriedade EQuanticSourceMaps, e o padrão dela segue a
configuração:
EQuanticSourceMaps |
Padrão em | O que o build escreve |
|---|---|---|
full |
Debug | um mapa ao lado de cada módulo, linkado a partir dele, com o C# dentro, para o depurador do browser |
external |
(opcional) | um mapa sem o C# e sem o link, para um serviço de erros que envia os mapas por conta própria; o debugId do bun é mantido |
none |
todas as outras configurações | nenhum mapa, e nenhum link |
Um mapa com o C# dentro é o código do componente, o corpo de um [ServerAction] incluído, e a pasta
de saída é uma raiz web: é por isso que só o Debug escreve um. Diga a propriedade o que disser, um
publish não leva mapa nenhum da saída do compilador. Para guardar mapas de um build publicado,
escreva-os sem o C#:
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<EQuanticSourceMaps>external</EQuanticSourceMaps>
</PropertyGroup>O eqc compõe cada mapa ele mesmo, em C#, sem instalar nada: o bun mapeia o JavaScript para o
TypeScript que o eqc escreveu, o mapa V3 do próprio eqc leva desse TypeScript ao C#, e os dois viram
um mapa só, do JavaScript que o browser roda até o C#. As fontes dele são nomeadas relativas ao mapa e
dentro do projeto, então um depurador mostra o caminho do próprio projeto; um arquivo de fora do
projeto (as fontes de um pacote no cache do NuGet) é nomeado só pelo nome do arquivo. Um módulo
escrito a partir de mais de um arquivo nomeia cada um, com o seu próprio C#: uma classe que adota o
padrão que uma interface fornece leva as linhas desse padrão ao arquivo da interface, onde o depurador
as mostra (Desde 0.2.0-preview.60). Um mapa é JSON seja o que for que o C# tenha, um form feed ou
qualquer outro caractere de controle num comentário inclusive (Desde 0.2.0-preview.60). Um mapa
full, resumido:
{
"version": 3,
"sources": ["../../Pages/Home.cs"],
"sourcesContent": ["…o C# de Pages/Home.cs…"],
"mappings": "AAAA;AACA;..."
}Cada instrução tem um segmento próprio (Desde 0.2.0-preview.58): um frame ou um breakpoint cai na
instrução de C# que lançou ou em que foi posto, não na primeira linha do seu método. Uma linha que o
compilador escreve por conta própria pertence à instrução que a produziu: o else if de um switch
com padrões aponta para o seu case, o dispose de um using para o using, a condição de um do
para ela mesma, e as instruções de uma função local e a expressão de um membro com corpo de
expressão para as suas próprias linhas. O bloco de uma lambda também mapeia instrução por instrução
(Desde 0.2.0-preview.60), e o que vem depois do bloco na linha em que ele fecha volta a apontar
para a instrução. Isso vale para uma lambda passada a um método de instância ou estático do próprio
app, a um método da própria lista (ForEach, Find, Exists…) ou a Where, Select, Any,
All, Aggregate e os outros operadores LINQ escritos como uma forma só, para uma lambda numa
expressão de coleção (children: [ … ]), e para uma guardada numa variável local, numa função
local ou num delegate; e, desde a mesma versão, para uma dentro de um membro com corpo de
expressão, de uma criação de objeto, de um inicializador de objeto ou de coleção ou de um objeto
anônimo. Cada instrução de um corpo que tem um parâmetro out ou ref também aponta para a sua
própria linha. Esse corpo roda dentro de uma arrow que o compilador acrescenta, então uma pilha lida
no browser tem um frame a mais que a do .NET entre o lançamento e quem chamou. Nos outros casos, o
bloco de uma lambda aponta, por enquanto, para a instrução que a contém: passada a um método de
extensão, a um delegate ou por ?., dada a First, Count, Sum, OrderBy, GroupBy e os
outros operadores com tradução própria.
Isso permite:
- Pôr breakpoints em código C#
- Percorrer a lógica C# passo a passo
- Inspecionar os nomes de variáveis do C#
- Ver os números de linha originais nos stack traces
Para inspecionar o estado e as props de um componente:
// No console do browser
window.__EQ_DEBUG = true; // Liga o modo de depuração
// Os componentes expõem o estado deles
const component = document.querySelector(
'[data-component-id="abc"]',
).__component;
console.log(component.state);
console.log(component.props);Para depurar problemas de renderização entre SSR e CSR:
test("SSR matches CSR", async ({ page }) => {
// Pega o HTML do SSR
const ssrResponse = await page.goto("http://localhost:5000");
const ssrHtml = await ssrResponse.text();
// Espera a hidratação do CSR
await page.waitForLoadState("networkidle");
const csrHtml = await page.content();
// Compara
expect(normalizeHtml(ssrHtml)).toBe(normalizeHtml(csrHtml));
});Depure o código C# normalmente com o Visual Studio ou o VS Code:
- Ponha breakpoints nos arquivos
.cs - Rode com o depurador anexado:
dotnet run - Os breakpoints são atingidos durante:
- A renderização no servidor (SSR)
- As invocações de Server Action
- A compilação dos componentes
Monitore os Server Actions no DevTools do browser:
- Abra a aba Network
- Filtre por
_equantic/actions - Inspecione:
- A carga da requisição (nome do método, argumentos)
- Os dados da resposta
- As informações de tempo
- Os erros (com stack traces)
Ao usar IRequireAssets, verifique se as dependências estão sendo injetadas corretamente:
- Inspecione a fonte: abra o "Ver código-fonte da página" no browser e procure pelas tags de script/estilo.
- Aba Network: confira se as URLs externas (por exemplo, CDNs) estão carregando com sucesso (Status 200).
- Deduplicação: verifique se vários componentes não injetaram o mesmo script duas vezes.
- Ordem: as folhas de estilo devem aparecer antes dos scripts para a renderização correta.
Se os assets estiverem faltando no HTML inicial:
- Verifique se o componente implementa
IRequireAssets. - Garanta que o
AddUI()é chamado noProgram.cs. - Confira se a
AssetCollectionestá reunindo os assets corretamente durante a passada de render.
O reconciliador rastreia métricas de performance em modo de desenvolvimento:
// Liga o rastreamento de performance
window.__EQ_PERF = true;
// Veja as métricas
console.table(window.__EQ_PERF_DATA);As métricas incluem:
- Tempo de render: quanto cada componente levou para renderizar
- Tempo de diff: tempo gasto no reconciliador
- Operações de DOM: número de mudanças reais no DOM
- Listeners de evento: contagem de listeners ativos
Monitore os tempos de compilação:
dotnet build -v:detailedProcure por:
- A duração do target
CompileEQuanticUI - O número de componentes compilados
- O tempo de geração do TypeScript
- O tempo de empacotamento do Bun
Sintoma: o boot() nunca executa, GET /_equantic/runtime.js devolve 404
Solução: quem responde o browser é o Server, não o arquivo em wwwroot/_equantic/: o app.MapUI() mapeia /_equantic/runtime.js para o bundle que o assembly eQuantic.UI.Server embarca. Um 404 vem ou desse endpoint, e aí a resposta lista os recursos que o assembly carrega, ou de endpoint nenhum, então confira que o app.MapUI() roda. A cópia do próprio build, wwwroot/_equantic/runtime.js, tem os mesmos bytes, para as ferramentas que carregam os módulos fora de um servidor; o target CopyEQuanticRuntime a tira do pacote Server, e o build falha com "the served runtime was not found" quando não consegue (veja Arquitetura de pacotes)
# A cópia vem do pacote Server (não do SDK)
ls ~/.nuget/packages/equantic.ui.server/<version>/tools/runtime/
# Force a reconstrução
dotnet clean
dotnet build -v:nSintoma: o HTML renderizado no servidor está tematizado, mas a renderização no cliente não
Causa raiz: o blob da ponte de tema não foi adotado no boot
Solução:
- Verifique se o runtime.js carrega antes dos scripts dos componentes
- Procure no console do browser por
[eQuantic.UI] Boot process started - Inspecione
window.__EQ_THEME__no console - deve conter o tema serializado
Sintoma: não dá para depurar o código C# original no DevTools do browser
Solução:
- Construa em Debug, ou defina
EQuanticSourceMapscomofull: um build em qualquer outra configuração não escreve mapa, e um mapaexternalnão é linkado a partir do módulo, então o browser não o encontra sozinho - Confira se os arquivos
.mapexistem emwwwroot/_equantic/ - Ligue os source maps nas configurações do DevTools do browser
- Limpe o cache do browser e reconstrua
- Um frame que para no intermediário TypeScript (
obj/eQuantic/ts/…) vem de um mapa que o eqc não conseguiu compor, e o eqc reporta cada um no log do build ("… leads to the TypeScript only")
Sintoma: erros logados no console mas nenhum overlay
Verificações:
- O
window.__EQ_DEV__é verdadeiro? (confira no console) - O overlay de erro foi importado? (confira se o runtime.js o inclui)
- O CSS do overlay de erro carregou? (procure pelos estilos de
#equantic-error-overlay)
Forçar a exibição:
// Dispare o overlay manualmente
import { errorOverlay } from "@equantic/ui-runtime/dev";
errorOverlay.show({ message: "Test error" });- Use o logger à vontade: adicione logs de depuração durante o desenvolvimento, eles são de graça em produção
-
Teste os dois modos: sempre teste com o ambiente
DevelopmenteProduction - Monitore a rede: deixe a aba Network do DevTools aberta para pegar Server Actions que falharam
-
Os source maps vêm com o Debug: um build Debug os escreve (lá o
EQuanticSourceMapséfull), então não há nada para ligar - Use o overlay de erro: não suprima os erros, deixe o overlay mostrá-los
Para problemas em produção:
- Logs do servidor: confira os logs do ASP.NET Core para erros de Server Action
-
Console do browser: só os logs de
warneerroraparecem - Sentry/AppInsights: integre serviços de rastreamento de erros
-
Source maps: um publish não leva nenhum. Construa com
EQuanticSourceMaps=externale envie os mapas que ele escreve emwwwroot/_equantic/para o seu serviço de rastreamento de erros; nunca sirva um mapafulla partir de uma raiz web, porque ele é o código do componente
Antes de reportar problemas:
- Conferir o console do browser por erros
- Verificar se
window.__EQ_DEV__é verdadeiro (dev) ou falso (prod) - Confirmar que o runtime.js carrega (aba Network)
- Conferir o blob da ponte de tema (
window.__EQ_THEME__) - Testar com o cache do browser desligado
- Tentar em modo anônimo/privado
- Comparar o HTML do SSR com o do CSR
- Conferir a saída do MSBuild por avisos
- Verificar se os pacotes NuGet estão nas versões corretas
- Arquitetura do runtime - entendendo o sistema de runtime
- Fluxo de build - como a compilação e o empacotamento funcionam
- Performance - técnicas de otimização
🌐 English · Português
🏁 Comece aqui
🏗️ Arquitetura
- Visão geral da arquitetura
- Componentes write-once
- Superfície declarativa
- Arquitetura de pacotes
- Componentes
- Estilo
- Localização
- Analytics e GTM
📱 Write-once
- Motor Photon
- Design System
- Capacidades
- Armazenamento
- Formulários
- Editor de código
- Markdown
- Mermaid
- Renderização de Email
⚙️ Compilação
⚡ Runtime
🔌 Servidor
🎨 Ecossistema
🚀 Desenvolvimento