eQuantic.UIeQuantic.UI
Docs
Playground
GitHub
DocsArchitecture
Package Architecture
Edit this page
11 min read
This document explains eQuantic.UI's package architecture and the principles behind its self-contained design.
Core Principle: Self-Contained Packages
Each eQuantic.UI package is self-contained and manages its own artifacts. The SDK acts as an orchestrator that references other packages via NuGet's auto-generated properties.
The Design Rationale
Anti-pattern the design rejects, the SDK embedding other packages' artifacts:
1
2
3
eQuantic.UI.Sdk.nupkg
❌
├─ tools/runtime/runtime.js (copied from Server)
└─ tools/StandardComponents/*.cs (copied from Components)
Why that shape fails:
•
Tight Coupling: SDK has direct knowledge of Server and Components internals
•
Version Conflicts: the consumer restores one Server version and the SDK carries a copy from another
•
Artifact Duplication: Same files exist in multiple packages
•
Inflexible: Can't update Server or Components without republishing SDK
The Architecture: Self-Contained Packages
1
2
3
4
5
6
7
8
9
10
11
12
13
eQuantic.UI.Server.nupkg
✅
├─ lib/net10.0/eQuantic.UI.Server.dll (embeds the runtime it serves at /_equantic/runtime.js)
└─ tools/runtime/runtime.js (the same bytes, for the SDK to copy)
eQuantic.UI.Components.nupkg
✅
└─ tools/source/*.cs (self-managed)
eQuantic.UI.Sdk.nupkg
✅
├─ Sdk/Sdk.props (auto-includes Primitives, Code, Components, Charts, Web, Server,
│ the platform bun package and the Generators analyzer)
├─ Sdk/Sdk.targets (resolves the other packages' artifacts via $(Pkg*) properties)
├─ tools/net10.0/ (eqc and eqicon, the two build tools the SDK runs)
└─ tools/netstandard2.0/ (the tasks that start them, and every other program, with no shell)
Benefits:
•
✅ Decoupling: Each package owns and manages its artifacts
•
✅ Correct Versioning: Consumer's installed version is always used
•
✅ No Duplication: Single source of truth per artifact
•
✅ Independent Evolution: Packages can be updated separately
•
✅ Clear Interface: SDK uses well-defined NuGet properties
Package Responsibilities
There is no eQuantic.UI.Core package. It was dissolved into the assemblies that owned its parts: the DOM surface went to Web, the contract attributes to Primitives, metadata and assets to Server, image optimization state to Images. A page that imported eQuantic.UI.Core for [Page] or [ServerAction] deletes the line: the namespace it already imports for the vocabulary carries them.
eQuantic.UI.Primitives
Purpose: The abstract vocabulary and the contracts
Contains:
•
The visual vocabulary a component is written against: nodes, layout, typed styles, tokens, theme
•
The component bases, StatelessComponent and StatefulComponent
•
The contract attributes: [Page], [ServerAction], [ServerOnly], [Authorize], [AllowAnonymous], [FormModel], [UiFactory]
Packages: Only compiled DLL (no additional artifacts). Zero dependencies.
eQuantic.UI.Web
Purpose: The web realizer, and the DOM escape hatch
Contains:
•
The realizer that lowers the shared components to DOM and atomic CSS
•
The escape hatch: HtmlElement, HtmlNode, HtmlStyle, DynamicElement, IComponent, RenderContext, ClassBuilder
Packages: Only compiled DLL (no additional artifacts)
eQuantic.UI.Components
Purpose: The write-once component library (Button, Input, Card, etc.), authored against Primitives and realized per target
Contains:
•
Compiled DLL for runtime usage
•
Source files (tools/source/*.cs) for compiler type resolution, with the SDK's own .resx beside its Designer
Packaging:
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>
Why Source Files?
The compiler (eqc.dll) builds a semantic model of the page it transpiles, and that model needs the component definitions: when a page composes Button(…), the compiler reads the Button class from the Components sources. The library's JavaScript is NOT compiled per app: the transpiled modules ship inside runtime.js, and eqc routes using eQuantic.UI.Components imports there.
SDK Usage:
1
2
3
4
5
6
7
8
<!-- Sdk/Sdk.targets, target CompileEQuanticUI -->
<_StandardComponentsDir Condition="'$(PkgeQuantic_UI_Components)' != ''">$(PkgeQuantic_UI_Components)/tools/source</_StandardComponentsDir>
<_EqcSourceDirs>$(MSBuildProjectDirectory);$(_StandardComponentsDir)</_EqcSourceDirs>
<!-- Handed to the compiler in a response file, one argument a line, with the exact assemblies
csc compiles against (refs). eqc is started with RunProgram, the compiler and that file as a
list of arguments, so no shell reads a path or a name on the way -->
<RunProgram Program="dotnet" Arguments="@(_EqcStartArgument)" />
eQuantic.UI.Runtime
Purpose: The browser runtime's TypeScript (Virtual DOM, reconciler, state management) and its proof
Packages: Nothing. The project is not packed (IsPackable=false): the bundle an app runs is written by eQuantic.UI.Server from boot.ts, which imports this TypeScript, and that package carries it (below). What the project runs is the runtime's proof, through the embedded bun: dotnet build src/eQuantic.UI.Runtime -t:TestRuntime installs the dependencies from bun.lock as pinned, type-checks with tsc and runs vitest once.
eQuantic.UI.Runtime.{Os}{Arch}
Purpose: The embedded Bun, one package per OS and architecture: Osx64, OsxArm64, Win64, WinArm64, Linux64, LinuxArm64
Contains:
•
The Bun executable, zipped (tools/bun/bun-darwin.zip, bun-linux.zip or bun.exe.zip); the SDK extracts it on the first build
•
Nothing else. The packages declare no dependencies
Why Separate Packages?
•
Sdk.props references exactly ONE of them, chosen by [MSBuild]::IsOSPlatform and the machine's OSArchitecture, so a consumer downloads one binary, never six
•
Clean separation of runtime logic vs. build tools
•
The version and the SHA-256 of every zip are pinned in bun-toolchain.json and checked by the tests. See Build Flow
eQuantic.UI.Server
Purpose: ASP.NET Core integration
Contains:
•
Server-side rendering (SSR)
•
Server Actions RPC system
•
Middleware and routing
•
Metadata (SeoBuilder, MetaTags, IHandleMetadata) and assets (IRequireAssets, AssetBuilder)
•
Embedded runtime.js served at /_equantic/runtime.js
•
tools/runtime/runtime.js: the same bytes as a file, for the SDK to copy beside an app's modules
Note: the Server is the runtime's one writer. Its BundleRuntime target bundles boot.ts into wwwroot/runtime.js before every build; the compiler embeds that file as an EmbeddedResource, which is what /_equantic/runtime.js answers, and the pack target CollectServedRuntime puts the same file at tools/runtime/runtime.js. The consumer's build-time copy is that file, byte for byte.
eQuantic.UI.Generators
Purpose: The source generator that writes the declarative factory surface for the APP's own components
Contains:
•
The generator only. Sdk.props delivers it as an analyzer (PrivateAssets="all"), so it is a build-time dependency and nothing of it ships with the app
•
Opt out with <EQuanticGenerateFactorySurface>false</EQuanticGenerateFactorySurface>. See Declarative Surface
eQuantic.UI.Sdk
Purpose: MSBuild SDK orchestrator
Contains:
•
Sdk.props - Auto-includes Primitives, Code, Components, Charts, Web, Server, the platform bun package and the Generators analyzer
•
Sdk.targets - MSBuild targets for compilation, the runtime.js copy, the vector catalog and the web app icon
•
tools/net10.0/eqc.dll - The compiler executable (project eQuantic.Build)
•
tools/net10.0/eqicon.dll - The icon tool (project eQuantic.UI.Native.Build): Assets/**/*.svg → Vectors.g.cs, and the app icon → wwwroot/_equantic/icons
•
tools/netstandard2.0/eQuantic.UI.Sdk.Tasks.dll - The MSBuild tasks the SDK starts every program with (project eQuantic.UI.Sdk.Tasks): RunProgram, a program and a list of arguments with no shell, and LinkDirectory, the node_modules link a BunPackage needs. netstandard2.0 is what every MSBuild loads, the .NET SDK's and Visual Studio's (Since 0.2.0-preview.62)
The two tools and the tasks reach tools/ as edges of the SDK project's own build graph: ProjectReference items with ReferenceOutputAssembly="false" and PrivateAssets="All", whose output the pack target CollectBuildOutput collects. Nothing links against them and the package gains no dependency.
Does NOT Contain:
•
❌ Runtime artifacts (references the Server package)
•
❌ Components source (references Components package)
Responsibilities:
1.
Package Management: Auto-includes required packages via Sdk.props
2.
Build Orchestration: Coordinates compilation, bundling and asset generation
3.
Artifact Resolution: Resolves runtime.js and component sources from their packages
4.
Tooling: Provides the compiler (eqc.dll) and the icon tool (eqicon.dll)
eQuantic.UI.Sdk.Native
Purpose: The same SDK for devices (macOS, iOS, Android). See Photon
It answers the two questions above the same way: the sibling packages resolve at the SDK's own version, and the tool it runs (eqicon, for the app icon, the bundle and the capability manifest) is either what the source tree just built or what the package shipped under tools/net10.0/.
eQuantic.UI.Lucide / Heroicons / ...
Purpose: Icon catalogs
Contains:
•
A generated IconGlyph per icon, as a property so the trimmer can drop the ones nobody names: write-once data, used on web and native alike
•
An EQuanticIconPack.marker at the source root. The SDK discovers a referenced pack by that marker and hands its sources to eqc as reference sources, so a glyph is inlined at the use site and no per-pack JavaScript module is shipped
•
No registration call: referencing the package is the whole setup. See Icons
eQuantic.UI.Charts.ChartJs / ApexCharts
Purpose: Specialized chart components
Contains:
•
Chart wrappers
•
Asset declarations via IRequireAssets
•
Fluent API: Registers itself via UseChartJs() / UseApexCharts() extensions on UIOptions.
NuGet Package Properties
NuGet generates a $(Pkg*) property for an installed package ONLY when its PackageReference carries GeneratePathProperty="true". Sdk.props sets it on exactly the packages whose CONTENT the targets read, namely Components, Charts, Server and the platform bun package:
1
2
3
4
5
6
7
<!-- Auto-generated in 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>
SDK uses these to resolve artifacts:
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>
Benefits:
•
✅ SDK doesn't need to know package structure details
•
✅ Works with whatever package version the consumer installs
•
✅ Automatic cache resolution by NuGet
•
✅ No hardcoded paths
Version Management
One Version
Every package is versioned from ONE line in the repository's Directory.Build.props, and a release tag publishes them all at that version. The current number is not quoted here on purpose: it changes every release, and a stale number in the docs is how a reader is misled. Read the file.
The SDK Pins Its Siblings to Its Own Version
Sdk.props reads the version from the installed SDK package's own nuspec and asks for every sibling at that version. The fallback is a wildcard, so a build never fails for lack of a number:
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)" />
<!-- The Server carries the runtime it serves as a file too (tools/runtime/runtime.js). -->
<PackageReference Include="eQuantic.UI.Server" Version="$(EQuanticUIVersion)" GeneratePathProperty="true" />
<!-- plus the ONE eQuantic.UI.Runtime.{Os}{Arch} package for this machine -->
</ItemGroup>
So the consumer states the version ONCE, in the msbuild-sdks entry in global.json that the template stamps, and the siblings follow. The native SDK does the same with a *-* fallback, so a preview SDK can restore its own preview siblings.
Users can override:
1
2
3
<PropertyGroup>
<EQuanticUIVersion>the-version-you-want</EQuanticUIVersion>
</PropertyGroup>
The property moves every sibling together; the conditions above only assign it when it is empty.
Development vs. Consumer Scenarios
Consumer Scenario (NuGet Packages)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
MyApp.csproj: <Project Sdk="eQuantic.UI.Sdk">
global.json: { "msbuild-sdks": { "eQuantic.UI.Sdk": "<version>" } }
dotnet restore
↓ Sdk.props: no source tree beside it → PackageReferences at $(EQuanticUIVersion)
↓ NuGet installs packages to cache
~/.nuget/packages/equantic.ui.server/<version>/
~/.nuget/packages/equantic.ui.components/<version>/
↓ NuGet generates $(Pkg*) properties
obj/MyApp.csproj.nuget.g.props
↓ SDK resolves artifacts
Sdk.targets uses $(PkgeQuantic_UI_Server)/tools/runtime/runtime.js
↓ and runs the tools it shipped
<Sdk package>/tools/net10.0/eqc.dll, eqicon.dll
Development Scenario (Source Tree)
A build from the repository's own tree (the samples, the site, a scaffold under test) goes through NO package. The same Sdk.props and Sdk.targets detect the tree beside them and switch to project references; there is no local feed, no cache to clear, and no pack step between an edit and its effect. dotnet build samples/DefaultUIDashboard is the whole loop.
A sample imports the SDK's two files directly:
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>
<!-- Icon packs are OPT-IN: reference the sets you use. -->
<ItemGroup>
<ProjectReference Include="../../src/eQuantic.UI.Lucide/eQuantic.UI.Lucide.csproj" />
</ItemGroup>
<Import Project="../../src/eQuantic.UI.Sdk/Sdk/Sdk.targets" />
</Project>
Sdk.props decides between packages and projects with ONE property, and in dev mode it also declares the two build tools as edges of the build graph:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!-- Sdk/Sdk.props -->
<IsEQuanticDevMode Condition="Exists('$(_DevRootDir)eQuantic.UI.Primitives/eQuantic.UI.Primitives.csproj')">true</IsEQuanticDevMode>
<ItemGroup Condition="'$(IsEQuanticDevMode)' == 'true'">
<!-- The BUILD TOOLS this project runs, as graph edges: nothing links against them, they only
have to EXIST before our targets run, which is exactly what an edge guarantees. -->
<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 the ONE eQuantic.UI.Runtime.{Os}{Arch} project, and eQuantic.UI.Generators as an analyzer -->
</ItemGroup>
Why edges and not an inline <MSBuild> task: an inline build ran a SECOND instance of each tool project under its own global properties, racing the solution's own build into the same bin/, and every target that ran the tool was guarded by Exists(eqicon.dll), which answered "no" on a cold build and "yes" on the second. It passed for months by the accident of where the projects sat in the .sln. An edge is ordered and serialized by MSBuild itself. Private="false" keeps an exe's apphost and json out of the app's bin/; GlobalPropertiesToRemove keeps a device head from handing a plain net10.0 tool its framework or runtime identifier.
Sdk.targets then asks ONE question (is there a source tree beside me?) to decide where both tools are, and where the artifacts come from when no $(Pkg*) property is set:
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>
<!-- A source tree runs what its edges just built; a package runs what it shipped under tools/.
An EqcCliPath the project states wins over both. -->
<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>
<!-- Artifacts: the package's $(Pkg*) first, the tree beside the SDK otherwise -->
<_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>
A tool that is missing anyway fails by name before anything runs: EQ4002 for eqc, EQ4001 for eqicon: a broken graph in a source tree, a broken package from NuGet, a wrong path under an explicit EqcCliPath. None of them is fixed by building twice. See Diagnostics.
The artifacts/packages directory the repository's nuget.config still declares as a local source is NOT part of this flow: nothing in a source-tree build writes to it or reads from it. To validate a change through the REAL consumer path (packages, global.json, restore), use the local-feed recipe in Build Flow.
Benefits:
•
Framework developers work directly with source; an edit is visible on the next dotnet build
•
No pack, no restore, no cache step between an edit and the sample that shows it
•
Same Sdk.props and Sdk.targets work for both scenarios: the consumer path is never a different code path, only a different answer to "is there a tree beside me?"
Best Practices
✅ Do
1.
Let packages manage their own artifacts
•
Server packages the runtime.js it serves
•
Components packages source files
2.
Reference via NuGet properties
•
Use $(PkgeQuantic_UI_*) instead of hardcoded paths
3.
Provide development fallbacks
•
Allow SDK to find artifacts in source tree when developing the framework
4.
Fail by name
•
A missing tool or artifact is an error that says which package or which edge is missing, never a warning and a build that goes on without JavaScript
❌ Don't
1.
Don't embed other packages' artifacts
•
SDK should NOT copy the Server's runtime.js into itself
2.
Don't use relative paths across packages
•
Bad: $(MSBuildThisFileDirectory)../../../Server/tools/runtime/
•
Good: $(PkgeQuantic_UI_Server)/tools/runtime/
3.
Don't stage a tool beside the SDK by hand
•
A copy an earlier build left there is stale by construction; the SDK runs what its edges just built, or what the package shipped
4.
Don't create circular dependencies
•
Packages should have clear dependency graph
Troubleshooting
Runtime.js not found
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) is empty, and there is no source tree beside the SDK whose Server project has written wwwroot/runtime.js (that file is the Server's build output)
Fix:
1
2
3
dotnet restore --force
# Check that the Server package carries the runtime
ls ~/.nuget/packages/equantic.ui.server/<version>/tools/runtime/
Components source not found
1
Error: eQuantic.UI: Standard components not found. Ensure the eQuantic.UI.Components package (version …) is installed.
Cause: $(PkgeQuantic_UI_Components) is empty and there is no source tree beside the SDK
Fix:
1
2
3
dotnet restore --force
# Verify the Components package has source files
ls ~/.nuget/packages/equantic.ui.components/<version>/tools/source/
EQ4002 / EQ4001: a build tool is missing
1
error EQ4002: The eQuantic compiler (eqc) is missing at '…/tools/net10.0/eqc.dll'. …
Cause: in a source tree, the tool's project did not build before this one (a broken build graph, read the errors ABOVE this one); from a package, the package shipped without tools/net10.0/; with an explicit EqcCliPath, the path names a file that is not there
Fix: none of them is fixed by building twice. Fix the graph, clear the eQuantic packages from the cache and restore again, or fix the path. See Diagnostics
Using wrong version
Symptom: Build uses old runtime.js despite a new Server package
Cause: NuGet cache not cleared
Fix:
1
2
3
4
5
# Clear the specific package from the cache
rm -rf ~/.nuget/packages/equantic.ui.server/<version>
# Force restore
dotnet restore --force --no-cache
From the framework checkout, dotnet msbuild -t:ClearEQuanticCache removes every equantic.* package from the cache at once.
Related Documentation
•
Build Flow - Complete build pipeline, and the local-feed recipe
•
Runtime - Runtime architecture and distribution
•
Compiler - How the C# to JS compiler works
•
Diagnostics - Every EQxxxx the SDK and the compiler report