Runic Assets

August 12, 2026 · View on GitHub

Runic Assets banner

Runic Assets

Package a Vite build once, embed it in your .NET application, and serve the same validated asset manifest in desktop, ASP.NET Core, or Runic Toolkit hosts. Runic Assets keeps paths, content metadata, caching, and archives independent of the UI and hosting framework, so the asset boundary stays portable from development through NativeAOT deployment.

Choose a package

All packages target .NET 10 and are currently published as previews. Use --prerelease until a stable release is available.

PackageChoose it whenInstall
RunicAssetsYou need the framework-neutral manifest, embedded sources, development sources, or Vite archive embedding.dotnet add package RunicAssets --prerelease
RunicAssets.AspNetCoreYou want exact GET endpoints for a Runic Assets source in ASP.NET Core.dotnet add package RunicAssets.AspNetCore --prerelease
RunicAssets.CsWebUiYou ship a private CS-WebUI desktop application and want it to serve a Runic Assets source.dotnet add package RunicAssets.CsWebUi --prerelease
RunicAssets.RunicToolkitYour Runic Toolkit host accepts IFrontendAssetProvider.dotnet add package RunicAssets.RunicToolkit --prerelease

Each adapter brings in RunicAssets transitively. See the individual package READMEs for a host-specific example.

Vite dist to an embedded archive

Use this path when a Vite build should travel inside your .NET application—no runtime static-files directory or per-file resource registrations required.

  1. Install the core package in the .NET application project:

    dotnet add package RunicAssets --prerelease
    
  2. Build the Vite application so its output directory exists:

    npm run build
    
  3. Point the application project at Vite's generated dist directory:

    <PropertyGroup>
      <RunicAssetsDist>../Client.Web/dist</RunicAssetsDist>
    </PropertyGroup>
    
  4. Build the .NET application, then load the embedded archive:

    dotnet build
    
    using System.Reflection;
    using RunicAssets;
    
    AssetArchiveSource assets = AssetArchive.ReadEmbedded(
        Assembly.GetExecutingAssembly());
    

The build target packages the complete directory into a canonical archive and embeds it as RunicAssets.StaticFiles. It is incremental and runs again when the project, target, packer, or a file under RunicAssetsDist changes. The archive remains embedded in single-file, trimmed, and NativeAOT applications; reading it does not extract files to disk.

index.html is the default entry point. Configure an alternate entry point or exclude generated files when necessary:

<PropertyGroup>
  <RunicAssetsEntryPoint>app.html</RunicAssetsEntryPoint>
  <RunicAssetsDistExclude>runic-assets.zip;stats.html</RunicAssetsDistExclude>
</PropertyGroup>

To embed an archive produced elsewhere, set RunicAssetsEmbeddedArchive instead of RunicAssetsDist. Change the logical resource name with RunicAssetsEmbeddedResourceName and pass the same name to AssetArchive.ReadEmbedded.

What travels with the assets

Every manifest entry has an exact safe path, media type, byte length, SHA-256 digest, strong entity tag, and cache policy. HTML uses revalidation caching; Vite's built non-HTML assets use immutable caching. AssetArchive is a standard ZIP with a validated runic-assets.json manifest; archive read limits can be set with AssetArchiveReadOptions when consuming untrusted input.

For development, DevelopmentDirectoryAssetSource provides refreshable local files with no-store caching. For small, hand-authored bundles, EmbeddedAssetSource maps explicit assembly resources directly.

Documentation and support

Preview packages are built and validated before release. Follow the repository for release status and use the issue tracker for questions and bug reports.