From e29ba3589f2fd96bb8226e4fd8de2e94d21fd7db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Fi=C5=A1era?= Date: Thu, 20 Feb 2025 14:59:26 +0100 Subject: [PATCH 1/5] Allow to fingerprint Blazor.js --- ...soft.NET.Sdk.BlazorWebAssembly.6_0.targets | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/src/BlazorWasmSdk/Targets/Microsoft.NET.Sdk.BlazorWebAssembly.6_0.targets b/src/BlazorWasmSdk/Targets/Microsoft.NET.Sdk.BlazorWebAssembly.6_0.targets index f632de9957f9..c88f66a3fe86 100644 --- a/src/BlazorWasmSdk/Targets/Microsoft.NET.Sdk.BlazorWebAssembly.6_0.targets +++ b/src/BlazorWasmSdk/Targets/Microsoft.NET.Sdk.BlazorWebAssembly.6_0.targets @@ -49,6 +49,7 @@ Copyright (c) .NET Foundation. All rights reserved. false false true + true <_TargetingNETBefore80>$([MSBuild]::VersionLessThan('$(TargetFrameworkVersion)', '8.0')) <_TargetingNET80OrLater>$([MSBuild]::VersionGreaterThanOrEquals('$(TargetFrameworkVersion)', '8.0')) @@ -83,6 +84,15 @@ Copyright (c) .NET Foundation. All rights reserved. GenerateBuildBlazorBootExtensionJson; + + $(ResolvePublishRelatedStaticWebAssetsDependsOn); + _ReplaceFingerprintedBlazorJsForPublish + + + $(ResolveCompressedFilesForPublishDependsOn); + _ReplaceFingerprintedBlazorJsForPublish + + $(GeneratePublishWasmBootJsonDependsOn); GeneratePublishBlazorBootExtensionJson; @@ -104,6 +114,7 @@ Copyright (c) .NET Foundation. All rights reserved. <_BlazorJsFile> _framework/%(Filename)%(Extension) + <_BlazorJSFingerprintPattern Include="Js" Pattern="*.js" Expression="#[.{fingerprint}]!" Condition="'$(BlazorFingerprintBlazorJs)' == 'true'" /> + + + <_BlazorJSStaticWebAsset Include="@(StaticWebAsset)" Condition="'%(FileName)' == '%(_BlazorJSFile.FileName)'" /> + <_BlazorJSPublishCandidate Include="%(_BlazorJSStaticWebAsset.RelativeDir)%(_BlazorJSStaticWebAsset.FileName).%(_BlazorJSStaticWebAsset.Fingerprint)%(_BlazorJSStaticWebAsset.Extension)" /> + + + + + + + + + + <_BlazorJSStaticWebAssetFullPath>@(_BlazorJSStaticWebAsset->'%(FullPath)') + + + <_BlazorJSStaticWebAsset Include="@(StaticWebAsset)" Condition="'%(AssetTraitName)' == 'Content-Encoding' and '%(RelatedAsset)' == '$(_BlazorJSStaticWebAssetFullPath)'" /> + + + + + + + + + + + + From 5bf13db70638d7f5f07b6fdfa4459c05da35690e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Fi=C5=A1era?= Date: Fri, 21 Feb 2025 10:57:04 +0100 Subject: [PATCH 2/5] Fix relative path for publish fingerprinted asset --- .../Targets/Microsoft.NET.Sdk.BlazorWebAssembly.6_0.targets | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/BlazorWasmSdk/Targets/Microsoft.NET.Sdk.BlazorWebAssembly.6_0.targets b/src/BlazorWasmSdk/Targets/Microsoft.NET.Sdk.BlazorWebAssembly.6_0.targets index c88f66a3fe86..2ebbddb1daaf 100644 --- a/src/BlazorWasmSdk/Targets/Microsoft.NET.Sdk.BlazorWebAssembly.6_0.targets +++ b/src/BlazorWasmSdk/Targets/Microsoft.NET.Sdk.BlazorWebAssembly.6_0.targets @@ -160,12 +160,15 @@ Copyright (c) .NET Foundation. All rights reserved. <_BlazorJSStaticWebAsset Include="@(StaticWebAsset)" Condition="'%(FileName)' == '%(_BlazorJSFile.FileName)'" /> <_BlazorJSPublishCandidate Include="%(_BlazorJSStaticWebAsset.RelativeDir)%(_BlazorJSStaticWebAsset.FileName).%(_BlazorJSStaticWebAsset.Fingerprint)%(_BlazorJSStaticWebAsset.Extension)" /> + <_BlazorJSPublishCandidate> + _framework/$([System.IO.Path]::GetFileNameWithoutExtension('%(Filename)'))%(Extension) + Date: Fri, 21 Feb 2025 10:57:26 +0100 Subject: [PATCH 3/5] Update test to assert fingerprinted blazor.js --- .../StaticWebAssetsFingerprintingTest.cs | 27 +++++++++---------- .../BlazorWasmMinimal/wwwroot/index.html | 2 +- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/test/Microsoft.NET.Sdk.Razor.Tests/StaticWebAssetsFingerprintingTest.cs b/test/Microsoft.NET.Sdk.Razor.Tests/StaticWebAssetsFingerprintingTest.cs index 10e90ba8d34b..d4ea7b283165 100644 --- a/test/Microsoft.NET.Sdk.Razor.Tests/StaticWebAssetsFingerprintingTest.cs +++ b/test/Microsoft.NET.Sdk.Razor.Tests/StaticWebAssetsFingerprintingTest.cs @@ -46,15 +46,15 @@ public void Build_FingerprintsContent_WhenEnabled() AssertBuildAssets(manifest1, outputPath, intermediateOutputPath); } - public static TheoryData WriteImportMapToHtmlData => new TheoryData + public static TheoryData WriteImportMapToHtmlData => new TheoryData { - { "VanillaWasm", true }, - { "BlazorWasmMinimal", false } + { "VanillaWasm", "main.js" }, + { "BlazorWasmMinimal", "_framework/blazor.webassembly.js" } }; [Theory] [MemberData(nameof(WriteImportMapToHtmlData))] - public void Build_WriteImportMapToHtml(string testAsset, bool assetMainJs) + public void Build_WriteImportMapToHtml(string testAsset, string scriptPath) { ProjectDirectory = CreateAspNetSdkTestAsset(testAsset); @@ -65,12 +65,12 @@ public void Build_WriteImportMapToHtml(string testAsset, bool assetMainJs) var indexHtmlPath = Directory.EnumerateFiles(Path.Combine(intermediateOutputPath, "staticwebassets", "importmaphtml", "build"), "*.html").Single(); var endpointsManifestPath = Path.Combine(intermediateOutputPath, $"staticwebassets.build.endpoints.json"); - AssertImportMapInHtml(indexHtmlPath, endpointsManifestPath, assetMainJs); + AssertImportMapInHtml(indexHtmlPath, endpointsManifestPath, scriptPath); } [Theory] [MemberData(nameof(WriteImportMapToHtmlData))] - public void Publish_WriteImportMapToHtml(string testAsset, bool assetMainJs) + public void Publish_WriteImportMapToHtml(string testAsset, string scriptPath) { ProjectDirectory = CreateAspNetSdkTestAsset(testAsset); @@ -83,26 +83,23 @@ public void Publish_WriteImportMapToHtml(string testAsset, bool assetMainJs) var indexHtmlPath = Path.Combine(outputPath, "wwwroot", "index.html"); var endpointsManifestPath = Path.Combine(outputPath, $"{projectName}.staticwebassets.endpoints.json"); - AssertImportMapInHtml(indexHtmlPath, endpointsManifestPath, assetMainJs); + AssertImportMapInHtml(indexHtmlPath, endpointsManifestPath, scriptPath); } - private void AssertImportMapInHtml(string indexHtmlPath, string endpointsManifestPath, bool assetMainJs) + private void AssertImportMapInHtml(string indexHtmlPath, string endpointsManifestPath, string scriptPath) { var indexHtmlContent = File.ReadAllText(indexHtmlPath); var endpoints = JsonSerializer.Deserialize(File.ReadAllText(endpointsManifestPath)); - if (assetMainJs) - { - var mainJs = GetFingerprintedPath("main.js"); - Assert.DoesNotContain("src=\"main.js\"", indexHtmlContent); - Assert.Contains($"src=\"{mainJs}\"", indexHtmlContent); - } + var fingerprintedScriptPath = GetFingerprintedPath(scriptPath); + Assert.DoesNotContain($"src=\"{scriptPath}\"", indexHtmlContent); + Assert.Contains($"src=\"{fingerprintedScriptPath}\"", indexHtmlContent); Assert.Contains(GetFingerprintedPath("_framework/dotnet.js"), indexHtmlContent); Assert.Contains(GetFingerprintedPath("_framework/dotnet.native.js"), indexHtmlContent); Assert.Contains(GetFingerprintedPath("_framework/dotnet.runtime.js"), indexHtmlContent); string GetFingerprintedPath(string route) - => endpoints.Endpoints.FirstOrDefault(e => e.Route == route && e.Selectors.Length == 0)?.AssetFile ?? throw new Exception($"Missing endpoint for file '{route}'"); + => endpoints.Endpoints.FirstOrDefault(e => e.Route == route && e.Selectors.Length == 0)?.AssetFile ?? throw new Exception($"Missing endpoint for file '{route}' in '{endpointsManifestPath}'"); } } diff --git a/test/TestAssets/TestProjects/BlazorWasmMinimal/wwwroot/index.html b/test/TestAssets/TestProjects/BlazorWasmMinimal/wwwroot/index.html index 137d7b54777f..a99f4e317e15 100644 --- a/test/TestAssets/TestProjects/BlazorWasmMinimal/wwwroot/index.html +++ b/test/TestAssets/TestProjects/BlazorWasmMinimal/wwwroot/index.html @@ -19,7 +19,7 @@ Reload 🗙 - + From c481361251f2ff7239d82f689b62e901b017ca96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Fi=C5=A1era?= Date: Fri, 21 Feb 2025 11:57:53 +0100 Subject: [PATCH 4/5] Fix testasset used by other tests --- .../StaticWebAssetsFingerprintingTest.cs | 30 ++++++++++++++----- .../BlazorWasmMinimal/wwwroot/index.html | 2 +- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/test/Microsoft.NET.Sdk.Razor.Tests/StaticWebAssetsFingerprintingTest.cs b/test/Microsoft.NET.Sdk.Razor.Tests/StaticWebAssetsFingerprintingTest.cs index d4ea7b283165..85612bd71224 100644 --- a/test/Microsoft.NET.Sdk.Razor.Tests/StaticWebAssetsFingerprintingTest.cs +++ b/test/Microsoft.NET.Sdk.Razor.Tests/StaticWebAssetsFingerprintingTest.cs @@ -46,17 +46,18 @@ public void Build_FingerprintsContent_WhenEnabled() AssertBuildAssets(manifest1, outputPath, intermediateOutputPath); } - public static TheoryData WriteImportMapToHtmlData => new TheoryData + public static TheoryData WriteImportMapToHtmlData => new TheoryData { - { "VanillaWasm", "main.js" }, - { "BlazorWasmMinimal", "_framework/blazor.webassembly.js" } + { "VanillaWasm", "main.js", null }, + { "BlazorWasmMinimal", "_framework/blazor.webassembly.js", "_framework/blazor.webassembly#[.{fingerprint}].js" } }; [Theory] [MemberData(nameof(WriteImportMapToHtmlData))] - public void Build_WriteImportMapToHtml(string testAsset, string scriptPath) + public void Build_WriteImportMapToHtml(string testAsset, string scriptPath, string scriptPathWithFingerprintPattern) { ProjectDirectory = CreateAspNetSdkTestAsset(testAsset); + ReplaceStringInIndexHtml(ProjectDirectory, scriptPath, scriptPathWithFingerprintPattern); var build = CreateBuildCommand(ProjectDirectory); ExecuteCommand(build, "-p:WriteImportMapToHtml=true").Should().Pass(); @@ -70,9 +71,10 @@ public void Build_WriteImportMapToHtml(string testAsset, string scriptPath) [Theory] [MemberData(nameof(WriteImportMapToHtmlData))] - public void Publish_WriteImportMapToHtml(string testAsset, string scriptPath) + public void Publish_WriteImportMapToHtml(string testAsset, string scriptPath, string scriptPathWithFingerprintPattern) { ProjectDirectory = CreateAspNetSdkTestAsset(testAsset); + ReplaceStringInIndexHtml(ProjectDirectory, scriptPath, scriptPathWithFingerprintPattern); var projectName = Path.GetFileNameWithoutExtension(Directory.EnumerateFiles(ProjectDirectory.TestRoot, "*.csproj").Single()); @@ -80,10 +82,24 @@ public void Publish_WriteImportMapToHtml(string testAsset, string scriptPath) ExecuteCommand(publish, "-p:WriteImportMapToHtml=true").Should().Pass(); var outputPath = publish.GetOutputDirectory(DefaultTfm, "Debug").ToString(); - var indexHtmlPath = Path.Combine(outputPath, "wwwroot", "index.html"); + var indexHtmlOutputPath = Path.Combine(outputPath, "wwwroot", "index.html"); var endpointsManifestPath = Path.Combine(outputPath, $"{projectName}.staticwebassets.endpoints.json"); - AssertImportMapInHtml(indexHtmlPath, endpointsManifestPath, scriptPath); + AssertImportMapInHtml(indexHtmlOutputPath, endpointsManifestPath, scriptPath); + } + + private void ReplaceStringInIndexHtml(TestAsset testAsset, string scriptPath, string scriptPathWithFingerprintPattern) + { + if (scriptPathWithFingerprintPattern != null) + { + var indexHtmlPath = Path.Combine(testAsset.TestRoot, "wwwroot", "index.html"); + var indexHtmlContent = File.ReadAllText(indexHtmlPath); + var newIndexHtmlContent = indexHtmlContent.Replace(scriptPath, scriptPathWithFingerprintPattern); + if (indexHtmlContent == newIndexHtmlContent) + throw new Exception($"Script replacement '{scriptPath}' for '{scriptPathWithFingerprintPattern}' didn't produce any change in '{indexHtmlPath}'"); + + File.WriteAllText(indexHtmlPath, newIndexHtmlContent); + } } private void AssertImportMapInHtml(string indexHtmlPath, string endpointsManifestPath, string scriptPath) diff --git a/test/TestAssets/TestProjects/BlazorWasmMinimal/wwwroot/index.html b/test/TestAssets/TestProjects/BlazorWasmMinimal/wwwroot/index.html index a99f4e317e15..137d7b54777f 100644 --- a/test/TestAssets/TestProjects/BlazorWasmMinimal/wwwroot/index.html +++ b/test/TestAssets/TestProjects/BlazorWasmMinimal/wwwroot/index.html @@ -19,7 +19,7 @@ Reload 🗙 - + From 4dcb1b7767019c5274f81d431cae595fd4bad72c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Fi=C5=A1era?= Date: Mon, 3 Mar 2025 13:21:53 +0100 Subject: [PATCH 5/5] Use BlazorFingerprintBlazorJs to switch FingerprintCandidates instead of defining patterns Aligns with WasmFingerprintAssets and when false it doesn't produce a hard nor soft fingerprint --- .../Targets/Microsoft.NET.Sdk.BlazorWebAssembly.6_0.targets | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/BlazorWasmSdk/Targets/Microsoft.NET.Sdk.BlazorWebAssembly.6_0.targets b/src/BlazorWasmSdk/Targets/Microsoft.NET.Sdk.BlazorWebAssembly.6_0.targets index 2ebbddb1daaf..16716864ec7b 100644 --- a/src/BlazorWasmSdk/Targets/Microsoft.NET.Sdk.BlazorWebAssembly.6_0.targets +++ b/src/BlazorWasmSdk/Targets/Microsoft.NET.Sdk.BlazorWebAssembly.6_0.targets @@ -114,7 +114,7 @@ Copyright (c) .NET Foundation. All rights reserved. <_BlazorJsFile> _framework/%(Filename)%(Extension) - <_BlazorJSFingerprintPattern Include="Js" Pattern="*.js" Expression="#[.{fingerprint}]!" Condition="'$(BlazorFingerprintBlazorJs)' == 'true'" /> + <_BlazorJSFingerprintPattern Include="Js" Pattern="*.js" Expression="#[.{fingerprint}]!" />