Skip to content

Commit

Permalink
feat: Generate HotReload-friendly merged file when HR is enabled
Browse files Browse the repository at this point in the history
  • Loading branch information
Youssef1313 committed Nov 8, 2023
1 parent de82876 commit 333dd48
Show file tree
Hide file tree
Showing 9 changed files with 119 additions and 5 deletions.
3 changes: 2 additions & 1 deletion src/Directory.Build.props
@@ -1,7 +1,8 @@
<Project ToolsVersion="15.0">

<PropertyGroup>
<PropertyGroup>
<Authors>unoplatform</Authors>
<LangVersion>11</LangVersion>
<PackageProjectUrl>https://github.com/unoplatform/uno.xamlmerge.task</PackageProjectUrl>
<PackageIconUrl>https://nv-assets.azurewebsites.net/logos/uno.png</PackageIconUrl>
<RepositoryUrl>https://github.com/unoplatform/uno.xamlmerge.task</RepositoryUrl>
Expand Down
74 changes: 74 additions & 0 deletions src/Uno.XamlMerge.Task/BatchMergeXaml.cs
Expand Up @@ -11,6 +11,7 @@
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;

namespace Uno.UI.Tasks.BatchMerge
Expand All @@ -28,6 +29,8 @@ public class BatchMergeXaml_v0 : CustomTask
[Required]
public string ProjectFullPath { get; set; }

public bool IsHotReloadEnabled { get; set; }

[Output]
public string[] FilesWritten
=> _filesWritten.ToArray();
Expand All @@ -44,6 +47,12 @@ public override bool Execute()
var filteredPages = Pages.ToList();
filteredPages.RemoveAll(e => MergedXamlFiles.Any(m => FullPathComparer.Default.Equals(e, m)));

if (IsHotReloadEnabled)
{
GenerateForHotReload(filteredPages);
return !HasLoggedErrors;
}

if (MergedXamlFiles.Length > 1)
{
foreach (var mergedXamlFile in MergedXamlFiles)
Expand All @@ -69,6 +78,71 @@ public override bool Execute()
return !HasLoggedErrors;
}

private string GenerateMergedDictionariesForHotReload(IEnumerable<ITaskItem> filteredPages)
{
var projectBasePath = Path.GetDirectoryName(Path.GetFullPath(ProjectFullPath));

var builder = new StringBuilder();
builder.Append("""
<!-- Generating a resource dictionary that references existing dictionaries for HotReload support -->
<!-- Proper merging of XAML files will happen if you build in Release configuration -->
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">
<ResourceDictionary.MergedDictionaries>

""");

foreach (var page in filteredPages)
{
var pagePath = Path.GetFullPath(page.ItemSpec).Replace(projectBasePath, "").TrimStart(Path.DirectorySeparatorChar).Replace('\\', '/');
builder.Append($"""
<ResourceDictionary Source="ms-appx:///{pagePath}" />

""");
}

builder.Append("""
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

""");

return builder.ToString();
}

/// <summary>
/// When HotReload is enabled, we want modifications to the original XAML files to be reflected.
/// This cannot be achieved when an actual merge happens.
/// So, for HotReload, we'll generate a XAML file that only references the original XAML files and not do an actual merge.
/// This way, it can work with HotReload perfectly.
/// </summary>
private void GenerateForHotReload(List<ITaskItem> filteredPages)
{
if (MergedXamlFiles.Length > 1)
{
foreach (var mergedXamlFile in MergedXamlFiles)
{
var mergeFileName = Path.GetFileName(mergedXamlFile.ItemSpec);
string fileContents = GenerateMergedDictionariesForHotReload(filteredPages.Where(p => string.Equals(p.GetMetadata("MergeFile"), mergeFileName, StringComparison.OrdinalIgnoreCase)));

Directory.CreateDirectory(Path.GetDirectoryName(mergedXamlFile.ItemSpec));
Utils.RewriteFileIfNecessary(mergedXamlFile.ItemSpec, fileContents);
}
}
else if (MergedXamlFiles.Length == 1)
{
// Single target file, without "MergeFile" attribution
var mergedXamlFile = MergedXamlFiles[0];
var mergeFileName = Path.GetFileName(mergedXamlFile.ItemSpec);
string fileContents = GenerateMergedDictionariesForHotReload(filteredPages);

Directory.CreateDirectory(Path.GetDirectoryName(mergedXamlFile.ItemSpec));
Utils.RewriteFileIfNecessary(mergedXamlFile.ItemSpec, fileContents);
}
}

private void ValidatePageMergeFileMetadata()
{
if (MergedXamlFiles.Length > 1)
Expand Down
1 change: 0 additions & 1 deletion src/Uno.XamlMerge.Task/Uno.XamlMerge.Task.csproj
Expand Up @@ -4,7 +4,6 @@
<TargetFramework>netstandard2.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>10.0</LangVersion>
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
<IsTool>true</IsTool>
<AssemblyName>Uno.XamlMerge.Task.v0</AssemblyName>
Expand Down
7 changes: 6 additions & 1 deletion src/Uno.XamlMerge.Task/build/Uno.XamlMerge.Task.targets
Expand Up @@ -12,9 +12,14 @@
DependsOnTargets="_XamlMergeFillProperties"
Condition="'$(BuildingProject)' == 'true' or '$(DesignTimeBuild)' != 'true'">

<PropertyGroup>
<BatchMergeGenerateForHotReload Condition="'$(Configuration)' == 'Debug' and '$(BatchMergeGenerateForHotReload)'==''">true</BatchMergeGenerateForHotReload>
</PropertyGroup>

<BatchMergeXaml_v0
ProjectFullPath="$(MSBuildProjectFullPath)"
Pages="@(XamlMergeInput)"
IsHotReloadEnabled="$(BatchMergeGenerateForHotReload)"
MergedXamlFiles="@(XamlMergeOutputFiles)" />
<Message Text="Merged resources XAML file was generated in $(XamlMergeOutputFile)" />

Expand All @@ -26,7 +31,7 @@
DependsOnTargets="_XamlMergeFillProperties">

<ItemGroup>
<Page Remove="@(XamlMergeInput)" />
<Page Remove="@(XamlMergeInput)" Condition="'$(BatchMergeGenerateForHotReload)' != 'true'" />
</ItemGroup>

<GeneratePageList_v0
Expand Down
13 changes: 12 additions & 1 deletion src/Uno.XamlMerge.Tests/Given_BatchMergeXaml.cs
Expand Up @@ -27,6 +27,16 @@ public void When_Empty()
ValidateOutput(task);
}

[TestMethod]
public void When_HR_Enabled()
{
var task = CreateMerger(isHotReloadEnabled: true);

Assert.IsTrue(task.Execute());

ValidateOutput(task);
}

[TestMethod]
public void When_Key_TargeType_Conflict()
{
Expand Down Expand Up @@ -324,7 +334,7 @@ private void ValidateOutput(BatchMergeXaml_v0 task, [CallerMemberName] string te
}
}

private BatchMergeXaml_v0 CreateMerger([CallerMemberName] string testName = "")
private BatchMergeXaml_v0 CreateMerger(bool isHotReloadEnabled = false, [CallerMemberName] string testName = "")
{
var basePath = GetBasePath(testName);

Expand Down Expand Up @@ -364,6 +374,7 @@ private BatchMergeXaml_v0 CreateMerger([CallerMemberName] string testName = "")
.Distinct()
.Select(f => new TaskItem(Path.Combine(basePath, "Output", f)))
.ToArray();
task.IsHotReloadEnabled = isHotReloadEnabled;
return task;
}

Expand Down
@@ -0,0 +1,7 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">

<x:String x:Key="Key1">Value1</x:String>
</ResourceDictionary>
@@ -0,0 +1,7 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">

<x:String x:Key="Key2">Value2</x:String>
</ResourceDictionary>
11 changes: 11 additions & 0 deletions src/Uno.XamlMerge.Tests/Scenarios/When_HR_Enabled/expected.xml
@@ -0,0 +1,11 @@
<!-- Generating a resource dictionary that references existing dictionaries for HotReload support -->
<!-- Proper merging of XAML files will happen if you build in Release configuration -->
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ms-appx:///When_HR_Enabled/Input_Dictionary_1.xml" />
<ResourceDictionary Source="ms-appx:///When_HR_Enabled/Input_Dictionary_2.xml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
1 change: 0 additions & 1 deletion src/Uno.XamlMerge.Tests/Uno.XamlMerge.Tests.csproj
Expand Up @@ -2,7 +2,6 @@

<PropertyGroup>
<TargetFrameworks>net7.0;net461</TargetFrameworks>
<LangVersion>10</LangVersion>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
Expand Down

0 comments on commit 333dd48

Please sign in to comment.