Skip to content

Commit

Permalink
[browser] Update browser template to use Wasm SDK (#90871)
Browse files Browse the repository at this point in the history
* Use WasmSdk in browser template

* Remove default html-path

* Use wwwroot when looking for main.js in template for replacement

* Temporarily remove WasmRuntimeAssetsLocation from WBT because WasmSDK doesn't support it yet

* Integrate console log forward into DevServer

* Replace UseRouter

* Use next middleware only if it's not console

* CancellationTokenSource on CancelKeyPress

* Address feedback from initial DevServer integration

* Update src/mono/wasm/host/BrowserHost.cs

Co-authored-by: Ankit Jain <radical@gmail.com>

* Remove debugging code

* Fix WBT

* Fix starting outside of project directory

* Support WasmRuntimeAssetsLocation in Wasm SDK

* Revert "Support WasmRuntimeAssetsLocation in Wasm SDK"

* Active issue for WasmRuntimeAssetsLocation

* Feedback

---------

Co-authored-by: Ankit Jain <radical@gmail.com>
  • Loading branch information
maraf and radical authored Aug 23, 2023
1 parent 0b6fe08 commit 819e288
Show file tree
Hide file tree
Showing 13 changed files with 88 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,13 @@ Copyright (c) .NET Foundation. All rights reserved.
<RunCommand Condition="'$(RunCommand)' == ''">dotnet</RunCommand>

<WasmAppHostDir>$([MSBuild]::NormalizeDirectory($(MSBuildThisFileDirectory), '..', 'WasmAppHost'))</WasmAppHostDir>
<_RuntimeConfigJsonPath>$([MSBuild]::NormalizePath($(OutputPath), '$(AssemblyName).runtimeconfig.json'))</_RuntimeConfigJsonPath>

<_RunWorkingDirectory>$(OutputPath)</_RunWorkingDirectory>
<_RunWorkingDirectory Condition="'$(_RunWorkingDirectory)' != '' and !$([System.IO.Path]::IsPathRooted($(_RunWorkingDirectory)))">$([System.IO.Path]::Combine($(MSBuildProjectDirectory), $(_RunWorkingDirectory)))</_RunWorkingDirectory>
<_RuntimeConfigJsonPath>$([MSBuild]::NormalizePath($(_RunWorkingDirectory), '$(AssemblyName).runtimeconfig.json'))</_RuntimeConfigJsonPath>

<RunArguments>exec &quot;$([MSBuild]::NormalizePath($(WasmAppHostDir), 'WasmAppHost.dll'))&quot; --use-staticwebassets --runtime-config &quot;$(_RuntimeConfigJsonPath)&quot; $(WasmHostArguments)</RunArguments>
<RunWorkingDirectory>$(OutputPath)</RunWorkingDirectory>
<RunWorkingDirectory>$(_RunWorkingDirectory)</RunWorkingDirectory>
</PropertyGroup>

<PropertyGroup>
Expand Down
7 changes: 4 additions & 3 deletions src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ private void UpdateProgramCS()

private void UpdateBrowserMainJs(string targetFramework, string runtimeAssetsRelativePath = DefaultRuntimeAssetsRelativePath)
{
string mainJsPath = Path.Combine(_projectDir!, "main.js");
string mainJsPath = Path.Combine(_projectDir!, "wwwroot", "main.js");
string mainJsContent = File.ReadAllText(mainJsPath);

// .withExitOnUnhandledError() is available only only >net7.0
Expand Down Expand Up @@ -408,11 +408,12 @@ public void ConsolePublishAndRun(string config, bool aot, bool relinking)

[Theory]
[InlineData("", BuildTestBase.DefaultTargetFramework, DefaultRuntimeAssetsRelativePath)]
[InlineData("", BuildTestBase.DefaultTargetFramework, "./")]
// [ActiveIssue("https://github.com/dotnet/runtime/issues/90979")]
// [InlineData("", BuildTestBase.DefaultTargetFramework, "./")]
// [InlineData("-f net8.0", "net8.0", "./")]
// [ActiveIssue("https://github.com/dotnet/runtime/issues/79313")]
// [InlineData("-f net7.0", "net7.0")]
[InlineData("-f net8.0", "net8.0", DefaultRuntimeAssetsRelativePath)]
[InlineData("-f net8.0", "net8.0", "./")]
public async Task BrowserBuildAndRun(string extraNewArgs, string targetFramework, string runtimeAssetsRelativePath)
{
string config = "Debug";
Expand Down
15 changes: 15 additions & 0 deletions src/mono/wasm/Wasm.Build.Tests/WasmSdkBasedProjectProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,21 @@ protected override IReadOnlySet<string> GetDotNetFilesExpectedSet(AssertBundleOp
return res;
}


public void AssertBundle(BuildArgs buildArgs, BuildProjectOptions buildProjectOptions)
{
AssertBundle(new(
Config: buildArgs.Config,
IsPublish: buildProjectOptions.Publish,
TargetFramework: buildProjectOptions.TargetFramework,
BinFrameworkDir: buildProjectOptions.BinFrameworkDir ?? FindBinFrameworkDir(buildArgs.Config, buildProjectOptions.Publish, buildProjectOptions.TargetFramework),
PredefinedIcudt: buildProjectOptions.PredefinedIcudt,
GlobalizationMode: buildProjectOptions.GlobalizationMode,
AssertSymbolsFile: false,
ExpectedFileType: buildProjectOptions.Publish && buildArgs.Config == "Release" ? NativeFilesType.Relinked : NativeFilesType.FromRuntimePack
));
}

public void AssertBundle(AssertWasmSdkBundleOptions assertOptions)
{
IReadOnlyDictionary<string, DotNetFileName> actualDotnetFiles = AssertBasicBundle(assertOptions);
Expand Down
28 changes: 23 additions & 5 deletions src/mono/wasm/Wasm.Build.Tests/WasmTemplateTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,31 +59,49 @@ public string CreateWasmTemplateProject(string id, string template = "wasmbrowse

public (string projectDir, string buildOutput) BuildTemplateProject(BuildArgs buildArgs,
string id,
BuildProjectOptions buildProjectOptions,
AssertTestMainJsAppBundleOptions? assertAppBundleOptions = null)
BuildProjectOptions buildProjectOptions)
{
(CommandResult res, string logFilePath) = BuildProjectWithoutAssert(id, buildArgs.Config, buildProjectOptions);
if (buildProjectOptions.UseCache)
_buildContext.CacheBuild(buildArgs, new BuildProduct(_projectDir!, logFilePath, true, res.Output));

if (buildProjectOptions.AssertAppBundle)
AssertBundle(buildArgs, buildProjectOptions, res.Output, assertAppBundleOptions);
{
if (buildProjectOptions.IsBrowserProject)
AssertWasmSdkBundle(buildArgs, buildProjectOptions, res.Output);
else
AssertTestMainJsBundle(buildArgs, buildProjectOptions, res.Output);
}
return (_projectDir!, res.Output);
}

public void AssertBundle(BuildArgs buildArgs,
public void AssertTestMainJsBundle(BuildArgs buildArgs,
BuildProjectOptions buildProjectOptions,
string? buildOutput = null,
AssertTestMainJsAppBundleOptions? assertAppBundleOptions = null)
{
if (buildOutput is not null)
ProjectProviderBase.AssertRuntimePackPath(buildOutput, buildProjectOptions.TargetFramework ?? DefaultTargetFramework);

// TODO: templates don't use wasm sdk yet
var testMainJsProvider = new TestMainJsProjectProvider(_testOutput, _projectDir!);
if (assertAppBundleOptions is not null)
testMainJsProvider.AssertBundle(assertAppBundleOptions);
else
testMainJsProvider.AssertBundle(buildArgs, buildProjectOptions);
}

public void AssertWasmSdkBundle(BuildArgs buildArgs,
BuildProjectOptions buildProjectOptions,
string? buildOutput = null,
AssertWasmSdkBundleOptions? assertAppBundleOptions = null)
{
if (buildOutput is not null)
ProjectProviderBase.AssertRuntimePackPath(buildOutput, buildProjectOptions.TargetFramework ?? DefaultTargetFramework);

var projectProvider = new WasmSdkBasedProjectProvider(_testOutput, _projectDir!);
if (assertAppBundleOptions is not null)
projectProvider.AssertBundle(assertAppBundleOptions);
else
projectProvider.AssertBundle(buildArgs, buildProjectOptions);
}
}
4 changes: 2 additions & 2 deletions src/mono/wasm/host/BrowserHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ private static DevServerOptions CreateDevServerOptions(BrowserArguments args, st
devServerOptions = CreateDevServerOptions(urls, staticWebAssetsPath, onConsoleConnected);

if (devServerOptions == null)
throw new CommandLineException("Please, provide mainAssembly in hostProperties of runtimeconfig");
throw new CommandLineException($"Please, provide mainAssembly in hostProperties of runtimeconfig. Alternatively leave the static web assets manifest ('*{staticWebAssetsV2Extension}') in the build output directory '{appPath}' .");
}

return devServerOptions;
Expand All @@ -183,7 +183,7 @@ private static DevServerOptions CreateDevServerOptions(BrowserArguments args, st
);

private static string? FindFirstFileWithExtension(string directory, string extension)
=> Directory.EnumerateFiles(directory, "*" + extension).First();
=> Directory.EnumerateFiles(directory, "*" + extension).FirstOrDefault();

private async Task RunConsoleMessagesPump(WebSocket socket, WasmTestMessagesProcessor messagesProcessor, CancellationToken token)
{
Expand Down
3 changes: 1 addition & 2 deletions src/mono/wasm/host/DevServer/DevServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,7 @@ private static IConfiguration ConfigureHostConfiguration(DevServerOptions option
[WebHostDefaults.EnvironmentKey] = "Development",
["Logging:LogLevel:Microsoft"] = "Warning",
["Logging:LogLevel:Microsoft.Hosting.Lifetime"] = "Information",
[WebHostDefaults.StaticWebAssetsKey] = options.StaticWebAssetsPath,
["ApplyCopHeaders"] = options.WebServerUseCrossOriginPolicy.ToString()
[WebHostDefaults.StaticWebAssetsKey] = options.StaticWebAssetsPath
};

config.AddInMemoryCollection(inMemoryConfiguration);
Expand Down
34 changes: 30 additions & 4 deletions src/mono/wasm/host/DevServer/DevServerStartup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.IO;
using System.Net.WebSockets;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.WebAssembly.AppHost;

namespace Microsoft.WebAssembly.AppHost.DevServer;
Expand All @@ -27,16 +30,16 @@ public static void ConfigureServices(IServiceCollection services)
services.AddRouting();
}

public static void Configure(IApplicationBuilder app, TaskCompletionSource<ServerURLs> realUrlsAvailableTcs, ILogger logger, IHostApplicationLifetime applicationLifetime, IConfiguration configuration)
public static void Configure(IApplicationBuilder app, IOptions<DevServerOptions> optionsContainer, TaskCompletionSource<ServerURLs> realUrlsAvailableTcs, ILogger logger, IHostApplicationLifetime applicationLifetime, IConfiguration configuration)
{
app.UseDeveloperExceptionPage();
EnableConfiguredPathbase(app, configuration);

app.UseWebAssemblyDebugging();

bool applyCopHeaders = configuration.GetValue<bool>("ApplyCopHeaders");
DevServerOptions options = optionsContainer.Value;

if (applyCopHeaders)
if (options.WebServerUseCrossOriginPolicy)
{
app.Use(async (ctx, next) =>
{
Expand All @@ -63,14 +66,37 @@ public static void Configure(IApplicationBuilder app, TaskCompletionSource<Serve
});

app.UseRouting();
app.UseWebSockets();

if (options.OnConsoleConnected is not null)
{
app.Use(async (ctx, next) =>
{
if (ctx.Request.Path.StartsWithSegments("/console"))
{
if (!ctx.WebSockets.IsWebSocketRequest)
{
ctx.Response.StatusCode = 400;
return;
}
using WebSocket socket = await ctx.WebSockets.AcceptWebSocketAsync();
await options.OnConsoleConnected(socket);
}
else
{
await next(ctx);
}
});
}

app.UseEndpoints(endpoints =>
{
endpoints.MapFallbackToFile("index.html", new StaticFileOptions
{
OnPrepareResponse = fileContext =>
{
if (applyCopHeaders)
if (options.WebServerUseCrossOriginPolicy)
{
// Browser multi-threaded runtime requires cross-origin policy headers to enable SharedArrayBuffer.
ApplyCrossOriginPolicyHeaders(fileContext.Context);
Expand Down
3 changes: 3 additions & 0 deletions src/mono/wasm/host/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ public static async Task<int> Main(string[] args)
RegisterHostHandler(WasmHost.Wasmtime, WasiEngineHost.InvokeAsync);

using CancellationTokenSource cts = new();

Console.CancelKeyPress += (object? sender, ConsoleCancelEventArgs e) => cts.Cancel();

ILoggerFactory loggerFactory = LoggerFactory.Create(builder =>
builder
.AddPassThroughConsole()
Expand Down
26 changes: 0 additions & 26 deletions src/mono/wasm/templates/templates/browser/README.md

This file was deleted.

11 changes: 2 additions & 9 deletions src/mono/wasm/templates/templates/browser/browser.0.csproj
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk.WebAssembly">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

<ItemGroup>
<WasmExtraFilesToDeploy Include="index.html" />
<WasmExtraFilesToDeploy Include="main.js" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@
"perHostConfig": [
{
"name": "browser",
"html-path": "index.html",
"Host": "browser"
"host": "browser"
}
]
}
}
}

0 comments on commit 819e288

Please sign in to comment.