diff --git a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets index 48360c01d7e993..3b5d827b381355 100644 --- a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets +++ b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets @@ -703,7 +703,7 @@ Copyright (c) .NET Foundation. All rights reserved. ? configProperties) + { + var path = Path.Combine(dir, fileName); + using var stream = File.OpenWrite(path); + using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions { Indented = true }); + writer.WriteStartObject(); + writer.WritePropertyName("runtimeOptions"); + writer.WriteStartObject(); + if (configProperties is not null) + { + writer.WritePropertyName("configProperties"); + writer.WriteStartObject(); + foreach (var (key, value) in configProperties) + writer.WriteString(key, value); + writer.WriteEndObject(); + } + writer.WriteEndObject(); + writer.WriteEndObject(); + return path; + } + + private sealed class TempDirectory : System.IDisposable + { + public string Path { get; } = System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetRandomFileName()); + + public TempDirectory() => Directory.CreateDirectory(Path); + + public void Dispose() + { + // Silently ignore cleanup failures to avoid masking actual test failures. + try { Directory.Delete(Path, recursive: true); } catch { } + } + } +} diff --git a/src/tasks.tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj b/src/tasks.tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj new file mode 100644 index 00000000000000..9adcea8712095e --- /dev/null +++ b/src/tasks.tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj @@ -0,0 +1,14 @@ + + + + $(NetCoreAppToolCurrent) + enable + + + + + + + + + diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/GenerateWasmBootJson.cs b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/GenerateWasmBootJson.cs index 07f5daa0ea14ab..784b2a77d71755 100644 --- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/GenerateWasmBootJson.cs +++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/GenerateWasmBootJson.cs @@ -61,6 +61,8 @@ public class GenerateWasmBootJson : Task public string? RuntimeConfigJsonPath { get; set; } + public string? RuntimeConfigDevJsonPath { get; set; } + public string Jiterpreter { get; set; } public string RuntimeOptions { get; set; } @@ -463,12 +465,7 @@ private void WriteBootConfig(string entryAssemblyName) } } - if (RuntimeConfigJsonPath != null && File.Exists(RuntimeConfigJsonPath)) - { - using var fs = File.OpenRead(RuntimeConfigJsonPath); - var runtimeConfig = JsonSerializer.Deserialize(fs, BootJsonBuilderHelper.JsonOptions); - result.runtimeConfig = runtimeConfig; - } + result.runtimeConfig = ReadRuntimeConfigFiles(RuntimeConfigJsonPath, IsPublish ? null : RuntimeConfigDevJsonPath); Profilers ??= Array.Empty(); var browserProfiler = Profilers.FirstOrDefault(p => p.StartsWith("browser:")); @@ -569,4 +566,36 @@ private Version ParsedTargetFrameworkVersion private bool IsTargeting90OrLater() => ParsedTargetFrameworkVersion >= version90; private bool IsTargeting100OrLater() => ParsedTargetFrameworkVersion >= version100; private bool IsTargeting110OrLater() => ParsedTargetFrameworkVersion >= version110; + + /// + /// Reads the main runtimeconfig.json and merges configProperties from the companion + /// runtimeconfig.dev.json (when it exists) into the result. Dev config values take precedence. + /// + internal static RuntimeConfigData? ReadRuntimeConfigFiles(string? mainConfigPath, string? devConfigPath) + { + if (!File.Exists(mainConfigPath)) + return null; + + using var fs = File.OpenRead(mainConfigPath); + var runtimeConfig = JsonSerializer.Deserialize(fs, BootJsonBuilderHelper.JsonOptions); + + if (File.Exists(devConfigPath)) + { + // Merge overrides from runtimeconfig.dev.json (e.g. Hot Reload switches set by the SDK in debug builds). + using var devFs = File.OpenRead(devConfigPath); + var devRuntimeConfig = JsonSerializer.Deserialize(devFs, BootJsonBuilderHelper.JsonOptions); + if (devRuntimeConfig?.runtimeOptions?.configProperties is { } devProps && devProps.Count > 0) + { + runtimeConfig ??= new RuntimeConfigData(); + runtimeConfig.runtimeOptions ??= new RuntimeOptionsData(); + runtimeConfig.runtimeOptions.configProperties ??= new Dictionary(); + foreach (var kvp in devProps) + { + runtimeConfig.runtimeOptions.configProperties[kvp.Key] = kvp.Value; + } + } + } + + return runtimeConfig; + } } diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.csproj b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.csproj index 90267a01c8e52a..ecf3510c8914df 100644 --- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.csproj +++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.csproj @@ -17,6 +17,7 @@ +