unoplatform / Uno.Wasm.Bootstrap

A simple nuget package to run C# code in a WASM-compatible browser
Other
366 stars 57 forks source link

Support for VFS preload/embed #259

Open TheSpydog opened 4 years ago

TheSpydog commented 4 years ago

When I add a content file to my project and attempt to access it at runtime, I get a System.IO.FileNotFoundException. Here's a simple example:

using System;
using System.IO;

class Program
{
    static void Main(string[] args)
    {
        using (FileStream fs = new FileStream("mytext.txt", FileMode.Open, FileAccess.Read))
        {
            using (StreamReader sr = new StreamReader(fs))
            {
                Console.WriteLine(sr.ReadToEnd());
            }
        }
    }
}

The csproj:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netstandard2.0</TargetFramework>
    <MonoRuntimeDebuggerEnabled Condition="'$(Configuration)'=='Debug'">true</MonoRuntimeDebuggerEnabled>
    <WasmShellMonoRuntimeExecutionMode>FullAOT</WasmShellMonoRuntimeExecutionMode>
  </PropertyGroup>

  <ItemGroup>
    <Content Include="mytext.txt" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="Uno.Wasm.Bootstrap" Version="1.3" />
    <PackageReference Include="Uno.Wasm.Bootstrap.DevServer" Version="1.3" PrivateAssets="all" />
 </ItemGroup>

</Project>

The "mytext.txt" file is in the same directory as the .csproj. When building and running this project with FullAOT, I see this in the browser console:

uno-bootstrap.js:190 Error: System.IO.FileNotFoundException: Could not find file "/mytext.txt"
File name: '/mytext.txt'

I'm not sure if this is a bug in Uno or if I'm just doing something wrong. From the README it seems like simply adding this Content property to the file is sufficient for Uno to include it in the virtual file system, but maybe not? Or maybe it's in a different directory? Any advice would be appreciated.

jeromelaban commented 4 years ago

Thanks for the report!

Files are a tricky topic. Content files are part of the website payload, but are not populated as part of the emscripten VFS. You'll need to download the file from the payload first. The files are located in the package_XXX folder, that you can get from the UNO_BOOTSTRAP_APP_BASE environment variable.

The bootstrapper itself does not provide any helper to get the file from the payload, aside from using the out-of-the-box .NET HttpClient to get the file.

TheSpydog commented 4 years ago

Ah, okay. Is there a particular reason Uno doesn't populate files into the VFS? I noticed that mono-wasm's packager tool supports preloading so I'm just curious.

jeromelaban commented 4 years ago

It's something we have not needed at this point, but we contemplating adding a specific metadata to flag (e.g. <Content Include="MyFile.txt" Prefetch="embed|prefetch" /> to enable that scenario.

In the larger Uno Platform project that uses the bootstrapper, we're going to avoid this difficult (and pretty much static) choice by wrapping the usage of Windows.Storage.StorageFile to automatically download files from the payload as needed using the ms-appx:// scheme, in async manner.

TheSpydog commented 4 years ago

we contemplating adding a specific metadata to flag (e.g. <Content Include="MyFile.txt" Prefetch="embed|prefetch" /> to enable that scenario

That would be very helpful. I found a workaround to enable preloading by manually passing --preload-file /mnt/c/path-to-file/<filename>@<filename> in the WasmShellExtraEmccFlags part of the csproj, but obviously that's cumbersome and not ideal.