Skip to content

Commit 4547cf7

Browse files
authored
[Blazor] Update SDK to account for the crypto worker file (#26966)
* Updates the Blazor SDK to account for the new crypto-worker-js file during build and publish. * Updates blazor.boot.json to include a new section with additional runtime assets that are consumed by the runtime directly at runtime.
1 parent 9b39946 commit 4547cf7

File tree

29 files changed

+1285
-603
lines changed

29 files changed

+1285
-603
lines changed

src/BlazorWasmSdk/Targets/Microsoft.NET.Sdk.BlazorWebAssembly.6_0.targets

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,9 @@ Copyright (c) .NET Foundation. All rights reserved.
157157
<!-- Remove dotnet.js/wasm from runtime pack, in favor of the relinked ones in @(WasmNativeAsset) -->
158158
<ReferenceCopyLocalPaths Remove="@(ReferenceCopyLocalPaths)"
159159
Condition="@(WasmNativeAsset->Count()) > 0 and '%(FileName)' == 'dotnet' and ('%(Extension)' == '.wasm' or '%(Extension)' == '.js')" />
160+
161+
<ReferenceCopyLocalPaths Remove="@(ReferenceCopyLocalPaths)"
162+
Condition="@(WasmNativeAsset->Count()) > 0 and '%(FileName)' == 'dotnet-crypto-worker' and '%(Extension)' == '.js'" />
160163
</ItemGroup>
161164

162165
<ComputeBlazorBuildAssets
@@ -403,6 +406,7 @@ Copyright (c) .NET Foundation. All rights reserved.
403406

404407
<ItemGroup>
405408
<_DotNetJsItem Include="@(ResolvedFileToPublish)" Condition="'%(ResolvedFileToPublish.DestinationSubPath)' == 'dotnet.js' AND '%(ResolvedFileToPublish.AssetType)' == 'native'" />
409+
<_DotNetJsItem Include="@(ResolvedFileToPublish)" Condition="'%(ResolvedFileToPublish.DestinationSubPath)' == 'dotnet-crypto-worker.js' AND '%(ResolvedFileToPublish.AssetType)' == 'native'" />
406410
</ItemGroup>
407411

408412
<PropertyGroup>

src/BlazorWasmSdk/Tasks/BootJsonData.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,13 @@ public class ResourcesData
9898
/// </summary>
9999
[DataMember(EmitDefaultValue = false)]
100100
public Dictionary<string, ResourceHashesByNameDictionary> extensions { get; set; }
101+
102+
/// <summary>
103+
/// Additional assets that the runtime consumes as part of the boot process.
104+
/// </summary>
105+
[DataMember(EmitDefaultValue = false)]
106+
public Dictionary<string, AdditionalAsset> runtimeAssets { get; set; }
107+
101108
}
102109

103110
public enum ICUDataMode : int

src/BlazorWasmSdk/Tasks/ComputeBlazorBuildAssets.cs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,28 @@ public override bool Execute()
118118
assetCandidates.Add(newDotNetJs);
119119
continue;
120120
}
121+
else if (candidate.GetMetadata("FileName") == "dotnet-crypto-worker" && candidate.GetMetadata("Extension") == ".js")
122+
{
123+
var itemHash = FileHasher.GetFileHash(candidate.ItemSpec);
124+
var cacheBustedDotNetCryptoWorkerJSFileName = $"dotnet-crypto-worker.{candidate.GetMetadata("NuGetPackageVersion")}.{itemHash}.js";
125+
126+
var originalFileFullPath = Path.GetFullPath(candidate.ItemSpec);
127+
var originalFileDirectory = Path.GetDirectoryName(originalFileFullPath);
128+
129+
var cacheBustedDotNetCryptoWorkerJSFullPath = Path.Combine(originalFileDirectory, cacheBustedDotNetCryptoWorkerJSFileName);
130+
131+
var newDotnetCryptoWorkerJs = new TaskItem(cacheBustedDotNetCryptoWorkerJSFullPath, candidate.CloneCustomMetadata());
132+
newDotnetCryptoWorkerJs.SetMetadata("OriginalItemSpec", candidate.ItemSpec);
133+
134+
var newRelativePath = $"_framework/{cacheBustedDotNetCryptoWorkerJSFileName}";
135+
newDotnetCryptoWorkerJs.SetMetadata("RelativePath", newRelativePath);
136+
137+
newDotnetCryptoWorkerJs.SetMetadata("AssetTraitName", "BlazorWebAssemblyResource");
138+
newDotnetCryptoWorkerJs.SetMetadata("AssetTraitValue", "js-module-crypto");
139+
140+
assetCandidates.Add(newDotnetCryptoWorkerJs);
141+
continue;
142+
}
121143
else if (string.IsNullOrEmpty(destinationSubPath))
122144
{
123145
var relativePath = candidate.GetMetadata("FileName") + candidate.GetMetadata("Extension");
@@ -280,7 +302,8 @@ public static bool ShouldFilterCandidate(
280302
".dat" when invariantGlobalization && fileName.StartsWith("icudt") => "invariant globalization is enabled",
281303
".json" when fromMonoPackage && (fileName == "emcc-props" || fileName == "package") => $"{fileName}{extension} is not used by Blazor",
282304
".ts" when fromMonoPackage && fileName == "dotnet.d" => "dotnet type definition is not used by Blazor",
283-
".js" when assetType == "native" && fileName != "dotnet" => $"{fileName}{extension} is not used by Blazor",
305+
".ts" when fromMonoPackage && fileName == "dotnet-legacy.d" => "dotnet type definition is not used by Blazor",
306+
".js" when assetType == "native" && fileName != "dotnet" && fileName != "dotnet-crypto-worker" => $"{fileName}{extension} is not used by Blazor",
284307
".pdb" when !copySymbols => "copying symbols is disabled",
285308
".symbols" when fromMonoPackage => "extension .symbols is not required.",
286309
_ => null

src/BlazorWasmSdk/Tasks/ComputeBlazorPublishAssets.cs

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,9 @@ private List<ITaskItem> ProcessNativeAssets(
157157
var key = kvp.Key;
158158
var asset = kvp.Value;
159159
var isDotNetJs = IsDotNetJs(key);
160+
var isDotNetCryptoJs = IsDotNetCryptoJs(key);
160161
var isDotNetWasm = IsDotNetWasm(key);
161-
if (!isDotNetJs && !isDotNetWasm)
162+
if (!isDotNetJs && !isDotNetWasm && !isDotNetCryptoJs)
162163
{
163164
if (resolvedNativeAssetToPublish.TryGetValue(Path.GetFileName(asset.GetMetadata("OriginalItemSpec")), out var existing))
164165
{
@@ -175,6 +176,7 @@ private List<ITaskItem> ProcessNativeAssets(
175176
}
176177
else
177178
{
179+
Log.LogMessage(MessageImportance.Low, "Removing asset '{0}'.", existing.ItemSpec);
178180
// This was a file that was filtered, so just remove it, we don't need to add any publish static web asset
179181
filesToRemove.Add(removed);
180182

@@ -214,6 +216,34 @@ private List<ITaskItem> ProcessNativeAssets(
214216
continue;
215217
}
216218

219+
if (isDotNetCryptoJs)
220+
{
221+
var aotDotNetCryptoJs = WasmAotAssets.SingleOrDefault(a => $"{a.GetMetadata("FileName")}{a.GetMetadata("Extension")}" == "dotnet-crypto-worker.js");
222+
ITaskItem newDotNetCryptoJs = null;
223+
if (aotDotNetCryptoJs != null)
224+
{
225+
newDotNetCryptoJs = new TaskItem(Path.GetFullPath(aotDotNetCryptoJs.ItemSpec), asset.CloneCustomMetadata());
226+
newDotNetCryptoJs.SetMetadata("OriginalItemSpec", aotDotNetCryptoJs.ItemSpec);
227+
newDotNetCryptoJs.SetMetadata("RelativePath", $"_framework/{$"dotnet-crypto-worker.{DotNetJsVersion}.{FileHasher.GetFileHash(aotDotNetCryptoJs.ItemSpec)}.js"}");
228+
229+
updateMap.Add(asset.ItemSpec, newDotNetCryptoJs);
230+
Log.LogMessage(MessageImportance.Low, "Replacing asset '{0}' with AoT version '{1}'", asset.ItemSpec, newDotNetCryptoJs.ItemSpec);
231+
}
232+
else
233+
{
234+
newDotNetCryptoJs = new TaskItem(asset);
235+
Log.LogMessage(MessageImportance.Low, "Promoting asset '{0}' to Publish asset.", asset.ItemSpec);
236+
}
237+
238+
ApplyPublishProperties(newDotNetCryptoJs);
239+
nativeStaticWebAssets.Add(newDotNetCryptoJs);
240+
if (resolvedNativeAssetToPublish.TryGetValue("dotnet-crypto-worker.js", out var resolved))
241+
{
242+
filesToRemove.Add(resolved);
243+
}
244+
continue;
245+
}
246+
217247
if (isDotNetWasm)
218248
{
219249
var aotDotNetWasm = WasmAotAssets.SingleOrDefault(a => $"{a.GetMetadata("FileName")}{a.GetMetadata("Extension")}" == "dotnet.wasm");
@@ -252,9 +282,14 @@ private List<ITaskItem> ProcessNativeAssets(
252282
static bool IsDotNetJs(string key)
253283
{
254284
var fileName = Path.GetFileName(key);
255-
return fileName.StartsWith("dotnet.", StringComparison.Ordinal) && fileName.EndsWith(".js", StringComparison.Ordinal);
285+
return fileName.StartsWith("dotnet.", StringComparison.Ordinal) && fileName.EndsWith(".js", StringComparison.Ordinal) && !fileName.Contains("worker");
256286
}
257287

288+
static bool IsDotNetCryptoJs(string key)
289+
{
290+
var fileName = Path.GetFileName(key);
291+
return fileName.StartsWith("dotnet-crypto-worker.", StringComparison.Ordinal) && fileName.EndsWith(".js", StringComparison.Ordinal);
292+
}
258293
static bool IsDotNetWasm(string key) => string.Equals("dotnet.wasm", Path.GetFileName(key), StringComparison.Ordinal);
259294
}
260295

@@ -411,7 +446,7 @@ private List<ITaskItem> ProcessCompressedAssets(
411446
Dictionary<string, ITaskItem> updatedAssets)
412447
{
413448
var processed = new List<string>();
414-
var additionalAssetsToUpdate = new List<ITaskItem>();
449+
var runtimeAssetsToUpdate = new List<ITaskItem>();
415450
foreach (var kvp in compressedRepresentations)
416451
{
417452
var compressedAsset = kvp.Value;
@@ -423,7 +458,7 @@ private List<ITaskItem> ProcessCompressedAssets(
423458
Log.LogMessage(MessageImportance.Low, "Related assembly for '{0}' was not updated and the compressed asset can be reused.", relatedAsset);
424459
var newCompressedAsset = new TaskItem(compressedAsset);
425460
ApplyPublishProperties(newCompressedAsset);
426-
additionalAssetsToUpdate.Add(newCompressedAsset);
461+
runtimeAssetsToUpdate.Add(newCompressedAsset);
427462
}
428463
else
429464
{
@@ -440,7 +475,7 @@ private List<ITaskItem> ProcessCompressedAssets(
440475
compressedRepresentations.Remove(element);
441476
}
442477

443-
return additionalAssetsToUpdate;
478+
return runtimeAssetsToUpdate;
444479
}
445480

446481
private static void UpdateRelatedAssetProperty(ITaskItem asset, TaskItem newAsset, Dictionary<string, ITaskItem> updatedAssetsMap)
@@ -603,10 +638,9 @@ private void GroupResolvedFilesToPublish(
603638
}
604639
}
605640

606-
private static bool IsNativeAsset(string traitValue) => string.Equals(traitValue, "native", StringComparison.Ordinal);
641+
private static bool IsNativeAsset(string traitValue) => string.Equals(traitValue, "native", StringComparison.Ordinal) || string.Equals(traitValue, "js-module-crypto", StringComparison.Ordinal);
607642

608643
private static bool IsRuntimeAsset(string traitValue) => string.Equals(traitValue, "runtime", StringComparison.Ordinal);
609-
610644
private static bool IsSymbolAsset(string traitValue) => string.Equals(traitValue, "symbol", StringComparison.Ordinal);
611645

612646
private static bool IsAlternative(ITaskItem asset) => string.Equals(asset.GetMetadata("AssetRole"), "Alternative", StringComparison.Ordinal);

src/BlazorWasmSdk/Tasks/GenerateBlazorWebAssemblyBootJson.cs

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System.IO;
99
using System.Linq;
1010
using System.Reflection;
11+
using System.Runtime.Serialization;
1112
using System.Runtime.Serialization.Json;
1213
using System.Text;
1314
using Microsoft.Build.Framework;
@@ -99,9 +100,11 @@ public void WriteBootJson(Stream output, string entryAssemblyName)
99100
var resourceData = result.resources;
100101
foreach (var resource in Resources)
101102
{
102-
ResourceHashesByNameDictionary resourceList;
103+
ResourceHashesByNameDictionary resourceList = null;
103104

105+
string behavior = null;
104106
var fileName = resource.GetMetadata("FileName");
107+
var fileExtension = resource.GetMetadata("Extension");
105108
var assetTraitName = resource.GetMetadata("AssetTraitName");
106109
var assetTraitValue = resource.GetMetadata("AssetTraitValue");
107110
var resourceName = Path.GetFileName(resource.GetMetadata("RelativePath"));
@@ -113,7 +116,7 @@ public void WriteBootJson(Stream output, string entryAssemblyName)
113116
resourceData.lazyAssembly ??= new ResourceHashesByNameDictionary();
114117
resourceList = resourceData.lazyAssembly;
115118
}
116-
else if (string.Equals("Culture", assetTraitName))
119+
else if (string.Equals("Culture", assetTraitName, StringComparison.OrdinalIgnoreCase))
117120
{
118121
Log.LogMessage(MessageImportance.Low, "Candidate '{0}' is defined as satellite assembly with culture '{1}'.", resource.ItemSpec, assetTraitValue);
119122
resourceData.satelliteResources ??= new Dictionary<string, ResourceHashesByNameDictionary>(StringComparer.OrdinalIgnoreCase);
@@ -149,6 +152,12 @@ public void WriteBootJson(Stream output, string entryAssemblyName)
149152
string.Equals(assetTraitValue, "native", StringComparison.OrdinalIgnoreCase))
150153
{
151154
Log.LogMessage(MessageImportance.Low, "Candidate '{0}' is defined as a native application resource.", resource.ItemSpec);
155+
if (string.Equals(fileName, "dotnet", StringComparison.OrdinalIgnoreCase) &&
156+
string.Equals(fileExtension, ".wasm", StringComparison.OrdinalIgnoreCase))
157+
{
158+
behavior = "dotnetwasm";
159+
}
160+
152161
resourceList = resourceData.runtime;
153162
}
154163
else if (string.Equals("JSModule", assetTraitName, StringComparison.OrdinalIgnoreCase) &&
@@ -161,6 +170,11 @@ public void WriteBootJson(Stream output, string entryAssemblyName)
161170
Debug.Assert(!string.IsNullOrEmpty(targetPath), "Target path for '{0}' must exist.", resource.ItemSpec);
162171
AddResourceToList(resource, resourceList, targetPath);
163172
continue;
173+
}
174+
else if(string.Equals(assetTraitName, "BlazorWebAssemblyResource", StringComparison.OrdinalIgnoreCase) &&
175+
string.Equals(assetTraitValue, "js-module-crypto", StringComparison.OrdinalIgnoreCase))
176+
{
177+
behavior = assetTraitValue;
164178
}
165179
else if (string.Equals("BlazorWebAssemblyResource", assetTraitName, StringComparison.OrdinalIgnoreCase) &&
166180
assetTraitValue.StartsWith("extension:", StringComparison.OrdinalIgnoreCase))
@@ -185,7 +199,16 @@ public void WriteBootJson(Stream output, string entryAssemblyName)
185199
continue;
186200
}
187201

188-
AddResourceToList(resource, resourceList, resourceName);
202+
if (resourceList != null)
203+
{
204+
AddResourceToList(resource, resourceList, resourceName);
205+
}
206+
207+
if (!string.IsNullOrEmpty(behavior))
208+
{
209+
resourceData.runtimeAssets ??= new Dictionary<string, AdditionalAsset>();
210+
AddToAdditionalResources(resource, resourceData.runtimeAssets, resourceName, behavior);
211+
}
189212
}
190213

191214
if (remainingLazyLoadAssemblies.Count > 0)
@@ -235,9 +258,32 @@ void AddResourceToList(ITaskItem resource, ResourceHashesByNameDictionary resour
235258
}
236259
}
237260

261+
private void AddToAdditionalResources(ITaskItem resource, Dictionary<string, AdditionalAsset> additionalResources, string resourceName, string behavior)
262+
{
263+
if (!additionalResources.ContainsKey(resourceName))
264+
{
265+
Log.LogMessage(MessageImportance.Low, "Added resource '{0}' to the list of additional assets in the manifest.", resource.ItemSpec);
266+
additionalResources.Add(resourceName, new AdditionalAsset
267+
{
268+
Hash = $"sha256-{resource.GetMetadata("FileHash")}",
269+
Behavior = behavior
270+
});
271+
}
272+
}
273+
238274
private bool TryGetLazyLoadedAssembly(string fileName, out ITaskItem lazyLoadedAssembly)
239275
{
240276
return (lazyLoadedAssembly = LazyLoadedAssemblies?.SingleOrDefault(a => a.ItemSpec == fileName)) != null;
241277
}
242278
}
279+
280+
[DataContract]
281+
public class AdditionalAsset
282+
{
283+
[DataMember(Name = "hash")]
284+
public string Hash { get; set; }
285+
286+
[DataMember(Name = "behavior")]
287+
public string Behavior { get; set; }
288+
}
243289
}

0 commit comments

Comments
 (0)