Skip to content

Commit a37b351

Browse files
authored
[wasm] Prepare for new boot config schema (#49373)
1 parent 6a3f3d4 commit a37b351

File tree

2 files changed

+236
-11
lines changed

2 files changed

+236
-11
lines changed

test/Microsoft.NET.Sdk.BlazorWebAssembly.Tests/BootJsonData.cs

Lines changed: 231 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Collections.Generic;
77
using System.Runtime.Serialization;
88
using System.Text.Json;
9+
using System.Text.Json.Serialization;
910
using ResourceHashesByNameDictionary = System.Collections.Generic.Dictionary<string, string>;
1011

1112
// For test purposes only. Actual build time implementation lives in runtime repository with WasmSDK
@@ -41,7 +42,11 @@ public string entryAssembly
4142
/// and values are SHA-256 hashes formatted in prefixed base-64 style (e.g., 'sha256-abcdefg...')
4243
/// as used for subresource integrity checking.
4344
/// </summary>
44-
public ResourcesData resources { get; set; } = new ResourcesData();
45+
[JsonIgnore]
46+
public ResourcesData resources => (ResourcesData)resourcesRaw;
47+
48+
[JsonPropertyName("resources")]
49+
public object resourcesRaw { get; set; }
4550

4651
/// <summary>
4752
/// Gets a value that determines whether to enable caching of the <see cref="resources"/>
@@ -148,6 +153,9 @@ public class ResourcesData
148153
[DataMember(EmitDefaultValue = false)]
149154
public ResourceHashesByNameDictionary jsModuleWorker { get; set; }
150155

156+
[DataMember(EmitDefaultValue = false)]
157+
public ResourceHashesByNameDictionary jsModuleDiagnostics { get; set; }
158+
151159
[DataMember(EmitDefaultValue = false)]
152160
public ResourceHashesByNameDictionary jsModuleNative { get; set; }
153161

@@ -158,16 +166,21 @@ public class ResourcesData
158166
public ResourceHashesByNameDictionary wasmNative { get; set; }
159167

160168
[DataMember(EmitDefaultValue = false)]
161-
public ResourceHashesByNameDictionary jsSymbols { get; set; }
169+
public ResourceHashesByNameDictionary wasmSymbols { get; set; }
162170

163171
[DataMember(EmitDefaultValue = false)]
164172
public ResourceHashesByNameDictionary icu { get; set; }
165173

174+
public ResourceHashesByNameDictionary coreAssembly { get; set; } = new ResourceHashesByNameDictionary();
175+
166176
/// <summary>
167177
/// "assembly" (.dll) resources
168178
/// </summary>
169179
public ResourceHashesByNameDictionary assembly { get; set; } = new ResourceHashesByNameDictionary();
170180

181+
[DataMember(EmitDefaultValue = false)]
182+
public ResourceHashesByNameDictionary corePdb { get; set; }
183+
171184
/// <summary>
172185
/// "debug" (.pdb) resources
173186
/// </summary>
@@ -212,13 +225,144 @@ public class ResourcesData
212225
[DataMember(EmitDefaultValue = false)]
213226
public Dictionary<string, AdditionalAsset> runtimeAssets { get; set; }
214227

228+
[DataMember(EmitDefaultValue = false)]
229+
public Dictionary<string, ResourceHashesByNameDictionary> coreVfs { get; set; }
230+
215231
[DataMember(EmitDefaultValue = false)]
216232
public Dictionary<string, ResourceHashesByNameDictionary> vfs { get; set; }
217233

218234
[DataMember(EmitDefaultValue = false)]
219235
public List<string> remoteSources { get; set; }
220236
}
221237

238+
public class AssetsData
239+
{
240+
/// <summary>
241+
/// Gets a hash of all resources
242+
/// </summary>
243+
public string hash { get; set; }
244+
245+
[DataMember(EmitDefaultValue = false)]
246+
public List<JsAsset> jsModuleWorker { get; set; }
247+
248+
[DataMember(EmitDefaultValue = false)]
249+
public List<JsAsset> jsModuleDiagnostics { get; set; }
250+
251+
[DataMember(EmitDefaultValue = false)]
252+
public List<JsAsset> jsModuleNative { get; set; }
253+
254+
[DataMember(EmitDefaultValue = false)]
255+
public List<JsAsset> jsModuleRuntime { get; set; }
256+
257+
[DataMember(EmitDefaultValue = false)]
258+
public List<WasmAsset> wasmNative { get; set; }
259+
260+
[DataMember(EmitDefaultValue = false)]
261+
public List<SymbolsAsset> wasmSymbols { get; set; }
262+
263+
[DataMember(EmitDefaultValue = false)]
264+
public List<GeneralAsset> icu { get; set; }
265+
266+
/// <summary>
267+
/// "assembly" (.dll) resources needed to start MonoVM
268+
/// </summary>
269+
public List<GeneralAsset> coreAssembly { get; set; } = new();
270+
271+
/// <summary>
272+
/// "assembly" (.dll) resources
273+
/// </summary>
274+
public List<GeneralAsset> assembly { get; set; } = new();
275+
276+
/// <summary>
277+
/// "debug" (.pdb) resources needed to start MonoVM
278+
/// </summary>
279+
[DataMember(EmitDefaultValue = false)]
280+
public List<GeneralAsset> corePdb { get; set; }
281+
282+
/// <summary>
283+
/// "debug" (.pdb) resources
284+
/// </summary>
285+
[DataMember(EmitDefaultValue = false)]
286+
public List<GeneralAsset> pdb { get; set; }
287+
288+
/// <summary>
289+
/// localization (.satellite resx) resources
290+
/// </summary>
291+
[DataMember(EmitDefaultValue = false)]
292+
public Dictionary<string, List<GeneralAsset>> satelliteResources { get; set; }
293+
294+
/// <summary>
295+
/// Assembly (.dll) resources that are loaded lazily during runtime
296+
/// </summary>
297+
[DataMember(EmitDefaultValue = false)]
298+
public List<GeneralAsset> lazyAssembly { get; set; }
299+
300+
/// <summary>
301+
/// JavaScript module initializers that Blazor will be in charge of loading.
302+
/// Used in .NET < 8
303+
/// </summary>
304+
[DataMember(EmitDefaultValue = false)]
305+
public List<JsAsset> libraryInitializers { get; set; }
306+
307+
[DataMember(EmitDefaultValue = false)]
308+
public List<JsAsset> modulesAfterConfigLoaded { get; set; }
309+
310+
[DataMember(EmitDefaultValue = false)]
311+
public List<JsAsset> modulesAfterRuntimeReady { get; set; }
312+
313+
/// <summary>
314+
/// Extensions created by users customizing the initialization process. The format of the file(s)
315+
/// is up to the user.
316+
/// </summary>
317+
[DataMember(EmitDefaultValue = false)]
318+
public Dictionary<string, ResourceHashesByNameDictionary> extensions { get; set; }
319+
320+
[DataMember(EmitDefaultValue = false)]
321+
public List<VfsAsset> coreVfs { get; set; }
322+
323+
[DataMember(EmitDefaultValue = false)]
324+
public List<VfsAsset> vfs { get; set; }
325+
}
326+
327+
[DataContract]
328+
public class JsAsset
329+
{
330+
public string name { get; set; }
331+
public string moduleExports { get; set; }
332+
}
333+
334+
[DataContract]
335+
public class SymbolsAsset
336+
{
337+
public string name { get; set; }
338+
}
339+
340+
[DataContract]
341+
public class WasmAsset
342+
{
343+
public string name { get; set; }
344+
public string integrity { get; set; }
345+
public string resolvedUrl { get; set; }
346+
}
347+
348+
[DataContract]
349+
public class GeneralAsset
350+
{
351+
public string virtualPath { get; set; }
352+
public string name { get; set; }
353+
public string integrity { get; set; }
354+
public string resolvedUrl { get; set; }
355+
}
356+
357+
[DataContract]
358+
public class VfsAsset
359+
{
360+
public string virtualPath { get; set; }
361+
public string name { get; set; }
362+
public string integrity { get; set; }
363+
public string resolvedUrl { get; set; }
364+
}
365+
222366
public enum GlobalizationMode : int
223367
{
224368
// Note that the numeric values are serialized and used in JS code, so don't change them without also updating the JS code
@@ -261,10 +405,65 @@ public class BootJsonDataLoader
261405
public static BootJsonData ParseBootData(string bootConfigPath)
262406
{
263407
string jsonContent = GetJsonContent(bootConfigPath);
264-
BootJsonData config = JsonSerializer.Deserialize<BootJsonData>(jsonContent, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
408+
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
409+
options.Converters.Add(new ResourcesConverter());
410+
BootJsonData config = JsonSerializer.Deserialize<BootJsonData>(jsonContent, options);
411+
if (config.resourcesRaw is AssetsData assets)
412+
{
413+
config.resourcesRaw = ConvertAssetsToResources(assets);
414+
}
415+
265416
return config;
266417
}
267418

419+
private static ResourcesData ConvertAssetsToResources(AssetsData assets)
420+
{
421+
static Dictionary<string, ResourceHashesByNameDictionary> ConvertSatelliteResources(Dictionary<string, List<GeneralAsset>> satelliteResources)
422+
{
423+
if (satelliteResources == null)
424+
return null;
425+
426+
var result = new Dictionary<string, ResourceHashesByNameDictionary>();
427+
foreach (var kvp in satelliteResources)
428+
result[kvp.Key] = kvp.Value.ToDictionary(a => a.name, a => a.integrity);
429+
430+
return result;
431+
}
432+
433+
static Dictionary<string, ResourceHashesByNameDictionary> ConvertVfsAssets(List<VfsAsset> vfsAssets)
434+
{
435+
return vfsAssets?.ToDictionary(a => a.virtualPath, a => new ResourceHashesByNameDictionary
436+
{
437+
{ a.name, a.integrity }
438+
});
439+
}
440+
441+
var resources = new ResourcesData
442+
{
443+
hash = assets.hash,
444+
jsModuleWorker = assets.jsModuleWorker?.ToDictionary(a => a.name, a => (string)null),
445+
jsModuleDiagnostics = assets.jsModuleDiagnostics?.ToDictionary(a => a.name, a => (string)null),
446+
jsModuleNative = assets.jsModuleNative?.ToDictionary(a => a.name, a => (string)null),
447+
jsModuleRuntime = assets.jsModuleRuntime?.ToDictionary(a => a.name, a => (string)null),
448+
wasmNative = assets.wasmNative?.ToDictionary(a => a.name, a => a.integrity),
449+
wasmSymbols = assets.wasmSymbols?.ToDictionary(a => a.name, a => (string)null),
450+
icu = assets.icu?.ToDictionary(a => a.name, a => a.integrity),
451+
coreAssembly = assets.coreAssembly?.ToDictionary(a => a.name, a => a.integrity),
452+
assembly = assets.assembly?.ToDictionary(a => a.name, a => a.integrity),
453+
corePdb = assets.corePdb?.ToDictionary(a => a.name, a => a.integrity),
454+
pdb = assets.pdb?.ToDictionary(a => a.name, a => a.integrity),
455+
satelliteResources = ConvertSatelliteResources(assets.satelliteResources),
456+
lazyAssembly = assets.lazyAssembly?.ToDictionary(a => a.name, a => a.integrity),
457+
libraryInitializers = assets.libraryInitializers?.ToDictionary(a => a.name, a => (string)null),
458+
modulesAfterConfigLoaded = assets.modulesAfterConfigLoaded?.ToDictionary(a => a.name, a => (string)null),
459+
modulesAfterRuntimeReady = assets.modulesAfterRuntimeReady?.ToDictionary(a => a.name, a => (string)null),
460+
extensions = assets.extensions,
461+
coreVfs = ConvertVfsAssets(assets.coreVfs),
462+
vfs = ConvertVfsAssets(assets.vfs)
463+
};
464+
return resources;
465+
}
466+
268467
public static string GetJsonContent(string bootConfigPath)
269468
{
270469
string startComment = "/*json-start*/";
@@ -284,3 +483,32 @@ public static string GetJsonContent(string bootConfigPath)
284483
return moduleContent;
285484
}
286485
}
486+
487+
internal class ResourcesConverter : JsonConverter<object>
488+
{
489+
public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
490+
{
491+
var nestedOptions = new JsonSerializerOptions(options);
492+
nestedOptions.Converters.Remove(this);
493+
494+
if (reader.TokenType == JsonTokenType.StartObject)
495+
{
496+
try
497+
{
498+
499+
return JsonSerializer.Deserialize<AssetsData>(ref reader, nestedOptions)!;
500+
}
501+
catch
502+
{
503+
return JsonSerializer.Deserialize<ResourcesData>(ref reader, nestedOptions)!;
504+
}
505+
}
506+
507+
return JsonSerializer.Deserialize<object>(ref reader, nestedOptions)!;
508+
}
509+
510+
public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
511+
{
512+
JsonSerializer.Serialize(writer, value, value.GetType(), options);
513+
}
514+
}

test/Microsoft.NET.Sdk.BlazorWebAssembly.Tests/WasmPublishIntegrationTestBase.cs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,12 @@ protected static void VerifyBootManifestHashes(TestAsset testAsset, string blazo
1616
var bootManifestResolvedPath = Path.Combine(blazorPublishDirectory, "_framework", WasmBootConfigFileName);
1717
var bootManifest = BootJsonDataLoader.ParseBootData(bootManifestResolvedPath);
1818

19+
VerifyBootManifestHashes(testAsset, blazorPublishDirectory, bootManifest.resources.coreAssembly);
1920
VerifyBootManifestHashes(testAsset, blazorPublishDirectory, bootManifest.resources.assembly);
21+
if (bootManifest.resources.corePdb != null)
22+
{
23+
VerifyBootManifestHashes(testAsset, blazorPublishDirectory, bootManifest.resources.corePdb);
24+
}
2025
if (bootManifest.resources.pdb != null)
2126
{
2227
VerifyBootManifestHashes(testAsset, blazorPublishDirectory, bootManifest.resources.pdb);
@@ -33,14 +38,6 @@ protected static void VerifyBootManifestHashes(TestAsset testAsset, string blazo
3338
{
3439
VerifyBootManifestHashes(testAsset, blazorPublishDirectory, bootManifest.resources.wasmNative);
3540
}
36-
if (bootManifest.resources.jsModuleNative != null)
37-
{
38-
VerifyBootManifestHashes(testAsset, blazorPublishDirectory, bootManifest.resources.jsModuleNative);
39-
}
40-
if (bootManifest.resources.jsModuleRuntime != null)
41-
{
42-
VerifyBootManifestHashes(testAsset, blazorPublishDirectory, bootManifest.resources.jsModuleRuntime);
43-
}
4441

4542
if (bootManifest.resources.satelliteResources != null)
4643
{

0 commit comments

Comments
 (0)