diff --git a/src/Components/Blazor/Blazor.Version.props b/src/Components/Blazor/Blazor.Version.props
new file mode 100644
index 0000000000..8c119d5413
--- /dev/null
+++ b/src/Components/Blazor/Blazor.Version.props
@@ -0,0 +1,2 @@
+
+
diff --git a/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyHost.cs b/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyHost.cs
index 3a2ccfbaae..b90878fdde 100644
--- a/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyHost.cs
+++ b/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyHost.cs
@@ -19,6 +19,11 @@ namespace Microsoft.AspNetCore.Blazor.Hosting
public WebAssemblyHost(IServiceProvider services, IJSRuntime runtime)
{
+ // To ensure JS-invoked methods don't get linked out, have a reference to their enclosing types
+ GC.KeepAlive(typeof(EntrypointInvoker));
+ GC.KeepAlive(typeof(JSInteropMethods));
+ GC.KeepAlive(typeof(WebAssemblyEventDispatcher));
+
Services = services ?? throw new ArgumentNullException(nameof(services));
_runtime = runtime ?? throw new ArgumentNullException(nameof(runtime));
}
diff --git a/src/Components/Blazor/Build/src/Tasks/GenerateTypeGranularityLinkingConfig.cs b/src/Components/Blazor/Build/src/Tasks/GenerateTypeGranularityLinkingConfig.cs
new file mode 100644
index 0000000000..8a56b7fc3d
--- /dev/null
+++ b/src/Components/Blazor/Build/src/Tasks/GenerateTypeGranularityLinkingConfig.cs
@@ -0,0 +1,48 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.IO;
+using System.Xml.Linq;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+namespace Microsoft.AspNetCore.Blazor.Build.Tasks
+{
+ public class GenerateTypeGranularityLinkingConfig : Task
+ {
+ [Required]
+ public ITaskItem[] Assemblies { get; set; }
+
+ [Required]
+ public string OutputPath { get; set; }
+
+ public override bool Execute()
+ {
+ var linkerElement = new XElement("linker",
+ new XComment(" THIS IS A GENERATED FILE - DO NOT EDIT MANUALLY "));
+
+ foreach (var assembly in Assemblies)
+ {
+ var assemblyElement = CreateTypeGranularityConfig(assembly);
+ linkerElement.Add(assemblyElement);
+ }
+
+ using var fileStream = File.Open(OutputPath, FileMode.Create);
+ new XDocument(linkerElement).Save(fileStream);
+
+ return true;
+ }
+
+ private XElement CreateTypeGranularityConfig(ITaskItem assembly)
+ {
+ // We match all types in the assembly, and for each one, tell the linker to preserve all
+ // its members (preserve=all) but only if there's some reference to the type (required=false)
+ return new XElement("assembly",
+ new XAttribute("fullname", Path.GetFileNameWithoutExtension(assembly.ItemSpec)),
+ new XElement("type",
+ new XAttribute("fullname", "*"),
+ new XAttribute("preserve", "all"),
+ new XAttribute("required", "false")));
+ }
+ }
+}
diff --git a/src/Components/Blazor/Build/src/targets/Blazor.MonoRuntime.targets b/src/Components/Blazor/Build/src/targets/Blazor.MonoRuntime.targets
index 0a3ba70a23..cdbe7169a0 100644
--- a/src/Components/Blazor/Build/src/targets/Blazor.MonoRuntime.targets
+++ b/src/Components/Blazor/Build/src/targets/Blazor.MonoRuntime.targets
@@ -22,8 +22,6 @@
@@ -160,6 +158,7 @@
+
- <_BlazorDependencyAssembly Include="@(_BlazorDependencyInput)" IsLinkable="$([System.String]::Copy('%(FileName)').StartsWith('System.'))" />
+ <_BlazorDependencyAssembly Include="@(_BlazorDependencyInput)" />
+ <_BlazorDependencyAssembly IsLinkable="true" Condition="$([System.String]::Copy('%(Filename)').StartsWith('System.'))" />
+ <_BlazorDependencyAssembly IsLinkable="true" TypeGranularity="true" Condition="$([System.String]::Copy('%(Filename)').StartsWith('Microsoft.AspNetCore.'))" />
+ <_BlazorDependencyAssembly IsLinkable="true" TypeGranularity="true" Condition="$([System.String]::Copy('%(Filename)').StartsWith('Microsoft.Extensions.'))" />
<_BlazorAssemblyToLink Include="@(_WebAssemblyBCLAssembly)" />
<_BlazorAssemblyToLink Include="@(_BlazorDependencyAssembly)" Condition="'%(_BlazorDependencyAssembly.IsLinkable)' == 'true'" />
@@ -201,6 +203,15 @@
<_DotNetHostFileName Condition=" '$(OS)' == 'Windows_NT' ">dotnet.exe
+
+ <_TypeGranularityLinkingConfig>$(BlazorIntermediateOutputPath)linker.typegranularityconfig.xml
+
+
+
+
+
+
+
+
+
diff --git a/src/Components/Blazor/Directory.Build.props b/src/Components/Blazor/Directory.Build.props
new file mode 100644
index 0000000000..c48cf8a1a9
--- /dev/null
+++ b/src/Components/Blazor/Directory.Build.props
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/ProjectTemplates/BlazorWasm.ProjectTemplates/Microsoft.AspNetCore.Blazor.Templates.csproj b/src/ProjectTemplates/BlazorWasm.ProjectTemplates/Microsoft.AspNetCore.Blazor.Templates.csproj
index 32c3197d04..65457a000d 100644
--- a/src/ProjectTemplates/BlazorWasm.ProjectTemplates/Microsoft.AspNetCore.Blazor.Templates.csproj
+++ b/src/ProjectTemplates/BlazorWasm.ProjectTemplates/Microsoft.AspNetCore.Blazor.Templates.csproj
@@ -1,4 +1,10 @@
+
+ $(RepoRoot)src\Components\Blazor\
+
+
+
+
$(DefaultNetCoreTargetFramework)
true
@@ -18,8 +24,6 @@
MicrosoftEntityFrameworkCoreSqlServerPackageVersion=$(MicrosoftEntityFrameworkCoreSqlServerPackageVersion);
MicrosoftAspNetCoreBlazorServerPackageVersion=$(MicrosoftAspNetCoreBlazorServerPackageVersion);
-
- $(RepoRoot)src\Components\Blazor\