Scope
We want to support building and shipping class libraries that include static content. This can include support for discovering and injecting these static assets at runtime where appropriate.
We also want to make it possible to do local development with multiple projects containing static files. This means that in development, it would be possible to serve files from multiple projects wwwroot folders.
These are both features that Blazor had prior to mondo-ization.
Can you share some details around what is the current idea to handle the scenario? Will the _content
approach up to version 0.8 remain? Is there any chance this goes to preview 3 instead of 4?
We've done some thinking on this, and here's an overview:
.csproj
.<StaticFile Include="dist/**/*.js" />
<StaticFilesRoot>dist</StaticFilesRoot>
_content/{packagename}/{filepath}
.<script src="_content/YourCompany.SuperMaps/js/main.js"></script>
<link rel="_content/YourCompany.SuperMaps/styles.css">
<script>
/<link>
/etc tags manually. This is the only reasonable design, because in general you have to be able to control ordering, and to be able to select which of the static assets you want (consider if a package provided 15 different localized versions of a given .js
file, or different CSS files for different themes). As such, library authors will need to document what tags users should add.app.UseDeveloperStaticFiles
, or we need to extend UseStaticFiles
to do this internally.wwwroot
), so that UseStaticFiles
will serve them without any extra code or config. The file paths we copy to will preserve the same URL formats, so you don't have to change any of your references to those files.dist
means this will automatically work with non-.NET servers without any extra stepsFor developers who prefer to bundle static assets using something like Webpack, we can extend this system with either of the following.
obj
). Then you can have a Webpack entrypoint that references files in there, as well as in your other projects via relative filenames.import '@YourCompany.SuperMaps/js/main.js';
, and you can reference static content from NuGet packages just as easily as from NPM packages.Either of these designs preserve's Webpack's ability to do immediate incremental rebuilds when you edit files in referenced projects. However we're not finalising this design yet and won't implement it in the first phase.
That's all there is to it. It's a minimal set of new concepts, and should work equally for Razor Components, Blazor, or any other ASP.NET Core web application that wants to consume static content from packages/projects.
Feel free to edit the top post.
Mechanically - how does this work for a nuget package. So if I'm building a library, what happens?
The point of this is so we can serve the static files directly from their original locations on disk in the source project, and don't have to copy them to some separate location on build. This is important so that you can freely edit those static files and refresh the browser to get changes immediately without having to run a .NET build.
I also want to see more detail about how this will work
Thought: Take into account what the Identity UI does today for the files in https://github.com/aspnet/AspNetCore/tree/master/src/Identity/UI/src/wwwroot and that we should update Identity UI to use this new pattern once it's available. cc @javiercn @HaoK
@Eilon Steve an I already chatted about this. We have a new plan in mind and I'm hoping we also move Identity UI to this model too.
TL;DR They will end up as published content during publish and they will be served from their original locations during development.
Assigning myself as I'm going to be doing the work here. (AFAIK)
In MatBlazor, I just created component MatBlazorInstall, where if now I am in RazorComponents (ServerSide Blazor) just make inline injection if js and css.
So, all you need - put somewhere in the beginning of your application <MatBlazorInstall />
.
Of course this is temporary resolution and not good, while we will have better solution.
I just add <style>content of css</style>
and <script>content of js</script>
BUT
In Blazor (client side) we have problem - doubled content loading. Bacause - content files loaded from server throw http, because build porcess copied them in another folder and then downloaded inside dll.
That's really not good.
@SamProf - if you think you have found a bug, please log a separate issue and provide a clear description.
Hey folks! I liked the design for this feature however, I have to drop my 2c:
Important: We are not planning to auto-add these tags at runtime like we did in the past for Blazor component libraries.
I understand that in some cases ordering of loading static resources matters. But we should have a way allow auto-add.
As one of the maintainers of BlazorExtensions, it would be a pretty bad dev experience if I have to ask everyone to not just install the nuget packages we provide, but also to read the docs/code to know which .css/.jss
each component exports (some cases there are many) and ask them to import it manually...
Perhaps we could create a taghelper/element or something that the developer woud add along with other <style>
/<script>
tags to the index.cshtml
like this:
<StaticResource Include="Blazor.Extensions.SignalR" />
So all the static resources exposed by the package would be added in an order defined by the component developer and respect the rest of the entries' order.
What do you think?
BUT
In Blazor (client side) we have problem - doubled content loading. Bacause - content files loaded from server throw http, because build porcess copied them in another folder and then downloaded inside dll.
That's really not good.
@SamProf If you look at my BlazorEmbedLibrary you'll see I do the same, but it protects against double-injection
I also agree with @galvesribeiro but would go one step further and ask could we have the old style Blazor content embedded automatically, but with an option to opt out of content from any libraries?
that way component producers will not be swamped with support requests.
Perhaps we could create a taghelper/element
You can certainly implement a tag helper that renders the tags needed for your library. You can bundle that tag helper into your package if you want.
We're not planning to make any framework-supplied one for the initial version. It's entirely possible that we might in the future, but that would be a new area for us to design. It's important that what we do put in the box is well designed and robust.
know which .css/.jss each component exports (some cases there are many)
I think that's your problem. Don't have many .css
/.js
files, since the runtime perf will be bad even when people do correctly import them all. Either:
.js
file and one .css
file). That will be easier to consume and will perform much better.My way is https://github.com/SamProf/EmbeddedBlazorContent
1) In server Startup.cs
configure server to host embedded files
app.UseEmbeddedBlazorContent(typeof(MatBlazor.BaseMatComponent).Assembly);
app.UseEmbeddedBlazorContent(typeof(MatBlazor.Demo.Pages.Index).Assembly);
2) For @Html
Razor helper in _Host.cshtml
i write helper to add inside <head>
section section with links to resources.
@Html.EmbeddedBlazorContent()
This will produce code like this:
<script src="/EmbeddedBlazorFile/dist/matBlazor.js"></script>
<script src="/EmbeddedBlazorFile/blazorFiddleLoader.js"></script>
<link href="/EmbeddedBlazorFile/site.css" rel="stylesheet" />
In action I use this method in my http://www.matblazor.com
https://github.com/aspnet/AspNetCore-Tooling/commit/87817bed3ec2d86afbce6b1e796cad567129cf05
https://github.com/aspnet/AspNetCore-Tooling/commit/50646aae64da0ef1f3e8fbadb7427a9b70f3bfaf
https://github.com/aspnet/AspNetCore-Tooling/commit/8e70013b70a5392519aebfcf417c95e7c6bb8dfd
https://github.com/aspnet/AspNetCore-Tooling/commit/62e33dac1d5ec88ab15d7af694c1adf29ffc4c59
https://github.com/aspnet/AspNetCore/commit/62c190da6ef92a487a9313ade37abe4ebaca029f
@javiercn
Can you add some information/documentation about marking a file in a class library as a static asset and how it will be referenced from a sample app? For example, is the syntax mentioned in https://github.com/aspnet/AspNetCore/issues/6349#issuecomment-469676381 be supported (or any variety of it):
<StaticFile Include="dist/**/*.js" />
or<StaticFilesRoot>dist</StaticFilesRoot>
We will be handling the documentation piece next week, but essentially you just need to put the files from the library inside a wwwroot folder and they will get exposed under the _content/<<library>>/
path.
For example, if your library name is MyLibrary and you have in your library wwwroot\sample.js
it will get exposed on consuming apps at _content/mylibrary/sample.js
(the contents of your library wwwroot folder will end up when you publish your app in the wwwroot folder of the published app, under _content/mylibrary
@javiercn Is it expected for a class library, whose package id contains dots to have its static assets path generated without the dots? If there is a library called MyCustomLib
and a js file called script.js
in the wwwroot
folder and its PackagedId
is specified as:
// in MyCustomLib.csproj
...
<PropertyGroup>
<PackageId>my.custom.lib</PackageId>
</PropertyGroup>
then the path to the file is _content/mycustomlib/script.js
instead of _content/my.custom.lib/script.js
. Is there a way to actually generate it as _content/my.custom.lib/script.js
?
@Stamo-Gochev Yes. We do some work to sanitize the url by removing dots and lower-casing everything (to minimize differences across OSs).
Is there a reason for you to want dots in the url? They can be problematic when combined with other things like redirect rules, file system providers, etc.
Did you take that into account?
The main concern is that the name of the class library consists of several words and combining them without the dots results in a long word that is harder to read. I cannot replaces the dots with dashes as it will be a breaking change. Can there be an option that can control if the dots will be stripped?
@Stamo-Gochev We do have some guidance coming up on how to properly author razor class libraries with static web assets. I don't remember if we have a switch for it, but I'll make sure it gets included in the docs if there is one.
The main concern is that the name of the class library consists of several words and combining them without the dots results in a long word that is harder to read.
If we were to replace the dots with something else (like _
) would that ease your concerns?
I wouldn't be too concerned about this for a few reasons.
We don't think it'll be very practical/common for people to be typing script urls by hand compared to copying them from the instructions for a specific library.
@javiercn Yes, the class library provides instructions on how to consume its static assets, so it is a copy and paste step.
The PackageId
can also be changed to include dashes instead of dots, but this will be a breaking change for us as this is connected with the name of the package at nuger.org. In addition, as most nuget packages use dots for delimiters instead of dashed, this might affect other vendors as well.
If a new class library is created now, it might not have such a problem as we are now aware of how its name will be exposed and it is up to us to decide how to name the new lib, so the problem only affects existing libraries. This is why having an option for displaying the name as is (without sanitization) might work for existing libs as the developer will be responsible for using the option.
I'm really liking this feature. I'd also like to maintain the dots in the library name. Although I think it would be better if there was MSBuild property to set it to cater for everyone. It would also be great if we could override the destination folder from "_content" to something else e.g. "assets".
@nfplee Seems like this will be updated with https://github.com/aspnet/AspNetCore/issues/11763
I'm using preview8 and static files(inside component libraries) doesn't seem to work in server-side Blazor. Am I right? Any eta?
Hi @arivoir .
It looks like you are posting on a closed issue!
We're very likely to lose track of your bug/feedback/question unless you:
Most helpful comment
We've done some thinking on this, and here's an overview:
.csproj
.<StaticFile Include="dist/**/*.js" />
<StaticFilesRoot>dist</StaticFilesRoot>
_content/{packagename}/{filepath}
.<script src="_content/YourCompany.SuperMaps/js/main.js"></script>
<link rel="_content/YourCompany.SuperMaps/styles.css">
<script>
/<link>
/etc tags manually. This is the only reasonable design, because in general you have to be able to control ordering, and to be able to select which of the static assets you want (consider if a package provided 15 different localized versions of a given.js
file, or different CSS files for different themes). As such, library authors will need to document what tags users should add.app.UseDeveloperStaticFiles
, or we need to extendUseStaticFiles
to do this internally.wwwroot
), so thatUseStaticFiles
will serve them without any extra code or config. The file paths we copy to will preserve the same URL formats, so you don't have to change any of your references to those files.dist
means this will automatically work with non-.NET servers without any extra stepsFor developers who prefer to bundle static assets using something like Webpack, we can extend this system with either of the following.
obj
). Then you can have a Webpack entrypoint that references files in there, as well as in your other projects via relative filenames.import '@YourCompany.SuperMaps/js/main.js';
, and you can reference static content from NuGet packages just as easily as from NPM packages.Either of these designs preserve's Webpack's ability to do immediate incremental rebuilds when you edit files in referenced projects. However we're not finalising this design yet and won't implement it in the first phase.
That's all there is to it. It's a minimal set of new concepts, and should work equally for Razor Components, Blazor, or any other ASP.NET Core web application that wants to consume static content from packages/projects.