Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions eng/testing/scenarios/BuildWasmAppsJobsList.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,4 @@ Wasm.Build.Tests.PreloadingTests
Wasm.Build.Tests.EnvVariablesTests
Wasm.Build.Tests.HttpTests
Wasm.Build.Tests.DiagnosticsTests
Wasm.Build.Tests.FilesToIncludeInFileSystemTests
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ Copyright (c) .NET Foundation. All rights reserved.
</PropertyGroup>

<ItemGroup>
<_WasmConfigFileCandidates Include="@(StaticWebAsset)" Condition="'%(SourceType)' == 'Discovered'" />
<_WasmDiscoveredFileCandidates Include="@(StaticWebAsset)" Condition="'%(SourceType)' == 'Discovered'" />

<!-- Remove dotnet.js/wasm from runtime pack, in favor of the relinked ones in @(WasmNativeAsset) -->
<ReferenceCopyLocalPaths Remove="@(ReferenceCopyLocalPaths)" Condition="$(_WasmNativeAssetFileNames.Contains(';%(FileName)%(Extension);'))" />
Expand Down Expand Up @@ -319,14 +319,13 @@ Copyright (c) .NET Foundation. All rights reserved.
</DefineStaticWebAssets>

<DefineStaticWebAssets
CandidateAssets="@(_WasmConfigFileCandidates)"
CandidateAssets="@(_WasmDiscoveredFileCandidates)"
AssetTraitName="WasmResource"
AssetTraitValue="settings"
RelativePathFilter="appsettings*.json"
>
<Output TaskParameter="Assets" ItemName="_WasmJsConfigStaticWebAsset" />
</DefineStaticWebAssets>

<DefineStaticWebAssetEndpoints
CandidateAssets="@(_WasmJsConfigStaticWebAsset)"
ExistingEndpoints="@(StaticWebAssetEndpoint)"
Expand All @@ -335,12 +334,42 @@ Copyright (c) .NET Foundation. All rights reserved.
<Output TaskParameter="Endpoints" ItemName="_WasmJsConfigStaticWebAssetEndpoint" />
</DefineStaticWebAssetEndpoints>

<ItemGroup>
<WasmFilesToIncludeInFileSystem Condition="'%(WasmFilesToIncludeInFileSystem.TargetPath)' == ''">
<TargetPath>/%(WasmFilesToIncludeInFileSystem.Identity)</TargetPath>
</WasmFilesToIncludeInFileSystem>
</ItemGroup>

<DefineStaticWebAssets
CandidateAssets="@(_WasmDiscoveredFileCandidates)"
AssetTraitName="WasmResource"
AssetTraitValue="vfs:%(WasmFilesToIncludeInFileSystem.TargetPath)"
RelativePathFilter="@(WasmFilesToIncludeInFileSystem)"
Condition="'@(WasmFilesToIncludeInFileSystem)' != ''"
>
<Output TaskParameter="Assets" ItemName="_WasmFilesToIncludeInFileSystemStaticWebAsset" />
</DefineStaticWebAssets>

<Error
Text="Some of the 'WasmFilesToIncludeInFileSystem' where not found in StaticWebAssets. WasmFilesToIncludeInFileSystem: @(WasmFilesToIncludeInFileSystem), matched StaticWebAssets: @(_WasmFilesToIncludeInFileSystemStaticWebAsset)"
Condition="'@(WasmFilesToIncludeInFileSystem->Count())' != '@(_WasmFilesToIncludeInFileSystemStaticWebAsset->Count())'" />

<DefineStaticWebAssetEndpoints
CandidateAssets="@(_WasmFilesToIncludeInFileSystemStaticWebAsset)"
ExistingEndpoints="@(StaticWebAssetEndpoint)"
ContentTypeMappings="@(StaticWebAssetContentTypeMapping)"
>
<Output TaskParameter="Endpoints" ItemName="_WasmFilesToIncludeInFileSystemStaticWebAssetEndpoint" />
</DefineStaticWebAssetEndpoints>

<ItemGroup>
<!-- Update the boot config static web asset since we've given it a trait -->
<StaticWebAsset Remove="@(_WasmJsConfigStaticWebAsset)" />
<StaticWebAsset Include="@(_WasmJsConfigStaticWebAsset)" />
<StaticWebAsset Remove="@(_WasmFilesToIncludeInFileSystemStaticWebAsset)" />
<StaticWebAsset Include="@(_WasmFilesToIncludeInFileSystemStaticWebAsset)" />
<StaticWebAssetEndpoint Include="@(_WasmJsConfigStaticWebAssetEndpoint)" />

<StaticWebAssetEndpoint Include="@(_WasmFilesToIncludeInFileSystemStaticWebAssetEndpoint)" />
<ReferenceCopyLocalPaths Remove="@(_WasmBuildFilesToRemove)" />
</ItemGroup>

Expand Down Expand Up @@ -385,8 +414,8 @@ Copyright (c) .NET Foundation. All rights reserved.
</DefineStaticWebAssetEndpoints>

<ResolveFingerprintedStaticWebAssetEndpointsForAssets
CandidateEndpoints="@(WasmStaticWebAssetEndpoint);@(_WasmJsModuleCandidatesForBuildEndpoint)"
CandidateAssets="@(WasmStaticWebAsset);@(_WasmJsModuleCandidatesForBuild)"
CandidateEndpoints="@(WasmStaticWebAssetEndpoint);@(_WasmJsModuleCandidatesForBuildEndpoint);@(StaticWebAssetEndpoint)"
CandidateAssets="@(WasmStaticWebAsset);@(_WasmJsModuleCandidatesForBuild);@(_WasmFilesToIncludeInFileSystemStaticWebAsset)"
IsStandalone="$(StaticWebAssetStandaloneHosting)"
>
<Output TaskParameter="ResolvedEndpoints" ItemName="_WasmResolvedEndpoints" />
Expand All @@ -395,7 +424,7 @@ Copyright (c) .NET Foundation. All rights reserved.
<GenerateWasmBootJson
AssemblyPath="@(IntermediateAssembly)"
ApplicationEnvironment="$(_WasmBuildApplicationEnvironmentName)"
Resources="@(WasmStaticWebAsset);@(_WasmJsModuleCandidatesForBuild)"
Resources="@(WasmStaticWebAsset);@(_WasmJsModuleCandidatesForBuild);@(_WasmFilesToIncludeInFileSystemStaticWebAsset)"
Endpoints="@(_WasmResolvedEndpoints)"
DebugBuild="true"
DebugLevel="$(WasmDebugLevel)"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Xunit;
using Xunit.Abstractions;

#nullable enable

namespace Wasm.Build.Tests;

public class FilesToIncludeInFileSystemTests : WasmTemplateTestsBase
{
public FilesToIncludeInFileSystemTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext)
: base(output, buildContext)
{
}

public static IEnumerable<object?[]> LoadFilesToVfsData()
{
if (!EnvironmentVariables.UseJavascriptBundler)
yield return new object?[] { false };

yield return new object?[] { true };
}

[Theory, TestCategory("bundler-friendly")]
[MemberData(nameof(LoadFilesToVfsData))]
public async Task LoadFilesToVfs(bool publish)
{
Configuration config = Configuration.Debug;
ProjectInfo info = CopyTestAsset(config, aot: false, TestAsset.WasmBasicTestApp, "FilesToIncludeInFileSystemTest");

if (publish)
PublishProject(info, config, new PublishOptions());
else
BuildProject(info, config, new BuildOptions());

BrowserRunOptions runOptions = new(
config,
TestScenario: "FilesToIncludeInFileSystemTest"
);
RunResult result = publish
? await RunForPublishWithWebServer(runOptions)
: await RunForBuildWithDotnetRun(runOptions);

Assert.Contains(result.TestOutput, m => m.Contains("'/myfiles/Vfs1.txt' exists 'True' with content 'Vfs1.txt'"));
Assert.Contains(result.TestOutput, m => m.Contains("'/myfiles/Vfs2.txt' exists 'True' with content 'Vfs2.txt'"));
Assert.Contains(result.TestOutput, m => m.Contains("'/subdir/subsubdir/Vfs3.txt' exists 'True' with content 'Vfs3.txt'"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default {
}),
files({
output: 'public',
extensions: /\.(json)$/,
extensions: /\.(json|txt)$/,
}),
nodeResolve({
extensions: ['.js']
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.IO;
using System.Text.Json;
using System.Runtime.InteropServices.JavaScript;

public partial class FilesToIncludeInFileSystemTest
{
[JSExport]
public static void Run()
{
// Check file presence in VFS based on application environment
PrintFileExistence("/myfiles/Vfs1.txt");
PrintFileExistence("/myfiles/Vfs2.txt");
PrintFileExistence("/subdir/subsubdir/Vfs3.txt");
}

// Synchronize with FilesToIncludeInFileSystemTests
private static void PrintFileExistence(string path) => TestOutput.WriteLine($"'{path}' exists '{File.Exists(path)}' with content '{File.ReadAllText(path)}'");
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,10 @@
<BlazorWebAssemblyLazyLoad Include="LazyLibrary$(WasmAssemblyExtension)" />
<WasmExtraFilesToDeploy Include="profiler.js" />
</ItemGroup>

<ItemGroup>
<WasmFilesToIncludeInFileSystem Include="Vfs1.txt" TargetPath="/myfiles/Vfs1.txt" />
<WasmFilesToIncludeInFileSystem Include="subdir/Vfs2.txt" TargetPath="/myfiles/Vfs2.txt" />
<WasmFilesToIncludeInFileSystem Include="subdir/subsubdir/Vfs3.txt" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Vfs1.txt
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,10 @@ try {
exports.AppSettingsTest.Run();
exit(0);
break;
case "FilesToIncludeInFileSystemTest":
exports.FilesToIncludeInFileSystemTest.Run();
exit(0);
break;
case "DownloadResourceProgressTest":
exit(0);
break;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Vfs2.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Vfs3.txt
Original file line number Diff line number Diff line change
Expand Up @@ -321,14 +321,14 @@ public string TransformResourcesToAssets(BootJsonData config, bool bundlerFriend
var asset = new VfsAsset()
{
virtualPath = a.Key,
name = a.Value.Keys.First(),
name = $"../{a.Value.Keys.First()}",
integrity = a.Value.Values.First()
};

if (bundlerFriendly)
{
string escaped = EscapeName(string.Concat(asset.name));
imports.Add($"import * as {escaped} from \"./{asset.name}\";");
imports.Add($"import {escaped} from \"./{asset.name}\";");
asset.resolvedUrl = EncodeJavascriptVariableInJson(escaped);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,8 @@ private void WriteBootConfig(string entryAssemblyName)
var assetTraitName = resource.GetMetadata("AssetTraitName");
var assetTraitValue = resource.GetMetadata("AssetTraitValue");
var resourceName = Path.GetFileName(resource.GetMetadata("OriginalItemSpec"));
var resourceRoute = Path.GetFileName(endpointByAsset[resource.ItemSpec].ItemSpec);
var resourceEndpoint = endpointByAsset[resource.ItemSpec].ItemSpec;
var resourceRoute = Path.GetFileName(resourceEndpoint);

if (TryGetLazyLoadedAssembly(lazyLoadAssembliesWithoutExtension, resourceName, out var lazyLoad))
{
Expand Down Expand Up @@ -354,6 +355,16 @@ private void WriteBootConfig(string entryAssemblyName)
AddResourceToList(resource, resourceList, targetPath);
continue;
}
else if (string.Equals("WasmResource", assetTraitName, StringComparison.OrdinalIgnoreCase) && assetTraitValue.StartsWith("vfs:", StringComparison.OrdinalIgnoreCase))
{
Log.LogMessage(MessageImportance.Low, "Candidate '{0}' is defined as VFS resource '{1}'.", resource.ItemSpec, assetTraitValue);

var targetPath = assetTraitValue.Substring("vfs:".Length);

resourceData.vfs ??= [];
resourceData.vfs[targetPath] = [];
AddResourceToList(resource, resourceData.vfs[targetPath], resourceEndpoint);
}
else
{
Log.LogMessage(MessageImportance.Low, "Skipping resource '{0}' since it doesn't belong to a defined category.", resource.ItemSpec);
Expand Down Expand Up @@ -418,7 +429,6 @@ private void WriteBootConfig(string entryAssemblyName)
}
}


if (EnvVariables != null && EnvVariables.Length > 0)
{
result.environmentVariables = new Dictionary<string, string>();
Expand All @@ -428,6 +438,7 @@ private void WriteBootConfig(string entryAssemblyName)
result.environmentVariables[name] = env.GetMetadata("Value");
}
}

if (Extensions != null && Extensions.Length > 0)
{
result.extensions = new Dictionary<string, Dictionary<string, object>>();
Expand Down
3 changes: 2 additions & 1 deletion src/tasks/WasmAppBuilder/WasmAppBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ protected override bool ExecuteInternal()
StringDictionary targetPathTable = new();
var vfs = new Dictionary<string, Dictionary<string, string>>();
var coreVfs = new Dictionary<string, Dictionary<string, string>>();
var virtualPathPrefix = !string.IsNullOrEmpty(RuntimeAssetsLocation) ? $"{RuntimeAssetsLocation}/supportFiles" : "supportFiles";
foreach (var item in FilesToIncludeInFileSystem)
{
string? targetPath = item.GetMetadata("TargetPath");
Expand Down Expand Up @@ -323,7 +324,7 @@ protected override bool ExecuteInternal()
};
vfsDict[targetPath] = new()
{
[$"supportFiles/{generatedFileName}"] = Utils.ComputeIntegrity(vfsPath)
[$"{virtualPathPrefix}/{generatedFileName}"] = Utils.ComputeIntegrity(vfsPath)
};
}

Expand Down
Loading