Arquitetura de pacotesEste 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 Server)
└─ tools/StandardComponents/*.cs (copiado do Components)
Por que esse formato falha:
•
Acoplamento forte: o SDK conhece diretamente as entranhas do Server e do Components
•
Conflitos de versão: o consumidor restaura uma versão do Server e o SDK carrega uma cópia de outra
•
Duplicação de artefatos: os mesmos arquivos existem em vários pacotes
•
Inflexível: não dá para atualizar o Server ou o Components sem republicar o SDK
A arquitetura: pacotes autocontidos
eQuantic.UI.Server.nupkg ✅
├─ lib/net10.0/eQuantic.UI.Server.dll (embarca o runtime que serve em /_equantic/runtime.js)
└─ tools/runtime/runtime.js (os mesmos bytes, para o SDK copiar)
eQuantic.UI.Components.nupkg ✅
└─ tools/source/*.cs (autogerido)
├─ Sdk/Sdk.props (inclui automaticamente Primitives, Code, Components, Charts, Web, Server,
│ o pacote do bun da plataforma e o analisador Generators)
├─ Sdk/Sdk.targets (resolve os artefatos dos outros pacotes pelas propriedades $(Pkg*))
├─ tools/net10.0/ (eqc e eqicon, as duas ferramentas de build que o SDK executa)
└─ tools/netstandard2.0/ (as tasks que as iniciam, e a todo outro programa, sem shell)
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
Não existe um pacote eQuantic.UI.Core. Ele foi dissolvido nos assemblies que eram donos das suas partes: a superfície do DOM foi para o Web, os atributos de contrato para o Primitives, metadados e assets para o Server, o estado de otimização de imagens para o Images. Uma página que importava eQuantic.UI.Core por causa de [Page] ou [ServerAction] apaga a linha: o namespace que ela já importa para o vocabulário os carrega.
Propósito: o vocabulário abstrato e os contratos
Contém:
•
O vocabulário visual contra o qual um componente é escrito: nós, layout, estilos tipados, tokens, tema
•
As bases de componente, StatelessComponent e StatefulComponent
•
Os atributos de contrato: [Page], [ServerAction], [ServerOnly], [Authorize], [AllowAnonymous], [FormModel], [UiFactory]
Empacota: apenas a DLL compilada (sem artefatos adicionais). Zero dependências.
Propósito: o realizador web, e a válvula de escape para o DOM
Contém:
•
O realizador que baixa os componentes compartilhados para DOM e CSS atômico
•
A válvula de escape: HtmlElement, HtmlNode, HtmlStyle, DynamicElement, IComponent, RenderContext, ClassBuilder
Empacota: apenas a DLL compilada (sem artefatos adicionais)
Propósito: a biblioteca de componentes write-once (Button, Input, Card, etc.), escrita contra o Primitives e realizada por alvo
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, com os .resx do próprio SDK ao lado do seu Designer
Empacotamento:
<!-- eQuantic.UI.Components.csproj -->
<Content Include="**\*.cs" Exclude="obj\**;bin\**" PackagePath="tools\source\" />
<Content Include="SdkResources*.resx" PackagePath="tools\source\" />
Por que arquivos de código?
O compilador (eqc.dll) constrói um modelo semântico da página que transpila, e esse modelo precisa das definições dos componentes: quando uma página compõe Button(…), o compilador lê a classe Button a partir das fontes do Components. O JavaScript da biblioteca NÃO é compilado por app: os módulos transpilados vêm dentro do runtime.js, e o eqc encaminha para lá os imports de using eQuantic.UI.Components.
Uso pelo SDK:
<!-- Sdk/Sdk.targets, target CompileEQuanticUI -->
<_StandardComponentsDir Condition="'$(PkgeQuantic_UI_Components)' != ''">$(PkgeQuantic_UI_Components)/tools/source</_StandardComponentsDir>
<_EqcSourceDirs>$(MSBuildProjectDirectory);$(_StandardComponentsDir)</_EqcSourceDirs>
<!-- Entregue ao compilador num arquivo de resposta, um argumento por linha, com os mesmos
assemblies contra os quais o csc compila (refs). O eqc é iniciado com a RunProgram, o compilador
e aquele arquivo como uma lista de argumentos, para nenhum shell ler um caminho ou um nome -->
<RunProgram Program="dotnet" Arguments="@(_EqcStartArgument)" />
Propósito: o TypeScript do runtime do browser (DOM virtual, reconciliador, gestão de estado) e a prova dele
Empacota: nada. O projeto não é empacotado (IsPackable=false): o bundle que um app roda é escrito pelo eQuantic.UI.Server a partir do boot.ts, que importa este TypeScript, e é esse pacote que o carrega (abaixo). O que o projeto roda é a prova do runtime, pelo bun embarcado: dotnet build src/eQuantic.UI.Runtime -t:TestRuntime instala as dependências do bun.lock como estão fixadas, verifica os tipos com o tsc e roda o vitest uma vez.
eQuantic.UI.Runtime.{Os}{Arch}
Propósito: o Bun embarcado, um pacote por sistema e arquitetura: Osx64, OsxArm64, Win64, WinArm64, Linux64, LinuxArm64
Contém:
•
O executável do Bun, compactado (tools/bun/bun-darwin.zip, bun-linux.zip ou bun.exe.zip); o SDK o extrai no primeiro build
•
Nada mais. Os pacotes não declaram dependências
Por que pacotes separados?
•
O Sdk.props referencia exatamente UM deles, escolhido por [MSBuild]::IsOSPlatform e pela OSArchitecture da máquina, então o consumidor baixa um binário, nunca seis
•
Separação limpa entre a lógica de runtime e as ferramentas de build
•
A versão e o SHA-256 de cada zip estão fixados no bun-toolchain.json e conferidos pelos testes. Veja Fluxo 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
•
Metadados (SeoBuilder, MetaTags, IHandleMetadata) e assets (IRequireAssets, AssetBuilder)
•
O runtime.js embarcado, servido em /_equantic/runtime.js
•
tools/runtime/runtime.js: os mesmos bytes como arquivo, para o SDK copiar ao lado dos módulos de um app
Nota: o Server é o único escritor do runtime. O target BundleRuntime dele empacota o boot.ts em wwwroot/runtime.js antes de todo build; o compilador embarca esse arquivo como EmbeddedResource, que é o que /_equantic/runtime.js responde, e o target de pack CollectServedRuntime coloca o mesmo arquivo em tools/runtime/runtime.js. A cópia de tempo de build do consumidor é esse arquivo, byte a byte.
Propósito: o gerador de código que escreve a superfície declarativa de factories para os componentes do PRÓPRIO app
Contém:
•
Só o gerador. O Sdk.props o entrega como analisador (PrivateAssets="all"), então é uma dependência de tempo de build e nada dele viaja com o app
•
Desligue com <EQuanticGenerateFactorySurface>false</EQuanticGenerateFactorySurface>. Veja Superfície declarativa Propósito: o orquestrador do SDK MSBuild
Contém:
•
Sdk.props - inclui automaticamente Primitives, Code, Components, Charts, Web, Server, o pacote do bun da plataforma e o analisador Generators
•
Sdk.targets - os targets MSBuild de compilação, da cópia do runtime.js, do catálogo de vetores e do ícone web do app
•
tools/net10.0/eqc.dll - o executável do compilador (projeto eQuantic.Build)
•
tools/net10.0/eqicon.dll - a ferramenta de ícones (projeto eQuantic.UI.Native.Build): Assets/**/*.svg → Vectors.g.cs, e o ícone do app → wwwroot/_equantic/icons
•
tools/netstandard2.0/eQuantic.UI.Sdk.Tasks.dll - as tasks do MSBuild com que o SDK inicia todo programa (projeto eQuantic.UI.Sdk.Tasks): a RunProgram, um programa e uma lista de argumentos sem shell, e a LinkDirectory, o link do node_modules que um BunPackage precisa. netstandard2.0 é o que todo MSBuild carrega, o do .NET SDK e o do Visual Studio (Desde 0.2.0-preview.62)
As duas ferramentas e as tasks chegam a tools/ como arestas do grafo de build do próprio projeto do SDK: itens ProjectReference com ReferenceOutputAssembly="false" e PrivateAssets="All", cuja saída o target de pack CollectBuildOutput recolhe. Nada linka contra elas e o pacote não ganha dependência.
NÃO contém:
•
❌ Artefatos do runtime (referencia o pacote Server)
•
❌ 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 assets
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 ferramenta de ícones (eqicon.dll)
Propósito: o mesmo SDK para dispositivos (macOS, iOS, Android). Veja Photon Ele responde às duas perguntas acima do mesmo jeito: os pacotes irmãos resolvem na versão do próprio SDK, e a ferramenta que ele executa (eqicon, para o ícone do app, o bundle e o manifesto de capacidades) é ou o que a árvore de código acabou de construir, ou o que o pacote enviou em tools/net10.0/.
eQuantic.UI.Lucide / Heroicons / ...
Propósito: catálogos de ícones
Contêm:
•
Um IconGlyph gerado por ícone, como propriedade para o trimmer poder descartar os que ninguém nomeia: dados write-once, usados igual na web e no nativo
•
Um EQuanticIconPack.marker na raiz do código. O SDK descobre um pacote referenciado por esse marcador e entrega as fontes dele ao eqc como fontes de referência, então um glifo é inserido no ponto de uso e nenhum módulo JavaScript por pacote é enviado
•
Nenhuma chamada de registro: referenciar o pacote é toda a configuração. Veja Ícones 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 uma propriedade $(Pkg*) para um pacote instalado SÓ quando o PackageReference dele carrega GeneratePathProperty="true". O Sdk.props a coloca exatamente nos pacotes cujo CONTEÚDO os targets leem, a saber Components, Charts, Server e o pacote do bun da plataforma:
<!-- Autogerado em obj/*.nuget.g.props -->
<PkgeQuantic_UI_Components>/Users/name/.nuget/packages/equantic.ui.components/<version></PkgeQuantic_UI_Components>
<PkgeQuantic_UI_Charts>/Users/name/.nuget/packages/equantic.ui.charts/<version></PkgeQuantic_UI_Charts>
<PkgeQuantic_UI_Server>/Users/name/.nuget/packages/equantic.ui.server/<version></PkgeQuantic_UI_Server>
<PkgeQuantic_UI_Runtime_OsxArm64>/Users/name/.nuget/packages/equantic.ui.runtime.osxarm64/<version></PkgeQuantic_UI_Runtime_OsxArm64>
O SDK usa essas para resolver artefatos:
<Target Name="CopyEQuanticRuntime">
<_RuntimeSourcePath>$(PkgeQuantic_UI_Server)/tools/runtime/runtime.js</_RuntimeSourcePath>
<Copy SourceFiles="$(_RuntimeSourcePath)" 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
Todo pacote é versionado a partir de UMA linha no Directory.Build.props do repositório, e uma tag de release publica todos nessa versão. O número atual não é citado aqui de propósito: ele muda a cada release, e um número velho na documentação é como se engana quem lê. Leia o arquivo.
O SDK fixa os irmãos na própria versão
O Sdk.props lê a versão do nuspec do próprio pacote do SDK instalado e pede cada irmão nessa versão. A alternativa é um curinga, para um build nunca falhar por falta de um número:
<PropertyGroup Condition="'$(EQuanticUIVersion)' == '' AND Exists('$(_EQuanticSdkNuspecPath)')">
<EQuanticUIVersion>$([System.Text.RegularExpressions.Regex]::Match($([System.IO.File]::ReadAllText('$(_EQuanticSdkNuspecPath)')),
'<version>(.+?)</version>').Groups[1].Value)</EQuanticUIVersion>
<PropertyGroup Condition="'$(EQuanticUIVersion)' == ''">
<EQuanticUIVersion>*</EQuanticUIVersion>
<ItemGroup Condition="'$(IsEQuanticDevMode)' != 'true'">
<PackageReference Include="eQuantic.UI.Primitives" Version="$(EQuanticUIVersion)" />
<PackageReference Include="eQuantic.UI.Code" Version="$(EQuanticUIVersion)" />
<PackageReference Include="eQuantic.UI.Components" Version="$(EQuanticUIVersion)" GeneratePathProperty="true" />
<PackageReference Include="eQuantic.UI.Charts" Version="$(EQuanticUIVersion)" GeneratePathProperty="true" />
<PackageReference Include="eQuantic.UI.Web" Version="$(EQuanticUIVersion)" />
<!-- O Server carrega o runtime que serve também como arquivo (tools/runtime/runtime.js). -->
<PackageReference Include="eQuantic.UI.Server" Version="$(EQuanticUIVersion)" GeneratePathProperty="true" />
<!-- mais o ÚNICO pacote eQuantic.UI.Runtime.{Os}{Arch} desta máquina -->
Assim o consumidor declara a versão UMA vez, na entrada msbuild-sdks do global.json que o template carimba, e os irmãos seguem. O SDK nativo faz o mesmo com a alternativa *-*, para um SDK preview conseguir restaurar os próprios irmãos preview.
Os usuários podem sobrepor:
<EQuanticUIVersion>a-versao-que-voce-quer</EQuanticUIVersion>
A propriedade move todos os irmãos juntos; as condições acima só a atribuem quando está vazia.
Cenários de desenvolvimento vs. de consumo
Cenário do consumidor (pacotes NuGet)
MyApp.csproj: <Project Sdk="eQuantic.UI.Sdk">
global.json: { "msbuild-sdks": { "eQuantic.UI.Sdk": "<version>" } }
↓ Sdk.props: sem árvore de código ao lado → PackageReferences em $(EQuanticUIVersion)
↓ O NuGet instala os pacotes no cache
~/.nuget/packages/equantic.ui.server/<version>/
~/.nuget/packages/equantic.ui.components/<version>/
↓ O NuGet gera as propriedades $(Pkg*)
obj/MyApp.csproj.nuget.g.props
↓ O SDK resolve os artefatos
O Sdk.targets usa $(PkgeQuantic_UI_Server)/tools/runtime/runtime.js
↓ e executa as ferramentas que ele mesmo enviou
<pacote do Sdk>/tools/net10.0/eqc.dll, eqicon.dll
Cenário de desenvolvimento (árvore de código)
Um build a partir da própria árvore do repositório (os samples, o site, um scaffold em teste) não passa por pacote NENHUM. Os mesmos Sdk.props e Sdk.targets detectam a árvore ao lado deles e trocam para referências de projeto; não há feed local, nem cache para limpar, nem passo de pack entre uma edição e o efeito dela. dotnet build samples/DefaultUIDashboard é o ciclo inteiro.
Um sample importa os dois arquivos do SDK diretamente:
<!-- samples/DefaultUIDashboard/DefaultUIDashboard.csproj -->
<Import Project="../../src/eQuantic.UI.Sdk/Sdk/Sdk.props" />
<TargetFramework>net10.0</TargetFramework>
<!-- Pacotes de ícones são OPT-IN: referencie os conjuntos que usa. -->
<ProjectReference Include="../../src/eQuantic.UI.Lucide/eQuantic.UI.Lucide.csproj" />
<Import Project="../../src/eQuantic.UI.Sdk/Sdk/Sdk.targets" />
O Sdk.props decide entre pacotes e projetos com UMA propriedade, e em modo dev também declara as duas ferramentas de build como arestas do grafo de build:
<IsEQuanticDevMode Condition="Exists('$(_DevRootDir)eQuantic.UI.Primitives/eQuantic.UI.Primitives.csproj')">true</IsEQuanticDevMode>
<ItemGroup Condition="'$(IsEQuanticDevMode)' == 'true'">
<!-- As FERRAMENTAS DE BUILD que este projeto executa, como arestas do grafo: nada linka contra
elas, só precisam EXISTIR antes dos nossos targets rodarem, que é exatamente o que uma
<ProjectReference Include="$(_DevRootDir)eQuantic.Build\eQuantic.Build.csproj"
ReferenceOutputAssembly="false" Private="false" SkipGetTargetFrameworkProperties="true"
GlobalPropertiesToRemove="$(_EqToolGlobalsToRemove)" />
<ProjectReference Include="$(_DevRootDir)eQuantic.UI.Native.Build\eQuantic.UI.Native.Build.csproj"
ReferenceOutputAssembly="false" Private="false" SkipGetTargetFrameworkProperties="true"
GlobalPropertiesToRemove="$(_EqToolGlobalsToRemove)" />
<ProjectReference Include="$(_DevRootDir)eQuantic.UI.Primitives\eQuantic.UI.Primitives.csproj" />
<ProjectReference Include="$(_DevRootDir)eQuantic.UI.Code\eQuantic.UI.Code.csproj" />
<ProjectReference Include="$(_DevRootDir)eQuantic.UI.Components\eQuantic.UI.Components.csproj" />
<ProjectReference Include="$(_DevRootDir)eQuantic.UI.Charts\eQuantic.UI.Charts.csproj" />
<ProjectReference Include="$(_DevRootDir)eQuantic.UI.Web\eQuantic.UI.Web.csproj" />
<ProjectReference Include="$(_DevRootDir)eQuantic.UI.Server\eQuantic.UI.Server.csproj" />
<!-- mais o ÚNICO projeto eQuantic.UI.Runtime.{Os}{Arch}, e o eQuantic.UI.Generators como analisador -->
Por que arestas e não uma tarefa <MSBuild> inline: um build inline rodava uma SEGUNDA instância de cada projeto de ferramenta sob as próprias propriedades globais, correndo contra o build da própria solução para o mesmo bin/, e todo target que executava a ferramenta estava guardado por Exists(eqicon.dll), que respondia "não" num build frio e "sim" no segundo. Passou durante meses pelo acidente de onde os projetos estavam na .sln. Uma aresta é ordenada e serializada pelo próprio MSBuild. Private="false" mantém o apphost e os json de um exe fora do bin/ do app; GlobalPropertiesToRemove impede que uma cabeça de dispositivo entregue a uma ferramenta net10.0 comum o seu framework ou identificador de runtime.
O Sdk.targets então faz UMA pergunta (existe uma árvore de código ao meu lado?) para decidir onde estão as duas ferramentas, e de onde vêm os artefatos quando nenhuma propriedade $(Pkg*) está definida:
<_SdkToolsDir>$(MSBuildThisFileDirectory)../tools/net10.0/</_SdkToolsDir>
<_EqSourceTree Condition="Exists('$(MSBuildThisFileDirectory)../../eQuantic.Build/eQuantic.Build.csproj')">true</_EqSourceTree>
<!-- Uma árvore de código executa o que as arestas dela acabaram de construir; um pacote executa o
que enviou em tools/. Um EqcCliPath declarado pelo projeto vence os dois. -->
<EqcCliPath Condition="'$(EqcCliPath)' == '' AND '$(_EqSourceTree)' == 'true'">$(MSBuildThisFileDirectory)../../eQuantic.Build/bin/$(Configuration)/net10.0/eqc.dll</EqcCliPath>
<EqcCliPath Condition="'$(EqcCliPath)' == ''">$(_SdkToolsDir)eqc.dll</EqcCliPath>
<_EqIconToolDir Condition="'$(_EqSourceTree)' == 'true'">$(MSBuildThisFileDirectory)../../eQuantic.UI.Native.Build/bin/$(Configuration)/net10.0/</_EqIconToolDir>
<_EqIconToolDir Condition="'$(_EqIconToolDir)' == ''">$(_SdkToolsDir)</_EqIconToolDir>
<!-- Artefatos: primeiro o $(Pkg*) do pacote, senão a árvore ao lado do SDK -->
<_StandardComponentsDir Condition="'$(_StandardComponentsDir)' == '' And Exists('$(_DevComponentsDir)')">$(_DevComponentsDir)</_StandardComponentsDir>
<_RuntimeSourcePath Condition="'$(_RuntimeSourcePath)' == '' And Exists('$(MSBuildThisFileDirectory)../../eQuantic.UI.Server/wwwroot/runtime.js')">$(MSBuildThisFileDirectory)../../eQuantic.UI.Server/wwwroot/runtime.js</_RuntimeSourcePath>
<BunZipPath Condition="'$(BunZipPath)' == '' and Exists('$(MSBuildThisFileDirectory)../../$(BunRuntimePackageId)/tools/bun/$(_BunZipName)')">$(MSBuildThisFileDirectory)../../$(BunRuntimePackageId)/tools/bun/$(_BunZipName)</BunZipPath>
Uma ferramenta que mesmo assim esteja faltando falha pelo nome antes de qualquer coisa rodar: EQ4002 para o eqc, EQ4001 para o eqicon: um grafo quebrado numa árvore de código, um pacote quebrado vindo do NuGet, um caminho errado sob um EqcCliPath explícito. Nenhum dos três se resolve construindo duas vezes. Veja Diagnósticos. O diretório artifacts/packages, que o nuget.config do repositório ainda declara como fonte local, NÃO faz parte deste fluxo: nada num build da árvore de código escreve nele ou lê dele. Para validar uma mudança pelo caminho REAL do consumidor (pacotes, global.json, restore), use a receita do feed local em Fluxo de build. Benefícios:
•
Quem desenvolve o framework trabalha direto no código; uma edição aparece no próximo dotnet build
•
Sem pack, sem restore, sem passo de cache entre uma edição e o sample que a mostra
•
Os mesmos Sdk.props e Sdk.targets funcionam nos dois cenários: o caminho do consumidor nunca é outro código, só outra resposta a "existe uma árvore ao meu lado?"
1.
Deixe cada pacote gerenciar os próprios artefatos
•
O Server empacota o runtime.js que ele serve
•
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
•
Uma ferramenta ou artefato faltando é um erro que diz qual pacote ou qual aresta falta, nunca um aviso e um build que segue sem JavaScript
1.
Não embarque artefatos de outros pacotes
•
O SDK NÃO deve copiar o runtime.js do Server para dentro dele
2.
Não use caminhos relativos entre pacotes
•
Ruim: $(MSBuildThisFileDirectory)../../../Server/tools/runtime/
•
Bom: $(PkgeQuantic_UI_Server)/tools/runtime/
3.
Não deixe uma ferramenta copiada à mão ao lado do SDK
•
Uma cópia que um build anterior deixou ali está velha por construção; o SDK executa o que as arestas dele acabaram de construir, ou o que o pacote enviou
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: the served runtime was not found. It ships inside the eQuantic.UI.Server package (version …) at tools/runtime/runtime.js; try 'dotnet restore --force'.
Causa: $(PkgeQuantic_UI_Server) está vazio, e não há ao lado do SDK uma árvore de código cujo projeto Server tenha escrito o wwwroot/runtime.js (esse arquivo é a saída de build do Server)
Correção:
# Confira que o pacote Server carrega o runtime
ls ~/.nuget/packages/equantic.ui.server/<version>/tools/runtime/
Código do Components não encontrado
Error: eQuantic.UI: Standard components not found. Ensure the eQuantic.UI.Components package (version …) is installed.
Causa: $(PkgeQuantic_UI_Components) está vazio e não há árvore de código ao lado do SDK
Correção:
# Verifique se o pacote Components tem os arquivos de código
ls ~/.nuget/packages/equantic.ui.components/<version>/tools/source/
EQ4002 / EQ4001: uma ferramenta de build está faltando
error EQ4002: The eQuantic compiler (eqc) is missing at '…/tools/net10.0/eqc.dll'. …
Causa: numa árvore de código, o projeto da ferramenta não foi construído antes deste (um grafo de build quebrado, leia os erros ACIMA deste); a partir de um pacote, o pacote saiu sem tools/net10.0/; com um EqcCliPath explícito, o caminho aponta para um arquivo que não está lá
Correção: nenhum dos três se resolve construindo duas vezes. Corrija o grafo, limpe os pacotes do eQuantic do cache e restaure de novo, ou corrija o caminho. Veja Diagnósticos Sintoma: o build usa um runtime.js velho apesar de um pacote Server novo
Causa: o cache do NuGet não foi limpo
Correção:
# Limpe o pacote específico do cache
rm -rf ~/.nuget/packages/equantic.ui.server/<version>
dotnet restore --force --no-cache
A partir do checkout do framework, dotnet msbuild -t:ClearEQuanticCache remove todo pacote equantic.* do cache de uma vez.
•
Fluxo de build - o pipeline de build completo, e a receita do feed local •
Runtime - a arquitetura e a distribuição do runtime •
Compilador - como o compilador de C# para JS funciona •
Diagnósticos - todo EQxxxx que o SDK e o compilador reportam