Arquitetura de pacotes🌐 Esta página em: English · Português Este documento explica a arquitetura de pacotes do eQuantic.UI e os princípios por trás do design autocontido dela.
Princípio central: pacotes autocontidos
Cada pacote do eQuantic.UI é autocontido e gerencia os próprios artefatos. O SDK age como um orquestrador que referencia os outros pacotes pelas propriedades autogeradas do NuGet.
O antipadrão que o design rejeita, o SDK embarcando artefatos de outros pacotes:
├─ tools/runtime/runtime.js (copiado do Runtime)
└─ tools/StandardComponents/*.cs (copiado do Components)
Por que esse formato falha:
•
Acoplamento forte: o SDK conhece diretamente as entranhas do Runtime e do Components
•
Conflitos de versão: o consumidor instala o Runtime 0.1.3 mas o SDK contém artefatos embarcados da 0.1.2
•
Duplicação de artefatos: os mesmos arquivos existem em vários pacotes
•
Inflexível: não dá para atualizar o Runtime ou o Components de forma independente sem republicar o SDK
A arquitetura: pacotes autocontidos
eQuantic.UI.Runtime.nupkg ✅
└─ tools/runtime/runtime.js (autogerido)
eQuantic.UI.Components.nupkg ✅
└─ tools/source/*.cs (autogerido)
├─ Sdk/Sdk.props (inclui Core, Components, Server e Runtime automaticamente)
└─ Sdk/Sdk.targets (referencia os pacotes pelas propriedades $(Pkg*))
Benefícios:
•
✅ Desacoplamento: cada pacote possui e gerencia os artefatos dele
•
✅ Versionamento correto: a versão instalada pelo consumidor é sempre a usada
•
✅ Sem duplicação: uma única fonte da verdade por artefato
•
✅ Evolução independente: os pacotes podem ser atualizados separadamente
•
✅ Interface clara: o SDK usa propriedades bem definidas do NuGet
Responsabilidades dos pacotes
Propósito: abstrações e tipos centrais
Contém:
•
Os tipos base HtmlNode, HtmlElement
•
Abstrações de ciclo de vida de componente
•
Contexto de renderização
Empacota: apenas a DLL compilada (sem artefatos adicionais)
Propósito: a biblioteca de componentes padrão (Button, Input, Container, etc.)
Contém:
•
A DLL compilada para uso em tempo de execução
•
Os arquivos de código (tools/source/*.cs) para a resolução de tipos do compilador
Empacotamento:
<!-- eQuantic.UI.Components.csproj -->
<Content Include="**\*.cs" Exclude="obj\**;bin\**"
PackagePath="tools\source\" />
Por que arquivos de código?
O compilador (eqc.dll) precisa de acesso ao código dos componentes para resolver tipos externos durante a compilação. Quando um consumidor usa <Button>, o compilador procura a definição da classe Button no pacote Components.
Uso pelo SDK:
<!-- Resolvido automaticamente pelo NuGet -->
<_ComponentsSource>$(PkgeQuantic_UI_Components)/tools/source</_ComponentsSource>
<!-- Passado ao compilador -->
<Exec Command="dotnet eqc.dll "$(ProjectDir);$(_ComponentsSource)" ..." />
Propósito: o runtime do browser (DOM virtual, reconciliador, gestão de estado)
Contém:
•
O runtime TypeScript/JavaScript compilado com o Vite
•
runtime.js (tools/runtime/runtime.js) - arquivo único empacotado (~49KB)
Empacotamento:
<!-- eQuantic.UI.Runtime.csproj -->
<Content Include="dist\index.js"
PackagePath="tools\runtime\runtime.js"
Condition="Exists('dist\index.js')" />
Processo de build:
1.
Código TypeScript → npm run build (Vite + tsc)
2.
Saída: dist/index.js (bundle único via inlineDynamicImports)
3.
Empacotado: eQuantic.UI.Runtime.nupkg/tools/runtime/runtime.js
Uso pelo SDK:
<!-- Resolvido automaticamente pelo NuGet -->
<_RuntimeSource>$(PkgeQuantic_UI_Runtime)/tools/runtime/runtime.js</_RuntimeSource>
<!-- Copiado para o wwwroot do consumidor -->
<Copy SourceFiles="$(_RuntimeSource)"
DestinationFiles="wwwroot/_equantic/runtime.js" />
eQuantic.UI.Runtime.{Plataforma}
Propósito: executáveis do Bun específicos de plataforma (Osx64, Win64, Linux64)
Contém:
•
O executável do Bun (compactado) para o empacotamento
•
Binários específicos de plataforma (~60MB cada)
Por que pacotes separados?
•
Os consumidores só baixam o executável da plataforma deles
•
Reduz o tamanho do pacote (não é preciso ter as 3 plataformas)
•
Separação limpa entre a lógica de runtime e as ferramentas de build
Propósito: integração com o ASP.NET Core
Contém:
•
Renderização no servidor (SSR)
•
O sistema de RPC dos Server Actions
•
O runtime.js embarcado, servido em /_equantic/runtime.js
Nota: o Server embarca a própria cópia do runtime.js como EmbeddedResource para servir por HTTP. Isso é separado da cópia de tempo de build do consumidor.
Propósito: o orquestrador do SDK MSBuild
Contém:
•
Sdk.props - inclui automaticamente os pacotes Core, Components, Server e Runtime
•
Sdk.targets - os targets MSBuild de compilação, empacotamento e geração de CSS
•
tools/net10.0/eqc.dll - o executável do compilador
NÃO contém:
•
❌ Artefatos do runtime (referencia o pacote Runtime)
•
❌ Código dos componentes (referencia o pacote Components)
Responsabilidades:
1.
Gestão de pacotes: inclui automaticamente os pacotes necessários pelo Sdk.props
2.
Orquestração do build: coordena compilação, empacotamento e geração de CSS
3.
Resolução de artefatos: resolve o runtime.js e as fontes dos componentes a partir dos pacotes deles
4.
Ferramental: fornece o compilador (eqc.dll) e a infraestrutura de build
eQuantic.UI.Lucide / Heroicons / ...
Propósito: provedores de conjuntos de ícones
Contêm:
•
Lógica de resolução de SVG
•
Componentes de ícone especializados
•
Implementação de IIconProvider
•
API fluente: registra a si mesmo pela extensão Use{Name}Icons() sobre o UIOptions.
eQuantic.UI.Charts.ChartJs / ApexCharts
Propósito: componentes de gráfico especializados
Contêm:
•
Declarações de asset via IRequireAssets
•
API fluente: registra a si mesmo pelas extensões UseChartJs() / UseApexCharts() sobre o UIOptions.
Propriedades de pacote do NuGet
O NuGet gera automaticamente propriedades $(Pkg*) para os pacotes instalados:
<!-- Autogerado em obj/*.nuget.g.props -->
<PkgeQuantic_UI_Core>/Users/name/.nuget/packages/equantic.ui.core/0.1.2</PkgeQuantic_UI_Core>
<PkgeQuantic_UI_Components>/Users/name/.nuget/packages/equantic.ui.components/0.1.2</PkgeQuantic_UI_Components>
<PkgeQuantic_UI_Runtime>/Users/name/.nuget/packages/equantic.ui.runtime/0.1.2</PkgeQuantic_UI_Runtime>
<PkgeQuantic_UI_Runtime_Osx64>/Users/name/.nuget/packages/equantic.ui.runtime.osx64/0.1.2</PkgeQuantic_UI_Runtime_Osx64>
O SDK usa essas para resolver artefatos:
<Target Name="CopyEQuanticRuntime">
<_RuntimeSource>$(PkgeQuantic_UI_Runtime)/tools/runtime/runtime.js</_RuntimeSource>
<Copy SourceFiles="$(_RuntimeSource)" DestinationFiles="..." />
Benefícios:
•
✅ O SDK não precisa conhecer os detalhes de estrutura dos pacotes
•
✅ Funciona com qualquer versão de pacote que o consumidor instale
•
✅ Resolução de cache automática pelo NuGet
Versionamento independente
Os pacotes podem evoluir de forma independente:
<!-- O consumidor pode misturar versões -->
<PackageReference Include="eQuantic.UI.Core" Version="0.1.3" />
<PackageReference Include="eQuantic.UI.Runtime" Version="0.1.4" />
<PackageReference Include="eQuantic.UI.Sdk" Version="0.1.2" />
O SDK vai usar:
•
O runtime.js do Runtime 0.1.4 (não a cópia embarcada da 0.1.2)
•
Os arquivos de código do Components 0.1.3 (não a cópia embarcada da 0.1.2)
Por simplicidade, o Sdk.props do SDK define uma versão padrão:
<EQuanticUIVersion>0.1.2</EQuanticUIVersion>
<PackageReference Include="eQuantic.UI.Core" Version="$(EQuanticUIVersion)" />
<PackageReference Include="eQuantic.UI.Components" Version="$(EQuanticUIVersion)" />
<PackageReference Include="eQuantic.UI.Runtime" Version="$(EQuanticUIVersion)" />
<PackageReference Include="eQuantic.UI.Server" Version="$(EQuanticUIVersion)" />
Os usuários podem sobrepor:
<EQuanticUIVersion>0.1.5</EQuanticUIVersion>
Ou especificar versões manualmente:
<PackageReference Include="eQuantic.UI.Runtime" Version="0.1.6" />
Cenários de desenvolvimento vs. de consumo
Cenário do consumidor (pacotes NuGet)
↓ O NuGet instala os pacotes no cache
~/.nuget/packages/equantic.ui.runtime/0.1.2/
~/.nuget/packages/equantic.ui.components/0.1.2/
↓ O NuGet gera as propriedades $(Pkg*)
obj/project.nuget.g.props
↓ O SDK resolve os artefatos
O Sdk.targets usa $(PkgeQuantic_UI_Runtime)/tools/runtime/runtime.js
Cenário de desenvolvimento (árvore de código)
Árvore de código em: /Users/name/equantic-ui/
↓ Pacotes locais em: artifacts/packages/
↓ O NuGet.config prioriza o local
<add key="local" value="../../artifacts/packages" />
↓ Caminhos alternativos no Sdk.targets
<_RuntimeSource Condition="'$(PkgeQuantic_UI_Runtime)' == ''">
$(MSBuildThisFileDirectory)../../eQuantic.UI.Runtime/dist/index.js
Benefícios:
•
Quem desenvolve o framework pode trabalhar direto no código
•
Não é preciso empacotar/restaurar a cada mudança
•
Os mesmos targets funcionam nos dois cenários
1.
Deixe cada pacote gerenciar os próprios artefatos
•
O Runtime empacota o runtime.js
•
O Components empacota os arquivos de código
2.
Referencie pelas propriedades do NuGet
•
Use $(PkgeQuantic_UI_*) em vez de caminhos fixos
3.
Forneça alternativas de desenvolvimento
•
Permita que o SDK encontre os artefatos na árvore de código ao desenvolver o framework
4.
Inclua mensagens de erro claras
•
Diga aos usuários qual pacote está faltando quando os artefatos não forem encontrados
1.
Não embarque artefatos de outros pacotes
•
O SDK NÃO deve copiar o runtime.js do Runtime para dentro dele
2.
Não use caminhos relativos entre pacotes
•
Ruim: $(MSBuildThisFileDirectory)../../../Runtime/dist/
•
Bom: $(PkgeQuantic_UI_Runtime)/tools/runtime/
3.
Não assuma que as versões dos pacotes batem
•
O consumidor pode usar Runtime 0.1.3 + SDK 0.1.2
4.
Não crie dependências circulares
•
Os pacotes devem ter um grafo de dependências claro
runtime.js não encontrado
Error: eQuantic.UI: Runtime not found. Ensure eQuantic.UI.Runtime package is installed.
Causa: $(PkgeQuantic_UI_Runtime) está vazio
Correção:
# Confira que o pacote Runtime está instalado
ls ~/.nuget/packages/equantic.ui.runtime/0.1.2/
Código do Components não encontrado
Error: eQuantic.UI: Standard components not found. Ensure eQuantic.UI.Components package is installed.
Causa: $(PkgeQuantic_UI_Components) está vazio
Correção:
# Verifique se o pacote Components tem os arquivos de código
ls ~/.nuget/packages/equantic.ui.components/0.1.2/tools/source/
Sintoma: o build usa um runtime.js velho apesar de o pacote Runtime ter sido atualizado
Causa: o cache do NuGet não foi limpo
Correção:
# Limpe o pacote específico do cache
rm -rf ~/.nuget/packages/equantic.ui.runtime/0.1.2
dotnet restore --force --no-cache
•
Runtime - a arquitetura e a distribuição do runtime •
Compilador - como o compilador de C# para JS funciona