Use BlazorWebAssemblySDK (#24371)

* Use BlazorWebAssemblySDK

* Update projects to use the BlazorSDK
* Remove tasks and targets from RazorSDK
* Remove workarounds from BlazorSDK

* Fixup

* Fixup
This commit is contained in:
Pranav K 2020-08-11 10:29:01 -07:00 committed by GitHub
parent 7efec87a14
commit 8e5533f2a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 46 additions and 1761 deletions

View File

@ -12,7 +12,7 @@
<PackageReference Include="MicroBuild.Core" Version="0.3.0" PrivateAssets="All" AllowExplicitReference="true" ExcludeAssets="All" />
</ItemGroup>
<ItemGroup Condition="'$(UsingMicrosoftNETSdkWeb)' == 'true' OR '$(RazorSdkCurrentVersionProps)' != ''">
<ItemGroup Condition="'$(UsingMicrosoftNETSdkWeb)' == 'true' OR '$(UsingMicrosoftNETSdkBlazorWebAssembly)' == 'true' OR '$(RazorSdkCurrentVersionProps)' != ''">
<!--
Use the Razor SDK as a project reference. The version of the .NET Core SDK we build with often contains a version of the Razor SDK
several versions older than latest. We reference the project to ensure it's built before the other projects that use it. Since this
@ -25,11 +25,28 @@
UndefineProperties="TargetFramework;TargetFrameworks" />
</ItemGroup>
<ImportGroup Condition="'$(UsingMicrosoftNETSdkWeb)' == 'true' OR '$(RazorSdkCurrentVersionProps)' != ''">
<ImportGroup Condition="'$(UsingMicrosoftNETSdkWeb)' == 'true' OR '$(UsingMicrosoftNETSdkBlazorWebAssembly)' == 'true' OR '$(RazorSdkCurrentVersionProps)' != ''">
<Import Project="$(RepoRoot)eng\targets\GetRazorSDKDirectory.props" />
<Import Project="$(RepoRoot)src\Razor\Microsoft.NET.Sdk.Razor\src\build\netstandard2.0\Microsoft.NET.Sdk.Razor.props" />
</ImportGroup>
<ItemGroup Condition="'$(UsingMicrosoftNETSdkBlazorWebAssembly)' == 'true'">
<!-- See comments further up in the file when we import the Razor SDK-->
<Reference Include="Microsoft.NET.Sdk.BlazorWebAssembly"
PrivateAssets="All"
ReferenceOutputAssembly="false"
SkipGetTargetFrameworkProperties="true"
UndefineProperties="TargetFramework;TargetFrameworks" />
</ItemGroup>
<ImportGroup Condition="'$(UsingMicrosoftNETSdkBlazorWebAssembly)' == 'true'">
<Import Project="$(RepoRoot)src\Components\WebAssembly\Sdk\src\build\net5.0\Microsoft.NET.Sdk.BlazorWebAssembly.props" />
</ImportGroup>
<PropertyGroup Condition="'$(UsingMicrosoftNETSdkBlazorWebAssembly)' == 'true'">
<BlazorWebAssemblySdkDirectoryRoot>$(ArtifactsBinDir)\Microsoft.NET.Sdk.BlazorWebAssembly\$(Configuration)\sdk-output\</BlazorWebAssemblySdkDirectoryRoot>
</PropertyGroup>
<ItemGroup Condition=" '$(IsTestProject)' != 'true' AND '$(DotNetBuildFromSource)' != 'true' ">
<Reference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" PrivateAssets="All" />
</ItemGroup>

View File

@ -1,5 +1,5 @@
<Project>
<PropertyGroup Condition="'$(UseBlazorWebAssembly)' == 'true'">
<PropertyGroup Condition="'$(UsingMicrosoftNETSdkBlazorWebAssembly)' == 'true'">
<BlazorWebAssemblyJSPath>$(RepoRoot)src\Components\Web.JS\dist\$(Configuration)\blazor.webassembly.js</BlazorWebAssemblyJSPath>
<BlazorWebAssemblyJSMapPath>$(BlazorWebAssemblyJSPath).map</BlazorWebAssemblyJSMapPath>
@ -12,7 +12,7 @@
<!-- Add a project dependency without reference output assemblies to enforce build order -->
<!-- Applying workaround for https://github.com/microsoft/msbuild/issues/2661 and https://github.com/dotnet/sdk/issues/952 -->
<ProjectReference
Condition="'$(UseBlazorWebAssembly)' == 'true' and '$(BuildNodeJS)' != 'false' and '$(BuildingInsideVisualStudio)' != 'true'"
Condition="'$(UsingMicrosoftNETSdkBlazorWebAssembly)' == 'true' and '$(BuildNodeJS)' != 'false' and '$(BuildingInsideVisualStudio)' != 'true'"
Include="$(RepoRoot)src\Components\Web.JS\Microsoft.AspNetCore.Components.Web.JS.npmproj"
ReferenceOutputAssemblies="false"
SkipGetTargetFrameworkProperties="true"

View File

@ -321,6 +321,8 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
project.AddProjectFileContent(
@"
<PropertyGroup>
<!-- Workaround for https://github.com/mono/linker/issues/1390 -->
<PublishTrimmed>false</PublishTrimmed>
<DefineConstants>$(DefineConstants);REFERENCE_classlibrarywithsatelliteassemblies</DefineConstants>
</PropertyGroup>
<ItemGroup>
@ -450,6 +452,8 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
wasmProject.AddProjectFileContent(
@"
<PropertyGroup>
<!-- Workaround for https://github.com/mono/linker/issues/1390 -->
<PublishTrimmed>false</PublishTrimmed>
<DefineConstants>$(DefineConstants);REFERENCE_classlibrarywithsatelliteassemblies</DefineConstants>
</PropertyGroup>
<ItemGroup>
@ -637,7 +641,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
// Arrange
using var project = ProjectDirectory.Create("blazorhosted", additionalProjects: new[] { "blazorwasm", "razorclasslibrary", });
File.WriteAllText(Path.Combine(project.SolutionPath, "blazorwasm", "App.razor.css"), "h1 { font-size: 16px; }");
project.Configuration = "Release";
var result = await MSBuildProcessManager.DotnetMSBuild(project, "Build", "/p:BuildInsideVisualStudio=true");
@ -701,6 +705,8 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
var existing = File.ReadAllText(blazorwasmProjFile);
var updatedContent = @"
<PropertyGroup>
<!-- Workaround for https://github.com/mono/linker/issues/1390 -->
<PublishTrimmed>false</PublishTrimmed>
<DefineConstants>$(DefineConstants);REFERENCE_classlibrarywithsatelliteassemblies</DefineConstants>
</PropertyGroup>
<ItemGroup>

View File

@ -12,5 +12,6 @@ Copyright (c) .NET Foundation. All rights reserved.
<Project ToolsVersion="14.0">
<PropertyGroup>
<_BlazorWebAssemblyPropsFile>$(MSBuildThisFileDirectory)..\..\targets\Microsoft.NET.Sdk.BlazorWebAssembly.Current.props</_BlazorWebAssemblyPropsFile>
<_BlazorWebAssemblyTargetsFile>$(MSBuildThisFileDirectory)..\..\targets\Microsoft.NET.Sdk.BlazorWebAssembly.Current.targets</_BlazorWebAssemblyTargetsFile>
</PropertyGroup>
</Project>

View File

@ -1,16 +0,0 @@
<!--
***********************************************************************************************
Microsoft.NET.Sdk.BlazorWebAssembly.props
WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
created a backup copy. Incorrect changes to this file will make it
impossible to load or build your projects from the command-line or the IDE.
Copyright (c) .NET Foundation. All rights reserved.
***********************************************************************************************
-->
<Project ToolsVersion="14.0">
<PropertyGroup>
<_BlazorWebAssemblyTargetsFile>$(MSBuildThisFileDirectory)..\..\targets\Microsoft.NET.Sdk.BlazorWebAssembly.Current.targets</_BlazorWebAssemblyTargetsFile>
</PropertyGroup>
</Project>

View File

@ -24,12 +24,7 @@ Copyright (c) .NET Foundation. All rights reserved.
<WarnOnPackingNonPackableProject>false</WarnOnPackingNonPackableProject>
</PropertyGroup>
<PropertyGroup>
<!-- Determines if this Sdk is responsible for importing Microsoft.NET.Sdk.Razor. Temporary workaround until we can create a SDK. -->
<_RazorSdkImportsMicrosoftNetSdkRazor Condition="'$(UsingMicrosoftNETSdkRazor)' != 'true'">true</_RazorSdkImportsMicrosoftNetSdkRazor>
</PropertyGroup>
<Import Sdk="Microsoft.NET.Sdk.Razor" Project="Sdk.props" Condition="'$(_RazorSdkImportsMicrosoftNetSdkRazor)' == 'true'" />
<Import Sdk="Microsoft.NET.Sdk.Razor" Project="Sdk.props" />
<Import Sdk="Microsoft.NET.Sdk.Web.ProjectSystem" Project="Sdk.props" />
<Import Sdk="Microsoft.NET.Sdk.Publish" Project="Sdk.props" />

View File

@ -15,7 +15,7 @@ Copyright (c) .NET Foundation. All rights reserved.
<EnableDefaultContentItems Condition=" '$(EnableDefaultContentItems)' == '' ">true</EnableDefaultContentItems>
</PropertyGroup>
<Import Sdk="Microsoft.NET.Sdk.Razor" Project="Sdk.targets" Condition="'$(_RazorSdkImportsMicrosoftNetSdkRazor)' == 'true'" />
<Import Sdk="Microsoft.NET.Sdk.Razor" Project="Sdk.targets" />
<Import Sdk="Microsoft.NET.Sdk.Web.ProjectSystem" Project="Sdk.targets" />
<Import Sdk="Microsoft.NET.Sdk.Publish" Project="Sdk.targets" />

View File

@ -1,6 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<Import Project="$(RepoRoot)src\Components\WebAssembly\Sdk\src\Sdk\Sdk.props" />
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
@ -26,6 +24,4 @@
<Reference Include="$(BinariesRoot)\Microsoft.AspNetCore.Razor.Test.ComponentShim.dll"/>
</ItemGroup>
<Import Project="$(RepoRoot)src\Components\WebAssembly\Sdk\src\Sdk\Sdk.targets" />
</Project>

View File

@ -1,6 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<Import Project="$(RepoRoot)src\Components\WebAssembly\Sdk\src\Sdk\Sdk.props" />
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
@ -52,6 +50,4 @@
<ServiceWorker Include="wwwroot\serviceworkers\my-service-worker.js" PublishedContent="wwwroot\serviceworkers\my-prod-service-worker.js" />
</ItemGroup>
<Import Project="$(RepoRoot)src\Components\WebAssembly\Sdk\src\Sdk\Sdk.targets" />
</Project>

View File

@ -1,9 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
<PropertyGroup>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
<UseBlazorWebAssembly>true</UseBlazorWebAssembly>
</PropertyGroup>
<ItemGroup>

View File

@ -1,10 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
<PropertyGroup>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
<UseBlazorWebAssembly>true</UseBlazorWebAssembly>
<FixupWebAssemblyHttpHandlerReference>true</FixupWebAssemblyHttpHandlerReference>
</PropertyGroup>
<ItemGroup>

View File

@ -1,9 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
<PropertyGroup>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
<UseBlazorWebAssembly>true</UseBlazorWebAssembly>
</PropertyGroup>
<ItemGroup>

View File

@ -1,9 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
<PropertyGroup>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
<UseBlazorWebAssembly>true</UseBlazorWebAssembly>
<IsTestAssetProject>true</IsTestAssetProject>
</PropertyGroup>

View File

@ -1,9 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
<PropertyGroup>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<UseBlazorWebAssembly>true</UseBlazorWebAssembly>
<RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
<!-- Must be defined before ReferenceFromSource.props is imported -->
<AdditionalRunArguments>--pathbase /subdir</AdditionalRunArguments>

View File

@ -141,7 +141,7 @@
<GenerateFileFromTemplate
TemplateFile="$(MSBuildThisFileDirectory)Infrastructure\Directory.Build.props.in"
Properties=""
Properties="RepoRoot=$(RepoRoot)"
OutputPath="$(TestTemplateCreationFolder)Directory.Build.props" />
<!-- Workaround https://github.com/dotnet/core-setup/issues/6420 - there is no MSBuild setting for rollforward yet -->

View File

@ -47,7 +47,6 @@ namespace Templates.Test
Environment.SetEnvironmentVariable("EnableDefaultScopedCssItems", "true");
var project = await ProjectFactory.GetOrCreateProject("blazorstandalone", Output);
project.RuntimeIdentifier = "browser-wasm";
var createResult = await project.RunDotNetNewAsync("blazorwasm");
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult));
@ -145,7 +144,6 @@ namespace Templates.Test
Environment.SetEnvironmentVariable("EnableDefaultScopedCssItems", "true");
var project = await ProjectFactory.GetOrCreateProject("blazorstandalonepwa", Output);
project.RuntimeIdentifier = "browser-wasm";
var createResult = await project.RunDotNetNewAsync("blazorwasm", args: new[] { "--pwa" });
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult));
@ -355,7 +353,6 @@ namespace Templates.Test
Environment.SetEnvironmentVariable("EnableDefaultScopedCssItems", "true");
var project = await ProjectFactory.GetOrCreateProject("blazorstandaloneindividual", Output);
project.RuntimeIdentifier = "browser-wasm";
var createResult = await project.RunDotNetNewAsync("blazorwasm", args: new[] {
"-au",

View File

@ -3,4 +3,6 @@
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<Import Project="${RepoRoot}src\Components\WebAssembly\Sdk\src\build\net5.0\Microsoft.NET.Sdk.BlazorWebAssembly.props" Condition="'$(UsingMicrosoftNETSdkBlazorWebAssembly)' == 'true'" />
</Project>

View File

@ -36,6 +36,7 @@
-->
<PropertyGroup>
<RazorSdkDirectoryRoot>${ArtifactsBinDir}Microsoft.NET.Sdk.Razor\${Configuration}\sdk-output\</RazorSdkDirectoryRoot>
<BlazorWebAssemblySdkDirectoryRoot>${ArtifactsBinDir}Microsoft.NET.Sdk.BlazorWebAssembly\${Configuration}\sdk-output\</BlazorWebAssemblySdkDirectoryRoot>
</PropertyGroup>
<Import Project="${RepoRoot}src\Razor\Microsoft.NET.Sdk.Razor\src\build\netstandard2.0\Microsoft.NET.Sdk.Razor.props" Condition="'$(UsingMicrosoftNETSdkWeb)' == 'true' OR '$(RazorSdkCurrentVersionProps)' != ''" />
</Project>

View File

@ -1,9 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
<PropertyGroup>
<TargetFramework>${DefaultNetCoreTargetFramework}</TargetFramework>
<RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
<UseBlazorWebAssembly>true</UseBlazorWebAssembly>
<!--#if PWA -->
<ServiceWorkerAssetsManifest>service-worker-assets.js</ServiceWorkerAssetsManifest>
<!--#endif -->

View File

@ -37,4 +37,5 @@
<RazorSdkDirectoryRoot>${ArtifactsBinDir}Microsoft.NET.Sdk.Razor\${Configuration}\sdk-output\</RazorSdkDirectoryRoot>
</PropertyGroup>
<Import Project="${RepoRoot}src\Razor\Microsoft.NET.Sdk.Razor\src\build\netstandard2.0\Microsoft.NET.Sdk.Razor.props" Condition="'$(UsingMicrosoftNETSdkWeb)' == 'true' OR '$(RazorSdkCurrentVersionProps)' != ''" />
<Import Project="${RepoRoot}src\Components\WebAssembly\Sdk\src\build\net5.0\Microsoft.NET.Sdk.BlazorWebAssembly.props" Condition="'$(UsingMicrosoftNETSdkBlazorWebAssembly)' == 'true'" />
</Project>

View File

@ -155,7 +155,7 @@
<GenerateFileFromTemplate
TemplateFile="$(MSBuildThisFileDirectory)Infrastructure\Directory.Build.props.in"
Properties=""
Properties="RepoRoot=$(RepoRoot)"
OutputPath="$(TestTemplateCreationFolder)Directory.Build.props" />
<!-- Workaround https://github.com/dotnet/core-setup/issues/6420 - there is no MSBuild setting for rollforward yet -->

View File

@ -33,11 +33,6 @@
<Reference Include="Microsoft.NET.Sdk.Razor" ReferenceOutputAssembly="false" SkipGetTargetFrameworkProperties="true" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\src\BootJsonData.cs" LinkBase="Wasm" />
<Compile Include="..\src\AssetsManifestFile.cs" LinkBase="Wasm" />
</ItemGroup>
<Target Name="GenerateTestData" BeforeTargets="GetAssemblyAttributes">
<Exec Condition="'$(OS)' == 'Windows_NT'" Command="&quot;$(NuGetPackageRoot)vswhere\$(VSWhereVersion)\tools\vswhere.exe&quot; -latest -prerelease -property installationPath -requires Microsoft.Component.MSBuild" ConsoleToMsBuild="true" StandardErrorImportance="high">
<Output TaskParameter="ConsoleOutput" PropertyName="_VSInstallDir" />

View File

@ -1,33 +0,0 @@
// 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.
namespace Microsoft.AspNetCore.Razor.Tasks
{
#pragma warning disable IDE1006 // Naming Styles
public class AssetsManifestFile
{
/// <summary>
/// Gets or sets a version string.
/// </summary>
public string version { get; set; }
/// <summary>
/// Gets or sets the assets. Keys are URLs; values are base-64-formatted SHA256 content hashes.
/// </summary>
public AssetsManifestFileEntry[] assets { get; set; }
}
public class AssetsManifestFileEntry
{
/// <summary>
/// Gets or sets the asset URL. Normally this will be relative to the application's base href.
/// </summary>
public string url { get; set; }
/// <summary>
/// Gets or sets the file content hash. This should be the base-64-formatted SHA256 value.
/// </summary>
public string hash { get; set; }
}
#pragma warning restore IDE1006 // Naming Styles
}

View File

@ -1,38 +0,0 @@
// 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.Linq;
using System.Xml.Linq;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
namespace Microsoft.AspNetCore.Razor.Tasks
{
public class BlazorReadSatelliteAssemblyFile : Task
{
[Output]
public ITaskItem[] SatelliteAssembly { get; set; }
[Required]
public ITaskItem ReadFile { get; set; }
public override bool Execute()
{
var document = XDocument.Load(ReadFile.ItemSpec);
SatelliteAssembly = document.Root
.Elements()
.Select(e =>
{
// <Assembly Name="..." Culture="..." DestinationSubDirectory="..." />
var taskItem = new TaskItem(e.Attribute("Name").Value);
taskItem.SetMetadata("Culture", e.Attribute("Culture").Value);
taskItem.SetMetadata("DestinationSubDirectory", e.Attribute("DestinationSubDirectory").Value);
return taskItem;
}).ToArray();
return true;
}
}
}

View File

@ -1,53 +0,0 @@
// 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;
using System.Xml.Linq;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
namespace Microsoft.AspNetCore.Razor.Tasks
{
public class BlazorWriteSatelliteAssemblyFile : Task
{
[Required]
public ITaskItem[] SatelliteAssembly { get; set; }
[Required]
public ITaskItem WriteFile { get; set; }
public override bool Execute()
{
using var fileStream = File.Create(WriteFile.ItemSpec);
WriteSatelliteAssemblyFile(fileStream);
return true;
}
internal void WriteSatelliteAssemblyFile(Stream stream)
{
var root = new XElement("SatelliteAssembly");
foreach (var item in SatelliteAssembly)
{
// <Assembly Name="..." Culture="..." DestinationSubDirectory="..." />
root.Add(new XElement("Assembly",
new XAttribute("Name", item.ItemSpec),
new XAttribute("Culture", item.GetMetadata("Culture")),
new XAttribute("DestinationSubDirectory", item.GetMetadata("DestinationSubDirectory"))));
}
var xmlWriterSettings = new XmlWriterSettings
{
Indent = true,
OmitXmlDeclaration = true
};
using var writer = XmlWriter.Create(stream, xmlWriterSettings);
var xDocument = new XDocument(root);
xDocument.Save(writer);
}
}
}

View File

@ -1,85 +0,0 @@
// 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.Collections.Generic;
using System.Runtime.Serialization;
using ResourceHashesByNameDictionary = System.Collections.Generic.Dictionary<string, string>;
namespace Microsoft.AspNetCore.Razor.Tasks
{
#pragma warning disable IDE1006 // Naming Styles
/// <summary>
/// Defines the structure of a Blazor boot JSON file
/// </summary>
public class BootJsonData
{
/// <summary>
/// Gets the name of the assembly with the application entry point
/// </summary>
public string entryAssembly { get; set; }
/// <summary>
/// Gets the set of resources needed to boot the application. This includes the transitive
/// closure of .NET assemblies (including the entrypoint assembly), the dotnet.wasm file,
/// and any PDBs to be loaded.
///
/// Within <see cref="ResourceHashesByNameDictionary"/>, dictionary keys are resource names,
/// and values are SHA-256 hashes formatted in prefixed base-64 style (e.g., 'sha256-abcdefg...')
/// as used for subresource integrity checking.
/// </summary>
public ResourcesData resources { get; set; } = new ResourcesData();
/// <summary>
/// Gets a value that determines whether to enable caching of the <see cref="resources"/>
/// inside a CacheStorage instance within the browser.
/// </summary>
public bool cacheBootResources { get; set; }
/// <summary>
/// Gets a value that determines if this is a debug build.
/// </summary>
public bool debugBuild { get; set; }
/// <summary>
/// Gets a value that determines if the linker is enabled.
/// </summary>
public bool linkerEnabled { get; set; }
/// <summary>
/// Config files for the application
/// </summary>
public List<string> config { get; set; }
}
public class ResourcesData
{
/// <summary>
/// .NET Wasm runtime resources (dotnet.wasm, dotnet.js) etc.
/// </summary>
public ResourceHashesByNameDictionary runtime { get; set; } = new ResourceHashesByNameDictionary();
/// <summary>
/// "assembly" (.dll) resources
/// </summary>
public ResourceHashesByNameDictionary assembly { get; set; } = new ResourceHashesByNameDictionary();
/// <summary>
/// "debug" (.pdb) resources
/// </summary>
[DataMember(EmitDefaultValue = false)]
public ResourceHashesByNameDictionary pdb { get; set; }
/// <summary>
/// localization (.satellite resx) resources
/// </summary>
[DataMember(EmitDefaultValue = false)]
public Dictionary<string, ResourceHashesByNameDictionary> satelliteResources { get; set; }
/// <summary>
/// Assembly (.dll) resources that are loaded lazily during runtime
/// </summary>
[DataMember(EmitDefaultValue = false)]
public ResourceHashesByNameDictionary lazyAssembly { get; set; }
}
#pragma warning restore IDE1006 // Naming Styles
}

View File

@ -1,99 +0,0 @@
// 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;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
namespace Microsoft.AspNetCore.Razor.Tasks
{
public class BrotliCompress : DotNetToolTask
{
private static readonly char[] InvalidPathChars = Path.GetInvalidFileNameChars();
[Required]
public ITaskItem[] FilesToCompress { get; set; }
[Output]
public ITaskItem[] CompressedFiles { get; set; }
[Required]
public string OutputDirectory { get; set; }
public string CompressionLevel { get; set; }
public bool SkipIfOutputIsNewer { get; set; }
internal override string Command => "brotli";
protected override string GenerateResponseFileCommands()
{
var builder = new StringBuilder();
builder.AppendLine(Command);
if (!string.IsNullOrEmpty(CompressionLevel))
{
builder.AppendLine("-c");
builder.AppendLine(CompressionLevel);
}
CompressedFiles = new ITaskItem[FilesToCompress.Length];
for (var i = 0; i < FilesToCompress.Length; i++)
{
var input = FilesToCompress[i];
var inputFullPath = input.GetMetadata("FullPath");
var relativePath = input.GetMetadata("RelativePath");
var outputRelativePath = Path.Combine(OutputDirectory, CalculateTargetPath(relativePath, ".br"));
var outputItem = new TaskItem(outputRelativePath);
input.CopyMetadataTo(outputItem);
// Relative path in the publish dir
outputItem.SetMetadata("RelativePath", relativePath + ".br");
CompressedFiles[i] = outputItem;
var outputFullPath = Path.GetFullPath(outputRelativePath);
if (SkipIfOutputIsNewer && File.Exists(outputFullPath) && File.GetLastWriteTimeUtc(inputFullPath) < File.GetLastWriteTimeUtc(outputFullPath))
{
Log.LogMessage(MessageImportance.Low, $"Skipping compression for '{input.ItemSpec}' because '{outputRelativePath}' is newer than '{input.ItemSpec}'.");
continue;
}
builder.AppendLine("-s");
builder.AppendLine(inputFullPath);
builder.AppendLine("-o");
builder.AppendLine(outputFullPath);
}
return builder.ToString();
}
internal static string CalculateTargetPath(string relativePath, string extension)
{
// RelativePath can be long and if used as-is to write the output, might result in long path issues on Windows.
// Instead we'll calculate a fixed length path by hashing the input file name. This uses SHA1 similar to the Hash task in MSBuild
// since it has no crytographic significance.
using var hash = SHA1.Create();
var bytes = Encoding.UTF8.GetBytes(relativePath);
var hashString = Convert.ToBase64String(hash.ComputeHash(bytes));
var builder = new StringBuilder();
for (var i = 0; i < 8; i++)
{
var c = hashString[i];
builder.Append(InvalidPathChars.Contains(c) ? '+' : c);
}
builder.Append(extension);
return builder.ToString();
}
}
}

View File

@ -1,79 +0,0 @@
// 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;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
namespace Microsoft.AspNetCore.Razor.Tasks
{
// Based on https://github.com/mono/linker/blob/3b329b9481e300bcf4fb88a2eebf8cb5ef8b323b/src/ILLink.Tasks/CreateRootDescriptorFile.cs
public class CreateBlazorTrimmerRootDescriptorFile : Task
{
[Required]
public ITaskItem[] Assemblies { get; set; }
[Required]
public ITaskItem TrimmerFile { get; set; }
public override bool Execute()
{
var rootDescriptor = CreateRootDescriptorContents();
if (File.Exists(TrimmerFile.ItemSpec))
{
var existing = File.ReadAllText(TrimmerFile.ItemSpec);
if (string.Equals(rootDescriptor, existing, StringComparison.Ordinal))
{
Log.LogMessage(MessageImportance.Low, "Skipping write to file {0} because contents would not change.", TrimmerFile.ItemSpec);
// Avoid writing if the file contents are identical. This is required for build incrementalism.
return !Log.HasLoggedErrors;
}
}
File.WriteAllText(TrimmerFile.ItemSpec, rootDescriptor);
return !Log.HasLoggedErrors;
}
internal string CreateRootDescriptorContents()
{
var roots = new XElement("linker");
foreach (var assembly in Assemblies.OrderBy(a => a.ItemSpec))
{
// NOTE: Descriptor files don't include the file extension
// in the assemblyName.
var assemblyName = assembly.GetMetadata("FileName");
var typePreserved = assembly.GetMetadata("Preserve");
var typeRequired = assembly.GetMetadata("Required");
var attributes = new List<XAttribute>
{
new XAttribute("fullname", "*"),
new XAttribute("required", typeRequired),
};
if (!string.IsNullOrEmpty(typePreserved))
{
attributes.Add(new XAttribute("preserve", typePreserved));
}
roots.Add(new XElement("assembly",
new XAttribute("fullname", assemblyName),
new XElement("type", attributes)));
}
var xmlWriterSettings = new XmlWriterSettings
{
Indent = true,
OmitXmlDeclaration = true
};
return new XDocument(roots).Root.ToString();
}
}
}

View File

@ -1,70 +0,0 @@
// 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;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
namespace Microsoft.AspNetCore.Razor.Tasks
{
public class GZipCompress : Task
{
[Required]
public ITaskItem[] FilesToCompress { get; set; }
[Output]
public ITaskItem[] CompressedFiles { get; set; }
[Required]
public string OutputDirectory { get; set; }
public override bool Execute()
{
CompressedFiles = new ITaskItem[FilesToCompress.Length];
Directory.CreateDirectory(OutputDirectory);
System.Threading.Tasks.Parallel.For(0, FilesToCompress.Length, i =>
{
var file = FilesToCompress[i];
var inputPath = file.ItemSpec;
var relativePath = file.GetMetadata("RelativePath");
var outputRelativePath = Path.Combine(
OutputDirectory,
BrotliCompress.CalculateTargetPath(relativePath, ".gz"));
var outputItem = new TaskItem(outputRelativePath);
outputItem.SetMetadata("RelativePath", relativePath + ".gz");
CompressedFiles[i] = outputItem;
if (File.Exists(outputRelativePath) && File.GetLastWriteTimeUtc(inputPath) < File.GetLastWriteTimeUtc(outputRelativePath))
{
// Incrementalism. If input source doesn't exist or it exists and is not newer than the expected output, do nothing.
Log.LogMessage(MessageImportance.Low, $"Skipping '{inputPath}' because '{outputRelativePath}' is newer than '{inputPath}'.");
return;
}
try
{
using var sourceStream = File.OpenRead(inputPath);
using var fileStream = File.Create(outputRelativePath);
using var stream = new GZipStream(fileStream, CompressionLevel.Optimal);
sourceStream.CopyTo(stream);
}
catch (Exception e)
{
Log.LogErrorFromException(e);
return;
}
});
return !Log.HasLoggedErrors;
}
}
}

View File

@ -1,155 +0,0 @@
// 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;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization.Json;
using System.Text;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using ResourceHashesByNameDictionary = System.Collections.Generic.Dictionary<string, string>;
namespace Microsoft.AspNetCore.Razor.Tasks
{
public class GenerateBlazorWebAssemblyBootJson : Task
{
[Required]
public string AssemblyPath { get; set; }
[Required]
public ITaskItem[] Resources { get; set; }
[Required]
public bool DebugBuild { get; set; }
[Required]
public bool LinkerEnabled { get; set; }
[Required]
public bool CacheBootResources { get; set; }
public ITaskItem[] ConfigurationFiles { get; set; }
[Required]
public string OutputPath { get; set; }
public ITaskItem[] LazyLoadedAssemblies { get; set; }
public override bool Execute()
{
using var fileStream = File.Create(OutputPath);
var entryAssemblyName = AssemblyName.GetAssemblyName(AssemblyPath).Name;
try
{
WriteBootJson(fileStream, entryAssemblyName);
}
catch (Exception ex)
{
Log.LogErrorFromException(ex);
}
return !Log.HasLoggedErrors;
}
// Internal for tests
public void WriteBootJson(Stream output, string entryAssemblyName)
{
var result = new BootJsonData
{
entryAssembly = entryAssemblyName,
cacheBootResources = CacheBootResources,
debugBuild = DebugBuild,
linkerEnabled = LinkerEnabled,
resources = new ResourcesData(),
config = new List<string>(),
};
// Build a two-level dictionary of the form:
// - assembly:
// - UriPath (e.g., "System.Text.Json.dll")
// - ContentHash (e.g., "4548fa2e9cf52986")
// - runtime:
// - UriPath (e.g., "dotnet.js")
// - ContentHash (e.g., "3448f339acf512448")
if (Resources != null)
{
var resourceData = result.resources;
foreach (var resource in Resources)
{
ResourceHashesByNameDictionary resourceList;
var fileName = resource.GetMetadata("FileName");
var extension = resource.GetMetadata("Extension");
var resourceCulture = resource.GetMetadata("Culture");
var assetType = resource.GetMetadata("AssetType");
var resourceName = $"{fileName}{extension}";
if (IsLazyLoadedAssembly(fileName))
{
resourceData.lazyAssembly ??= new ResourceHashesByNameDictionary();
resourceList = resourceData.lazyAssembly;
}
else if (!string.IsNullOrEmpty(resourceCulture))
{
resourceData.satelliteResources ??= new Dictionary<string, ResourceHashesByNameDictionary>(StringComparer.OrdinalIgnoreCase);
resourceName = resourceCulture + "/" + resourceName;
if (!resourceData.satelliteResources.TryGetValue(resourceCulture, out resourceList))
{
resourceList = new ResourceHashesByNameDictionary();
resourceData.satelliteResources.Add(resourceCulture, resourceList);
}
}
else if (string.Equals(extension, ".pdb", StringComparison.OrdinalIgnoreCase))
{
resourceData.pdb ??= new ResourceHashesByNameDictionary();
resourceList = resourceData.pdb;
}
else if (string.Equals(extension, ".dll", StringComparison.OrdinalIgnoreCase))
{
resourceList = resourceData.assembly;
}
else if (string.Equals(assetType, "native", StringComparison.OrdinalIgnoreCase))
{
resourceList = resourceData.runtime;
}
else
{
// This should include items such as XML doc files, which do not need to be recorded in the manifest.
continue;
}
if (!resourceList.ContainsKey(resourceName))
{
resourceList.Add(resourceName, $"sha256-{resource.GetMetadata("FileHash")}");
}
}
}
if (ConfigurationFiles != null)
{
foreach (var configFile in ConfigurationFiles)
{
result.config.Add(Path.GetFileName(configFile.ItemSpec));
}
}
var serializer = new DataContractJsonSerializer(typeof(BootJsonData), new DataContractJsonSerializerSettings
{
UseSimpleDictionaryFormat = true
});
using var writer = JsonReaderWriterFactory.CreateJsonWriter(output, Encoding.UTF8, ownsStream: false, indent: true);
serializer.WriteObject(writer, result);
}
private bool IsLazyLoadedAssembly(string fileName)
{
return LazyLoadedAssemblies != null && LazyLoadedAssemblies.Any(a => a.ItemSpec == fileName);
}
}
}

View File

@ -1,97 +0,0 @@
// 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;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Json;
using System.Security.Cryptography;
using System.Text;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
namespace Microsoft.AspNetCore.Razor.Tasks
{
public partial class GenerateServiceWorkerAssetsManifest : Task
{
[Required]
public ITaskItem[] Assets { get; set; }
public string Version { get; set; }
[Required]
public string OutputPath { get; set; }
[Output]
public string CalculatedVersion { get; set; }
public override bool Execute()
{
using var fileStream = File.Create(OutputPath);
CalculatedVersion = GenerateAssetManifest(fileStream);
return true;
}
internal string GenerateAssetManifest(Stream stream)
{
var assets = new AssetsManifestFileEntry[Assets.Length];
System.Threading.Tasks.Parallel.For(0, assets.Length, i =>
{
var item = Assets[i];
var hash = item.GetMetadata("FileHash");
var url = item.GetMetadata("AssetUrl");
if (string.IsNullOrEmpty(hash))
{
// Some files that are part of the service worker manifest may not have their hashes previously
// calcualted. Calculate them at this time.
using var sha = SHA256.Create();
using var file = File.OpenRead(item.ItemSpec);
var bytes = sha.ComputeHash(file);
hash = Convert.ToBase64String(bytes);
}
assets[i] = new AssetsManifestFileEntry
{
hash = "sha256-" + hash,
url = url,
};
});
var version = Version;
if (string.IsNullOrEmpty(version))
{
// If a version isn't specified (which is likely the most common case), construct a Version by combining
// the file names + hashes of all the inputs.
var combinedHash = string.Join(
Environment.NewLine,
assets.OrderBy(f => f.url, StringComparer.Ordinal).Select(f => f.hash));
using var sha = SHA256.Create();
var bytes = sha.ComputeHash(Encoding.UTF8.GetBytes(combinedHash));
version = Convert.ToBase64String(bytes).Substring(0, 8);
}
var data = new AssetsManifestFile
{
version = version,
assets = assets,
};
using var streamWriter = new StreamWriter(stream, Encoding.UTF8, bufferSize: 50, leaveOpen: true);
streamWriter.Write("self.assetsManifest = ");
streamWriter.Flush();
using var jsonWriter = JsonReaderWriterFactory.CreateJsonWriter(stream, Encoding.UTF8, ownsStream: false, indent: true);
new DataContractJsonSerializer(typeof(AssetsManifestFile)).WriteObject(jsonWriter, data);
jsonWriter.Flush();
streamWriter.WriteLine(";");
return version;
}
}
}

View File

@ -1,166 +0,0 @@
<!--
***********************************************************************************************
Microsoft.NET.Sdk.Razor.Components.ServiceWorkerAssetsManifest.targets
WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
created a backup copy. Incorrect changes to this file will make it
impossible to load or build your projects from the command-line or the IDE.
Copyright (c) .NET Foundation. All rights reserved.
***********************************************************************************************
-->
<Project>
<UsingTask TaskName="Microsoft.AspNetCore.Razor.Tasks.GenerateServiceWorkerAssetsManifest" AssemblyFile="$(RazorSdkBuildTasksAssembly)" />
<Target Name="_ComputeServiceWorkerAssets" BeforeTargets="ResolveStaticWebAssetsInputs">
<PropertyGroup>
<_ServiceWorkerAssetsManifestIntermediateOutputPath>$(IntermediateOutputPath)$(ServiceWorkerAssetsManifest)</_ServiceWorkerAssetsManifestIntermediateOutputPath>
<_ServiceWorkerAssetsManifestFullPath>$([System.IO.Path]::GetFullPath('$(MSBuildProjectDirectory)/$(_ServiceWorkerAssetsManifestIntermediateOutputPath)'))</_ServiceWorkerAssetsManifestFullPath>
</PropertyGroup>
<ItemGroup>
<_ManifestStaticWebAsset Include="$(_ServiceWorkerAssetsManifestFullPath)">
<SourceType></SourceType>
<SourceId>$(PackageId)</SourceId>
<ContentRoot>$([MSBuild]::NormalizeDirectory('$(TargetDir)wwwroot\'))</ContentRoot>
<BasePath>$(StaticWebAssetBasePath)</BasePath>
<RelativePath>$(ServiceWorkerAssetsManifest)</RelativePath>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</_ManifestStaticWebAsset>
<!-- Figure out where we're getting the content for each @(ServiceWorker) entry, depending on whether there's a PublishedContent value -->
<_ServiceWorkerIntermediateFile Include="@(ServiceWorker->'$(IntermediateOutputPath)serviceworkers\%(Identity)')">
<ContentSourcePath Condition="'%(_ServiceWorker.PublishedContent)' != ''">%(ServiceWorker.PublishedContent)</ContentSourcePath>
<ContentSourcePath Condition="'%(_ServiceWorker.PublishedContent)' == ''">%(ServiceWorker.Identity)</ContentSourcePath>
<OriginalPath>%(ServiceWorker.Identity)</OriginalPath>
<TargetOutputPath>%(ServiceWorker.Identity)</TargetOutputPath>
<TargetOutputPath Condition="$([System.String]::Copy('%(ServiceWorker.Identity)').Replace('\','/').StartsWith('wwwroot/'))">$([System.String]::Copy('%(ServiceWorker.Identity)').Substring(8))</TargetOutputPath>
</_ServiceWorkerIntermediateFile>
<_ServiceWorkerStaticWebAsset Include="%(_ServiceWorkerIntermediateFile.FullPath)">
<SourceType></SourceType>
<SourceId>$(PackageId)</SourceId>
<ContentRoot>$([MSBuild]::NormalizeDirectory('$(TargetDir)wwwroot\'))</ContentRoot>
<BasePath>$(StaticWebAssetBasePath)</BasePath>
<RelativePath>%(TargetOutputPath)</RelativePath>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</_ServiceWorkerStaticWebAsset>
<StaticWebAsset Include="
@(_ManifestStaticWebAsset);
@(_ServiceWorkerStaticWebAsset)" />
</ItemGroup>
</Target>
<Target Name="_WriteServiceWorkerAssetsManifest"
DependsOnTargets="_ComputeServiceWorkerAssets;ResolveStaticWebAssetsInputs">
<ItemGroup>
<_ServiceWorkItem Include="@(StaticWebAsset)" Exclude="$(_ServiceWorkerAssetsManifestFullPath);@(_ServiceWorkerStaticWebAsset)">
<AssetUrl>$([System.String]::Copy('$([System.String]::Copy('%(StaticWebAsset.BasePath)').TrimEnd('/'))/%(StaticWebAsset.RelativePath)').Replace('\','/').TrimStart('/'))</AssetUrl>
</_ServiceWorkItem>
</ItemGroup>
<GenerateServiceWorkerAssetsManifest
Version="$(ServiceWorkerAssetsManifestVersion)"
Assets="@(_ServiceWorkItem)"
OutputPath="$(_ServiceWorkerAssetsManifestIntermediateOutputPath)">
<Output TaskParameter="CalculatedVersion" PropertyName="_ServiceWorkerAssetsManifestVersion" />
</GenerateServiceWorkerAssetsManifest>
<Copy
SourceFiles="%(_ServiceWorkerIntermediateFile.ContentSourcePath)"
DestinationFiles="%(_ServiceWorkerIntermediateFile.Identity)" />
<WriteLinesToFile
File="%(_ServiceWorkerIntermediateFile.Identity)"
Lines="/* Manifest version: $(_ServiceWorkerAssetsManifestVersion) */"
Condition="'$(_ServiceWorkerAssetsManifestVersion)' != ''" />
<ItemGroup>
<FileWrites Include="@(_ServiceWorkerIntermediateFile)" />
<FileWrites Include="$(_ServiceWorkerAssetsManifestIntermediateOutputPath)" />
</ItemGroup>
</Target>
<Target Name="_BlazorStaticAssetsCopyFilesToOutputDirectory" AfterTargets="CopyFilesToOutputDirectory" DependsOnTargets="_WriteServiceWorkerAssetsManifest">
<Copy
SourceFiles="@(_ManifestStaticWebAsset);@(_ServiceWorkerStaticWebAsset)"
DestinationFiles="$(OutDir)wwwroot\%(RelativePath)"
SkipUnchangedFiles="$(SkipCopyUnchangedFiles)"
OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)"
Retries="$(CopyRetryCount)"
RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
UseHardlinksIfPossible="$(CreateHardLinksForCopyFilesToOutputDirectoryIfPossible)"
UseSymboliclinksIfPossible="$(CreateSymbolicLinksForCopyFilesToOutputDirectoryIfPossible)"
ErrorIfLinkFails="$(ErrorIfLinkFailsForCopyFilesToOutputDirectory)">
<Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>
</Copy>
</Target>
<Target Name="_OmitServiceWorkerContent"
BeforeTargets="AssignTargetPaths;ResolveCurrentProjectStaticWebAssetsInputs">
<ItemGroup>
<!-- Don't emit the service worker source files to the output -->
<Content Remove="@(ServiceWorker)" />
<Content Remove="@(ServiceWorker->'%(PublishedContent)')" />
</ItemGroup>
</Target>
<Target Name="_GenerateServiceWorkerFileForPublish"
BeforeTargets="_BlazorCompressPublishFiles"
AfterTargets="_ProcessPublishFilesForBlazor">
<PropertyGroup>
<_ServiceWorkerAssetsManifestPublishIntermediateOutputPath>$(IntermediateOutputPath)publish-$(ServiceWorkerAssetsManifest)</_ServiceWorkerAssetsManifestPublishIntermediateOutputPath>
</PropertyGroup>
<ItemGroup>
<_ServiceWorkerIntermediatePublishFile Include="$(IntermediateOutputPath)serviceworkers\%(FileName).publish%(Extension)">
<ContentSourcePath Condition="'%(ServiceWorker.PublishedContent)' != ''">%(ServiceWorker.PublishedContent)</ContentSourcePath>
<ContentSourcePath Condition="'%(ServiceWorker.PublishedContent)' == ''">%(ServiceWorker.Identity)</ContentSourcePath>
<RelativePath>%(ServiceWorker.Identity)</RelativePath>
</_ServiceWorkerIntermediatePublishFile>
<_ServiceWorkerPublishFile Include="@(ResolvedFileToPublish)" Condition="$([System.String]::Copy('%(ResolvedFileToPublish.RelativePath)').Replace('\','/').StartsWith('wwwroot/'))">
<AssetUrl>$([System.String]::Copy('%(ResolvedFileToPublish.RelativePath)').Replace('\','/').TrimStart('/'))</AssetUrl>
<AssetUrl>$([System.String]::Copy('%(RelativePath)').Replace('\','/').Substring(8))</AssetUrl>
</_ServiceWorkerPublishFile>
</ItemGroup>
<GenerateServiceWorkerAssetsManifest
Version="$(ServiceWorkerAssetsManifestVersion)"
Assets="@(_ServiceWorkerPublishFile)"
OutputPath="$(_ServiceWorkerAssetsManifestPublishIntermediateOutputPath)">
<Output TaskParameter="CalculatedVersion" PropertyName="_ServiceWorkerPublishAssetsManifestVersion" />
</GenerateServiceWorkerAssetsManifest>
<Copy SourceFiles="%(_ServiceWorkerIntermediatePublishFile.ContentSourcePath)"
DestinationFiles="%(_ServiceWorkerIntermediatePublishFile.Identity)" />
<WriteLinesToFile
File="%(_ServiceWorkerIntermediatePublishFile.Identity)"
Lines="/* Manifest version: $(_ServiceWorkerPublishAssetsManifestVersion) */" />
<ItemGroup>
<ResolvedFileToPublish
Include="@(_ServiceWorkerIntermediatePublishFile)"
CopyToPublishDirectory="PreserveNewest"
RelativePath="%(_ServiceWorkerIntermediatePublishFile.RelativePath)"
ExcludeFromSingleFile="true" />
<ResolvedFileToPublish
Include="$(_ServiceWorkerAssetsManifestPublishIntermediateOutputPath)"
CopyToPublishDirectory="PreserveNewest"
RelativePath="wwwroot\$(ServiceWorkerAssetsManifest)"
ExcludeFromSingleFile="true" />
</ItemGroup>
</Target>
</Project>

View File

@ -1,550 +0,0 @@
<!--
***********************************************************************************************
Microsoft.NET.Sdk.Razor.Components.Wasm.targets
WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
created a backup copy. Incorrect changes to this file will make it
impossible to load or build your projects from the command-line or the IDE.
Copyright (c) .NET Foundation. All rights reserved.
***********************************************************************************************
-->
<Project ToolsVersion="14.0">
<UsingTask TaskName="Microsoft.AspNetCore.Razor.Tasks.GenerateBlazorWebAssemblyBootJson" AssemblyFile="$(RazorSdkBuildTasksAssembly)" />
<UsingTask TaskName="Microsoft.AspNetCore.Razor.Tasks.BlazorWriteSatelliteAssemblyFile" AssemblyFile="$(RazorSdkBuildTasksAssembly)" />
<UsingTask TaskName="Microsoft.AspNetCore.Razor.Tasks.BlazorReadSatelliteAssemblyFile" AssemblyFile="$(RazorSdkBuildTasksAssembly)" />
<UsingTask TaskName="Microsoft.AspNetCore.Razor.Tasks.BrotliCompress" AssemblyFile="$(RazorSdkBuildTasksAssembly)" />
<UsingTask TaskName="Microsoft.AspNetCore.Razor.Tasks.GzipCompress" AssemblyFile="$(RazorSdkBuildTasksAssembly)" />
<UsingTask TaskName="Microsoft.AspNetCore.Razor.Tasks.CreateBlazorTrimmerRootDescriptorFile" AssemblyFile="$(RazorSdkBuildTasksAssembly)" />
<PropertyGroup>
<SelfContained>true</SelfContained>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<!-- Trimmer defaults -->
<PublishTrimmed Condition="'$(PublishTrimmed)' == ''">true</PublishTrimmed>
<TrimMode Condition="'$(TrimMode)' == ''">link</TrimMode>
<TrimmerRemoveSymbols Condition="'$(TrimmerRemoveSymbols)' == ''">false</TrimmerRemoveSymbols>
<!-- Runtime feature defaults to trim unnecessary code -->
<EventSourceSupport Condition="'$(EventSourceSupport)' == ''">false</EventSourceSupport>
<UseSystemResourceKeys Condition="'$(UseSystemResourceKeys)' == ''">true</UseSystemResourceKeys>
<EnableUnsafeUTF7Encoding Condition="'$(EnableUnsafeUTF7Encoding)' == ''">false</EnableUnsafeUTF7Encoding>
<HttpActivityPropagationSupport Condition="'$(HttpActivityPropagationSupport)' == ''">false</HttpActivityPropagationSupport>
<DebuggerSupport Condition="'$(DebuggerSupport)' == '' and '$(Configuration)' == 'Release'">false</DebuggerSupport>
<StaticWebAssetBasePath Condition="'$(StaticWebAssetBasePath)' == ''">/</StaticWebAssetBasePath>
<BlazorCacheBootResources Condition="'$(BlazorCacheBootResources)' == ''">true</BlazorCacheBootResources>
<!-- Turn off parts of the build that do not apply to WASM projects -->
<GenerateDependencyFile>false</GenerateDependencyFile>
<GenerateRuntimeConfigurationFiles>false</GenerateRuntimeConfigurationFiles>
<PreserveCompilationContext>false</PreserveCompilationContext>
<PreserveCompilationReferences>false</PreserveCompilationReferences>
<AddRazorSupportForMvc>false</AddRazorSupportForMvc>
<OutputType>exe</OutputType>
<!-- Internal properties -->
<_BlazorOutputPath>wwwroot\_framework\</_BlazorOutputPath>
<_BlazorSatelliteAssemblyCacheFile>$(IntermediateOutputPath)blazor.satelliteasm.props</_BlazorSatelliteAssemblyCacheFile>
<!-- Workaround for https://github.com/dotnet/sdk/issues/12114-->
<PublishDir Condition="'$(AppendRuntimeIdentifierToOutputPath)' != 'true' AND '$(PublishDir)' == '$(OutputPath)$(RuntimeIdentifier)\$(PublishDirName)\'">$(OutputPath)$(PublishDirName)\</PublishDir>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Remove="Microsoft.AspNetCore.App" />
<KnownFrameworkReference Remove="Microsoft.AspNetCore.App" />
</ItemGroup>
<Import Project="Microsoft.NET.Sdk.Razor.Components.ServiceWorkerAssetsManifest.targets" Condition="'$(ServiceWorkerAssetsManifest)' != ''" />
<Target Name="_ScrambleDotnetJsFileName" AfterTargets="ResolveRuntimePackAssets">
<!--
We want the dotnet.js file output to have a version to better work with caching. We'll append the runtime version to the file name as soon as file has been discovered.
-->
<PropertyGroup>
<_DotNetJsVersion>$(BundledNETCoreAppPackageVersion)</_DotNetJsVersion>
<_DotNetJsVersion Condition="'$(RuntimeFrameworkVersion)' != ''">$(RuntimeFrameworkVersion)</_DotNetJsVersion>
<_BlazorDotnetJsFileName>dotnet.$(_DotNetJsVersion).js</_BlazorDotnetJsFileName>
<_BlazorDotNetJsFilePath>$(IntermediateOutputPath)$(_BlazorDotnetJsFileName)</_BlazorDotNetJsFilePath>
</PropertyGroup>
<ItemGroup>
<_DotNetJsItem Include="@(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.DestinationSubPath)' == 'dotnet.js' AND '%(ReferenceCopyLocalPaths.AssetType)' == 'native'" />
</ItemGroup>
<Copy
SourceFiles="@(_DotNetJsItem)"
DestinationFiles="$(_BlazorDotNetJsFilePath)"
SkipUnchangedFiles="true"
OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)" />
<ItemGroup Condition="'@(_DotNetJsItem->Count())' != '0'">
<ReferenceCopyLocalPaths
Include="$(_BlazorDotNetJsFilePath)"
AssetType="native"
CopyLocal="true"
DestinationSubPath="$(_BlazorDotnetJsFileName)" />
<ReferenceCopyLocalPaths Remove="@(_DotNetJsItem)" />
</ItemGroup>
</Target>
<Target Name="_ResolveBlazorWasmOutputs" DependsOnTargets="ResolveReferences;PrepareResourceNames;ComputeIntermediateSatelliteAssemblies">
<!--
Calculates the outputs and the paths for Blazor WASM. This target is invoked frequently and should perform minimal work.
-->
<ItemGroup>
<_BlazorJSFile Include="$(BlazorWebAssemblyJSPath)" />
<_BlazorJSFile Include="$(BlazorWebAssemblyJSMapPath)" Condition="Exists('$(BlazorWebAssemblyJSMapPath)')" />
<_BlazorConfigFile Include="wwwroot\appsettings*.json" />
<!-- Clear out temporary build artifacts that the runtime packages -->
<ReferenceCopyLocalPaths Remove="@(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.Extension)' == '.a'" />
<!--
ReferenceCopyLocalPaths includes satellite assemblies from referenced projects but are inexpicably missing
any metadata that might allow them to be differentiated. We'll explicitly add those
to _BlazorOutputWithTargetPath so that satellite assemblies from packages, the current project and referenced project
are all treated the same.
-->
<_BlazorCopyLocalPath
Include="@(ReferenceCopyLocalPaths)"
Exclude="@(ReferenceSatellitePaths)"/>
<_BlazorCopyLocalPath Include="@(IntermediateSatelliteAssembliesWithTargetPath)">
<DestinationSubDirectory>%(IntermediateSatelliteAssembliesWithTargetPath.Culture)\</DestinationSubDirectory>
</_BlazorCopyLocalPath>
<_BlazorOutputWithTargetPath Include="
@(_BlazorCopyLocalPath);
@(IntermediateAssembly);
@(_DebugSymbolsIntermediatePath);
@(_BlazorJSFile)" />
<_BlazorOutputWithTargetPath Include="@(ReferenceSatellitePaths)">
<Culture>$([System.String]::Copy('%(ReferenceSatellitePaths.DestinationSubDirectory)').Trim('\').Trim('/'))</Culture>
</_BlazorOutputWithTargetPath>
</ItemGroup>
<!--
BuildingProject=false is typically set for referenced projects when building inside VisualStudio.
When building with BuildingProject=false, satellite assemblies do not get resolved (the ones for the current project and the one for
referenced project). Satellite assemblies from packages get resolved.
To workaround this, we'll cache metadata during a regular build, and rehydrate from it when BuildingProject=false.
-->
<BlazorReadSatelliteAssemblyFile
ReadFile="$(_BlazorSatelliteAssemblyCacheFile)"
Condition="'$(BuildingProject)' != 'true' AND EXISTS('$(_BlazorSatelliteAssemblyCacheFile)')">
<Output TaskParameter="SatelliteAssembly" ItemName="_BlazorReadSatelliteAssembly" />
</BlazorReadSatelliteAssemblyFile>
<ItemGroup>
<!-- We've imported a previously Cacheed file. Let's turn in to a _BlazorOutputWithTargetPath -->
<_BlazorOutputWithTargetPath
Include="@(_BlazorReadSatelliteAssembly)"
Exclude="@(_BlazorOutputWithTargetPath)"
Condition="'@(_BlazorReadSatelliteAssembly->Count())' != '0'" />
<!-- Calculate the target path -->
<_BlazorOutputWithTargetPath
TargetPath="$(_BlazorOutputPath)%(_BlazorOutputWithTargetPath.DestinationSubDirectory)%(FileName)%(Extension)"
Condition="'%(__BlazorOutputWithTargetPath.TargetPath)' == ''" />
</ItemGroup>
</Target>
<Target Name="_ProcessBlazorWasmOutputs" DependsOnTargets="_ResolveBlazorWasmOutputs">
<PropertyGroup>
<_BlazorBuildGZipCompressDirectory>$(IntermediateOutputPath)build-gz\</_BlazorBuildGZipCompressDirectory>
</PropertyGroup>
<!--
Compress referenced binaries using GZip during build. This skips files such as the project's assemblies
that change from build to build. Runtime assets contribute to the bulk of the download size. Compressing it
has the most benefit while avoiding any ongoing costs to the dev inner loop.
-->
<ItemGroup>
<_GzipFileToCompressForBuild
Include="@(ReferenceCopyLocalPaths)"
RelativePath="$(_BlazorOutputPath)%(ReferenceCopyLocalPaths.DestinationSubDirectory)%(FileName)%(Extension)"
Condition="'%(Extension)' == '.dll' or '%(ReferenceCopyLocalPaths.AssetType)' == 'native'" />
</ItemGroup>
<GZipCompress
FilesToCompress="@(_GzipFileToCompressForBuild)"
OutputDirectory="$(_BlazorBuildGZipCompressDirectory)">
<Output TaskParameter="CompressedFiles" ItemName="_BlazorBuildGZipCompressedFile" />
<Output TaskParameter="CompressedFiles" ItemName="FileWrites" />
</GZipCompress>
<ItemGroup>
<_BlazorWriteSatelliteAssembly Include="@(_BlazorOutputWithTargetPath->HasMetadata('Culture'))" />
<!-- Retarget ReferenceCopyLocalPaths to copy to the wwwroot directory -->
<ReferenceCopyLocalPaths DestinationSubDirectory="$(_BlazorOutputPath)%(ReferenceCopyLocalPaths.DestinationSubDirectory)" />
</ItemGroup>
<!-- A missing blazor.webassembly.js is our packaging error. Produce an error so it's discovered early. -->
<Error
Text="Unable to find BlazorWebAssembly JS files. This usually indicates a packaging error."
Code="RAZORSDK1007"
Condition="'@(_BlazorJSFile->Count())' == '0'" />
<!--
When building with BuildingProject=false, satellite assemblies do not get resolved (the ones for the current project and the one for
referenced project). BuildingProject=false is typically set for referenced projects when building inside VisualStudio.
To workaround this, we'll cache metadata during a regular build, and rehydrate from it when BuildingProject=false.
-->
<BlazorWriteSatelliteAssemblyFile
SatelliteAssembly="@(_BlazorWriteSatelliteAssembly)"
WriteFile="$(_BlazorSatelliteAssemblyCacheFile)"
Condition="'$(BuildingProject)' == 'true' AND '@(_BlazorWriteSatelliteAssembly->Count())' != '0'" />
<Delete
Files="$(_BlazorSatelliteAssemblyCacheFile)"
Condition="'$(BuildingProject)' == 'true' AND '@(_BlazorWriteSatelliteAssembly->Count())' == '0' and EXISTS('$(_BlazorSatelliteAssemblyCacheFile)')" />
<ItemGroup>
<FileWrites Include="$(_BlazorSatelliteAssemblyCacheFile)" Condition="Exists('$(_BlazorSatelliteAssemblyCacheFile)')" />
</ItemGroup>
<GetFileHash Files="@(_BlazorOutputWithTargetPath)" Algorithm="SHA256" HashEncoding="base64">
<Output TaskParameter="Items" ItemName="_BlazorOutputWithHash" />
</GetFileHash>
</Target>
<PropertyGroup>
<PrepareForRunDependsOn>
_BlazorWasmPrepareForRun;
$(PrepareForRunDependsOn)
</PrepareForRunDependsOn>
<GetCurrentProjectStaticWebAssetsDependsOn>
$(GetCurrentProjectStaticWebAssetsDependsOn);
_BlazorWasmPrepareForRun;
</GetCurrentProjectStaticWebAssetsDependsOn>
</PropertyGroup>
<Target Name="_BlazorWasmPrepareForRun" DependsOnTargets="_ProcessBlazorWasmOutputs">
<PropertyGroup>
<_BlazorBuildBootJsonPath>$(IntermediateOutputPath)blazor.boot.json</_BlazorBuildBootJsonPath>
</PropertyGroup>
<GenerateBlazorWebAssemblyBootJson
AssemblyPath="@(IntermediateAssembly)"
Resources="@(_BlazorOutputWithHash)"
DebugBuild="true"
LinkerEnabled="false"
CacheBootResources="$(BlazorCacheBootResources)"
OutputPath="$(_BlazorBuildBootJsonPath)"
ConfigurationFiles="@(_BlazorConfigFile)"
LazyLoadedAssemblies="@(BlazorWebAssemblyLazyLoad)" />
<ItemGroup>
<FileWrites Include="$(OutDir)$(_BlazorOutputPath)blazor.boot.json" />
</ItemGroup>
<ItemGroup>
<_BlazorWebAssemblyStaticWebAsset Include="$(_BlazorBuildBootJsonPath)">
<SourceId>$(PackageId)</SourceId>
<SourceType></SourceType>
<ContentRoot>$([MSBuild]::NormalizeDirectory('$(TargetDir)wwwroot\'))</ContentRoot>
<BasePath>$(StaticWebAssetBasePath)</BasePath>
<RelativePath>_framework/blazor.boot.json</RelativePath>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</_BlazorWebAssemblyStaticWebAsset>
<_BlazorWebAssemblyStaticWebAsset Include="@(_BlazorOutputWithHash)">
<SourceId>$(PackageId)</SourceId>
<SourceType></SourceType>
<ContentRoot>$([MSBuild]::NormalizeDirectory('$(TargetDir)wwwroot\'))</ContentRoot>
<BasePath>$(StaticWebAssetBasePath)</BasePath>
<RelativePath>$([System.String]::Copy('%(_BlazorOutputWithHash.TargetPath)').Replace('\','/').Substring(8))</RelativePath>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</_BlazorWebAssemblyStaticWebAsset>
<_BlazorWebAssemblyStaticWebAsset Include="@(_BlazorBuildGZipCompressedFile)">
<SourceId>$(PackageId)</SourceId>
<SourceType></SourceType>
<ContentRoot>$([MSBuild]::NormalizeDirectory('$(TargetDir)wwwroot\'))</ContentRoot>
<BasePath>$(StaticWebAssetBasePath)</BasePath>
<RelativePath>$([System.String]::Copy('%(_BlazorBuildGZipCompressedFile.RelativePath)').Replace('\','/').Substring(8))</RelativePath>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</_BlazorWebAssemblyStaticWebAsset>
<StaticWebAsset Include="@(_BlazorWebAssemblyStaticWebAsset)" />
<_ExternalStaticWebAsset Include="@(_BlazorWebAssemblyStaticWebAsset)" SourceType="Generated" />
</ItemGroup>
</Target>
<!-- Mimics the behavior of CopyFilesToOutputDirectory. We simply copy relevant build outputs to the wwwroot directory -->
<Target Name="_BlazorCopyFilesToOutputDirectory" AfterTargets="CopyFilesToOutputDirectory">
<Copy
SourceFiles="@(IntermediateAssembly)"
DestinationFolder="$(OutDir)$(_BlazorOutputPath)"
SkipUnchangedFiles="$(SkipCopyUnchangedFiles)"
OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)"
Retries="$(CopyRetryCount)"
RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
UseHardlinksIfPossible="$(CreateHardLinksForCopyFilesToOutputDirectoryIfPossible)"
UseSymboliclinksIfPossible="$(CreateSymbolicLinksForCopyFilesToOutputDirectoryIfPossible)"
ErrorIfLinkFails="$(ErrorIfLinkFailsForCopyFilesToOutputDirectory)"
Condition="'$(CopyBuildOutputToOutputDirectory)' == 'true' and '$(SkipCopyBuildProduct)' != 'true'">
<Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>
</Copy>
<Message Importance="High" Text="$(MSBuildProjectName) (Blazor output) -&gt; $(TargetDir)wwwroot" Condition="'$(CopyBuildOutputToOutputDirectory)' == 'true' and '$(SkipCopyBuildProduct)'!='true'" />
<Copy
SourceFiles="@(_DebugSymbolsIntermediatePath)"
DestinationFolder="$(OutDir)$(_BlazorOutputPath)"
SkipUnchangedFiles="$(SkipCopyUnchangedFiles)"
OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)"
Retries="$(CopyRetryCount)"
RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
UseHardlinksIfPossible="$(CreateHardLinksForCopyFilesToOutputDirectoryIfPossible)"
UseSymboliclinksIfPossible="$(CreateSymbolicLinksForCopyFilesToOutputDirectoryIfPossible)"
ErrorIfLinkFails="$(ErrorIfLinkFailsForCopyFilesToOutputDirectory)"
Condition="'$(_DebugSymbolsProduced)'=='true' and '$(SkipCopyingSymbolsToOutputDirectory)' != 'true' and '$(CopyOutputSymbolsToOutputDirectory)'=='true'">
<Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>
</Copy>
<Copy
SourceFiles="@(IntermediateSatelliteAssembliesWithTargetPath)"
DestinationFiles="@(IntermediateSatelliteAssembliesWithTargetPath->'$(OutDir)$(_BlazorOutputPath)%(Culture)\$(TargetName).resources.dll')"
SkipUnchangedFiles="$(SkipCopyUnchangedFiles)"
OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)"
Retries="$(CopyRetryCount)"
RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
UseHardlinksIfPossible="$(CreateHardLinksForCopyFilesToOutputDirectoryIfPossible)"
UseSymboliclinksIfPossible="$(CreateSymbolicLinksForCopyFilesToOutputDirectoryIfPossible)"
ErrorIfLinkFails="$(ErrorIfLinkFailsForCopyFilesToOutputDirectory)"
Condition="'@(IntermediateSatelliteAssembliesWithTargetPath)' != ''" >
<Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>
</Copy>
<Copy
SourceFiles="@(_BlazorJSFile);$(_BlazorBuildBootJsonPath)"
DestinationFolder="$(OutDir)$(_BlazorOutputPath)"
SkipUnchangedFiles="$(SkipCopyUnchangedFiles)"
OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)"
Retries="$(CopyRetryCount)"
RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
UseHardlinksIfPossible="$(CreateHardLinksForCopyFilesToOutputDirectoryIfPossible)"
UseSymboliclinksIfPossible="$(CreateSymbolicLinksForCopyFilesToOutputDirectoryIfPossible)"
ErrorIfLinkFails="$(ErrorIfLinkFailsForCopyFilesToOutputDirectory)">
<Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>
</Copy>
<Copy
SourceFiles="@(_BlazorBuildGZipCompressedFile)"
DestinationFiles="@(_BlazorBuildGZipCompressedFile->'$(OutDir)%(RelativePath)')"
SkipUnchangedFiles="$(SkipCopyUnchangedFiles)"
OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)"
Retries="$(CopyRetryCount)"
RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
UseHardlinksIfPossible="$(CreateHardLinksForCopyFilesToOutputDirectoryIfPossible)"
UseSymboliclinksIfPossible="$(CreateSymbolicLinksForCopyFilesToOutputDirectoryIfPossible)"
ErrorIfLinkFails="$(ErrorIfLinkFailsForCopyFilesToOutputDirectory)">
<Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>
</Copy>
</Target>
<Target Name="_BlazorWasmPrepareForLink" BeforeTargets="PrepareForILLink">
<PropertyGroup>
<_BlazorTypeGranularTrimmerDescriptorFile>$(IntermediateOutputPath)typegranularity.trimmerdescriptor.xml</_BlazorTypeGranularTrimmerDescriptorFile>
</PropertyGroup>
<ItemGroup>
<_BlazorTypeGranularAssembly
Include="@(ManagedAssemblyToLink)"
Condition="'%(Extension)' == '.dll' AND ($([System.String]::Copy('%(Filename)').StartsWith('Microsoft.AspNetCore.')) or $([System.String]::Copy('%(Filename)').StartsWith('Microsoft.Extensions.')))">
<Required>false</Required>
<Preserve>all</Preserve>
</_BlazorTypeGranularAssembly>
<ManagedAssemblyToLink
IsTrimmable="true"
Condition="'%(Extension)' == '.dll' AND ($([System.String]::Copy('%(Filename)').StartsWith('Microsoft.AspNetCore.')) or $([System.String]::Copy('%(Filename)').StartsWith('Microsoft.Extensions.')))" />
</ItemGroup>
<CreateBlazorTrimmerRootDescriptorFile
Assemblies="@(_BlazorTypeGranularAssembly)"
TrimmerFile="$(_BlazorTypeGranularTrimmerDescriptorFile)" />
<ItemGroup>
<TrimmerRootDescriptor Include="$(_BlazorTypeGranularTrimmerDescriptorFile)" />
<FileWrites Include="$(_BlazorTypeGranularTrimmerDescriptorFile)" />
</ItemGroup>
</Target>
<Target Name="_ProcessPublishFilesForBlazor" DependsOnTargets="_ResolveBlazorWasmOutputs" AfterTargets="ILLink">
<!--
ResolvedFileToPublish.Culture is missing for satellite assemblies from project references.
Since we need the culture to correctly generate blazor.boot.json, we cross-reference the culture we calculate as part of _ResolveBlazorWasmOutputs
-->
<JoinItems Left="@(ResolvedFileToPublish)"
Right="@(_BlazorOutputWithTargetPath->HasMetadata('Culture'))"
LeftMetadata="*"
RightMetadata="Culture"
ItemSpecToUse="Left">
<Output TaskParameter="JoinResult" ItemName="_ResolvedSatelliteToPublish" />
</JoinItems>
<ItemGroup>
<ResolvedFileToPublish Remove="@(_ResolvedSatelliteToPublish)" />
<ResolvedFileToPublish Include="@(_ResolvedSatelliteToPublish)" />
<ResolvedFileToPublish Remove="@(ResolvedFileToPublish)" Condition="'%(Extension)' == '.a'" />
<!-- Remove dotnet.js from publish output -->
<ResolvedFileToPublish Remove="@(ResolvedFileToPublish)" Condition="'%(ResolvedFileToPublish.RelativePath)' == 'dotnet.js'" />
<!-- Retarget so that items are published to the wwwroot directory -->
<ResolvedFileToPublish
RelativePath="$(_BlazorOutputPath)%(ResolvedFileToPublish.RelativePath)"
Condition="'%(ResolvedFileToPublish.RelativePath)' != 'web.config' AND !$([System.String]::Copy('%(ResolvedFileToPublish.RelativePath)').Replace('\','/').StartsWith('wwwroot/'))" />
<!-- Remove pdbs from the publish output -->
<ResolvedFileToPublish Remove="@(ResolvedFileToPublish)" Condition="'$(DebuggerSupport)' == 'false' AND '%(Extension)' == '.pdb'" />
</ItemGroup>
<ItemGroup Condition="'@(ResolvedFileToPublish->AnyHaveMetadataValue('RelativePath', 'web.config'))' != 'true'">
<ResolvedFileToPublish
Include="$(MSBuildThisFileDirectory)BlazorWasm.web.config"
ExcludeFromSingleFile="true"
CopyToPublishDirectory="PreserveNewest"
RelativePath="web.config" />
</ItemGroup>
<!-- Generate the publish boot json -->
<ItemGroup>
<_BlazorPublishBootResource
Include="@(ResolvedFileToPublish)"
Condition="$([System.String]::Copy('%(RelativePath)').Replace('\','/').StartsWith('wwwroot/_framework')) AND '%(Extension)' != '.a'" />
</ItemGroup>
<GetFileHash Files="@(_BlazorPublishBootResource)" Algorithm="SHA256" HashEncoding="base64">
<Output TaskParameter="Items" ItemName="_BlazorPublishBootResourceWithHash" />
</GetFileHash>
<GenerateBlazorWebAssemblyBootJson
AssemblyPath="@(IntermediateAssembly)"
Resources="@(_BlazorPublishBootResourceWithHash)"
DebugBuild="false"
LinkerEnabled="$(PublishTrimmed)"
CacheBootResources="$(BlazorCacheBootResources)"
OutputPath="$(IntermediateOutputPath)blazor.publish.boot.json"
ConfigurationFiles="@(_BlazorConfigFile)"
LazyLoadedAssemblies="@(BlazorWebAssemblyLazyLoad)" />
<ItemGroup>
<ResolvedFileToPublish
Include="$(IntermediateOutputPath)blazor.publish.boot.json"
RelativePath="$(_BlazorOutputPath)blazor.boot.json" />
<ResolvedFileToPublish
Include="@(_BlazorJSFile)"
RelativePath="$(_BlazorOutputPath)%(FileName)%(Extension)" />
</ItemGroup>
</Target>
<Target Name="_BlazorCompressPublishFiles" AfterTargets="_ProcessPublishFilesForBlazor" Condition="'$(BlazorEnableCompression)' != 'false'">
<PropertyGroup>
<_CompressedFileOutputPath>$(IntermediateOutputPath)compress\</_CompressedFileOutputPath>
<_BlazorWebAssemblyBrotliIncremental>true</_BlazorWebAssemblyBrotliIncremental>
</PropertyGroup>
<ItemGroup>
<_FileToCompress
Include="@(ResolvedFileToPublish)"
Condition="$([System.String]::Copy('%(ResolvedFileToPublish.RelativePath)').Replace('\','/').StartsWith('wwwroot/'))" />
</ItemGroup>
<Message Text="Compressing Blazor WebAssembly publish artifacts. This may take a while..." Importance="High" />
<MakeDir Directories="$(_CompressedFileOutputPath)" Condition="!Exists('$(_CompressedFileOutputPath)')" />
<BrotliCompress
OutputDirectory="$(_CompressedFileOutputPath)"
FilesToCompress="@(_FileToCompress)"
CompressionLevel="$(_BlazorBrotliCompressionLevel)"
SkipIfOutputIsNewer="$(_BlazorWebAssemblyBrotliIncremental)"
ToolAssembly="$(_RazorSdkToolAssembly)">
<Output TaskParameter="CompressedFiles" ItemName="_BrotliCompressedFile" />
<Output TaskParameter="CompressedFiles" ItemName="FileWrites" />
</BrotliCompress>
<GZipCompress
OutputDirectory="$(_CompressedFileOutputPath)"
FilesToCompress="@(_FileToCompress)">
<Output TaskParameter="CompressedFiles" ItemName="_BlazorPublishGZipCompressedFile" />
<Output TaskParameter="CompressedFiles" ItemName="FileWrites" />
</GZipCompress>
<ItemGroup>
<ResolvedFileToPublish Include="@(_BrotliCompressedFile)" />
<ResolvedFileToPublish Include="@(_BlazorPublishGZipCompressedFile)" />
</ItemGroup>
</Target>
<Target Name="_SetupPublishSemaphore" BeforeTargets="PrepareForPublish">
<PropertyGroup>
<!--
Add marker that indicates Blazor WASM is doing a publish. This is used to identify when GetCopyToPublishDirectoryItems
is invoked as a result of a P2P reference.
-->
<_PublishingBlazorWasmProject>true</_PublishingBlazorWasmProject>
</PropertyGroup>
</Target>
<Target Name="_GetBlazorWasmFilesForPublishInner"
DependsOnTargets="_ResolveBlazorWasmOutputs;ComputeFilesToPublish"
Returns="@(ResolvedFileToPublish)" />
<Target Name="_GetBlazorWasmFilesForPublish" BeforeTargets="GetCopyToPublishDirectoryItems">
<MSBuild
Projects="$(MSBuildProjectFullPath)"
Targets="_GetBlazorWasmFilesForPublishInner"
Properties="BuildProjectReferences=false;ResolveAssemblyReferencesFindRelatedSatellites=true;_PublishingBlazorWasmProject=true"
RemoveProperties="NoBuild;RuntimeIdentifier"
BuildInParallel="$(BuildInParallel)"
Condition="'$(_PublishingBlazorWasmProject)' != 'true'">
<Output TaskParameter="TargetOutputs" ItemName="_ResolvedFileToPublish" />
</MSBuild>
<ItemGroup>
<AllPublishItemsFullPathWithTargetPath Include="@(_ResolvedFileToPublish->'%(FullPath)')">
<TargetPath>%(RelativePath)</TargetPath>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</AllPublishItemsFullPathWithTargetPath>
</ItemGroup>
</Target>
<Target Name="_BlazorApplyLinkPreferencesToContent" BeforeTargets="AssignTargetPaths;ResolveCurrentProjectStaticWebAssetsInputs;ResolveStaticWebAssetsInputs" Returns="@(Content)">
<ItemGroup>
<Content
Condition="'%(Content.Link)' != '' AND '%(Content.CopyToPublishDirectory)' == '' AND $([System.String]::Copy('%(Content.Link)').Replace('\','/').StartsWith('wwwroot/'))"
CopyToPublishDirectory="PreserveNewest" />
</ItemGroup>
</Target>
</Project>

View File

@ -58,7 +58,7 @@ Integration with static web assets:
<_ScopedCssExtension>.rz.scp.css</_ScopedCssExtension>
<ResolveStaticWebAssetsInputsDependsOn>$(ResolveStaticWebAssetsInputsDependsOn);_CollectAllScopedCssAssets;AddScopedCssBundle</ResolveStaticWebAssetsInputsDependsOn>
<ResolveCurrentProjectStaticWebAssetsInputsDependsOn>$(ResolveCurrentProjectStaticWebAssetsInputsDependsOn);_AddGeneratedScopedCssFiles</ResolveCurrentProjectStaticWebAssetsInputsDependsOn>
<GetCurrentProjectStaticWebAssetsDependsOn Condition="'$(UseBlazorWebAssembly)' == 'true'">$(GetCurrentProjectStaticWebAssetsDependsOn);IncludeScopedCssBundle;</GetCurrentProjectStaticWebAssetsDependsOn>
<GetCurrentProjectStaticWebAssetsDependsOn Condition="'$(UsingMicrosoftNETSdkBlazorWebAssembly)' == 'true'">$(GetCurrentProjectStaticWebAssetsDependsOn);IncludeScopedCssBundle;</GetCurrentProjectStaticWebAssetsDependsOn>
</PropertyGroup>
<Target Name="ResolveScopedCssInputs">

View File

@ -362,8 +362,6 @@ Copyright (c) .NET Foundation. All rights reserved.
<Import Project="Microsoft.NET.Sdk.Razor.MvcApplicationPartsDiscovery.targets" Condition="'$(_TargetingNETCoreApp30OrLater)' == 'true'" />
<Import Project="Microsoft.NET.Sdk.Razor.Components.Wasm.targets" Condition="'$(_TargetingNET50OrLater)' == 'true' AND '$(UseBlazorWebAssembly)' == 'true'" />
<!--
These are the targets that actually do compilation using CSC, separated from the main file for ease of maintenance.

View File

@ -1,68 +0,0 @@
// 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.Collections.Generic;
using System.IO;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Moq;
using Xunit;
namespace Microsoft.AspNetCore.Razor.Tasks
{
public class BlazorReadSatelliteAssemblyFileTest
{
[Fact]
public void WritesAndReadsRoundTrip()
{
// Arrange/Act
var tempFile = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
var writer = new BlazorWriteSatelliteAssemblyFile
{
BuildEngine = Mock.Of<IBuildEngine>(),
WriteFile = new TaskItem(tempFile),
SatelliteAssembly = new[]
{
new TaskItem("Resources.fr.dll", new Dictionary<string, string>
{
["Culture"] = "fr",
["DestinationSubDirectory"] = "fr\\",
}),
new TaskItem("Resources.ja-jp.dll", new Dictionary<string, string>
{
["Culture"] = "ja-jp",
["DestinationSubDirectory"] = "ja-jp\\",
}),
},
};
var reader = new BlazorReadSatelliteAssemblyFile
{
BuildEngine = Mock.Of<IBuildEngine>(),
ReadFile = new TaskItem(tempFile),
};
writer.Execute();
Assert.True(File.Exists(tempFile), "Write should have succeeded.");
reader.Execute();
Assert.Collection(
reader.SatelliteAssembly,
assembly =>
{
Assert.Equal("Resources.fr.dll", assembly.ItemSpec);
Assert.Equal("fr", assembly.GetMetadata("Culture"));
Assert.Equal("fr\\", assembly.GetMetadata("DestinationSubDirectory"));
},
assembly =>
{
Assert.Equal("Resources.ja-jp.dll", assembly.ItemSpec);
Assert.Equal("ja-jp", assembly.GetMetadata("Culture"));
Assert.Equal("ja-jp\\", assembly.GetMetadata("DestinationSubDirectory"));
});
}
}
}

View File

@ -1,195 +0,0 @@
// 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.Linq;
using System.Runtime.Serialization.Json;
using Microsoft.Build.Framework;
using Moq;
using Xunit;
namespace Microsoft.AspNetCore.Razor.Tasks
{
public class GenerateBlazorWebAssemblyBootJsonTest
{
[Fact]
public void GroupsResourcesByType()
{
// Arrange
var taskInstance = new GenerateBlazorWebAssemblyBootJson
{
AssemblyPath = "MyApp.Entrypoint.dll",
Resources = new[]
{
CreateResourceTaskItem(
("FileName", "My.Assembly1"),
("Extension", ".dll"),
("FileHash", "abcdefghikjlmnopqrstuvwxyz")),
CreateResourceTaskItem(
("FileName", "My.Assembly2"),
("Extension", ".dll"),
("FileHash", "012345678901234567890123456789")),
CreateResourceTaskItem(
("FileName", "SomePdb"),
("Extension", ".pdb"),
("FileHash", "pdbhashpdbhashpdbhash")),
CreateResourceTaskItem(
("FileName", "My.Assembly1"),
("Extension", ".pdb"),
("FileHash", "pdbdefghikjlmnopqrstuvwxyz")),
CreateResourceTaskItem(
("FileName", "some-runtime-file"),
("FileHash", "runtimehashruntimehash"),
("AssetType", "native")),
CreateResourceTaskItem(
("FileName", "satellite-assembly1"),
("Extension", ".dll"),
("FileHash", "hashsatelliteassembly1"),
("Culture", "en-GB")),
CreateResourceTaskItem(
("FileName", "satellite-assembly2"),
("Extension", ".dll"),
("FileHash", "hashsatelliteassembly2"),
("Culture", "fr")),
CreateResourceTaskItem(
("FileName", "satellite-assembly3"),
("Extension", ".dll"),
("FileHash", "hashsatelliteassembly3"),
("Culture", "en-GB")),
}
};
using var stream = new MemoryStream();
// Act
taskInstance.WriteBootJson(stream, "MyEntrypointAssembly");
// Assert
var parsedContent = ParseBootData(stream);
Assert.Equal("MyEntrypointAssembly", parsedContent.entryAssembly);
var resources = parsedContent.resources.assembly;
Assert.Equal(2, resources.Count);
Assert.Equal("sha256-abcdefghikjlmnopqrstuvwxyz", resources["My.Assembly1.dll"]);
Assert.Equal("sha256-012345678901234567890123456789", resources["My.Assembly2.dll"]);
resources = parsedContent.resources.pdb;
Assert.Equal(2, resources.Count);
Assert.Equal("sha256-pdbhashpdbhashpdbhash", resources["SomePdb.pdb"]);
Assert.Equal("sha256-pdbdefghikjlmnopqrstuvwxyz", resources["My.Assembly1.pdb"]);
resources = parsedContent.resources.runtime;
Assert.Single(resources);
Assert.Equal("sha256-runtimehashruntimehash", resources["some-runtime-file"]);
var satelliteResources = parsedContent.resources.satelliteResources;
Assert.Collection(
satelliteResources.OrderBy(kvp => kvp.Key),
kvp =>
{
Assert.Equal("en-GB", kvp.Key);
Assert.Collection(
kvp.Value.OrderBy(item => item.Key),
item =>
{
Assert.Equal("en-GB/satellite-assembly1.dll", item.Key);
Assert.Equal("sha256-hashsatelliteassembly1", item.Value);
},
item =>
{
Assert.Equal("en-GB/satellite-assembly3.dll", item.Key);
Assert.Equal("sha256-hashsatelliteassembly3", item.Value);
});
},
kvp =>
{
Assert.Equal("fr", kvp.Key);
Assert.Collection(
kvp.Value.OrderBy(item => item.Key),
item =>
{
Assert.Equal("fr/satellite-assembly2.dll", item.Key);
Assert.Equal("sha256-hashsatelliteassembly2", item.Value);
});
});
}
[Theory]
[InlineData(false)]
[InlineData(true)]
public void CanSpecifyCacheBootResources(bool flagValue)
{
// Arrange
var taskInstance = new GenerateBlazorWebAssemblyBootJson { CacheBootResources = flagValue };
using var stream = new MemoryStream();
// Act
taskInstance.WriteBootJson(stream, "MyEntrypointAssembly");
// Assert
var parsedContent = ParseBootData(stream);
Assert.Equal(flagValue, parsedContent.cacheBootResources);
}
[Theory]
[InlineData(false)]
[InlineData(true)]
public void CanSpecifyDebugBuild(bool flagValue)
{
// Arrange
var taskInstance = new GenerateBlazorWebAssemblyBootJson { DebugBuild = flagValue };
using var stream = new MemoryStream();
// Act
taskInstance.WriteBootJson(stream, "MyEntrypointAssembly");
// Assert
var parsedContent = ParseBootData(stream);
Assert.Equal(flagValue, parsedContent.debugBuild);
}
[Theory]
[InlineData(false)]
[InlineData(true)]
public void CanSpecifyLinkerEnabled(bool flagValue)
{
// Arrange
var taskInstance = new GenerateBlazorWebAssemblyBootJson { LinkerEnabled = flagValue };
using var stream = new MemoryStream();
// Act
taskInstance.WriteBootJson(stream, "MyEntrypointAssembly");
// Assert
var parsedContent = ParseBootData(stream);
Assert.Equal(flagValue, parsedContent.linkerEnabled);
}
private static BootJsonData ParseBootData(Stream stream)
{
stream.Position = 0;
var serializer = new DataContractJsonSerializer(
typeof(BootJsonData),
new DataContractJsonSerializerSettings { UseSimpleDictionaryFormat = true });
return (BootJsonData)serializer.ReadObject(stream);
}
private static ITaskItem CreateResourceTaskItem(params (string key, string value)[] values)
{
var mock = new Mock<ITaskItem>();
foreach (var (key, value) in values)
{
mock.Setup(m => m.GetMetadata(key)).Returns(value);
}
return mock.Object;
}
}
}

View File

@ -7,9 +7,6 @@
<ProjectReference Include="..\SimpleMvc21\SimpleMvc21.csproj" />
<ProjectReference Include="..\SimpleMvc31\SimpleMvc31.csproj" />
<ProjectReference Include="..\blazor31\blazor31.csproj" />
<ProjectReference Include="..\blazorhosted\blazorhosted.csproj" />
<ProjectReference Include="..\blazorhosted-rid\blazorhosted-rid.csproj" />
<ProjectReference Include="..\blazorwasm\blazorwasm.csproj" />
<ProjectReference Include="..\ClassLibraryMvc21\ClassLibraryMvc21.csproj" />
<ProjectReference Include="..\AppWithP2PReference\AppWithP2PReference.csproj" />
<ProjectReference Include="..\AppWithPackageAndP2PReferenceAndRID\AppWithPackageAndP2PReferenceAndRID.csproj" />