Browser StaticWebAssets sdk support (#14225)

* Property support StaticWebAssets SDK when it's available

* Fix browser issue with dispatcher used before initialization

* Use RequestAnimationFrame instead of WebEmbeddableControlRoot hack

* Always include both types of assets by default, as I couldn't find a reliable way to detect project capabilities properly

* Remove "WasmRuntimeAssetsLocation" override, instead let users use default value set by .NET SDK

* Revert "Fix browser issue with dispatcher used before initialization"

This reverts commit fc43c7e3d5.

* Add AvaloniaAllowWebGl2 prop

* What
This commit is contained in:
Max Katz 2024-02-11 05:51:09 -08:00 коммит произвёл GitHub
Родитель 798c712865
Коммит 0c0d4497ef
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
17 изменённых файлов: 68 добавлений и 156 удалений

1
.gitignore поставляемый
Просмотреть файл

@ -218,3 +218,4 @@ src/Browser/Avalonia.Browser.Blazor/webapp/package-lock.json
src/Browser/Avalonia.Browser.Blazor/wwwroot
src/Browser/Avalonia.Browser/wwwroot
api/diff
src/Browser/Avalonia.Browser/staticwebassets

Просмотреть файл

@ -22,8 +22,8 @@
<Import Project="..\..\build\ReferenceCoreLibraries.props" />
<Import Project="..\..\build\BuildTargets.targets" />
<Import Project="..\..\src\Browser\Avalonia.Browser\Avalonia.Browser.props" />
<Import Project="..\..\src\Browser\Avalonia.Browser\Avalonia.Browser.targets" />
<Import Project="..\..\src\Browser\Avalonia.Browser\build\Avalonia.Browser.props" />
<Import Project="..\..\src\Browser\Avalonia.Browser\build\Avalonia.Browser.targets" />
</Project>

Просмотреть файл

@ -1,6 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="../../src/Browser/Avalonia.Browser/Avalonia.Browser.props" />
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
@ -8,6 +6,7 @@
<OutputType>Exe</OutputType>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<MSBuildEnableWorkloadResolver>true</MSBuildEnableWorkloadResolver>
<WasmRuntimeAssetsLocation>./</WasmRuntimeAssetsLocation>
</PropertyGroup>
<ItemGroup>
@ -20,5 +19,6 @@
<WasmExtraFilesToDeploy Include="AppBundle/**" />
</ItemGroup>
<Import Project="../../src/Browser/Avalonia.Browser/Avalonia.Browser.targets" />
<Import Project="../../src/Browser/Avalonia.Browser/build/Avalonia.Browser.props" />
<Import Project="../../src/Browser/Avalonia.Browser/build/Avalonia.Browser.targets" />
</Project>

Просмотреть файл

@ -7,25 +7,10 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<MSBuildEnableWorkloadResolver>true</MSBuildEnableWorkloadResolver>
<WasmBuildNative>true</WasmBuildNative>
<EmccFlags>-sVERBOSE -sERROR_ON_UNDEFINED_SYMBOLS=0</EmccFlags>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'">
<RunAOTCompilation>true</RunAOTCompilation>
<PublishTrimmed>true</PublishTrimmed>
<TrimMode>full</TrimMode>
<WasmBuildNative>true</WasmBuildNative>
<InvariantGlobalization>true</InvariantGlobalization>
<EmccCompileOptimizationFlag>-O2</EmccCompileOptimizationFlag>
<EmccLinkOptimizationFlag>-O2</EmccLinkOptimizationFlag>
<WasmRuntimeAssetsLocation>./</WasmRuntimeAssetsLocation>
</PropertyGroup>
<ItemGroup>
<TrimmerRootDescriptor Include="Roots.xml" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Skia\Avalonia.Skia\Avalonia.Skia.csproj" />
<ProjectReference Include="..\..\src\Browser\Avalonia.Browser\Avalonia.Browser.csproj" />
<ProjectReference Include="..\MobileSandbox\MobileSandbox.csproj" />
</ItemGroup>
@ -38,6 +23,6 @@
<WasmExtraFilesToDeploy Include="app.css" />
</ItemGroup>
<Import Project="..\..\src\Browser\Avalonia.Browser\Avalonia.Browser.props" />
<Import Project="..\..\src\Browser\Avalonia.Browser\Avalonia.Browser.targets" />
<Import Project="..\..\src\Browser\Avalonia.Browser\build\Avalonia.Browser.props" />
<Import Project="..\..\src\Browser\Avalonia.Browser\build\Avalonia.Browser.targets" />
</Project>

Просмотреть файл

@ -1,7 +0,0 @@
<linker>
<assembly fullname="MobileSandbox" preserve="All" />
<assembly fullname="MobileSandbox.Browser" preserve="All" />
<assembly fullname="Avalonia.Themes.Fluent" preserve="All" />
<assembly fullname="Avalonia.Themes.Simple" preserve="All" />
<assembly fullname="Avalonia.Controls.ColorPicker" preserve="All" />
</linker>

Просмотреть файл

@ -1,8 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ResolveStaticWebAssetsInputsDependsOn>_IncludeGeneratedAvaloniaStaticFiles;$(ResolveStaticWebAssetsInputsDependsOn)</ResolveStaticWebAssetsInputsDependsOn>
</PropertyGroup>
<ItemGroup>
@ -20,22 +19,4 @@
<ItemGroup>
<ProjectReference Include="../Avalonia.Browser/Avalonia.Browser.csproj" />
</ItemGroup>
<Target Name="_IncludeGeneratedAvaloniaStaticFiles">
<ItemGroup>
<_AvaloniaWebAssets Include="$(MSBuildThisFileDirectory)../Avalonia.Browser/wwwroot/**/*.*" />
</ItemGroup>
<DefineStaticWebAssets SourceId="$(PackageId)"
SourceType="Computed"
AssetKind="All"
AssetRole="Primary"
CopyToOutputDirectory="PreserveNewest"
CopyToPublishDirectory="PreserveNewest"
ContentRoot="$(MSBuildThisFileDirectory)../Avalonia.Browser/wwwroot/"
BasePath="_content/$(PackageId)"
CandidateAssets="@(_AvaloniaWebAssets)"
RelativePathFilter="**.js">
<Output TaskParameter="Assets" ItemName="StaticWebAsset" />
</DefineStaticWebAssets>
</Target>
</Project>

Просмотреть файл

@ -17,9 +17,6 @@ public static class BlazorAppBuilder
/// <param name="options">Browser backend specific options.</param>
public static async Task StartBlazorAppAsync(this AppBuilder builder, BrowserPlatformOptions? options = null)
{
options ??= new BrowserPlatformOptions();
options.FrameworkAssetPathResolver ??= filePath => $"/_content/Avalonia.Browser.Blazor/{filePath}";
builder = await BrowserAppBuilder.PreSetupBrowser(builder, options);
builder.SetupWithLifetime(new BlazorSingleViewLifetime());

Просмотреть файл

@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
@ -22,21 +21,26 @@
</ItemGroup>
<ItemGroup>
<Content Include="*.props">
<!-- See https://github.com/dotnet/sdk/blob/9d4d2c4ca35b0856af7df63d6a38b3259aa6917c/src/StaticWebAssetsSdk/Targets/Microsoft.NET.Sdk.StaticWebAssets.Pack.targets#L64-L66 -->
<Content Include="build\Microsoft.AspNetCore.StaticWebAssets.props">
<Pack>true</Pack>
<PackagePath>build/</PackagePath>
</Content>
<Content Include="*.targets">
<Content Include="build\Avalonia.Browser.props">
<Pack>true</Pack>
<PackagePath>build/;buildTransitive/;buildMultiTargeting/</PackagePath>
</Content>
<Content Include="build\Avalonia.Browser.targets">
<Pack>true</Pack>
<PackagePath>build/;buildTransitive/</PackagePath>
</Content>
<Content Include="interop.js">
<Content Include="build\interop.js">
<Pack>true</Pack>
<PackagePath>build/interop.js;buildTransitive/interop.js</PackagePath>
</Content>
<Content Include="wwwroot/**/*.*">
<Content Include="staticwebassets/**/*.*">
<Pack>true</Pack>
<PackagePath>build/wwwroot;buildTransitive/wwwroot</PackagePath>
<PackagePath>staticwebassets/</PackagePath>
</Content>
</ItemGroup>

Просмотреть файл

@ -1,10 +0,0 @@
<Project>
<PropertyGroup>
<ShouldIncludeAvaloniaJavaScript Condition=" '$(ShouldIncludeAvaloniaJavaScript)' == '' ">True</ShouldIncludeAvaloniaJavaScript>
<ShouldIncludeNativeSkiaSharp Condition=" '$(ShouldIncludeNativeSkiaSharp)' == '' ">True</ShouldIncludeNativeSkiaSharp>
<ShouldIncludeNativeHarfBuzzSharp Condition=" '$(ShouldIncludeNativeHarfBuzzSharp)' == '' ">True</ShouldIncludeNativeHarfBuzzSharp>
<!-- .NET 8 changes default location for dotnet script to the "_framework" subfolder, -->
<!-- But this change would introduce a breaking change to Avalonia users, so we revert it back to the .NET 7 state. -->
<WasmRuntimeAssetsLocation Condition="'$(WasmRuntimeAssetsLocation)' == ''">./</WasmRuntimeAssetsLocation>
</PropertyGroup>
</Project>

Просмотреть файл

@ -71,26 +71,18 @@ namespace Avalonia.Browser
_splash = DomHelper.GetElementById("avalonia-splash");
_topLevelImpl = new BrowserTopLevelImpl(this, _containerElement);
_topLevel = new WebEmbeddableControlRoot(_topLevelImpl, () =>
{
Dispatcher.UIThread.Post(() =>
{
if (_splash != null)
{
DomHelper.AddCssClass(_splash, "splash-close");
}
});
});
_topLevelImpl.SetCssCursor = (cursor) =>
{
InputHelper.SetCursor(_containerElement, cursor);
};
_topLevel = new EmbeddableControlRoot(_topLevelImpl);
_topLevel.Prepare();
_topLevel.Renderer.Start();
if (_splash != null)
{
_topLevel.RequestAnimationFrame(_ => DomHelper.AddCssClass(_splash, "splash-close"));
}
InputHelper.InitializeBackgroundHandlers();

Просмотреть файл

@ -49,5 +49,5 @@ internal class BrowserSingleViewLifetime : ISingleViewApplicationLifetime, IActi
public event EventHandler<ActivatedEventArgs>? Deactivated;
public bool TryLeaveBackground() => false;
public bool TryEnterBackground() => true;
public bool TryEnterBackground() => false;
}

Просмотреть файл

@ -1,68 +0,0 @@
using System;
using Avalonia.Controls.Embedding;
using Avalonia.Media;
using Avalonia.Platform;
using Avalonia.Rendering.SceneGraph;
namespace Avalonia.Browser
{
internal class WebEmbeddableControlRoot : EmbeddableControlRoot
{
class SplashScreenCloseCustomDrawingOperation : ICustomDrawOperation
{
private bool _hasRendered;
private Action _onFirstRender;
public SplashScreenCloseCustomDrawingOperation(Action onFirstRender)
{
_onFirstRender = onFirstRender;
}
public Rect Bounds => default;
public bool HasRendered => _hasRendered;
public void Dispose()
{
}
public bool Equals(ICustomDrawOperation? other)
{
return false;
}
public bool HitTest(Point p)
{
return false;
}
public void Render(ImmediateDrawingContext context)
{
_hasRendered = true;
_onFirstRender();
}
}
public WebEmbeddableControlRoot(ITopLevelImpl impl, Action onFirstRender) : base(impl)
{
_splashCloseOp = new SplashScreenCloseCustomDrawingOperation(() =>
{
_splashCloseOp = null;
onFirstRender();
});
}
private SplashScreenCloseCustomDrawingOperation? _splashCloseOp;
public override void Render(DrawingContext context)
{
base.Render(context);
if (_splashCloseOp != null)
{
context.Custom(_splashCloseOp);
}
}
}
}

Просмотреть файл

@ -0,0 +1,13 @@
<Project>
<PropertyGroup>
<AvaloniaAllowWebGl2 Condition="'$(AvaloniaAllowWebGl2)' == ''">true</AvaloniaAllowWebGl2>
<ShouldIncludeAvaloniaAssets Condition=" '$(ShouldIncludeAvaloniaAssets)' == '' ">True</ShouldIncludeAvaloniaAssets>
<ShouldIncludeAvaloniaLegacyAssets Condition=" '$(ShouldIncludeAvaloniaLegacyAssets)' == '' AND '$(ShouldIncludeAvaloniaAssets)' == 'True'">True</ShouldIncludeAvaloniaLegacyAssets>
<ShouldIncludeAvaloniaStaticAssets Condition=" '$(ShouldIncludeAvaloniaStaticAssets)' == '' AND '$(ShouldIncludeAvaloniaAssets)' == 'True'">True</ShouldIncludeAvaloniaStaticAssets>
<ShouldIncludeNativeSkiaSharp Condition=" '$(ShouldIncludeNativeSkiaSharp)' == '' ">True</ShouldIncludeNativeSkiaSharp>
<ShouldIncludeNativeHarfBuzzSharp Condition=" '$(ShouldIncludeNativeHarfBuzzSharp)' == '' ">True</ShouldIncludeNativeHarfBuzzSharp>
</PropertyGroup>
<Import Project="$(MSBuildThisFileDirectory)/../build/Microsoft.AspNetCore.StaticWebAssets.props" />
</Project>

Просмотреть файл

@ -1,12 +1,14 @@
<Project>
<PropertyGroup>
<EmccExtraLDFlags>$(EmccExtraLDFlags) --js-library="$(MSBuildThisFileDirectory)/interop.js"</EmccExtraLDFlags>
<EmccFlags>$(EmccExtraLDFlags) -sERROR_ON_UNDEFINED_SYMBOLS=0</EmccFlags>
<EmccFlags>$(EmccFlags) -sERROR_ON_UNDEFINED_SYMBOLS=0</EmccFlags>
<EmccFlags Condition="'$(AvaloniaAllowWebGl2)' == 'true'">$(EmccFlags) -sUSE_WEBGL2=1 -sMAX_WEBGL_VERSION=2 -lGL </EmccFlags>
</PropertyGroup>
<ItemGroup>
<WasmExtraFilesToDeploy Condition="'$(WasmRuntimeAssetsLocation)' == ''" Include="$(MSBuildThisFileDirectory)/wwwroot/**/*.*" />
<WasmExtraFilesToDeploy Condition="'$(WasmRuntimeAssetsLocation)' != ''" Include="$(MSBuildThisFileDirectory)/wwwroot/**/*.*" TargetPath="$(WasmRuntimeAssetsLocation)/%(FileName)%(Extension)" />
<!-- Fallback for applications without StaticWebAssetsEnabled (legacy WASM SDK) -->
<ItemGroup Condition="'$(ShouldIncludeAvaloniaLegacyAssets)' == 'True'">
<WasmExtraFilesToDeploy Condition="'$(WasmRuntimeAssetsLocation)' == ''" Include="$(MSBuildThisFileDirectory)/../staticwebassets/**/*.*" />
<WasmExtraFilesToDeploy Condition="'$(WasmRuntimeAssetsLocation)' != ''" Include="$(MSBuildThisFileDirectory)/../staticwebassets/**/*.*" TargetPath="$(WasmRuntimeAssetsLocation)/%(FileName)%(Extension)" />
</ItemGroup>
<PropertyGroup Condition="'$(ShouldIncludeNativeSkiaSharp)' == 'True' or '$(ShouldIncludeNativeHarfBuzzSharp)' == 'True'">

Просмотреть файл

@ -0,0 +1,22 @@
<Project>
<PropertyGroup>
<_AvaloniaWebAssetsFolder>$([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)../staticwebassets/))</_AvaloniaWebAssetsFolder>
</PropertyGroup>
<ItemGroup Condition="'$(ShouldIncludeAvaloniaStaticAssets)' == 'True'">
<!-- This file repricates how StaticWebAsset SDK generates static web assets for Blazor nuget packages, which we don't use here. -->
<_AvaloniaWebAssets Include="$(_AvaloniaWebAssetsFolder)**/*.*" />
<StaticWebAsset Include="@(_AvaloniaWebAssets)">
<SourceType>Package</SourceType>
<SourceId>Avalonia.Browser</SourceId>
<ContentRoot>$(_AvaloniaWebAssetsFolder)</ContentRoot>
<BasePath>/</BasePath>
<RelativePath>$(WasmRuntimeAssetsLocation)/%(FileName)%(Extension)</RelativePath>
<AssetKind>All</AssetKind>
<AssetMode>All</AssetMode>
<AssetRole>Primary</AssetRole>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<OriginalItemSpec>$(_AvaloniaWebAssetsFolder)%(FileName)%(Extension)</OriginalItemSpec>
</StaticWebAsset>
</ItemGroup>
</Project>

Просмотреть файл

@ -4,7 +4,7 @@ require("esbuild").build({
"./modules/storage.ts",
"./modules/sw.ts"
],
outdir: "../wwwroot",
outdir: "../staticwebassets",
bundle: true,
minify: true,
format: "esm",