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 3d48cf2d7cf0f..941993a9e83d4 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
@@ -169,6 +169,8 @@ Copyright (c) .NET Foundation. All rights reserved.
<_WasmInvariantGlobalization Condition="'$(_WasmInvariantGlobalization)' == ''">true
<_WasmCopyOutputSymbolsToOutputDirectory>$(CopyOutputSymbolsToOutputDirectory)
<_WasmCopyOutputSymbolsToOutputDirectory Condition="'$(_WasmCopyOutputSymbolsToOutputDirectory)'==''">true
+ <_WasmEnableThreads>$(WasmEnableThreads)
+ <_WasmEnableThreads Condition="'$(_WasmEnableThreads)' == ''">false
<_WasmEnableWebcil>$(WasmEnableWebcil)
<_WasmEnableWebcil Condition="'$(_WasmEnableWebcil)' == ''">false
<_BlazorWebAssemblyStartupMemoryCache>$(BlazorWebAssemblyStartupMemoryCache)
@@ -203,6 +205,7 @@ Copyright (c) .NET Foundation. All rights reserved.
CopySymbols="$(_WasmCopyOutputSymbolsToOutputDirectory)"
OutputPath="$(OutputPath)"
FingerprintDotNetJs="$(WasmFingerprintDotnetJs)"
+ EnableThreads="$(_WasmEnableThreads)"
>
@@ -374,6 +377,7 @@ Copyright (c) .NET Foundation. All rights reserved.
ExistingAssets="@(_WasmPublishPrefilteredAssets)"
DotNetJsVersion="$(_DotNetJsVersion)"
FingerprintDotNetJs="$(WasmFingerprintDotnetJs)"
+ EnableThreads="$(_WasmEnableThreads)"
IsWebCilEnabled="$(_WasmEnableWebcil)"
>
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 2854594ae1054..46bc35c0325ef 100644
--- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/AssetsComputingHelper.cs
+++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/AssetsComputingHelper.cs
@@ -12,21 +12,26 @@ namespace Microsoft.NET.Sdk.WebAssembly;
public class AssetsComputingHelper
{
+ private static readonly string[] monoPackageIds = new[]
+ {
+ "Microsoft.NETCore.App.Runtime.Mono.browser-wasm",
+ "Microsoft.NETCore.App.Runtime.Mono.multithread.browser-wasm",
+ "Microsoft.NETCore.App.Runtime.Mono.perftrace.browser-wasm",
+ };
+
public static bool ShouldFilterCandidate(
ITaskItem candidate,
bool timezoneSupport,
bool invariantGlobalization,
bool copySymbols,
string customIcuCandidateFilename,
+ bool enableThreads,
out string reason)
{
var extension = candidate.GetMetadata("Extension");
var fileName = candidate.GetMetadata("FileName");
var assetType = candidate.GetMetadata("AssetType");
- var fromMonoPackage = string.Equals(
- candidate.GetMetadata("NuGetPackageId"),
- "Microsoft.NETCore.App.Runtime.Mono.browser-wasm",
- StringComparison.Ordinal);
+ bool fromMonoPackage = IsFromMonoPackage(candidate);
reason = extension switch
{
@@ -45,7 +50,7 @@ public static bool ShouldFilterCandidate(
".json" when fromMonoPackage && (fileName == "emcc-props" || fileName == "package") => $"{fileName}{extension} is not used by Blazor",
".ts" when fromMonoPackage && fileName == "dotnet.d" => "dotnet type definition is not used by Blazor",
".ts" when fromMonoPackage && fileName == "dotnet-legacy.d" => "dotnet type definition is not used by Blazor",
- ".js" when assetType == "native" && fileName != "dotnet" => $"{fileName}{extension} is not used by Blazor",
+ ".js" when assetType == "native" && !(fileName == "dotnet" || enableThreads && fileName == "dotnet.worker") => $"{fileName}{extension} is not used by Blazor",
".pdb" when !copySymbols => "copying symbols is disabled",
".symbols" when fromMonoPackage => "extension .symbols is not required.",
_ => null
@@ -54,6 +59,12 @@ public static bool ShouldFilterCandidate(
return reason != null;
}
+ private static bool IsFromMonoPackage(ITaskItem candidate)
+ {
+ string packageId = candidate.GetMetadata("NuGetPackageId");
+ return monoPackageIds.Contains(packageId, StringComparer.Ordinal);
+ }
+
public static string GetCandidateRelativePath(ITaskItem candidate)
{
var destinationSubPath = candidate.GetMetadata("DestinationSubPath");
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 68a563322f613..97caad5a38574 100644
--- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmBuildAssets.cs
+++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmBuildAssets.cs
@@ -45,6 +45,8 @@ public class ComputeWasmBuildAssets : Task
public bool FingerprintDotNetJs { get; set; }
+ public bool EnableThreads { get; set; }
+
[Output]
public ITaskItem[] AssetCandidates { get; set; }
@@ -79,7 +81,7 @@ public override bool Execute()
for (int i = 0; i < Candidates.Length; i++)
{
var candidate = Candidates[i];
- if (AssetsComputingHelper.ShouldFilterCandidate(candidate, TimeZoneSupport, InvariantGlobalization, CopySymbols, customIcuCandidateFilename, out var reason))
+ if (AssetsComputingHelper.ShouldFilterCandidate(candidate, TimeZoneSupport, InvariantGlobalization, CopySymbols, customIcuCandidateFilename, EnableThreads, out var reason))
{
Log.LogMessage(MessageImportance.Low, "Skipping asset '{0}' because '{1}'", candidate.ItemSpec, reason);
filesToRemove.Add(candidate);
@@ -104,14 +106,15 @@ public override bool Execute()
continue;
}
- if (candidate.GetMetadata("FileName") == "dotnet" && candidate.GetMetadata("Extension") == ".js")
+ string candidateFileName = candidate.GetMetadata("FileName");
+ if ((candidateFileName == "dotnet" || candidateFileName == "dotnet.worker") && candidate.GetMetadata("Extension") == ".js")
{
string newDotnetJSFileName = null;
string newDotNetJSFullPath = null;
if (FingerprintDotNetJs)
{
var itemHash = FileHasher.GetFileHash(candidate.ItemSpec);
- newDotnetJSFileName = $"dotnet.{candidate.GetMetadata("NuGetPackageVersion")}.{itemHash}.js";
+ newDotnetJSFileName = $"{candidateFileName}.{candidate.GetMetadata("NuGetPackageVersion")}.{itemHash}.js";
var originalFileFullPath = Path.GetFullPath(candidate.ItemSpec);
var originalFileDirectory = Path.GetDirectoryName(originalFileFullPath);
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 ed7115d3f36c4..78d886ce57636 100644
--- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs
+++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs
@@ -55,6 +55,8 @@ public class ComputeWasmPublishAssets : Task
public bool FingerprintDotNetJs { get; set; }
+ public bool EnableThreads { get; set; }
+
public bool IsWebCilEnabled { get; set; }
[Output]
@@ -163,8 +165,10 @@ private List ProcessNativeAssets(
var key = kvp.Key;
var asset = kvp.Value;
var isDotNetJs = IsDotNetJs(key);
+ var isDotNetWorkerJs = IsDotNetWorkerJs(key);
var isDotNetWasm = IsDotNetWasm(key);
- if (!isDotNetJs && !isDotNetWasm)
+
+ if (!isDotNetJs && !isDotNetWasm && !isDotNetWorkerJs)
{
if (resolvedNativeAssetToPublish.TryGetValue(Path.GetFileName(asset.GetMetadata("OriginalItemSpec")), out var existing))
{
@@ -197,11 +201,16 @@ private List ProcessNativeAssets(
{
var aotDotNetJs = WasmAotAssets.SingleOrDefault(a => $"{a.GetMetadata("FileName")}{a.GetMetadata("Extension")}" == "dotnet.js");
ITaskItem newDotNetJs = null;
- if (aotDotNetJs != null && FingerprintDotNetJs)
+ if (aotDotNetJs != null)
{
newDotNetJs = new TaskItem(Path.GetFullPath(aotDotNetJs.ItemSpec), asset.CloneCustomMetadata());
newDotNetJs.SetMetadata("OriginalItemSpec", aotDotNetJs.ItemSpec);
- newDotNetJs.SetMetadata("RelativePath", $"_framework/{$"dotnet.{DotNetJsVersion}.{FileHasher.GetFileHash(aotDotNetJs.ItemSpec)}.js"}");
+
+ string relativePath = FingerprintDotNetJs
+ ? $"_framework/{$"dotnet.{DotNetJsVersion}.{FileHasher.GetFileHash(aotDotNetJs.ItemSpec)}.js"}"
+ : "_framework/dotnet.js";
+
+ newDotNetJs.SetMetadata("RelativePath", relativePath);
updateMap.Add(asset.ItemSpec, newDotNetJs);
Log.LogMessage(MessageImportance.Low, "Replacing asset '{0}' with AoT version '{1}'", asset.ItemSpec, newDotNetJs.ItemSpec);
@@ -221,6 +230,35 @@ private List ProcessNativeAssets(
continue;
}
+ if (isDotNetWorkerJs)
+ {
+ var aotDotNetWorkerJs = WasmAotAssets.SingleOrDefault(a => $"{a.GetMetadata("FileName")}{a.GetMetadata("Extension")}" == "dotnet.worker.js");
+ ITaskItem newDotNetWorkerJs = null;
+ if (aotDotNetWorkerJs != null)
+ {
+ newDotNetWorkerJs = new TaskItem(Path.GetFullPath(aotDotNetWorkerJs.ItemSpec), asset.CloneCustomMetadata());
+ newDotNetWorkerJs.SetMetadata("OriginalItemSpec", aotDotNetWorkerJs.ItemSpec);
+ newDotNetWorkerJs.SetMetadata("RelativePath", "_framework/dotnet.worker.js");
+
+ updateMap.Add(asset.ItemSpec, newDotNetWorkerJs);
+ Log.LogMessage(MessageImportance.High, "Replacing asset '{0}' with AoT version '{1}'", asset.ItemSpec, newDotNetWorkerJs.ItemSpec);
+ }
+ else
+ {
+ newDotNetWorkerJs = new TaskItem(asset);
+ newDotNetWorkerJs.SetMetadata("RelativePath", "_framework/dotnet.worker.js");
+ Log.LogMessage(MessageImportance.High, "Promoting asset '{0}' to Publish asset.", asset.ItemSpec);
+ }
+
+ ApplyPublishProperties(newDotNetWorkerJs);
+ nativeStaticWebAssets.Add(newDotNetWorkerJs);
+ if (resolvedNativeAssetToPublish.TryGetValue("dotnet.worker.js", out var resolved))
+ {
+ filesToRemove.Add(resolved);
+ }
+ continue;
+ }
+
if (isDotNetWasm)
{
var aotDotNetWasm = WasmAotAssets.SingleOrDefault(a => $"{a.GetMetadata("FileName")}{a.GetMetadata("Extension")}" == "dotnet.wasm");
@@ -262,6 +300,8 @@ static bool IsDotNetJs(string key)
return fileName.StartsWith("dotnet.", StringComparison.Ordinal) && fileName.EndsWith(".js", StringComparison.Ordinal) && !fileName.Contains("worker");
}
+ static bool IsDotNetWorkerJs(string key) => string.Equals("dotnet.worker.js", Path.GetFileName(key), StringComparison.Ordinal);
+
static bool IsDotNetWasm(string key) => string.Equals("dotnet.wasm", Path.GetFileName(key), StringComparison.Ordinal);
}
@@ -540,7 +580,7 @@ private void GroupResolvedFilesToPublish(
foreach (var candidate in resolvedFilesToPublish)
{
- if (AssetsComputingHelper.ShouldFilterCandidate(candidate, TimeZoneSupport, InvariantGlobalization, CopySymbols, customIcuCandidateFilename, out var reason))
+ if (AssetsComputingHelper.ShouldFilterCandidate(candidate, TimeZoneSupport, InvariantGlobalization, CopySymbols, customIcuCandidateFilename, EnableThreads, out var reason))
{
Log.LogMessage(MessageImportance.Low, "Skipping asset '{0}' because '{1}'", candidate.ItemSpec, reason);
if (!resolvedFilesToPublishToRemove.ContainsKey(candidate.ItemSpec))