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

Avoid 'dist' subdirectory in published artifacts (requires changing UseBlazor middleware) #5493

Closed
guardrex opened this issue Mar 28, 2018 · 11 comments
Assignees
Labels
area-blazor Includes: Blazor, Razor Components investigate

Comments

@guardrex
Copy link
Contributor

On publish, the assets are going into a folder with the same name as the app and web.config sits at the root of publish with rewrite rules to serve from {app_name}/dist.

publish
    -- StandaloneApp
        -- dist
            -- _framework
            -- css
            -- index.html
    -- web.config

... but I was expecting a much flatter structure akin to what has been done with ASP.NET Core ... something along the lines of ...

publish
   -- _framework
   -- css
   -- index.html
   -- web.config

I have the notion that dist is a holdover from other frameworks. Having the app name in the mix seems strange. Just wondering why it was setup this way?

Would it be an improvement to use the flatter structure (following the ASP.NET Core publishing philosophy these days)? The structure is simpler and the rewrite rules can be dropped. There might be an additional reason to use the flatter structure: My understanding was that the web.config was placed into a flat structure in ASP.NET Core because it allows publishing of multiple apps with WebDeploy. cc/ @shirhatti

@SteveSandersonMS
Copy link
Member

SteveSandersonMS commented Mar 29, 2018

I think you're right that we could avoid the dist subdirectory in the published output. The only reason we have this currently is that the UseBlazor middleware expects there to be one. If we improved this code a bit so it didn't assume there would be a dist, and instead got that information from the .blazor.config file, we could avoid it in the publish output.

As for the other artifacts:

  • It's inevitable that standalone publishing has to have some URL rewriting rules, as that's the only way to make client-side routing work properly (for background info, see https://learn-blazor.com/getting-started/static-hosting/). This applies to all SPA frameworks, not just Blazor.
  • We do want to have the ClientAppName subdirectory, because this unifies standalone and hosted publishing. During hosted publishing, we want each of the client apps for a given server project to be deployed to OutputDir/ClientAppName/ so as to guarantee no filename clashes.

I'll rename this issue to just "remove the 'dist' subdirectory" and leave it open on the backlog.

@SteveSandersonMS SteveSandersonMS changed the title web.config location question Avoid 'dist' subdirectory in published artifacts (requires changing UseBlazor middleware) Mar 29, 2018
@guardrex
Copy link
Contributor Author

It's inevitable that standalone publishing has to have some URL rewriting rules

I added a note (Redirects for correct routing) to our tracking issue for the Host and deploy topic to make sure it's covered: dotnet/AspNetCore.Docs#5771

We do want to have the ClientAppName subdirectory

I see. I naively thought each project is published to its own bin folder, thus published to its own publish folder (per config). I take away from this that in the hosted project scenario that there's one project (one bin; one publish per config) that contains a single hosting app and one or more client apps. I linked this to our high level planning Wiki so that this will be covered in the Blazor directory structure topic.

@guardrex
Copy link
Contributor Author

guardrex commented Apr 3, 2018

Just adding a note here for future discussion of serverless Azure CDN hosting.

In addition to the lack of redirect capabilities at the moment for anything other than a Premium Azure CDN endpoint, there's another smaller problem with the directory structure of a published Blazor app: Without a completely flat directory structure, deployment to Azure CDN's $root container isn't going to be possible. No / path delimiters are allowed in $root, thus no artificial folder structure is permissible. Hopefully, the upcoming Azure CDN default doc/redirect features will cover this hosting scenario. https://feedback.azure.com/forums/217298-storage/suggestions/6417741-static-website-hosting-in-azure-blob-storage

[EDIT] Relative links don't work properly (perhaps because requests for assets don't take the Azure storage container name into account (not part of the URL segment for the requests)]. [EDIT v2 😄] I've since learned about changing the <base> tag in index.html, so this shouldn't be a problem.

[EDIT] Was going to attempt to move assets, such as the _framework folder out of a nested container into their own containers, but another problem arose: Container names must start with a letter or a number. They can't start with an underscore, so the _framework folder of a Blazor deployment can't be a container. The blazor.js script needs a hack to make that work.

@guardrex
Copy link
Contributor Author

guardrex commented Apr 7, 2018

Azure Storage / Azure CDN for a completely serverless hosting setup

I have the standalone template app running on Azure Storage (and I think it will run on the Azure CDN in this configuration), but it took some hacks:

OPTION 1

  1. Because it has to be hosted in a non-$root container [path delimiters (/) aren't allowed in $root], I used an app container to hold the app.
  2. The <base> href in index.html is set to /app.
  3. Pages/Index.cshtml 👉 add @page "/app/index.html".
  4. index.html 👉 <link> and <script> links prefixed with app/.
  5. _framework/blazor.js 👉 Prefix four instances of _framework with app/ in the script.
  6. Pages/FetchData.cshtml 👉 Prefix URL for GetJsonAsync with app/.
  7. Set the Content-Type for mono.wasm to application/wasm.

OPTION 2

  1. Because it has to be hosted in a non-$root container [path delimiters (/) aren't allowed in $root], I used an app container to hold the app.
  2. Set the <base> href in index.html to /app/.
  3. Pages/Index.cshtml 👉 add @page "/index.html".
  4. Shared/NavMenu.cshtml 👉 Add /app to every NavLink, including the Home link, which becomes href="/app/".
  5. Pages/FetchData.cshtml 👉 Prefix URL for GetJsonAsync with /app.
  6. Set the Content-Type for mono.wasm to application/wasm.

OPTION 3

Very hacked to demo a completely flat deployment. asm.js is dropped and bootstrap fonts aren't referenced properly for this dirty hack ...

  1. Create the $root container. Deploy to $root, so no container name is part of the path for this option.

  2. Pages/Index.cshtml 👉 add @page "/index.html".

  3. index.html remove the folders from script and css paths.

  4. Pages/FetchData.cshtml 👉 Make the path to the data file: /weather.json.

  5. blazor.js

    • Line 355 remove "_framework/_bin/" + leaving return filename;
    • Line 488 Strip everything out of addScriptTagsToDocument and leave ...
      document.write("<script defer src=\"mono.js\"></script>");
      
    • Lines 505 and 514 for mono.asm.js remove these lines
  6. Dump everything except asmjs folder files into $root ...

    capture

  7. Set the Content-Type for mono.wasm to application/wasm.

No rewriting ... client-side routing only

You'll need to wait on the upcoming Azure Storage/CDN rewriting feature or go without address bar routing. Alternatively, the Premium Verizon CDN offers the Rules Engine that has a rewrite feature (might be $$$ ... idk).

If there was a completely flat publish option, it would have been possible to host in $root. It wouldn't need all of those app/ path prefixes. It would have only required the route template addition (item 3 in the options above).

Please reconsider the extra folder in the standalone publish scenario

In the hosted Blazor app scenario, I do understand the need to publish Blazor apps in their own folders in the published output.

I hope you'll reconsider tho for the standalone case. I still think that a single standalone app deployment doesn't need to be further nested inside another folder.

@SteveSandersonMS
Copy link
Member

I suspect if you set the base href to /app/ (with trailing slash) then you wouldn’t need to modify the other files to put in any prefixes there.

@guardrex
Copy link
Contributor Author

guardrex commented Apr 7, 2018

I tried it ...

Using /app/ ...

  • The app loads
  • It gets the CSS/JS loaded
  • The index page appears (with @page "/index.html" added to Index.cshtml)

... but internal routing 💥. I'll play with it a bit more.

[EDIT] I wonder if I need to add /app/* routing to the other pages.

[EDIT v2] Yes 👍 ... got it working ... I needed to add it to the nav links, e.g., ...

<li>
    <NavLink href="/app/counter">
        <span class='glyphicon glyphicon-education'></span> APP Counter
    </NavLink>
</li>

@guardrex
Copy link
Contributor Author

guardrex commented Apr 7, 2018

@SteveSandersonMS Thanks ... I added an "Option 2" ☝️ with that approach, which is definitely better because it eliminates having to mess around inside the blazor.js script.

However, to get rid of the app totally, it will need a completely flat publish option to avoid / delimiters, which aren't welcome in the Azure Storage $root container. I'll see about hacking up an "Option 3" that would allow that type of deployment (just for fun 😄).

[EDIT] I made a nasty hack to make it run with a flat directory structure from $root as "Option 3" ☝️.

@aspnet-hello aspnet-hello transferred this issue from dotnet/blazor Dec 17, 2018
@aspnet-hello aspnet-hello added area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates area-blazor Includes: Blazor, Razor Components labels Dec 17, 2018
@mkArtakMSFT
Copy link
Member

@SteveSandersonMS is there any action pending here?

@guardrex
Copy link
Contributor Author

guardrex commented Jan 23, 2019

@mkArtakMSFT @SteveSandersonMS Because I ❤️ this concept so much, I'd like to make a final pitch for it:

If a flat publish directory structure option doesn't become an option, there's no opportunity to host a client-side Blazor (Razor Components) app on the Azure Storage CDN (at the root). $root doesn't permit slashes (pseudo folders), and current published output has plenty of folders (e.g., _bin, wasm, _framework).

This has perhaps been considered and rejected by management. I just wanted one last shot at suggesting it here because the client-side Blazor (Razor Components) app on the Azure CDN (Look ma! ... NO SERVER!) approach 🎷 ROCKS! 🎸 conceptually.

Thanks for hearing me out.

@SteveSandersonMS
Copy link
Member

It's good feedback, but not something we have plans to handle currently. Realistic apps just aren't going to be a flat list of files, because the moment you bring in 3rd-party JS libraries or nontrivial amounts of static content, it's going to be in a directory hierarchy for certain, and that hierarchy must be reflected in the deployment otherwise it will fail at runtime. We can't somehow rewrite 3rd-party JS libraries to change their internal expectations about where content should be loaded from.

Since I don't see any way beyond this, and we have considered it at length, I'll mark it closed. But @guardrex / @mkArtakMSFT / @danroth27, if you think this needs further consideration or I've missed something, please reopen or let me know!

@guardrex
Copy link
Contributor Author

bring in 3rd-party JS libraries or nontrivial amounts of static content, it's going to be in a directory hierarchy for certain

Doesn't have to be that way tho in many cases. The obvious problem is file name conflicts. I don't understand how any other problems with 3rd party JS or static assets could be an issue.

where content should be loaded from

I don't have your knowledge and experience with that, so I'll take your word for that. If you say that's a problem, I believe you.

Client-side Blazor (Razor Components) on Azure CDN (at the root) is a gorgeous hosting scenario. Hosting outside of $root is still an option. That's cool. I'll give that go. I think Option 1/2 ☝️ in the list should work.

Thanks for considering it. The alternative is that $root gains the same capability that Azure Storage containers have to contain / (forward slashes; pseudo paths). I may pitch an ask to the Azure folks for that.

@mkArtakMSFT mkArtakMSFT removed area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates labels May 9, 2019
@ghost ghost locked as resolved and limited conversation to collaborators Dec 4, 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 investigate
Projects
None yet
Development

No branches or pull requests

4 participants