SuaveIO / suave

Suave is a simple web development F# library providing a lightweight web server and a set of combinators to manipulate route flow and task composition.
https://suave.io
Other
1.32k stars 198 forks source link

Enhancements for browsing embedded resources #776

Closed louietan closed 1 year ago

louietan commented 1 year ago

Rationale:

TL;DR: to make Suave able to serve an entire directory of files that were embedded in an assembly, which is convenient for single-file deployments to include all web assets inside the final executable.

By default, the original file name will be transformed into a resource name at build-time, e.g. in project Suave.Tests, embedded-resource.txt become Suave.Tests.embedded-resource.txt.

There is an undocumented build property "UseStandardResourceNames" for F#, which disables this transformation when set to false, so that embedded-resource.txt remain embedded-resource.txt.

But this doesn't work well with embedding nested directories of files, e.g. with project property <EmbeddedResource Include="wwwroot\**" /> and file wwwroot/js/vendor/jquery.min.js, the resource name become jquery.min.js, losing the directory parts.

ASP.NET Core solves this problem by abstracting file system access through the use of File Providers, one of them is the ManifestEmbeddedFileProvider.

To use this provider, the application has to reference nuget package Microsoft.Extensions.FileProviders.Embedded and set a build property <GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>.

This setup will generate one additional resource, which is the manifest that describes the source structure.

This PR parses that manifest file to construct a mapping between source paths to actual resource names, e.g. "wwwroot/js/vendor/jquery.min.js" maps to "Suave.Tests.wwwroot.js.vendor.jquery.min.js", so Suave is able to serve the entire wwwroot directory just like a physical directory.

This PR also handles when Assembly.Location is empty for reading the last modification time and falls back to the process startup time. (I can't think of better alternatives, in ASP.NET Core, they uses the current time)

Unit tests were updated to cover this change.

About the dependency on Microsoft.Extensions.FileProviders.Embedded

ademar commented 1 year ago

Good stuff. Thanks!