eQuantic.UIeQuantic.UI
Docs
Playground
GitHub
START HERE
Getting Started
WRITE-ONCE
Write-Once Components
Declarative Surface
Photon Engine
Design System
Capabilities
Storage
Forms
Code Editor
Markdown
Mermaid
Email Rendering
ARCHITECTURE
Architecture Overview
Package Architecture
Components
Styling
Localization
Analytics & GTM
COMPILATION
Compiler
Compile-Time Evaluation
Supported C# Features
External Type Resolution
Build Flow
Diagnostics
RUNTIME
Runtime (TypeScript)
Performance
SERVER
Server Integration
Assets
BunPackage
Security
ECOSYSTEM
Image
Charts
Icons
Lottie
DEVELOPMENT
Visual Editor
Debug
Roadmap
PT-BR
Analytics-pt-BR
Architecture-pt-BR
Assets-pt-BR
BuildFlow-pt-BR
BunPackage-pt-BR
Capabilities-pt-BR
Charts-pt-BR
CodeEditor-pt-BR
Compiler-pt-BR
CompileTimeEvaluation-pt-BR
Components-pt-BR
Debug-pt-BR
DeclarativeSurface-pt-BR
DesignSystem-pt-BR
Diagnostics-pt-BR
EmailRealizer-pt-BR
ExternalTypeResolution-pt-BR
Forms-pt-BR
GettingStarted-pt-BR
Home-pt-BR
Icons-pt-BR
Image-pt-BR
Localization-pt-BR
Lottie-pt-BR
Markdown-pt-BR
Mermaid-pt-BR
PackageArchitecture-pt-BR
Performance-pt-BR
Photon-pt-BR
Roadmap-pt-BR
Runtime-pt-BR
Security-pt-BR
ServerIntegration-pt-BR
Storage-pt-BR
Styling-pt-BR
SupportedFeatures-pt-BR
VisualEditor-pt-BR
WriteOnceComponents-pt-BR
ACTIONS & INPUTS
Button
IconButton
TextInput
Select
Checkbox
Switch
RadioGroup
SegmentedControl
Slider
Stepper
SearchField
SURFACES & DISPLAY
Card
Badge
Chip
Avatar
Banner
ProgressBar
EmptyState
Divider
NAVIGATION
Tabs
AppBar
BottomNavigation
Breadcrumb
Pagination
PageIndicator
Menu
Drawer
OVERLAYS
Dialog
BottomSheet
Toast
Popover
Tooltip
LISTS & DATA
List
ListView
Table
Accordion
CodeBlock
TOUCH INTERACTION
PullToRefresh
SwipeableRow
Docspt-BR
Fluxo de build do eQuantic.UI
Edit this page
4 min read
🌐 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.
Fluxo visual
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
┌─────────────────────────────────────────────────────────────────────────────┐
│ 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
Origem do Bun por componente
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)
Requisitos do consumidor
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.
Consumir um SDK não lançado a partir de pacotes locais
Since 0.2.0-preview.45
Valide uma mudança do framework num app REAL — pacotes, global.json, restore, o caminho inteiro do consumidor — sem cortar versão nem correr pipeline. O primeiro consumidor do Trilho W provou a sua migração assim: frames byte-idênticos entre o build por pacotes e o build por source.
No checkout do framework:
1
dotnet pack -c Release -p:PackageVersion=1.0.0-dev -o artifacts/local-feed
1.0.0-dev nunca colide com uma versão publicada, o Sdk.Native deriva a versão de cada pacote irmão da sua própria, e os samples não empacotam — o feed é só produto. No app:
global.json: { "msbuild-sdks": { "eQuantic.UI.Sdk.Native": "1.0.0-dev" } } (ou eQuantic.UI.Sdk)
nuget.config: <clear />, depois o feed local PRIMEIRO, nuget.org a seguir
o ficheiro de projeto: Sdk="eQuantic.UI.Sdk.Native", sem atributo de versão
Depois de cada repack, limpe a cópia em cache e restaure de novo — o NuGet nunca baixa outra vez uma versão que já tem. O ClearEQuanticCache vive no Directory.Build.targets do framework, então corra a partir desse checkout; ele remove todo pacote equantic.* do cache do NuGet reativamente (uma lista mantida à mão já deixou passar todos os pacotes nativos):
1
dotnet msbuild -t:ClearEQuanticCache src/eQuantic.UI.Core/eQuantic.UI.Core.csproj
1
dotnet restore --force
Prova headless para um app nativo, sem janela: --Photon:ScreenshotPath out.png.
Arquivos-chave
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
Targets do MSBuild (ordem de execução)
No SDK (consumidor)
1.
ResolveBunZipPath - encontra o .zip do Bun no cache do NuGet
2.
EnsureBunExtracted - extrai o executável se preciso
3.
ResolveBunPath - define $(BunPath) para uso posterior
4.
InstallBunPackages - instala os itens <BunPackage> via bun add (veja BunPackage)
5.
CompileEQuanticUI - transpila C# → TypeScript → JavaScript
6.
CopyEQuanticRuntime - copia o runtime.js do pacote Runtime para wwwroot/\_equantic/
No Server (desenvolvimento)
1.
ResolveBunForServer - encontra o Bun na árvore de código
2.
BundleRuntime - compila boot.ts → runtime.js
Arquitetura de pacotes e autocontenção
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.
Princípios da arquitetura
Antes (problemático):
1
2
3
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):
1
2
3
4
5
6
7
8
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
Entrega do runtime.js
1. Empacotamento (desenvolvimento)
Durante o dotnet pack do eQuantic.UI.Runtime:
1
2
3
4
5
<!-- 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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!-- 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>
Entrega das fontes do Components
1. Empacotamento (desenvolvimento)
Durante o dotnet pack do eQuantic.UI.Components:
1
2
3
4
<!-- 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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!-- 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) &quot;$(MSBuildProjectDirectory);$(_StandardComponentsDir)&quot; ..." />
</Target>
Principais benefícios da arquitetura
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
Estratégia de bundle único do runtime
O Runtime usa a configuração inlineDynamicImports: true do Vite para criar um bundle único:
1
2
3
4
5
6
7
8
9
10
// 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.