Skip to content

Commit a173be2

Browse files
authored
Add support for <BlazorWebAssemblyLazyLoad /> item group (#23071)
* Add support for <BlazorLazyLoad /> item group * Respond to feedback from peer review
1 parent ab7f3f2 commit a173be2

File tree

3 files changed

+186
-1
lines changed

3 files changed

+186
-1
lines changed

src/Components/WebAssembly/Build/src/Tasks/GenerateBlazorBootJson.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ internal void WriteBootJson(Stream output, string entryAssemblyName)
8888
case "assembly":
8989
resourceList = resourceData.assembly;
9090
break;
91+
case "dynamicAssembly":
92+
resourceList = resourceData.dynamicAssembly;
93+
break;
9194
case "pdb":
9295
resourceData.pdb ??= new ResourceHashesByNameDictionary();
9396
resourceList = resourceData.pdb;
@@ -207,6 +210,11 @@ public class ResourcesData
207210
/// </summary>
208211
public ResourceHashesByNameDictionary assembly { get; set; } = new ResourceHashesByNameDictionary();
209212

213+
/// <summary>
214+
/// Assembly (.dll) resources that are loaded dynamically during runtime
215+
/// </summary>
216+
public ResourceHashesByNameDictionary dynamicAssembly { get; set; } = new ResourceHashesByNameDictionary();
217+
210218
/// <summary>
211219
/// "debug" (.pdb) resources
212220
/// </summary>
@@ -221,4 +229,4 @@ public class ResourcesData
221229
}
222230
#pragma warning restore IDE1006 // Naming Styles
223231
}
224-
}
232+
}

src/Components/WebAssembly/Build/src/targets/Blazor.MonoRuntime.targets

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@
129129
<_BlazorOutputWithTargetPath Include="@(_BlazorResolvedAssembly)">
130130
<BootManifestResourceType Condition="'%(Extension)' == '.dll'">assembly</BootManifestResourceType>
131131
<BootManifestResourceType Condition="'%(Extension)' == '.pdb'">pdb</BootManifestResourceType>
132+
<BootManifestResourceType Condition="@(BlazorWebAssemblyLazyLoad->AnyHaveMetadataValue('Identity', '%(Filename)')) != ''">dynamicAssembly</BootManifestResourceType>
132133
<BootManifestResourceName>%(FileName)%(Extension)</BootManifestResourceName>
133134
<TargetOutputPath>$(_BlazorRuntimeBinOutputPath)%(FileName)%(Extension)</TargetOutputPath>
134135
</_BlazorOutputWithTargetPath>
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Diagnostics;
6+
using System.IO;
7+
using System.Text.Json;
8+
using System.Threading.Tasks;
9+
using Microsoft.AspNetCore.Testing;
10+
using Xunit;
11+
using static Microsoft.AspNetCore.Components.WebAssembly.Build.WebAssemblyRuntimePackage;
12+
13+
namespace Microsoft.AspNetCore.Components.WebAssembly.Build
14+
{
15+
public class BuildLazyLoadTest
16+
{
17+
[Fact]
18+
public async Task Build_LazyLoadExplicitAssembly_Debug_Works()
19+
{
20+
// Arrange
21+
using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" });
22+
project.Configuration = "Debug";
23+
24+
project.AddProjectFileContent(
25+
@"
26+
<ItemGroup>
27+
<BlazorWebAssemblyLazyLoad Include='RazorClassLibrary.dll' />
28+
</ItemGroup>
29+
");
30+
31+
var result = await MSBuildProcessManager.DotnetMSBuild(project);
32+
33+
var buildOutputDirectory = project.BuildOutputDirectory;
34+
35+
// Verify that a blazor.boot.json file has been created
36+
Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json");
37+
// And that the assembly is in the output
38+
Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "_bin", "RazorClassLibrary.dll");
39+
40+
var bootJson = ReadBootJsonData(result, Path.Combine(buildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json"));
41+
42+
// And that it has been labelled as a dynamic assembly in the boot.json
43+
var dynamicAssemblies = bootJson.resources.dynamicAssembly;
44+
var assemblies = bootJson.resources.assembly;
45+
46+
Assert.NotNull(dynamicAssemblies);
47+
Assert.Contains("RazorClassLibrary.dll", dynamicAssemblies.Keys);
48+
Assert.DoesNotContain("RazorClassLibrary.dll", assemblies.Keys);
49+
50+
// App assembly should not be lazy loaded
51+
Assert.DoesNotContain("standalone.dll", dynamicAssemblies.Keys);
52+
Assert.Contains("standalone.dll", assemblies.Keys);
53+
}
54+
55+
[Fact]
56+
public async Task Build_LazyLoadExplicitAssembly_Release_Works()
57+
{
58+
// Arrange
59+
using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" });
60+
project.Configuration = "Release";
61+
62+
project.AddProjectFileContent(
63+
@"
64+
<ItemGroup>
65+
<BlazorWebAssemblyLazyLoad Include='RazorClassLibrary.dll' />
66+
</ItemGroup>
67+
");
68+
69+
var result = await MSBuildProcessManager.DotnetMSBuild(project);
70+
71+
var buildOutputDirectory = project.BuildOutputDirectory;
72+
73+
// Verify that a blazor.boot.json file has been created
74+
Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json");
75+
// And that the assembly is in the output
76+
Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "_bin", "RazorClassLibrary.dll");
77+
78+
var bootJson = ReadBootJsonData(result, Path.Combine(buildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json"));
79+
80+
// And that it has been labelled as a dynamic assembly in the boot.json
81+
var dynamicAssemblies = bootJson.resources.dynamicAssembly;
82+
var assemblies = bootJson.resources.assembly;
83+
84+
Assert.NotNull(dynamicAssemblies);
85+
Assert.Contains("RazorClassLibrary.dll", dynamicAssemblies.Keys);
86+
Assert.DoesNotContain("RazorClassLibrary.dll", assemblies.Keys);
87+
88+
// App assembly should not be lazy loaded
89+
Assert.DoesNotContain("standalone.dll", dynamicAssemblies.Keys);
90+
Assert.Contains("standalone.dll", assemblies.Keys);
91+
}
92+
93+
[Fact]
94+
public async Task Publish_LazyLoadExplicitAssembly_Debug_Works()
95+
{
96+
// Arrange
97+
using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" });
98+
project.Configuration = "Debug";
99+
100+
project.AddProjectFileContent(
101+
@"
102+
<ItemGroup>
103+
<BlazorWebAssemblyLazyLoad Include='RazorClassLibrary.dll' />
104+
</ItemGroup>
105+
");
106+
107+
var result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish");
108+
109+
var publishDirectory = project.PublishOutputDirectory;
110+
111+
// Verify that a blazor.boot.json file has been created
112+
Assert.FileExists(result, publishDirectory, "wwwroot", "_framework", "blazor.boot.json");
113+
// And that the assembly is in the output
114+
Assert.FileExists(result, publishDirectory, "wwwroot", "_framework", "_bin", "RazorClassLibrary.dll");
115+
116+
var bootJson = ReadBootJsonData(result, Path.Combine(publishDirectory, "wwwroot", "_framework", "blazor.boot.json"));
117+
118+
// And that it has been labelled as a dynamic assembly in the boot.json
119+
var dynamicAssemblies = bootJson.resources.dynamicAssembly;
120+
var assemblies = bootJson.resources.assembly;
121+
122+
Assert.NotNull(dynamicAssemblies);
123+
Assert.Contains("RazorClassLibrary.dll", dynamicAssemblies.Keys);
124+
Assert.DoesNotContain("RazorClassLibrary.dll", assemblies.Keys);
125+
126+
// App assembly should not be lazy loaded
127+
Assert.DoesNotContain("standalone.dll", dynamicAssemblies.Keys);
128+
Assert.Contains("standalone.dll", assemblies.Keys);
129+
}
130+
131+
[Fact]
132+
public async Task Publish_LazyLoadExplicitAssembly_Release_Works()
133+
{
134+
// Arrange
135+
using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" });
136+
project.Configuration = "Release";
137+
138+
project.AddProjectFileContent(
139+
@"
140+
<ItemGroup>
141+
<BlazorWebAssemblyLazyLoad Include='RazorClassLibrary.dll' />
142+
</ItemGroup>
143+
");
144+
145+
var result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish");
146+
147+
var publishDirectory = project.PublishOutputDirectory;
148+
149+
// Verify that a blazor.boot.json file has been created
150+
Assert.FileExists(result, publishDirectory, "wwwroot", "_framework", "blazor.boot.json");
151+
// And that the assembly is in the output
152+
Assert.FileExists(result, publishDirectory, "wwwroot", "_framework", "_bin", "RazorClassLibrary.dll");
153+
154+
var bootJson = ReadBootJsonData(result, Path.Combine(publishDirectory, "wwwroot", "_framework", "blazor.boot.json"));
155+
156+
// And that it has been labelled as a dynamic assembly in the boot.json
157+
var dynamicAssemblies = bootJson.resources.dynamicAssembly;
158+
var assemblies = bootJson.resources.assembly;
159+
160+
Assert.NotNull(dynamicAssemblies);
161+
Assert.Contains("RazorClassLibrary.dll", dynamicAssemblies.Keys);
162+
Assert.DoesNotContain("RazorClassLibrary.dll", assemblies.Keys);
163+
164+
// App assembly should not be lazy loaded
165+
Assert.DoesNotContain("standalone.dll", dynamicAssemblies.Keys);
166+
Assert.Contains("standalone.dll", assemblies.Keys);
167+
}
168+
169+
private static GenerateBlazorBootJson.BootJsonData ReadBootJsonData(MSBuildResult result, string path)
170+
{
171+
return JsonSerializer.Deserialize<GenerateBlazorBootJson.BootJsonData>(
172+
File.ReadAllText(Path.Combine(result.Project.DirectoryPath, path)),
173+
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
174+
}
175+
}
176+
}

0 commit comments

Comments
 (0)