-
Notifications
You must be signed in to change notification settings - Fork 1
BuildFlow pt BR
🌐 Esta página em: English · Português
Este documento descreve o fluxo de build do eQuantic.UI, demonstrando como o framework mantém zero dependências externas para o consumidor.
┌─────────────────────────────────────────────────────────────────────────────┐
│ DESENVOLVIMENTO (árvore de código) │
└─────────────────────────────────────────────────────────────────────────────┘
reconciler.ts, component.ts, etc.
│
▼
┌──────────────────────────────────┐
│ npm run build │ (só durante o desenvolvimento)
│ (eQuantic.UI.Runtime) │
└──────────────────────────────────┘
│
▼
dist/index.js (runtime compilado)
│
│
boot.ts ──────importa─────────┘
│
▼
┌──────────────────────────────────┐
│ dotnet build │
│ (eQuantic.UI.Server) │
│ │
│ Target ResolveBunForServer: │
│ ├─ Procura o Bun em: │
│ │ Runtime.Osx64/tools/bun/ │
│ │ Runtime.Win64/tools/bun/ │
│ │ Runtime.Linux64/tools/bun/ │
│ ├─ Extrai do .zip se preciso │
│ └─ chmod +x (Unix) │
│ │
│ Target BundleRuntime: │
│ └─ "$(_BunPath)" build boot.ts │
└──────────────────────────────────┘
│
▼
wwwroot/runtime.js (embarcado no Server.dll)
│
▼
┌──────────────────────────────────┐
│ dotnet pack │
│ (eQuantic.UI.Server) │
└──────────────────────────────────┘
│
▼
artifacts/packages/eQuantic.UI.Server.0.1.1.nupkg
┌─────────────────────────────────────────────────────────────────────────────┐
│ CONSUMIDOR (projeto cliente) │
└─────────────────────────────────────────────────────────────────────────────┘
MyApp.csproj
├─ Sdk="eQuantic.UI.Sdk/0.1.1"
└─ PackageReference: eQuantic.UI.Server, eQuantic.UI.Runtime
│
▼
┌──────────────────────────────────┐
│ dotnet restore │
│ │
│ O NuGet instala os pacotes: │
│ ├─ eQuantic.UI.Sdk │
│ ├─ eQuantic.UI.Server │
│ ├─ eQuantic.UI.Runtime │
│ │ └─ (metapacote) │
│ └─ eQuantic.UI.Runtime.Osx64 │ ◄── o Bun vem embarcado aqui!
│ └─ tools/bun/bun-darwin.zip │
└──────────────────────────────────┘
> **Qual Bun?** O `src/eQuantic.UI.Runtime/bun-toolchain.json` guarda a versão e um SHA-256 por
> plataforma, conferidos a cada execução dos testes. Os digests provam que os bytes comitados são os
> que o release publicou; a versão é verificada extraindo o binário do host e rodando ele, porque um
> manifesto que ninguém compara com aquilo que ele descreve acaba se afastando dele.
>
> Os seis pacotes de plataforma (`Osx64`, `OsxArm64`, `Win64`, `WinArm64`, `Linux64`, `LinuxArm64`)
> carregam o mesmo build; um Bun diferente por arquitetura é como se consegue um bundle que só falha
> na máquina de uma pessoa.
>
> Para atualizar: troque os arquivos `.zip`, rode os testes uma vez com `EQ_UPDATE_BUN_MANIFEST=1`, e
> leia o diff. Uma versão que mudou com digests que não mudaram é um erro, e o contrário também.
│
▼
┌──────────────────────────────────┐
│ dotnet build │
│ │
│ O SDK.targets executa: │
│ │
│ 1. ResolveBunZipPath │
│ └─ $(PkgeQuantic_UI_Runtime_ │
│ Osx64)/tools/bun/*.zip │
│ │
│ 2. EnsureBunExtracted │
│ ├─ Descompacta se preciso │
│ └─ chmod +x (Unix) │
│ │
│ 3. ResolveBunPath │
│ └─ Define $(BunPath) │
│ │
│ 4. InstallBunPackages │
│ ├─ <BunPackage> → bun add │
│ └─ Symlink node_modules │
│ │
│ 5. CompileEQuanticUI │
│ └─ dotnet eqc.dll ... --bun │
│ "$(BunPath)" │
│ │
│ 6. CopyEQuanticRuntime │ ◄── entrega do runtime.js
│ └─ Copia do pacote Runtime │
│ para wwwroot/_equantic/ │
│ │
│ └─ "$(BunPath)" x │
└──────────────────────────────────┘
│
▼
wwwroot/_equantic/
├─ runtime.js (do pacote Runtime)
└─ *.js (componentes compilados)
│
▼
┌──────────────────────────────────┐
│ dotnet run │
│ │
│ O servidor serve: │
│ ├─ runtime.js (do Server.dll) │
│ └─ *.js (de wwwroot/_equantic) │
└──────────────────────────────────┘
│
▼
O browser carrega a aplicação
| Componente | Origem do Bun |
|---|---|
| Server (build do pacote) |
eQuantic.UI.Runtime.{OS}/tools/bun/ (árvore de código) |
| SDK (consumidor) |
$(PkgeQuantic_UI_Runtime_{OS})/tools/bun/ (cache do NuGet) |
O consumidor só precisa de:
- .NET SDK 10.0
-
dotnet restore+dotnet build
Nenhuma instalação de Node.js, npm ou Bun global é necessária.
| Arquivo | Responsabilidade |
|---|---|
Sdk/Sdk.targets |
Resolve o Bun, instala os itens <BunPackage>, compila os componentes |
Server.csproj |
Resolve o Bun na árvore de código, empacota o runtime.js |
Runtime.{OS}.csproj |
Empacota o executável do Bun para cada plataforma |
- ResolveBunZipPath - encontra o .zip do Bun no cache do NuGet
- EnsureBunExtracted - extrai o executável se preciso
-
ResolveBunPath - define
$(BunPath)para uso posterior -
InstallBunPackages - instala os itens
<BunPackage>viabun add(veja BunPackage) - CompileEQuanticUI - transpila C# → TypeScript → JavaScript
- CopyEQuanticRuntime - copia o runtime.js do pacote Runtime para wwwroot/_equantic/
- ResolveBunForServer - encontra o Bun na árvore de código
- BundleRuntime - compila boot.ts → runtime.js
O eQuantic.UI segue uma arquitetura de pacotes autocontidos, em que cada pacote gerencia os próprios artefatos. O SDK age como orquestrador, referenciando os outros pacotes pelas propriedades $(Pkg*) do NuGet.
Antes (problemático):
Pacote SDK ❌
├─ runtime.js embarcado (copiado do Runtime)
└─ arquivos *.cs embarcados (copiados do Components)
Problemas: acoplamento forte, conflitos de versão, duplicação de artefatos
Depois (correto):
Pacote Runtime ✅
└─ tools/runtime/runtime.js (autocontido)
Pacote Components ✅
└─ tools/source/*.cs (autocontido)
Pacote SDK ✅
└─ Referencia os outros pacotes via $(PkgeQuantic_UI_*)
Benefícios: desacoplamento, versionamento correto, sem duplicação
1. Empacotamento (desenvolvimento)
Durante o dotnet pack do eQuantic.UI.Runtime:
<!-- eQuantic.UI.Runtime.csproj -->
<ItemGroup>
<Content Include="dist\index.js" PackagePath="tools\runtime\runtime.js"
Condition="Exists('dist\index.js')" />
</ItemGroup>O pacote Runtime embarca o próprio artefato JavaScript compilado.
2. Entrega (build do consumidor)
Durante o dotnet build, o target CopyEQuanticRuntime do SDK executa:
<!-- Sdk/Sdk.targets -->
<Target Name="CopyEQuanticRuntime" AfterTargets="CompileEQuanticUI"
Condition="'$(EnableEQuanticUICompilation)' == 'true'">
<PropertyGroup>
<!-- Resolve a partir do pacote Runtime pela propriedade do NuGet -->
<_RuntimeSourcePath Condition="'$(PkgeQuantic_UI_Runtime)' != ''">
$(PkgeQuantic_UI_Runtime)/tools/runtime/runtime.js
</_RuntimeSourcePath>
<!-- Alternativa pela árvore de código (só em desenvolvimento) -->
<_RuntimeSourcePath Condition="'$(_RuntimeSourcePath)' == ''">
$(MSBuildThisFileDirectory)../../eQuantic.UI.Runtime/dist/index.js
</_RuntimeSourcePath>
<_RuntimeDestPath>$(MSBuildProjectDirectory)/$(EQuanticOutputPath)runtime.js</_RuntimeDestPath>
</PropertyGroup>
<Error Text="eQuantic.UI: Runtime not found. Ensure eQuantic.UI.Runtime package is installed."
Condition="'$(_RuntimeSourcePath)' == '' Or !Exists('$(_RuntimeSourcePath)')" />
<Copy SourceFiles="$(_RuntimeSourcePath)" DestinationFiles="$(_RuntimeDestPath)" />
</Target>1. Empacotamento (desenvolvimento)
Durante o dotnet pack do eQuantic.UI.Components:
<!-- eQuantic.UI.Components.csproj -->
<ItemGroup>
<Content Include="**\*.cs" Exclude="obj\**;bin\**" PackagePath="tools\source\" />
</ItemGroup>O pacote Components embarca os próprios arquivos de código C# para a resolução de tipos do compilador.
2. Compilação (build do consumidor)
Durante o dotnet build, o target CompileEQuanticUI do SDK executa:
<!-- Sdk/Sdk.targets -->
<Target Name="CompileEQuanticUI" BeforeTargets="Build">
<PropertyGroup>
<!-- Resolve a partir do pacote Components pela propriedade do NuGet -->
<_StandardComponentsDir Condition="'$(PkgeQuantic_UI_Components)' != ''">
$(PkgeQuantic_UI_Components)/tools/source
</_StandardComponentsDir>
<!-- Alternativa pela árvore de código (só em desenvolvimento) -->
<_StandardComponentsDir Condition="'$(_StandardComponentsDir)' == ''">
$(MSBuildThisFileDirectory)../../eQuantic.UI.Components
</_StandardComponentsDir>
</PropertyGroup>
<Error Text="eQuantic.UI: Standard components not found. Ensure eQuantic.UI.Components package is installed."
Condition="'$(_StandardComponentsDir)' == '' Or !Exists('$(_StandardComponentsDir)')" />
<Exec Command="dotnet $(EqcCliPath) "$(MSBuildProjectDirectory);$(_StandardComponentsDir)" ..." />
</Target>- Desacoplamento: o SDK não embarca artefatos de outros pacotes
- Versionamento correto: o consumidor pode usar Runtime 0.1.3 + SDK 0.1.2 de forma independente
- Sem duplicação: cada artefato existe só no pacote de origem dele
- Flexibilidade: os pacotes evoluem independentemente, sem acoplamento forte
-
Interface clara: o SDK referencia os pacotes por propriedades bem definidas do NuGet (
$(Pkg*)) - Alternativa em desenvolvimento: os caminhos da árvore de código funcionam para o desenvolvimento do framework
O Runtime usa a configuração inlineDynamicImports: true do Vite para criar um bundle único:
// eQuantic.UI.Runtime/vite.config.ts
export default defineConfig({
build: {
rollupOptions: {
output: {
inlineDynamicImports: true, // ← Cria um bundle único
},
},
},
});Por que um bundle único?
- Entrega simplificada: só um arquivo para copiar (runtime.js)
- Sem gestão de chunks: evita problemas com chunks separados de logger-.js, error-overlay-.js
- Distribuição confiável: garante que todos os recursos do runtime (logger, overlay de erro) estejam incluídos
- Tamanho pequeno: ~49KB minificado com todos os recursos incluídos
Sem isso, o Vite criaria chunks separados para os imports dinâmicos, e o SDK precisaria copiar vários arquivos com nomes baseados em hash.
🌐 English · Português
🏁 Comece aqui
📱 Write-once
- Componentes write-once
- Superfície declarativa
- Motor Photon
- Design System
- Capacidades
- Armazenamento
- Formulários
- Editor de código
- Markdown
- Mermaid
- Renderização de Email
🏗️ Arquitetura
⚙️ Compilação
- Compilador
- Avaliação em tempo de compilação
- Recursos C# suportados
- Resolução de tipos externos
- Fluxo de build
- Diagnósticos
⚡ Runtime
🔌 Servidor
🎨 Ecossistema
🚀 Desenvolvimento