<!--
***********************************************************************************************
Microsoft.NET.Sdk.BlazorWebAssembly.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">
  <PropertyGroup>
    <EnableDefaultContentItems Condition=" '$(EnableDefaultContentItems)' == '' ">true</EnableDefaultContentItems>

    <!-- Trimmer defaults that depend on user-definable settings.
        This must be configured before it's initialized in the .NET SDK targets (which are imported by the Razor SDK). -->
    <SuppressTrimAnalysisWarnings Condition="'$(SuppressTrimAnalysisWarnings)' == '' And '$(TrimmerDefaultAction)' != 'link'">true</SuppressTrimAnalysisWarnings>
  </PropertyGroup>

  <!--
    Targets supporting Razor MSBuild integration. Contain support for generating C# code using Razor
    and including the generated code in the project lifecycle, including compiling, publishing and producing
    nuget packages.
  -->

  <PropertyGroup>
    <!-- Paths to tools, tasks, and extensions are calculated relative to the BlazorWebAssemblySdkDirectoryRoot. This can be modified to test a local build. -->
    <BlazorWebAssemblySdkDirectoryRoot Condition="'$(BlazorWebAssemblySdkDirectoryRoot)'==''">$(MSBuildThisFileDirectory)..\</BlazorWebAssemblySdkDirectoryRoot>
    <_BlazorWebAssemblySdkTasksTFM Condition=" '$(MSBuildRuntimeType)' == 'Core'">net8.0</_BlazorWebAssemblySdkTasksTFM>
    <_BlazorWebAssemblySdkTasksTFM Condition=" '$(MSBuildRuntimeType)' != 'Core'">net472</_BlazorWebAssemblySdkTasksTFM>
    <_BlazorWebAssemblySdkTasksAssembly>$(BlazorWebAssemblySdkDirectoryRoot)tools\$(_BlazorWebAssemblySdkTasksTFM)\Microsoft.NET.Sdk.BlazorWebAssembly.Tasks.dll</_BlazorWebAssemblySdkTasksAssembly>
    <_BlazorWebAssemblySdkToolAssembly>$(BlazorWebAssemblySdkDirectoryRoot)tools\net8.0\Microsoft.NET.Sdk.BlazorWebAssembly.Tool.dll</_BlazorWebAssemblySdkToolAssembly>
  </PropertyGroup>

  <UsingTask TaskName="Microsoft.NET.Sdk.BlazorWebAssembly.GenerateBlazorWebAssemblyBootJson50" AssemblyFile="$(_BlazorWebAssemblySdkTasksAssembly)" />
  <UsingTask TaskName="Microsoft.NET.Sdk.BlazorWebAssembly.BlazorWriteSatelliteAssemblyFile" AssemblyFile="$(_BlazorWebAssemblySdkTasksAssembly)" />
  <UsingTask TaskName="Microsoft.NET.Sdk.BlazorWebAssembly.BlazorReadSatelliteAssemblyFile" AssemblyFile="$(_BlazorWebAssemblySdkTasksAssembly)" />
  <UsingTask TaskName="Microsoft.NET.Sdk.BlazorWebAssembly.BrotliCompress" AssemblyFile="$(_BlazorWebAssemblySdkTasksAssembly)" />
  <UsingTask TaskName="Microsoft.NET.Sdk.BlazorWebAssembly.GzipCompress" AssemblyFile="$(_BlazorWebAssemblySdkTasksAssembly)" />
  <UsingTask TaskName="Microsoft.NET.Sdk.BlazorWebAssembly.CreateBlazorTrimmerRootDescriptorFile" AssemblyFile="$(_BlazorWebAssemblySdkTasksAssembly)" />

  <PropertyGroup>
    <SelfContained>true</SelfContained>
    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

    <!-- Runtime feature defaults to trim unnecessary code -->
    <InvariantGlobalization Condition="'$(InvariantGlobalization)' == ''">false</InvariantGlobalization>
    <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)' != 'Debug'">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>
    <IsWebConfigTransformDisabled>true</IsWebConfigTransformDisabled>

    <!-- Don't generate a NETSDK1151 error if a non self-contained Exe references a Blazor Exe -->
    <ShouldBeValidatedAsExecutableReference>false</ShouldBeValidatedAsExecutableReference>

    <!-- Internal properties -->
    <_BlazorOutputPath>wwwroot\_framework\</_BlazorOutputPath>

    <_TargetingNET60OrLater Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp' AND $([MSBuild]::VersionGreaterThanOrEquals('$(TargetFrameworkVersion)', '6.0'))">true</_TargetingNET60OrLater>
  </PropertyGroup>

  <ItemGroup>
    <!-- Configuration for the platform compatibility analyzer. See https://github.com/dotnet/designs/blob/main/accepted/2020/platform-exclusion/platform-exclusion.md#build-configuration-for-platforms -->
    <SupportedPlatform Remove="@(SupportedPlatform)" />
    <SupportedPlatform Include="browser" />
  </ItemGroup>

  <Import Project="Microsoft.NET.Sdk.BlazorWebAssembly.ServiceWorkerAssetsManifest.5_0.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.
    -->
    <ItemGroup>
      <_DotNetJsItem Include="@(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.DestinationSubPath)' == 'dotnet.js' AND '%(ReferenceCopyLocalPaths.AssetType)' == 'native'" />
    </ItemGroup>

    <PropertyGroup>
      <_DotNetJsVersion>%(_DotNetJsItem.NuGetPackageVersion)</_DotNetJsVersion>
      <_BlazorDotnetJsFileName>dotnet.$(_DotNetJsVersion).js</_BlazorDotnetJsFileName>
      <_BlazorDotNetJsFilePath>$(IntermediateOutputPath)$(_BlazorDotnetJsFileName)</_BlazorDotNetJsFilePath>
    </PropertyGroup>

    <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.
    -->

    <PropertyGroup>
      <_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>

      <_BlazorWebAssemblyLoadAllGlobalizationData>$(BlazorWebAssemblyLoadAllGlobalizationData)</_BlazorWebAssemblyLoadAllGlobalizationData>
      <_BlazorWebAssemblyLoadAllGlobalizationData Condition="'$(_BlazorWebAssemblyLoadAllGlobalizationData)' == ''">false</_BlazorWebAssemblyLoadAllGlobalizationData>
    </PropertyGroup>

    <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 Remove="@(ReferenceCopyLocalPaths)"
        Condition="'$(BlazorEnableTimeZoneSupport)' == 'false' AND '%(ReferenceCopyLocalPaths.FileName)%(ReferenceCopyLocalPaths.Extension)' == 'dotnet.timezones.blat'" />

      <ReferenceCopyLocalPaths Remove="@(ReferenceCopyLocalPaths)"
        Condition="'$(InvariantGlobalization)' == 'true' AND '%(ReferenceCopyLocalPaths.Extension)' == '.dat' AND $([System.String]::Copy('%(ReferenceCopyLocalPaths.FileName)').StartsWith('icudt'))" />

      <!--
        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);
      _BlazorWasmReplaceBundle;
      _BlazorWasmPrepareForRun;
    </GetCurrentProjectStaticWebAssetsDependsOn>

    <GetCurrentProjectStaticWebAssetsV2DependsOn>
      $(GetCurrentProjectStaticWebAssetsV2DependsOn);
      _UpdateBlazorWasmStaticWebAssetsForV2;
    </GetCurrentProjectStaticWebAssetsV2DependsOn>
  </PropertyGroup>

  <Target Name="_BlazorWasmReplaceBundle">
    <ItemGroup>
      <StaticWebAsset Include="@(_AppBundleStaticWebAsset)" />
      <Staticwebasset Remove="@(_ProjectBundleStaticWebAsset)" />
    </ItemGroup>
  </Target>

  <Target Name="_UpdateBlazorWasmStaticWebAssetsForV2" DependsOnTargets="GetCurrentProjectStaticWebAssets">
    <ItemGroup>
      <_CurrentWasmProjectStaticWebAssets Include="@(_ThisProjectStaticWebAssets)" Condition="'%(SourceId)' == '$(PackageId)'" />
      <_CurrentWasmProjectStaticWebAssets>
        <!-- We set the asset kind explicitly to build because blazor before 6.0 did its own publishing and was
             not fully integrated with static web assets, so we let it be even when called from 6.0 targets
        -->
        <AssetKind>Build</AssetKind>
      </_CurrentWasmProjectStaticWebAssets>
      <_ThisProjectStaticWebAssets Remove="@(_CurrentWasmProjectStaticWebAssets)" />
      <_ThisProjectStaticWebAssets Include="@(_CurrentWasmProjectStaticWebAssets)" />
    </ItemGroup>
  </Target>

  <Target Name="_BlazorWasmPrepareForRun" DependsOnTargets="_ProcessBlazorWasmOutputs" BeforeTargets="_RazorPrepareForRun" AfterTargets="GetCurrentProjectStaticWebAssets">
    <PropertyGroup>
      <_BlazorBuildBootJsonPath>$(IntermediateOutputPath)blazor.boot.json</_BlazorBuildBootJsonPath>
      <_BlazorOutputContent>@(_BlazorOutputWithHash)</_BlazorOutputContent>
      <_BlazorWebAssemblyLoadAllGlobalizationData Condition="'$(BlazorWebAssemblyLoadAllGlobalizationData)' == ''">false</_BlazorWebAssemblyLoadAllGlobalizationData>
    </PropertyGroup>

    <Error
      Text="Unable to find %(BlazorWebAssemblyLazyLoad.Identity) to be lazy loaded later. Confirm that project or package references are included and the reference is used in the project."
      Code="BLAZORSDK1001"
      Condition="'@(BlazorWebAssemblyLazyLoad)' != '' And !($([System.String]::Copy('$(_BlazorOutputContent)').Contains('%(BlazorWebAssemblyLazyLoad.Identity)')))" />

    <GenerateBlazorWebAssemblyBootJson50
      AssemblyPath="@(IntermediateAssembly)"
      Resources="@(_BlazorOutputWithHash)"
      DebugBuild="true"
      LinkerEnabled="false"
      CacheBootResources="$(BlazorCacheBootResources)"
      OutputPath="$(_BlazorBuildBootJsonPath)"
      ConfigurationFiles="@(_BlazorConfigFile)"
      LazyLoadedAssemblies="@(BlazorWebAssemblyLazyLoad)"
      InvariantGlobalization="$(InvariantGlobalization)"
      LoadAllICUData="$(_BlazorWebAssemblyLoadAllGlobalizationData)" />

    <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>

  <!--
    This target configures special trimming for Microsoft.Extensions.* and Microsoft.AspNetCore.* assemblies.
    We only need this for net5.0 projects since trimmablity is declared using assembly attributes in net6.0 and later.
  -->
  <Target Name="_BlazorWasmPrepareForLink" BeforeTargets="PrepareForILLink" Condition="'$(_TargetingNET60OrLater)' != 'true'">
    <PropertyGroup>
      <_BlazorTypeGranularTrimmerDescriptorFile>$(IntermediateOutputPath)typegranularity.trimmerdescriptor.xml</_BlazorTypeGranularTrimmerDescriptorFile>
    </PropertyGroup>

    <ItemGroup>
      <_BlazorTypeGranularAssembly
          Include="@(ManagedAssemblyToLink)"
          Condition="'%(Extension)' == '.dll' AND $([System.String]::Copy('%(Filename)').StartsWith('Microsoft.AspNetCore.'))">
        <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>

    <PropertyGroup>
      <_BlazorPublishOutputPath Condition="'$(StaticWebAssetBasePath)' != '/'">wwwroot\$(StaticWebAssetBasePath.Replace('/', '\').Trim('\'))\</_BlazorPublishOutputPath>
      <_BlazorPublishOutputPath Condition="'$(StaticWebAssetBasePath)' == '/'">wwwroot\</_BlazorPublishOutputPath>
      <_BlazorFrameworkPublishPath>$(_BlazorPublishOutputPath)_framework\</_BlazorFrameworkPublishPath>
    </PropertyGroup>

    <ItemGroup>
      <ResolvedFileToPublish Remove="@(_ResolvedSatelliteToPublish)" />
      <ResolvedFileToPublish Include="@(_ResolvedSatelliteToPublish)" />

      <ResolvedFileToPublish Remove="@(ResolvedFileToPublish)" Condition="'%(Extension)' == '.a'" />

      <ResolvedFileToPublish Remove="@(ResolvedFileToPublish)"
        Condition="'$(BlazorEnableTimeZoneSupport)' == 'false' AND '%(ResolvedFileToPublish.FileName)%(ResolvedFileToPublish.Extension)' == 'dotnet.timezones.blat'" />

      <ResolvedFileToPublish Remove="@(ResolvedFileToPublish)"
        Condition="'$(InvariantGlobalization)' == 'true' AND '%(ResolvedFileToPublish.Extension)' == '.dat' AND $([System.String]::Copy('%(ResolvedFileToPublish.FileName)').StartsWith('icudt'))" />

      <!-- Remove dotnet.js from publish output -->
      <ResolvedFileToPublish Remove="@(ResolvedFileToPublish)" Condition="'%(ResolvedFileToPublish.RelativePath)' == 'dotnet.js'" />

      <!-- Remove pdbs from the publish output -->
      <ResolvedFileToPublish Remove="@(ResolvedFileToPublish)" Condition="'$(CopyOutputSymbolsToPublishDirectory)' != 'true' AND '%(Extension)' == '.pdb'" />

      <!-- Retarget so that items are published to the wwwroot directory -->
      <!--
        This changes files (such as wwwroot/index.html) that are published to $(PublishDir)wwwroot\ -> $(PublishDir)wwwroot\$(StaticWebAssetBasePath)\.
        Ignore any user specified web.config in the process.
      -->
      <ResolvedFileToPublish
        RelativePath="$(_BlazorPublishOutputPath)$([System.String]::Copy('%(ResolvedFileToPublish.RelativePath)').Replace('/','\').Substring(8))"
        Condition="'$(StaticWebAssetBasePath)' != '/' AND $([System.String]::Copy('%(ResolvedFileToPublish.RelativePath)').Replace('/','\').StartsWith('wwwroot\'))" />

      <!--
        Change all remaining publish output to publish to appear under the $(PublishDir)wwwroot\$(StaticWebAssetBasePath) path.
      -->
      <ResolvedFileToPublish
        RelativePath="$(_BlazorFrameworkPublishPath)%(ResolvedFileToPublish.RelativePath)"
        Condition="'%(ResolvedFileToPublish.RelativePath)' != 'web.config' AND !$([System.String]::Copy('%(ResolvedFileToPublish.RelativePath)').Replace('/','\').StartsWith('wwwroot\'))" />
    </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($(_BlazorFrameworkPublishPath.Replace('\', '/')))) AND '%(Extension)' != '.a'" />
    </ItemGroup>

    <GetFileHash Files="@(_BlazorPublishBootResource)" Algorithm="SHA256" HashEncoding="base64">
      <Output TaskParameter="Items" ItemName="_BlazorPublishBootResourceWithHash" />
    </GetFileHash>

    <PropertyGroup>
      <_BlazorOutputContent>@(_BlazorPublishBootResourceWithHash)</_BlazorOutputContent>
    </PropertyGroup>

    <Error
      Text="Unable to find %(BlazorWebAssemblyLazyLoad.Identity) to be lazy loaded later. Confirm that project or package references are included and the reference is used in the project."
      Code="BLAZORSDK1001"
      Condition="'@(BlazorWebAssemblyLazyLoad)' != '' And !($([System.String]::Copy('$(_BlazorOutputContent)').Contains('%(BlazorWebAssemblyLazyLoad.Identity)')))" />

    <GenerateBlazorWebAssemblyBootJson50
      AssemblyPath="@(IntermediateAssembly)"
      Resources="@(_BlazorPublishBootResourceWithHash)"
      DebugBuild="false"
      LinkerEnabled="$(PublishTrimmed)"
      CacheBootResources="$(BlazorCacheBootResources)"
      OutputPath="$(IntermediateOutputPath)blazor.publish.boot.json"
      ConfigurationFiles="@(_BlazorConfigFile)"
      LazyLoadedAssemblies="@(BlazorWebAssemblyLazyLoad)"
      InvariantGlobalization="$(InvariantGlobalization)"
      LoadAllICUData="$(_BlazorWebAssemblyLoadAllGlobalizationData)" />

    <ItemGroup>
      <ResolvedFileToPublish
        Include="$(IntermediateOutputPath)blazor.publish.boot.json"
        RelativePath="$(_BlazorFrameworkPublishPath)blazor.boot.json" />

      <ResolvedFileToPublish
        Include="@(_BlazorJSFile)"
        RelativePath="$(_BlazorFrameworkPublishPath)%(FileName)%(Extension)" />
    </ItemGroup>
  </Target>

  <Target
      Name="_BlazorWasmNative"
      DependsOnTargets="_EnsureWasmRuntimeWorkload;_GatherWasmFilesToBuild;WasmBuildApp"
      BeforeTargets="_ProcessPublishFilesForBlazor"
      Condition="'$(UsingBrowserRuntimeWorkload)' == 'true'">

    <!--
      Native compilation produces a copy of the dotnet.js and dotnet.wasm file that are required to run the app. Replace the regular js and wams files with the AOTed version.
      But first, mangle the new dotnet.js file to include the runtime version.
    -->

    <Copy SourceFiles="@(WasmNativeAsset)" DestinationFiles="%(RootDir)%(Directory)\dotnet.$(_DotNetJsVersion).js" Condition="%(FileName) == 'dotnet' AND %(Extension) == '.js'">
      <Output TaskParameter="CopiedFiles" ItemName="_PublishNativeDotnetJsFile" />
    </Copy>

    <ItemGroup>
      <ResolvedFileToPublish Remove="$(_BlazorDotNetJSFilePath)" Condition="'@(WasmNativeAsset->Count())' != '0'"/>
      <ResolvedFileToPublish Remove="@(ResolvedFileToPublish)" Condition="(%(FileName) == 'dotnet' AND %(Extension) == '.wasm') AND '@(WasmNativeAsset->Count())' != '0'" />

      <ResolvedFileToPublish Include="@(_PublishNativeDotnetJsFile)" AssetType="native" RelativePath="%(FileName)%(Extension)" />
      <ResolvedFileToPublish Include="@(WasmNativeAsset)" AssetType="native" RelativePath="dotnet.wasm" Condition="%(FileName) == 'dotnet' AND %(Extension) == '.wasm'"/>
    </ItemGroup>
  </Target>

  <Target Name="_EnsureWasmRuntimeWorkload" Condition="'$(UsingBlazorAOTWorkloadManifest)' != 'true'">
    <Error
      Text="Publishing with AOT enabled requires the .NET WebAssembly AOT workload to be installed. To learn more, visit https://aka.ms/AAb4uzl."
      Code="BLAZORSDK1002" />
  </Target>

  <Target Name="_GatherWasmFilesToBuild">
    <ItemGroup>
      <WasmAssembliesToBundle Include="%(ResolvedFileToPublish.FullPath)" Exclude="@(_Exclude)" Condition="%(Extension) == '.dll' AND %(FileName) != 'Microsoft.JSInterop.WebAssembly'" />
    </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)')" />

    <PropertyGroup Condition="'$(DOTNET_HOST_PATH)' == ''">
      <_DotNetHostDirectory>$(NetCoreRoot)</_DotNetHostDirectory>
      <_DotNetHostFileName>dotnet</_DotNetHostFileName>
      <_DotNetHostFileName Condition="'$(OS)' == 'Windows_NT'">dotnet.exe</_DotNetHostFileName>
    </PropertyGroup>

    <BrotliCompress
      OutputDirectory="$(_CompressedFileOutputPath)"
      FilesToCompress="@(_FileToCompress)"
      CompressionLevel="$(_BlazorBrotliCompressionLevel)"
      SkipIfOutputIsNewer="$(_BlazorWebAssemblyBrotliIncremental)"
      ToolAssembly="$(_BlazorWebAssemblySdkToolAssembly)"
      ToolExe="$(_DotNetHostFileName)"
      ToolPath="$(_DotNetHostDirectory)">

      <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>
