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 707ce66956448e..74353513b2bac3 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 @@ -334,6 +334,7 @@ Copyright (c) .NET Foundation. All rights reserved. EnableThreads="$(_WasmEnableThreads)" EnableDiagnostics="$(_WasmEmitDiagnosticModuleBuild)" EmitSourceMap="$(_WasmEmitSourceMapBuild)" + EmitSymbolMap="$(WasmEmitSymbolMap)" FingerprintAssets="$(_WasmFingerprintAssets)" FingerprintDotnetJs="$(_WasmFingerprintDotnetJs)" > @@ -362,6 +363,7 @@ Copyright (c) .NET Foundation. All rights reserved. <_WasmFingerprintPatterns Include="DllFiles" Pattern="*.dll" Expression="#[.{fingerprint}]!" /> <_WasmFingerprintPatterns Include="DatFiles" Pattern="*.dat" Expression="#[.{fingerprint}]!" /> <_WasmFingerprintPatterns Include="Pdb" Pattern="*.pdb" Expression="#[.{fingerprint}]!" /> + <_WasmFingerprintPatterns Include="Symbols" Pattern="*.js.symbols" Expression="#[.{fingerprint}]!" /> diff --git a/src/mono/wasm/Wasm.Build.Tests/ModuleConfigTests.cs b/src/mono/wasm/Wasm.Build.Tests/ModuleConfigTests.cs index 6e62d3edf324c9..a9c220e4d07973 100644 --- a/src/mono/wasm/Wasm.Build.Tests/ModuleConfigTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/ModuleConfigTests.cs @@ -122,4 +122,29 @@ public async Task AssetIntegrity() "There are assets without integrity hash" ); } + + [Theory] + [InlineData(true, false)] + [InlineData(true, true)] + [InlineData(false, false)] + [InlineData(false, true)] + public void SymbolMapFileEmitted(bool emitSymbolMap, bool isPublish) + { + Configuration config = Configuration.Release; + string extraProperties = $"{emitSymbolMap.ToString().ToLowerInvariant()}"; + ProjectInfo info = CopyTestAsset(config, aot: false, TestAsset.WasmBasicTestApp, + $"SymbolMapFile_{emitSymbolMap}_{isPublish}", extraProperties: extraProperties); + + if (isPublish) + PublishProject(info, config, new PublishOptions(AssertAppBundle: false)); + else + BuildProject(info, config, new BuildOptions(AssertAppBundle: false)); + + string frameworkDir = GetBinFrameworkDir(config, forPublish: isPublish); + + // The file may be fingerprinted (e.g. dotnet.native..js.symbols), + // so use a glob pattern to find it. + bool symbolsFileExists = Directory.EnumerateFiles(frameworkDir, "dotnet.native*.js.symbols").Any(); + Assert.Equal(emitSymbolMap, symbolsFileExists); + } } diff --git a/src/mono/wasm/Wasm.Build.Tests/WasmSdkBasedProjectProvider.cs b/src/mono/wasm/Wasm.Build.Tests/WasmSdkBasedProjectProvider.cs index 93cb9af858aa01..e4988229b8ee37 100644 --- a/src/mono/wasm/Wasm.Build.Tests/WasmSdkBasedProjectProvider.cs +++ b/src/mono/wasm/Wasm.Build.Tests/WasmSdkBasedProjectProvider.cs @@ -32,7 +32,7 @@ protected override IReadOnlyDictionary GetAllKnownDotnetFilesToFin { "dotnet.js", true }, { "dotnet.js.map", false }, { "dotnet.native.js", true }, - { "dotnet.native.js.symbols", false }, + { "dotnet.native.js.symbols", true }, { "dotnet.native.wasm", true }, { "dotnet.native.worker.mjs", true }, { "dotnet.runtime.js", true }, diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/AssetsComputingHelper.cs b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/AssetsComputingHelper.cs index 0dbe5e23f6a3c3..3c386681dab3c4 100644 --- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/AssetsComputingHelper.cs +++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/AssetsComputingHelper.cs @@ -53,6 +53,7 @@ public static bool ShouldFilterCandidate( bool enableThreads, bool enableDiagnostics, bool emitSourceMap, + bool emitSymbolMap, out string reason) { var extension = candidate.GetMetadata("Extension"); @@ -90,7 +91,7 @@ public static bool ShouldFilterCandidate( ".js" when assetType == "native" => $"{fileName}{extension} is not used by Blazor", ".mjs" when assetType == "native" && !(enableThreads && fileName == "dotnet.native.worker") => $"{fileName}{extension} is not used by Blazor", ".pdb" when !copySymbols => "copying symbols is disabled", - ".symbols" when fromMonoPackage => "extension .symbols is not required.", + ".symbols" when !emitSymbolMap => "emitting wasm symbol map is not enabled", _ => null }; diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmBuildAssets.cs b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmBuildAssets.cs index 34dcf1647aa3e2..c0d117a2027eab 100644 --- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmBuildAssets.cs +++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmBuildAssets.cs @@ -52,6 +52,8 @@ public class ComputeWasmBuildAssets : Task public bool EmitSourceMap { get; set; } + public bool EmitSymbolMap { get; set; } + public bool FingerprintAssets { get; set; } public bool FingerprintDotNetJs { get; set; } @@ -91,7 +93,7 @@ public override bool Execute() for (int i = 0; i < Candidates.Length; i++) { var candidate = Candidates[i]; - if (AssetsComputingHelper.ShouldFilterCandidate(candidate, TimeZoneSupport, InvariantGlobalization, LoadFullICUData, CopySymbols, customIcuCandidateFilename, EnableThreads, EnableDiagnostics, EmitSourceMap, out var reason)) + if (AssetsComputingHelper.ShouldFilterCandidate(candidate, TimeZoneSupport, InvariantGlobalization, LoadFullICUData, CopySymbols, customIcuCandidateFilename, EnableThreads, EnableDiagnostics, EmitSourceMap, EmitSymbolMap, out var reason)) { Log.LogMessage(MessageImportance.Low, "Skipping asset '{0}' because '{1}'", candidate.ItemSpec, reason); filesToRemove.Add(candidate); @@ -251,6 +253,7 @@ private static void ApplyUniqueMetadataProperties(ITaskItem candidate) case ".js" when filename.StartsWith("dotnet"): case ".mjs" when filename.StartsWith("dotnet"): case ".dat" when filename.StartsWith("icudt"): + case ".symbols" when filename.StartsWith("dotnet.native"): candidate.SetMetadata("AssetTraitName", "WasmResource"); candidate.SetMetadata("AssetTraitValue", "native"); break; diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs index 69205e6f3b982f..bdf13fd5662fb7 100644 --- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs +++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs @@ -58,6 +58,8 @@ public class ComputeWasmPublishAssets : Task public bool EmitSourceMap { get; set; } + public bool EmitSymbolMap { get; set; } + public bool IsWebCilEnabled { get; set; } public bool FingerprintAssets { get; set; } @@ -676,7 +678,7 @@ private void GroupResolvedFilesToPublish( foreach (var candidate in resolvedFilesToPublish) { #pragma warning disable CA1864 // Prefer the 'IDictionary.TryAdd(TKey, TValue)' method. Dictionary.TryAdd() not available in .Net framework. - if (AssetsComputingHelper.ShouldFilterCandidate(candidate, TimeZoneSupport, InvariantGlobalization, LoadFullICUData, CopySymbols, customIcuCandidateFilename, EnableThreads, EnableDiagnostics, EmitSourceMap, out var reason)) + if (AssetsComputingHelper.ShouldFilterCandidate(candidate, TimeZoneSupport, InvariantGlobalization, LoadFullICUData, CopySymbols, customIcuCandidateFilename, EnableThreads, EnableDiagnostics, EmitSourceMap, EmitSymbolMap, out var reason)) { Log.LogMessage(MessageImportance.Low, "Skipping asset '{0}' because '{1}'", candidate.ItemSpec, reason); if (!resolvedFilesToPublishToRemove.ContainsKey(candidate.ItemSpec))