diff options
5 files changed, 163 insertions, 28 deletions
diff --git a/src/Components/WebAssembly/Build/src/Tasks/GzipCompressBlazorApplicationFiles.cs b/src/Components/WebAssembly/Build/src/Tasks/GzipCompressBlazorApplicationFiles.cs index 65aeb409f5..53d26328a3 100644 --- a/src/Components/WebAssembly/Build/src/Tasks/GzipCompressBlazorApplicationFiles.cs +++ b/src/Components/WebAssembly/Build/src/Tasks/GzipCompressBlazorApplicationFiles.cs @@ -32,18 +32,16 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build var inputSource = file.InputSource; var targetCompressionPath = file.Target; - if (!File.Exists(inputSource) || - (File.Exists(targetCompressionPath) && File.GetLastWriteTime(inputSource) > File.GetLastWriteTime(targetCompressionPath))) + if (!File.Exists(inputSource)) + { + Log.LogMessage($"Skipping '{inputPath}' because '{inputSource}' does not exist."); + return; + } + + if (File.Exists(targetCompressionPath) && File.GetLastWriteTimeUtc(inputSource) < File.GetLastWriteTimeUtc(targetCompressionPath)) { // Incrementalism. If input source doesn't exist or it exists and is not newer than the expected output, do nothing. - if (!File.Exists(inputSource)) - { - Log.LogMessage($"Skipping '{inputPath}' because '{inputSource}' does not exist."); - } - else - { - Log.LogMessage($"Skipping '{inputPath}' because '{inputSource}' is newer than '{targetCompressionPath}'."); - } + Log.LogMessage($"Skipping '{inputPath}' because '{targetCompressionPath}' is newer than '{inputSource}'."); return; } diff --git a/src/Components/WebAssembly/Build/src/targets/Blazor.MonoRuntime.targets b/src/Components/WebAssembly/Build/src/targets/Blazor.MonoRuntime.targets index 5027568d5f..b2be704147 100644 --- a/src/Components/WebAssembly/Build/src/targets/Blazor.MonoRuntime.targets +++ b/src/Components/WebAssembly/Build/src/targets/Blazor.MonoRuntime.targets @@ -146,9 +146,9 @@ </ItemGroup> <ItemGroup> - <_ExistingBlazorOutputWithTargetPath Include="@(_BlazorOutputWithTargetPath)" Condition="Exists('%(FullPath)')" /> + <_ExistingBlazorOutputWithTargetPath Include="@(_BlazorOutputWithTargetPath)" Condition="Exists('%(FullPath)')" /> </ItemGroup> - + <GetFileHash Files="@(_ExistingBlazorOutputWithTargetPath)" Algorithm="SHA256" HashEncoding="base64"> <Output TaskParameter="Items" ItemName="_BlazorOutputWithHash" /> </GetFileHash> @@ -156,7 +156,7 @@ <ItemGroup> <_BlazorOutputWithIntegrity Include="@(_BlazorOutputWithHash)"> <Integrity>%(_BlazorOutputWithHash.FileHash)</Integrity> - <IntegrityFile>$(IntermediateOutputPath)integrity\$([System.String]::Copy('%(FileHash)').Replace('/','-').Replace('+','_')).hash'</IntegrityFile> + <IntegrityFile>$(IntermediateOutputPath)integrity\$([System.String]::Copy('%(FileHash)').Replace('/','-').Replace('+','_')).hash</IntegrityFile> </_BlazorOutputWithIntegrity> <_BlazorOutputWithTargetPath Remove="@(_BlazorOutputWithIntegrity)" /> @@ -409,7 +409,7 @@ <_BlazorBootJsonWithIntegrity Include="@(_BlazorBootJsonWithHash)"> <Integrity>%(FileHash)</Integrity> - <IntegrityFile>$(IntermediateOutputPath)integrity\$([System.String]::Copy('%(FileHash)').Replace('/','-').Replace('+','_')).hash'</IntegrityFile> + <IntegrityFile>$(IntermediateOutputPath)integrity\$([System.String]::Copy('%(FileHash)').Replace('/','-').Replace('+','_')).hash</IntegrityFile> </_BlazorBootJsonWithIntegrity> <_BlazorOutputWithTargetPath Include="@(_BlazorBootJsonWithIntegrity)" RemoveMetadata="FileHash;FileHashAlgorithm"> diff --git a/src/Components/WebAssembly/Build/src/targets/ServiceWorkerAssetsManifest.targets b/src/Components/WebAssembly/Build/src/targets/ServiceWorkerAssetsManifest.targets index fcf1b38503..74654a8d33 100644 --- a/src/Components/WebAssembly/Build/src/targets/ServiceWorkerAssetsManifest.targets +++ b/src/Components/WebAssembly/Build/src/targets/ServiceWorkerAssetsManifest.targets @@ -55,7 +55,7 @@ <Target Name="_ComputeManifestIntegrity" Condition="'$(ServiceWorkerAssetsManifest)' != ''" BeforeTargets="_BlazorStaticWebAssetsCopyGeneratedFilesToOutputDirectory;_GzipCompressBlazorApplicationFiles"> - + <GetFileHash Files="$(_ServiceWorkerAssetsManifestIntermediateOutputPath)" Algorithm="SHA256" HashEncoding="base64"> <Output TaskParameter="Items" ItemName="_ServiceWorkerManifestWithHash" /> </GetFileHash> @@ -64,7 +64,7 @@ <_ServiceWorkerManifestWithIntegrity Include="@(_ServiceWorkerManifestWithHash)"> <Integrity>%(FileHash)</Integrity> - <IntegrityFile>$(IntermediateOutputPath)integrity\$([System.String]::Copy('%(FileHash)').Replace('/','-').Replace('+','_')).hash'</IntegrityFile> + <IntegrityFile>$(IntermediateOutputPath)integrity\$([System.String]::Copy('%(FileHash)').Replace('/','-').Replace('+','_')).hash</IntegrityFile> </_ServiceWorkerManifestWithIntegrity> <FileWrites Include="%(_ServiceWorkerManifestWithIntegrity.IntegrityFile)" /> @@ -74,7 +74,7 @@ <WriteLinesToFile Lines="%(_ServiceWorkerManifestWithIntegrity.Integrity)" File="%(_ServiceWorkerManifestWithIntegrity.IntegrityFile)" WriteOnlyWhenDifferent="true" Overwrite="true" /> <PropertyGroup> - <_ServiceWorkerManifestIntegrityFile>$(IntermediateOutputPath)integrity\$([System.String]::Copy('%(_ServiceWorkerManifestWithIntegrity.FileHash)').Replace('/','-').Replace('+','_')).hash'</_ServiceWorkerManifestIntegrityFile> + <_ServiceWorkerManifestIntegrityFile>$(IntermediateOutputPath)integrity\$([System.String]::Copy('%(_ServiceWorkerManifestWithIntegrity.FileHash)').Replace('/','-').Replace('+','_')).hash</_ServiceWorkerManifestIntegrityFile> </PropertyGroup> <ItemGroup> @@ -178,7 +178,7 @@ <Target Name="_OmitServiceWorkerContent" Condition="'$(ServiceWorkerAssetsManifest)' != ''" - BeforeTargets="AssignTargetPaths"> + BeforeTargets="AssignTargetPaths;ResolveCurrentProjectStaticWebAssets"> <ItemGroup> <!-- Don't emit the service worker source files to the output --> diff --git a/src/Components/WebAssembly/Build/test/BuildIntegrationTests/BuildCompressionTests.cs b/src/Components/WebAssembly/Build/test/BuildIntegrationTests/BuildCompressionTests.cs index 5c2e8e9c8e..f1e6ea85e7 100644 --- a/src/Components/WebAssembly/Build/test/BuildIntegrationTests/BuildCompressionTests.cs +++ b/src/Components/WebAssembly/Build/test/BuildIntegrationTests/BuildCompressionTests.cs @@ -1,6 +1,7 @@ // 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.Threading.Tasks; @@ -41,6 +42,45 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build } [Fact] + public async Task Build_WithLinkerAndCompression_UpdatesFilesWhenSourcesChange() + { + // Arrange + using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" }); + var result = await MSBuildProcessManager.DotnetMSBuild(project); + + Assert.BuildPassed(result); + + var mainAppDll = Path.Combine(project.DirectoryPath, project.BuildOutputDirectory, "wwwroot", "_framework", "_bin", "standalone.dll"); + var mainAppDllThumbPrint = FileThumbPrint.Create(mainAppDll); + var mainAppCompressedDll = Path.Combine(project.DirectoryPath, project.BuildOutputDirectory, "wwwroot", "_framework", "_bin", "standalone.dll.gz"); + var mainAppCompressedDllThumbPrint = FileThumbPrint.Create(mainAppCompressedDll); + + var blazorBootJson = Path.Combine(project.DirectoryPath, project.BuildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json"); + var blazorBootJsonThumbPrint = FileThumbPrint.Create(blazorBootJson); + var blazorBootJsonCompressed = Path.Combine(project.DirectoryPath, project.BuildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json.gz"); + var blazorBootJsonCompressedThumbPrint = FileThumbPrint.Create(blazorBootJsonCompressed); + + // Act + var programFile = Path.Combine(project.DirectoryPath, "Program.cs"); + var programFileContents = File.ReadAllText(programFile); + File.WriteAllText(programFile, programFileContents.Replace("args", "arguments")); + result = await MSBuildProcessManager.DotnetMSBuild(project); + + // Assert + Assert.BuildPassed(result); + var newMainAppDllThumbPrint = FileThumbPrint.Create(mainAppDll); + var newMainAppCompressedDllThumbPrint = FileThumbPrint.Create(mainAppCompressedDll); + var newBlazorBootJsonThumbPrint = FileThumbPrint.Create(blazorBootJson); + var newBlazorBootJsonCompressedThumbPrint = FileThumbPrint.Create(blazorBootJsonCompressed); + + Assert.NotEqual(mainAppDllThumbPrint, newMainAppDllThumbPrint); + Assert.NotEqual(mainAppCompressedDllThumbPrint, newMainAppCompressedDllThumbPrint); + + Assert.NotEqual(blazorBootJsonThumbPrint, newBlazorBootJsonThumbPrint); + Assert.NotEqual(blazorBootJsonCompressedThumbPrint, newBlazorBootJsonCompressedThumbPrint); + } + + [Fact] public async Task Build_WithoutLinkerAndCompression_IsIncremental() { // Arrange @@ -71,6 +111,34 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build } [Fact] + public async Task Build_WithoutLinkerAndCompression_UpdatesFilesWhenSourcesChange() + { + // Arrange + using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" }); + var result = await MSBuildProcessManager.DotnetMSBuild(project, args: "/p:BlazorWebAssemblyEnableLinking=false"); + + // Act + var mainAppDll = Path.Combine(project.DirectoryPath, project.BuildOutputDirectory, "wwwroot", "_framework", "_bin", "standalone.dll"); + var mainAppDllThumbPrint = FileThumbPrint.Create(mainAppDll); + + var mainAppCompressedDll = Path.Combine(project.DirectoryPath, project.BuildOutputDirectory, "wwwroot", "_framework", "_bin", "standalone.dll.gz"); + var mainAppCompressedDllThumbPrint = FileThumbPrint.Create(mainAppCompressedDll); + + var programFile = Path.Combine(project.DirectoryPath, "Program.cs"); + var programFileContents = File.ReadAllText(programFile); + File.WriteAllText(programFile, programFileContents.Replace("args", "arguments")); + + // Assert + result = await MSBuildProcessManager.DotnetMSBuild(project, args: "/p:BlazorWebAssemblyEnableLinking=false"); + Assert.BuildPassed(result); + var newMainAppDllThumbPrint = FileThumbPrint.Create(mainAppDll); + var newMainAppCompressedDllThumbPrint = FileThumbPrint.Create(mainAppCompressedDll); + + Assert.NotEqual(mainAppDllThumbPrint, newMainAppDllThumbPrint); + Assert.NotEqual(mainAppCompressedDllThumbPrint, newMainAppCompressedDllThumbPrint); + } + + [Fact] public async Task Build_CompressesAllFrameworkFiles() { // Arrange @@ -148,6 +216,77 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build } [Fact] + public async Task Publish_WithLinkerAndCompression_UpdatesFilesWhenSourcesChange() + { + // Arrange + using var project = ProjectDirectory.Create("blazorhosted", additionalProjects: new[] { "standalone", "razorclasslibrary" }); + project.TargetFramework = "netcoreapp3.1"; + var result = await MSBuildProcessManager.DotnetMSBuild(project, target: "publish"); + + Assert.BuildPassed(result); + + // Act + var mainAppDll = Path.Combine(project.DirectoryPath, project.PublishOutputDirectory, "wwwroot", "_framework", "_bin", "standalone.dll"); + var mainAppDllThumbPrint = FileThumbPrint.Create(mainAppDll); + var mainAppCompressedDll = Path.Combine(project.DirectoryPath, project.PublishOutputDirectory, "wwwroot", "_framework", "_bin", "standalone.dll.br"); + var mainAppCompressedDllThumbPrint = FileThumbPrint.Create(mainAppCompressedDll); + + var blazorBootJson = Path.Combine(project.DirectoryPath, project.PublishOutputDirectory, "wwwroot", "_framework", "blazor.boot.json"); + var blazorBootJsonThumbPrint = FileThumbPrint.Create(blazorBootJson); + var blazorBootJsonCompressed = Path.Combine(project.DirectoryPath, project.PublishOutputDirectory, "wwwroot", "_framework", "blazor.boot.json.br"); + var blazorBootJsonCompressedThumbPrint = FileThumbPrint.Create(blazorBootJsonCompressed); + + var programFile = Path.Combine(project.DirectoryPath, "..", "standalone", "Program.cs"); + var programFileContents = File.ReadAllText(programFile); + File.WriteAllText(programFile, programFileContents.Replace("args", "arguments")); + + // Assert + result = await MSBuildProcessManager.DotnetMSBuild(project, target: "publish"); + Assert.BuildPassed(result); + var newMainAppDllThumbPrint = FileThumbPrint.Create(mainAppDll); + var newMainAppCompressedDllThumbPrint = FileThumbPrint.Create(mainAppCompressedDll); + var newBlazorBootJsonThumbPrint = FileThumbPrint.Create(blazorBootJson); + var newBlazorBootJsonCompressedThumbPrint = FileThumbPrint.Create(blazorBootJsonCompressed); + + Assert.NotEqual(mainAppDllThumbPrint, newMainAppDllThumbPrint); + Assert.NotEqual(mainAppCompressedDllThumbPrint, newMainAppCompressedDllThumbPrint); + + Assert.NotEqual(blazorBootJsonThumbPrint, newBlazorBootJsonThumbPrint); + Assert.NotEqual(blazorBootJsonCompressedThumbPrint, newBlazorBootJsonCompressedThumbPrint); + } + + [Fact] + public async Task Publish_WithoutLinkerAndCompression_UpdatesFilesWhenSourcesChange() + { + // Arrange + using var project = ProjectDirectory.Create("blazorhosted", additionalProjects: new[] { "standalone", "razorclasslibrary" }); + project.TargetFramework = "netcoreapp3.1"; + var result = await MSBuildProcessManager.DotnetMSBuild(project, target: "publish", args: "/p:BlazorWebAssemblyEnableLinking=false"); + + Assert.BuildPassed(result); + + // Act + var mainAppDll = Path.Combine(project.DirectoryPath, project.PublishOutputDirectory, "wwwroot", "_framework", "_bin", "standalone.dll"); + var mainAppDllThumbPrint = FileThumbPrint.Create(mainAppDll); + + var mainAppCompressedDll = Path.Combine(project.DirectoryPath, project.PublishOutputDirectory, "wwwroot", "_framework", "_bin", "standalone.dll.br"); + var mainAppCompressedDllThumbPrint = FileThumbPrint.Create(mainAppCompressedDll); + + var programFile = Path.Combine(project.DirectoryPath, "..", "standalone", "Program.cs"); + var programFileContents = File.ReadAllText(programFile); + File.WriteAllText(programFile, programFileContents.Replace("args", "arguments")); + + // Assert + result = await MSBuildProcessManager.DotnetMSBuild(project, target: "publish", args: "/p:BlazorWebAssemblyEnableLinking=false"); + Assert.BuildPassed(result); + var newMainAppDllThumbPrint = FileThumbPrint.Create(mainAppDll); + var newMainAppCompressedDllThumbPrint = FileThumbPrint.Create(mainAppCompressedDll); + + Assert.NotEqual(mainAppDllThumbPrint, newMainAppDllThumbPrint); + Assert.NotEqual(mainAppCompressedDllThumbPrint, newMainAppCompressedDllThumbPrint); + } + + [Fact] public async Task Publish_WithLinkerAndCompression_IsIncremental() { // Arrange diff --git a/src/Components/WebAssembly/Compression/src/Program.cs b/src/Components/WebAssembly/Compression/src/Program.cs index 093b2159ef..3391e96036 100644 --- a/src/Components/WebAssembly/Compression/src/Program.cs +++ b/src/Components/WebAssembly/Compression/src/Program.cs @@ -35,18 +35,16 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build.BrotliCompression var inputSource = file.InputSource; var targetCompressionPath = file.Target; - if (!File.Exists(inputSource) || - (File.Exists(targetCompressionPath) && File.GetLastWriteTime(inputSource) > File.GetLastWriteTime(targetCompressionPath))) + if (!File.Exists(inputSource)) + { + Console.WriteLine($"Skipping '{inputPath}' because '{inputSource}' does not exist."); + return; + } + + if (File.Exists(targetCompressionPath) && File.GetLastWriteTimeUtc(inputSource) < File.GetLastWriteTimeUtc(targetCompressionPath)) { // Incrementalism. If input source doesn't exist or it exists and is not newer than the expected output, do nothing. - if (!File.Exists(inputSource)) - { - Console.WriteLine($"Skipping '{inputPath}' because '{inputSource}' does not exist."); - } - else - { - Console.WriteLine($"Skipping '{inputPath}' because '{inputSource}' is newer than '{targetCompressionPath}'."); - } + Console.WriteLine($"Skipping '{inputPath}' because '{targetCompressionPath}' is newer than '{inputSource}'."); return; } |