Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Embedded Content (how static assets work with multi-project scenarios) #6349

Closed
rynowak opened this issue Jan 3, 2019 · 26 comments
Closed
Assignees
Labels
area-blazor Includes: Blazor, Razor Components Components Big Rock This issue tracks a big effort which can span multiple issues Done This issue has been fixed

Comments

@rynowak
Copy link
Member

rynowak commented Jan 3, 2019

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.

@wicked-sick
Copy link

wicked-sick commented Feb 19, 2019

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?

@rynowak rynowak added the Components Big Rock This issue tracks a big effort which can span multiple issues label Mar 4, 2019
@rynowak rynowak mentioned this issue Mar 4, 2019
56 tasks
@SteveSandersonMS
Copy link
Member

SteveSandersonMS commented Mar 5, 2019

We've done some thinking on this, and here's an overview:

  • Libraries (whether consumed as projects or packages) can expose static files using some syntax in their .csproj.

    • We might do it on a per-file basis, via an itemgroup like <StaticFile Include="dist/**/*.js" />
    • ... but there are good reasons why we might prefer to do it on a per-directory basis, e.g., with a property like <StaticFilesRoot>dist</StaticFilesRoot>
  • With this alone, apps consuming that project/package (including transitively) will be able to reference all such files via URLs in some standard format, e.g., _content/{packagename}/{filepath}.

    • Example: <script src="_content/YourCompany.SuperMaps/js/main.js"></script>
    • Example: <link rel="_content/YourCompany.SuperMaps/styles.css">
    • Important: We are not planning to auto-add these tags at runtime like we did in the past for Blazor component libraries. You will have to put in the relevant <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.
  • In development,

    • To make your server actually serve those static files, we need either some new middleware (e.g., app.UseDeveloperStaticFiles, or we need to extend UseStaticFiles to do this internally.
    • 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.
  • In production,

    • On publish, we'll copy all the static files to locations within your content root (typically, 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.
    • For Blazor apps, the fact that we already publish content root files to dist means this will automatically work with non-.NET servers without any extra steps
    • In case you don't want to include the static content from any given projects/packages in your publish output, there will be some syntax on the project/package reference item to say the static content should be ignored.
  • For developers who prefer to bundle static assets using something like Webpack, we can extend this system with either of the following.

    • We could have optional MSBuild targets that, on build, copy any static files exposed by package (not project) references into a well-known staging location in your app (e.g., under obj). Then you can have a Webpack entrypoint that references files in there, as well as in your other projects via relative filenames.
    • Or, more advanced, we could build a Webpack file resolver that knows how to locate static files exposed by NuGet package references. Then you Webpack entrypoint could reference things like 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.

@rynowak
Copy link
Member Author

rynowak commented Mar 5, 2019

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?

@rynowak
Copy link
Member Author

rynowak commented Mar 5, 2019

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

@Eilon
Copy link
Member

Eilon commented Mar 5, 2019

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

@javiercn
Copy link
Member

javiercn commented Mar 5, 2019

@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.

@rynowak rynowak removed the Needs: Design This issue requires design work before implementating. label Mar 13, 2019
@danroth27 danroth27 added this to the 3.0.0-preview6 milestone Apr 25, 2019
@SamProf
Copy link
Contributor

SamProf commented Apr 30, 2019

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);
  1. 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

@mkArtakMSFT mkArtakMSFT removed area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates labels May 9, 2019
@javiercn javiercn added Done This issue has been fixed and removed Working labels May 31, 2019
@javiercn
Copy link
Member

@Stamo-Gochev
Copy link

Stamo-Gochev commented May 31, 2019

@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 #6349 (comment) be supported (or any variety of it):

  1. <StaticFile Include="dist/**/*.js" /> or
  2. <StaticFilesRoot>dist</StaticFilesRoot>

@javiercn
Copy link
Member

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

@Stamo-Gochev
Copy link

Stamo-Gochev commented Jun 17, 2019

@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?

@javiercn
Copy link
Member

@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?

@Stamo-Gochev
Copy link

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?

@javiercn
Copy link
Member

@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 expect library authors to provide code snippets in the instructions detailing how to use their library, so that users can simply copy/paste your script/link tags into their page's body/header tags.
  • You can write a partial view/tag-helper to inject the scripts on the page.
  • We might have tooling in the future that will give you completions, which greatly reduces errors.

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.

@Stamo-Gochev
Copy link

Stamo-Gochev commented Jun 17, 2019

@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.

@nfplee
Copy link

nfplee commented Jun 27, 2019

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".

@Stamo-Gochev
Copy link

@nfplee Seems like this will be updated with #11763

@arivoir
Copy link

arivoir commented Aug 19, 2019

I'm using preview8 and static files(inside component libraries) doesn't seem to work in server-side Blazor. Am I right? Any eta?

@javiercn
Copy link
Member

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:

  1. Open a new issue
  2. Explain very clearly what you need help with
  3. If you think you have found a bug, include detailed repro steps and a repro project so that we can investigate the problem

@ghost ghost locked as resolved and limited conversation to collaborators Dec 3, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-blazor Includes: Blazor, Razor Components Components Big Rock This issue tracks a big effort which can span multiple issues Done This issue has been fixed
Projects
None yet
Development

No branches or pull requests