eQuantic.UIeQuantic.UI
Docs
Playground
GitHub
DocsArchitecture
Architecture des paquets
Edit this page
13 min read
Ce document explique l'architecture des paquets d'eQuantic.UI et les principes derrière sa conception autonome.
Principe central : des paquets autonomes
Chaque paquet eQuantic.UI est autonome et gère ses propres artefacts. Le SDK agit comme un orchestrateur qui référence les autres paquets via les propriétés que NuGet génère lui-même.
La raison de cette conception
L'antipattern que la conception rejette, le SDK embarquant les artefacts d'autres paquets :
1
2
3
eQuantic.UI.Sdk.nupkg
❌
├─ tools/runtime/runtime.js (copié depuis Server)
└─ tools/StandardComponents/*.cs (copié depuis Components)
Pourquoi cette forme échoue :
•
Couplage fort : le SDK connaît directement les entrailles de Server et de Components
•
Conflits de version : le consommateur restaure une version de Server et le SDK porte une copie d'une autre
•
Duplication d'artefacts : les mêmes fichiers existent dans plusieurs paquets
•
Rigide : impossible de mettre à jour Server ou Components sans republier le SDK
L'architecture : des paquets autonomes
1
2
3
4
5
6
7
8
9
10
11
12
13
eQuantic.UI.Server.nupkg
✅
├─ lib/net10.0/eQuantic.UI.Server.dll (embarque le runtime qu'il sert sur /_equantic/runtime.js)
└─ tools/runtime/runtime.js (les mêmes octets, pour que le SDK les copie)
eQuantic.UI.Components.nupkg
✅
└─ tools/source/*.cs (auto-géré)
eQuantic.UI.Sdk.nupkg
✅
├─ Sdk/Sdk.props (inclut d'office Primitives, Code, Components, Charts, Web, Server,
│ le paquet bun de la plateforme et l'analyseur Generators)
├─ Sdk/Sdk.targets (résout les artefacts des autres paquets via les propriétés $(Pkg*))
├─ tools/net10.0/ (eqc et eqicon, les deux outils de build que le SDK lance)
└─ tools/netstandard2.0/ (les tâches qui les démarrent, et tout autre programme, sans shell)
Bénéfices :
•
✅ Découplage : chaque paquet possède et gère ses artefacts
•
✅ Versionnage correct : la version installée par le consommateur est toujours celle utilisée
•
✅ Aucune duplication : une seule source de vérité par artefact
•
✅ Évolution indépendante : les paquets peuvent être mis à jour séparément
•
✅ Interface claire : le SDK utilise des propriétés NuGet bien définies
Responsabilités des paquets
Il n'existe pas de paquet eQuantic.UI.Core. Il a été dissous dans les assemblys qui possédaient ses parties : la surface DOM est allée à Web, les attributs de contrat à Primitives, les métadonnées et les assets à Server, l'état d'optimisation d'images à Images. Une page qui importait eQuantic.UI.Core pour [Page] ou [ServerAction] supprime la ligne : le namespace qu'elle importe déjà pour le vocabulaire les porte.
eQuantic.UI.Primitives
Objet : le vocabulaire abstrait et les contrats
Contient :
•
Le vocabulaire visuel contre lequel un composant est écrit : nœuds, layout, styles typés, tokens, thème
•
Les bases de composant, StatelessComponent et StatefulComponent
•
Les attributs de contrat : [Page], [ServerAction], [ServerOnly], [Authorize], [AllowAnonymous], [FormModel], [UiFactory]
Empaquette : seulement la DLL compilée (aucun artefact supplémentaire). Zéro dépendance.
eQuantic.UI.Web
Objet : le réalisateur web, et l'échappatoire DOM
Contient :
•
Le réalisateur qui abaisse les composants partagés en DOM et CSS atomique
•
L'échappatoire : HtmlElement, HtmlNode, HtmlStyle, DynamicElement, IComponent, RenderContext, ClassBuilder
Empaquette : seulement la DLL compilée (aucun artefact supplémentaire)
eQuantic.UI.Components
Objet : la bibliothèque de composants write-once (Button, Input, Card, etc.), écrite contre Primitives et réalisée par cible
Contient :
•
La DLL compilée pour l'usage à l'exécution
•
Des fichiers source (tools/source/*.cs) pour la résolution de types du compilateur, avec le .resx propre au SDK à côté de son Designer
Empaquetage :
1
2
3
4
5
<!-- eQuantic.UI.Components.csproj -->
<ItemGroup>
<Content Include="**\*.cs" Exclude="obj\**;bin\**" PackagePath="tools\source\" />
<Content Include="SdkResources*.resx" PackagePath="tools\source\" />
</ItemGroup>
Pourquoi des fichiers source ?
Le compilateur (eqc.dll) construit un modèle sémantique de la page qu'il transpile, et ce modèle a besoin des définitions des composants : quand une page compose Button(…), le compilateur lit la classe Button depuis les sources de Components. Le JavaScript de la bibliothèque n'est PAS compilé par application : les modules transpilés voyagent dans runtime.js, et eqc y aiguille les imports de using eQuantic.UI.Components.
Usage par le SDK :
1
2
3
4
5
6
7
8
<!-- Sdk/Sdk.targets, cible CompileEQuanticUI -->
<_StandardComponentsDir Condition="'$(PkgeQuantic_UI_Components)' != ''">$(PkgeQuantic_UI_Components)/tools/source</_StandardComponentsDir>
<_EqcSourceDirs>$(MSBuildProjectDirectory);$(_StandardComponentsDir)</_EqcSourceDirs>
<!-- Remis au compilateur dans un fichier de réponse, un argument par ligne, avec les assemblys
exacts contre lesquels csc compile (refs). eqc est démarré avec RunProgram, le compilateur et
ce fichier en liste d'arguments, donc aucun shell ne lit un chemin ni un nom en route -->
<RunProgram Program="dotnet" Arguments="@(_EqcStartArgument)" />
eQuantic.UI.Runtime
Objet : le TypeScript du runtime du navigateur (DOM virtuel, réconciliateur, gestion d'état) et sa preuve
Empaquette : rien. Le projet n'est pas packé (IsPackable=false) : le bundle qu'exécute une application est écrit par eQuantic.UI.Server depuis boot.ts, qui importe ce TypeScript, et c'est ce paquet qui le porte (plus bas). Ce que le projet exécute, c'est la preuve du runtime, via le bun embarqué : dotnet build src/eQuantic.UI.Runtime -t:TestRuntime installe les dépendances de bun.lock telles qu'elles sont figées, vérifie les types avec tsc et lance vitest une fois.
eQuantic.UI.Runtime.{Os}{Arch}
Objet : le Bun embarqué, un paquet par OS et architecture : Osx64, OsxArm64, Win64, WinArm64, Linux64, LinuxArm64
Contient :
•
L'exécutable Bun, zippé (tools/bun/bun-darwin.zip, bun-linux.zip ou bun.exe.zip) ; le SDK l'extrait au premier build
•
Rien d'autre. Les paquets ne déclarent aucune dépendance
Pourquoi des paquets séparés ?
•
Sdk.props référence exactement UN d'entre eux, choisi par [MSBuild]::IsOSPlatform et l'OSArchitecture de la machine, donc un consommateur télécharge un binaire, jamais six
•
Séparation nette entre la logique du runtime et les outils de build
•
La version et le SHA-256 de chaque zip sont figés dans bun-toolchain.json et vérifiés par les tests. Voir Flux de build
eQuantic.UI.Server
Objet : l'intégration ASP.NET Core
Contient :
•
Le rendu côté serveur (SSR)
•
Le système RPC des Server Actions
•
Les middlewares et le routage
•
Les métadonnées (SeoBuilder, MetaTags, IHandleMetadata) et les assets (IRequireAssets, AssetBuilder)
•
Le runtime.js embarqué, servi sur /_equantic/runtime.js
•
tools/runtime/runtime.js : les mêmes octets sous forme de fichier, pour que le SDK le copie à côté des modules d'une application
Note : le Server est le seul à écrire le runtime. Sa cible BundleRuntime empaquette boot.ts dans wwwroot/runtime.js avant chaque build ; le compilateur embarque ce fichier comme EmbeddedResource, ce qui est ce que répond /_equantic/runtime.js, et la cible de pack CollectServedRuntime place le même fichier dans tools/runtime/runtime.js. La copie utilisée au build du consommateur est ce fichier, octet pour octet.
eQuantic.UI.Generators
Objet : le générateur de source qui écrit la surface déclarative de factories pour les composants de l'APPLICATION elle-même
Contient :
•
Le générateur seul. Sdk.props le livre comme analyseur (PrivateAssets="all"), c'est donc une dépendance de build et rien de lui ne part avec l'application
•
Désactivable avec <EQuanticGenerateFactorySurface>false</EQuanticGenerateFactorySurface>. Voir Surface déclarative
eQuantic.UI.Sdk
Objet : l'orchestrateur du SDK MSBuild
Contient :
•
Sdk.props - inclut d'office Primitives, Code, Components, Charts, Web, Server, le paquet bun de la plateforme et l'analyseur Generators
•
Sdk.targets - les cibles MSBuild pour la compilation, la copie de runtime.js, le catalogue de vecteurs et l'icône de l'application web
•
tools/net10.0/eqc.dll - l'exécutable du compilateur (projet eQuantic.Build)
•
tools/net10.0/eqicon.dll - l'outil d'icônes (projet eQuantic.UI.Native.Build) : Assets/**/*.svg → Vectors.g.cs, et l'icône de l'application → wwwroot/_equantic/icons
•
tools/netstandard2.0/eQuantic.UI.Sdk.Tasks.dll - les tâches MSBuild avec lesquelles le SDK démarre chaque programme (projet eQuantic.UI.Sdk.Tasks) : RunProgram, un programme et une liste d'arguments sans shell, et LinkDirectory, le lien vers node_modules dont un BunPackage a besoin. netstandard2.0 est ce que charge tout MSBuild, celui du SDK .NET comme celui de Visual Studio (Depuis 0.2.0-preview.62)
Les deux outils et les tâches atteignent tools/ comme arêtes du graphe de build du projet du SDK lui-même : des items ProjectReference avec ReferenceOutputAssembly="false" et PrivateAssets="All", dont la cible de pack CollectBuildOutput récupère la sortie. Rien ne se lie contre eux et le paquet ne gagne aucune dépendance.
Ne contient PAS :
•
❌ d'artefacts de runtime (il référence le paquet Server)
•
❌ les sources de Components (il référence le paquet Components)
Responsabilités :
1.
Gestion des paquets : inclut d'office les paquets nécessaires via Sdk.props
2.
Orchestration du build : coordonne la compilation, l'empaquetage et la génération des assets
3.
Résolution des artefacts : résout runtime.js et les sources des composants depuis leurs paquets
4.
Outillage : fournit le compilateur (eqc.dll) et l'outil d'icônes (eqicon.dll)
eQuantic.UI.Sdk.Native
Objet : le même SDK pour les appareils (macOS, iOS, Android). Voir Photon
Il répond aux deux questions ci-dessus de la même façon : les paquets frères se résolvent à la version du SDK lui-même, et l'outil qu'il lance (eqicon, pour l'icône de l'application, le bundle et le manifeste de capacités) est soit ce que l'arbre de sources vient de construire, soit ce que le paquet a livré sous tools/net10.0/.
eQuantic.UI.Lucide / Heroicons / ...
Objet : des catalogues d'icônes
Contient :
•
Un IconGlyph généré par icône, sous forme de propriété pour que le trimmer puisse jeter celles que personne ne nomme : des données write-once, utilisées sur le web comme en natif
•
Un EQuanticIconPack.marker à la racine des sources. Le SDK découvre un pack référencé grâce à ce marqueur et remet ses sources à eqc comme sources de référence, si bien qu'un glyphe est inliné au site d'usage et qu'aucun module JavaScript par pack n'est livré
•
Aucun appel d'enregistrement : référencer le paquet est toute la configuration. Voir Icônes
eQuantic.UI.Charts.ChartJs / ApexCharts
Objet : des composants de graphiques spécialisés
Contient :
•
Des enveloppes de graphiques
•
Des déclarations d'assets via IRequireAssets
•
API fluide : il s'enregistre lui-même via les extensions UseChartJs() / UseApexCharts() sur UIOptions.
Propriétés de paquet NuGet
NuGet génère une propriété $(Pkg*) pour un paquet installé SEULEMENT quand sa PackageReference porte GeneratePathProperty="true". Sdk.props la met exactement sur les paquets dont les cibles lisent le CONTENU, à savoir Components, Charts, Server et le paquet bun de la plateforme :
1
2
3
4
5
6
7
<!-- Auto-généré dans obj/*.nuget.g.props -->
<PropertyGroup>
<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>
</PropertyGroup>
Le SDK les utilise pour résoudre les artefacts :
1
2
3
4
5
6
7
<!-- Sdk/Sdk.targets -->
<Target Name="CopyEQuanticRuntime">
<PropertyGroup>
<_RuntimeSourcePath>$(PkgeQuantic_UI_Server)/tools/runtime/runtime.js</_RuntimeSourcePath>
</PropertyGroup>
<Copy SourceFiles="$(_RuntimeSourcePath)" DestinationFiles="..." />
</Target>
Bénéfices :
•
✅ Le SDK n'a pas besoin de connaître les détails de structure du paquet
•
✅ Fonctionne avec la version de paquet que le consommateur installe, quelle qu'elle soit
•
✅ Résolution automatique du cache par NuGet
•
✅ Aucun chemin écrit en dur
Gestion des versions
Une version
Chaque paquet est versionné depuis UNE ligne dans le Directory.Build.props du dépôt, et une étiquette de release les publie tous à cette version. Le numéro courant n'est pas cité ici à dessein : il change à chaque release, et un numéro périmé dans la documentation est la façon dont un lecteur est trompé. Lisez le fichier.
Le SDK fige ses frères à sa propre version
Sdk.props lit la version dans le nuspec du paquet SDK installé lui-même et demande chaque frère à cette version. Le repli est un joker, donc un build n'échoue jamais faute de numéro :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!-- Sdk/Sdk.props -->
<PropertyGroup Condition="'$(EQuanticUIVersion)' == '' AND Exists('$(_EQuanticSdkNuspecPath)')">
<EQuanticUIVersion>$([System.Text.RegularExpressions.Regex]::Match($([System.IO.File]::ReadAllText('$(_EQuanticSdkNuspecPath)')),
'&lt;version&gt;(.+?)&lt;/version&gt;').Groups[1].Value)</EQuanticUIVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(EQuanticUIVersion)' == ''">
<EQuanticUIVersion>*</EQuanticUIVersion>
</PropertyGroup>
<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)" />
<!-- Le Server porte aussi le runtime qu'il sert sous forme de fichier (tools/runtime/runtime.js). -->
<PackageReference Include="eQuantic.UI.Server" Version="$(EQuanticUIVersion)" GeneratePathProperty="true" />
<!-- plus le SEUL paquet eQuantic.UI.Runtime.{Os}{Arch} pour cette machine -->
</ItemGroup>
Ainsi le consommateur énonce la version UNE fois, dans l'entrée msbuild-sdks du global.json que le modèle estampille, et les frères suivent. Le SDK natif fait de même avec un repli *-*, pour qu'un SDK preview puisse restaurer ses propres frères preview.
On peut la surcharger :
1
2
3
<PropertyGroup>
<EQuanticUIVersion>la-version-voulue</EQuanticUIVersion>
</PropertyGroup>
La propriété déplace tous les frères ensemble ; les conditions ci-dessus ne l'assignent que lorsqu'elle est vide.
Scénario de développement contre scénario de consommation
Scénario de consommation (paquets NuGet)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
MonApp.csproj: <Project Sdk="eQuantic.UI.Sdk">
global.json: { "msbuild-sdks": { "eQuantic.UI.Sdk": "<version>" } }
dotnet restore
↓ Sdk.props : pas d'arbre de sources à côté → PackageReferences à $(EQuanticUIVersion)
↓ NuGet installe les paquets dans le cache
~/.nuget/packages/equantic.ui.server/<version>/
~/.nuget/packages/equantic.ui.components/<version>/
↓ NuGet génère les propriétés $(Pkg*)
obj/MonApp.csproj.nuget.g.props
↓ le SDK résout les artefacts
Sdk.targets utilise $(PkgeQuantic_UI_Server)/tools/runtime/runtime.js
↓ et lance les outils qu'il a livrés
<paquet du Sdk>/tools/net10.0/eqc.dll, eqicon.dll
Scénario de développement (arbre de sources)
Un build depuis l'arbre du dépôt lui-même (les exemples, le site, un scaffold à l'essai) ne passe par AUCUN paquet. Les mêmes Sdk.props et Sdk.targets détectent l'arbre à côté d'eux et basculent sur des références de projet ; il n'y a pas de feed local, pas de cache à vider, et pas d'étape de pack entre une modification et son effet. dotnet build samples/DefaultUIDashboard est toute la boucle.
Un exemple importe les deux fichiers du SDK directement :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- samples/DefaultUIDashboard/DefaultUIDashboard.csproj -->
<Project>
<Import Project="../../src/eQuantic.UI.Sdk/Sdk/Sdk.props" />
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
<!-- Les packs d'icônes sont OPT-IN : référencez les ensembles que vous utilisez. -->
<ItemGroup>
<ProjectReference Include="../../src/eQuantic.UI.Lucide/eQuantic.UI.Lucide.csproj" />
</ItemGroup>
<Import Project="../../src/eQuantic.UI.Sdk/Sdk/Sdk.targets" />
</Project>
Sdk.props tranche entre paquets et projets avec UNE propriété, et en mode développement il déclare en plus les deux outils de build comme arêtes du graphe de build :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!-- Sdk/Sdk.props -->
<IsEQuanticDevMode Condition="Exists('$(_DevRootDir)eQuantic.UI.Primitives/eQuantic.UI.Primitives.csproj')">true</IsEQuanticDevMode>
<ItemGroup Condition="'$(IsEQuanticDevMode)' == 'true'">
<!-- Les OUTILS de build que ce projet lance, en arêtes du graphe : rien ne se lie contre eux,
ils doivent seulement EXISTER avant que nos cibles tournent, ce qu'une arête garantit
exactement. -->
<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" />
<!-- plus le SEUL projet eQuantic.UI.Runtime.{Os}{Arch}, et eQuantic.UI.Generators en analyseur -->
</ItemGroup>
Pourquoi des arêtes et non une tâche <MSBuild> en ligne : un build en ligne lançait une SECONDE instance de chaque projet d'outil sous ses propres propriétés globales, en course avec le build de la solution vers le même bin/, et chaque cible qui lançait l'outil était gardée par Exists(eqicon.dll), qui répondait "non" sur un build à froid et "oui" sur le second. Cela a passé pendant des mois par l'accident de l'endroit où se trouvaient les projets dans le .sln. Une arête est ordonnée et sérialisée par MSBuild lui-même. Private="false" garde l'apphost et le json d'un exe hors du bin/ de l'application ; GlobalPropertiesToRemove empêche une tête d'appareil de remettre à un outil net10.0 simple son framework ou son identifiant de runtime.
Sdk.targets pose alors UNE question (y a-t-il un arbre de sources à côté de moi ?) pour décider où sont les deux outils, et d'où viennent les artefacts quand aucune propriété $(Pkg*) n'est posée :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- Sdk/Sdk.targets -->
<_SdkToolsDir>$(MSBuildThisFileDirectory)../tools/net10.0/</_SdkToolsDir>
<_EqSourceTree Condition="Exists('$(MSBuildThisFileDirectory)../../eQuantic.Build/eQuantic.Build.csproj')">true</_EqSourceTree>
<!-- Un arbre de sources lance ce que ses arêtes viennent de construire ; un paquet lance ce qu'il
a livré sous tools/. Un EqcCliPath que le projet énonce gagne sur les deux. -->
<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>
<!-- Artefacts : le $(Pkg*) du paquet d'abord, l'arbre à côté du SDK sinon -->
<_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>
Un outil manquant échoue de toute façon par son nom avant que quoi que ce soit ne tourne : EQ4002 pour eqc, EQ4001 pour eqicon : un graphe cassé dans un arbre de sources, un paquet cassé venu de NuGet, un mauvais chemin sous un EqcCliPath explicite. Aucun d'eux ne se règle en construisant deux fois. Voir Diagnostics.
Le répertoire artifacts/packages que le nuget.config du dépôt déclare encore comme source locale ne fait PAS partie de ce flux : rien dans un build depuis l'arbre de sources n'y écrit ni n'y lit. Pour valider une modification par le VRAI chemin du consommateur (paquets, global.json, restore), utilisez la recette de feed local dans Flux de build.
Bénéfices :
•
Qui développe le framework travaille directement avec les sources ; une modification est visible au dotnet build suivant
•
Pas de pack, pas de restore, pas d'étape de cache entre une modification et l'exemple qui la montre
•
Les mêmes Sdk.props et Sdk.targets marchent dans les deux scénarios : le chemin du consommateur n'est jamais un autre code, seulement une autre réponse à "y a-t-il un arbre à côté de moi ?"
Bonnes pratiques
✅ À faire
1.
Laissez chaque paquet gérer ses propres artefacts
•
Server empaquette le runtime.js qu'il sert
•
Components empaquette des fichiers source
2.
Référencez via les propriétés NuGet
•
Utilisez $(PkgeQuantic_UI_*) plutôt que des chemins écrits en dur
3.
Prévoyez des replis pour le développement
•
Permettez au SDK de trouver les artefacts dans l'arbre de sources quand on développe le framework
4.
Échouez par le nom
•
Un outil ou un artefact manquant est une erreur qui dit quel paquet ou quelle arête manque, jamais un avertissement et un build qui continue sans JavaScript
❌ À éviter
1.
N'embarquez pas les artefacts d'autres paquets
•
Le SDK ne devrait PAS copier le runtime.js du Server en lui
2.
N'utilisez pas de chemins relatifs entre paquets
•
Mauvais : $(MSBuildThisFileDirectory)../../../Server/tools/runtime/
•
Bon : $(PkgeQuantic_UI_Server)/tools/runtime/
3.
Ne déposez pas un outil à côté du SDK à la main
•
Une copie qu'un build antérieur a laissée là est périmée par construction ; le SDK lance ce que ses arêtes viennent de construire, ou ce que le paquet a livré
4.
Ne créez pas de dépendances circulaires
•
Les paquets doivent avoir un graphe de dépendances clair
Dépannage
runtime.js introuvable
1
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'.
Cause : $(PkgeQuantic_UI_Server) est vide, et il n'y a pas d'arbre de sources à côté du SDK dont le projet Server a écrit wwwroot/runtime.js (ce fichier est la sortie de build du Server)
Correctif :
1
2
3
dotnet restore --force
# Vérifiez que le paquet Server porte le runtime
ls ~/.nuget/packages/equantic.ui.server/<version>/tools/runtime/
Sources de Components introuvables
1
Error: eQuantic.UI: Standard components not found. Ensure the eQuantic.UI.Components package (version …) is installed.
Cause : $(PkgeQuantic_UI_Components) est vide et il n'y a pas d'arbre de sources à côté du SDK
Correctif :
1
2
3
dotnet restore --force
# Vérifiez que le paquet Components a des fichiers source
ls ~/.nuget/packages/equantic.ui.components/<version>/tools/source/
EQ4002 / EQ4001 : un outil de build manque
1
error EQ4002: The eQuantic compiler (eqc) is missing at '…/tools/net10.0/eqc.dll'. …
Cause : dans un arbre de sources, le projet de l'outil ne s'est pas construit avant celui-ci (un graphe de build cassé, lisez les erreurs AU-DESSUS de celle-ci) ; depuis un paquet, le paquet est sorti sans tools/net10.0/ ; avec un EqcCliPath explicite, le chemin nomme un fichier absent
Correctif : aucun d'eux ne se règle en construisant deux fois. Réparez le graphe, videz les paquets eQuantic du cache et restaurez à nouveau, ou corrigez le chemin. Voir Diagnostics
Mauvaise version utilisée
Symptôme : le build utilise un ancien runtime.js malgré un nouveau paquet Server
Cause : le cache NuGet n'a pas été vidé
Correctif :
1
2
3
4
5
# Videz ce paquet précis du cache
rm -rf ~/.nuget/packages/equantic.ui.server/<version>
# Forcez le restore
dotnet restore --force --no-cache
Depuis le checkout du framework, dotnet msbuild -t:ClearEQuanticCache retire du cache tous les paquets equantic.* d'un coup.
Documentation associée
•
Flux de build - la pipeline de build complète, et la recette du feed local
•
Runtime - l'architecture du runtime et sa distribution
•
Compilateur - comment fonctionne le compilateur C# vers JS
•
Diagnostics - chaque EQxxxx que rapportent le SDK et le compilateur