HotAvalonia

repository·main·Indexed 19 days ago

https://github.com/kira-nt/hotavalonia

An IDE-agnostic hot reload plugin for the Avalonia UI framework that allows developers to see XAML UI changes in real time during debugging. It supports Windows, Linux, macOS, and Android. The library provides capabilities for hot reloading XAML files and embedded assets (via MonoMod.RuntimeDetour), remote development via HARFS (HotAvalonia Remote File System), and customizable reload aggressiveness modes (Minimal, Balanced, Aggressive).

Tokens
8.2K
Snippets
19
Records
27
Agent score
68%

What's inside HotAvalonia

  1. Overview of HotAvalonia.Xaml primitives

    main

    The HotAvalonia.Xaml namespace contains the core logic for XAML hot reloading:

    • XamlDocument: Input for the compiler.
    • CompiledXamlDocument: Contains compiled control info (URI, root type) and methods to build or repopulate controls.
    • XamlCompiler: Compiles XamlDocument instances.
    • XamlScanner: Utilities for processing precompiled XAML, such as extracting controls from an assembly.
    • XamlPatcher: Handles complex scenarios like MergeResourceInclude. It replaces inlinable declarations with semantically identical but non-inlined versions (e.g., replacing MergeResourceInclude with ResourceInclude) to ensure changes to inlined resources trigger a hot reload.
  2. Use custom FileSystem accessors for remote or mobile development

    main

    HotAvalonia uses an IFileSystem to access source files. You can choose from several implementations:

    • FileSystem.Current: The default. Used when source files are on the same machine as the app.
    • FileSystem.Empty: A no-op fallback.
    • FileSystem.Connect(IPEndPoint, byte[] secret, IFileSystem fallbackFileSystem): Used for mobile/emulator development. Connects to a remote file system server (see HotAvalonia.Remote) to access source files on your development machine.

    To use a custom file system, pass it into an AvaloniaHotReloadConfig object, which is then used to create your AvaloniaHotReloadContext instances.

    // Connect to a file system server.
    IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse("192.168.0.42"), 20158);
    byte[] secret = Encoding.UTF8.GetBytes("My Super Secret Value");
    IFileSystem fileSystem = FileSystem.Connect(endpoint, secret, fallbackFileSystem: FileSystem.Empty);
    
    // Create a hot reload config.
    AvaloniaHotReloadConfig config = AvaloniaHotReloadConfig.Default with { FileSystem = fileSystem };
    
    // Add path hints if needed.
    config.ProjectLocator.AddHint(assembly => assembly.GetName().Name == "MyProject" ? "/home/user/projects/MyProject/src/MyProject" : null);
    
    // Provide your customized config to the hot reload context factories.
    IHotReloadContext appDomainContext = AvaloniaHotReloadContext.FromAppDomain(config);
    IHotReloadContext assetContext = AvaloniaHotReloadContext.ForAssets(config);
    
    // Finally, enable your combined hot reload context.
    _context = appDomainContext.Combine(assetContext);
    _context.EnableHotReload();
  3. Run the HotAvalonia.Remote (HARFS) server

    main

    The harfs executable runs a secure, read-only file system server that enables hot reload on remote devices. It requires a root directory and a secret for authentication. You can specify the network address, port, and security certificates via CLI flags.

    # Example: Serve a specific directory with a plain text secret on a specific IP and port
    harfs --root "C:/Files" --secret text:MySecret --address 192.168.1.100 --port 8080
    
    # Example: Serve a directory using an environment variable for the secret and a specific endpoint
    harfs -r "/home/user/files" -s env:MY_SECRET -e 0.0.0.0:20158 --allow-shutdown-requests
  4. Enable hot reload for embedded assets via MonoMod.RuntimeDetour

    main

    By default, HotAvalonia only supports hot reloading XAML files. If you need to hot reload embedded assets such as icons and images, you must add the MonoMod.RuntimeDetour package to your startup project. This allows HotAvalonia to perform method injections into optimized code.

    <PackageReference Include="MonoMod.RuntimeDetour" Version="*" PrivateAssets="All" />
  5. Build HotAvalonia.Remote (HARFS) as a standalone executable

    main

    To compile HotAvalonia.Remote (also known as HARFS) as a standalone native executable, use the dotnet publish command. You can optionally enable UPX compression to reduce the binary size using the PublishLzmaCompressed property.

    # Standard build
    dotnet publish --ucr -f net9.0 -p:AssemblyName=harfs -o ./dist
    
    # Build with UPX compression for smaller binary size
    dotnet publish --ucr -f net9.0 -p:AssemblyName=harfs -p:PublishLzmaCompressed=true -o ./dist
  6. Configure HotAvalonia.Fody via WeaverConfiguration

    main

    If you are using HotAvalonia.Fody directly, you can configure it either via FodyWeavers.xml or by using the WeaverConfiguration property in your project file.

    Below is an example of configuring the weaver within a .csproj file, defining the solution path, project paths, and specific feature settings.

    <PropertyGroup>
      <WeaverConfiguration>
        <Weavers>
          <HotAvalonia>
            <Solution Path="$(SolutionPath)">
              <Project Path="/home/user/projects/MyApp/src/MyApp/MyApp.csproj" AssemblyName="MyApp" />
              <Project Path="/home/user/projects/MyApp/src/MyApp.Desktop/MyApp.Desktop.csproj" AssemblyName="MyApp.Desktop" />
            </Solution>
            <PopulateOverride Enable="true" />
            <UseHotReload Enable="true" GeneratePathResolver="true" />
            <References Enable="false" Exclude="HotAvalonia.Core;Avalonia.Markup.Xaml.Loader" />
          </HotAvalonia>
        </Weavers>
      </WeaverConfiguration>
    </PropertyGroup>
  7. Install HotAvalonia

    main

    To enable hot reload for Avalonia XAML files, add the following package references to your project file (.csproj, .fsproj, or .vbproj).

    Important Requirements:

    • Startup Project: HotAvalonia must be installed in your startup project (the one producing the final executable).
    • Multi-project setups: It is highly recommended to also install it in every project containing Avalonia controls for maximum stability.
    • Development Only: HotAvalonia is a development-only dependency and will not affect Release builds or be shipped with your application.
    <!-- Don't forget to replace $(AvaloniaVersion) with the actual Avalonia package version. -->
    <PackageReference Include="Avalonia.Markup.Xaml.Loader" Version="$(AvaloniaVersion)" PrivateAssets="All" Publish="True" />
    <PackageReference Include="HotAvalonia" Version="3.*" PrivateAssets="All" Publish="True" />
  8. Enable PopulateOverride for Avalonia resources

    main

    The PopulateOverride feature injects logic into Avalonia resources (like styles and resource dictionaries) to allow their original Populate method to be overridden at runtime. This is useful in environments where method injection is unavailable.

    Important: For this to work, Fody must run after Avalonia has compiled the XAML files. You must ensure this dependency in your project file:

    <FodyDependsOnTargets>$(FodyDependsOnTargets);CompileAvaloniaXaml</FodyDependsOnTargets>
    NameDescriptionDefault
    EnableEnables the PopulateOverride feature weaver.false
  9. Enable UseHotReload to automate app initialization

    main

    The UseHotReload feature automatically calls HotAvalonia.AvaloniaHotReloadExtensions.UseHotReload(AppBuilder) on your AppBuilder instance during app initialization. This allows you to enable hot reload without modifying your source code.

    NameDescriptionDefault
    EnableEnables the UseHotReload feature weaver.false
    GeneratePathResolverIf true, automatically generates HotAvalonia.AvaloniaHotReloadExtensions.ResolveProjectPath(Assembly) based on the <Solution> element if it doesn't already exist.false
  10. Configure HotAvalonia.Core dependencies

    main

    When installing HotAvalonia.Core, you need to manage its shadow dependencies in your project file:

    1. Avalonia.Markup.Xaml.Loader (Required): This is the official Avalonia package for runtime XAML parsing. Crucial: Its version must match your application's Avalonia package version.
    2. MonoMod.RuntimeDetour (Optional): Including this enables injection-based hot reload, which is required if you want to hot reload embedded assets like icons and images.
    <PackageReference Include="HotAvalonia.Core" Version="..." PrivateAssets="All" />
    <PackageReference Include="Avalonia.Markup.Xaml.Loader" Version="..." PrivateAssets="All" />
    <!-- Include the following for embedded asset hot reload support -->
    <!-- <PackageReference Include="MonoMod.RuntimeDetour" Version="*" PrivateAssets="All" /> -->
  11. Configure HotAvalonia via MSBuild DefineConstants

    main

    The behavior of AvaloniaHotReloadExtensions is controlled by compiler constants defined in your project file (<DefineConstants>). Use these to enable features, strip code from Release builds, or provide custom implementations.

    <!-- Example of how these might be applied in a .csproj file -->
    <PropertyGroup>
      <DefineConstants>$(DefineConstants);HOTAVALONIA_ENABLE</DefineConstants>
    </PropertyGroup>