Skip to content

Commit

Permalink
webassets;doc update;ignoring files fix.
Browse files Browse the repository at this point in the history
  • Loading branch information
tesar-tech committed Jan 20, 2024
1 parent 6548f84 commit 0386232
Show file tree
Hide file tree
Showing 12 changed files with 185 additions and 17 deletions.
1 change: 0 additions & 1 deletion .github/workflows/publish-to-ghpages-and-nuget.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ jobs:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Download build artifacts
uses: actions/download-artifact@v3
with:
Expand Down
19 changes: 19 additions & 0 deletions BlazorStaticWebsite/BlazorStaticWebsite.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,16 @@

<ItemGroup>
<PackageReference Include="Markdig" Version="0.33.0" />
<!--To showcase it works-->
<PackageReference Include="Microsoft.FluentUI.AspNetCore.Components" Version="4.3.1" />
<PackageReference Include="YamlDotNet" Version="13.7.1" />
</ItemGroup>

<ItemGroup>
<None Update="README.md">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Remove="output\**" />
</ItemGroup>

<ItemGroup>
Expand All @@ -32,4 +35,20 @@
<ProjectReference Include="..\src\BlazorStatic.csproj" />
</ItemGroup>

<ItemGroup>
<Compile Remove="output\**" />
</ItemGroup>

<ItemGroup>
<EmbeddedResource Remove="output\**" />
</ItemGroup>

<ItemGroup>
<Content Remove="output\**" />
</ItemGroup>

<ItemGroup>
<_ContentIncludedByDefault Remove="output\BlazorStaticWebsite.modules.json" />
</ItemGroup>

</Project>
43 changes: 43 additions & 0 deletions BlazorStaticWebsite/Components/Pages/ComponentLibs.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
@page "/docs/componentlibs"
@using Microsoft.FluentUI.AspNetCore.Components

<div class="prose prose-invert">
<h1>Fluent UI (and Other Component Libraries) with BlazorStatic</h1>
<p>
You can use FluentUI with BlazorStatic, as long as you understand its limitations.
</p>

<p>
Only the interactivity handled by JavaScript will work.
</p>
<p>
BlazorStatic will copy all necessary files to the output folder, as expected upon app publish.
</p>
<p>
BlazorStatic is based on Blazor Server-Side Rendering (SSR). For FluentUI to work with SSR, reference the necessary JavaScript as described in the <a href="https://github.com/microsoft/fluentui-blazor?tab=readme-ov-file#script">FluentUI documentation</a>.
</p>
<p>
This information is not tied exclusively to FluentUI; it allows you to use any Blazor component library.
</p>

</div>

<div class="prose prose-invert">

<h2 class="prose prose-invert"> Example using some FluentUI components</h2>
</div>

<FluentButton Appearance="@Appearance.Accent">Button</FluentButton>
<FluentBadge>Badge</FluentBadge>

<FluentSelect Value=@("a string value") TOption="string">
<FluentOption>Option1</FluentOption>
<FluentOption>Option2</FluentOption>
<FluentOption>Option3</FluentOption>
</FluentSelect>


<script src="_content/Microsoft.FluentUI.AspNetCore.Components/Microsoft.FluentUI.AspNetCore.Components.lib.module.js" type="module" async></script>
@code {

}
77 changes: 77 additions & 0 deletions BlazorStaticWebsite/Content/Blog/release-1.0.0-beta.4.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
---
title: Release of 1.0.0-beta.4
lead: Static web assets are always copied. The IsDraft property in the default FrontMatter is now supported.
published: 2024-01-20
tags: [release]
authors:
- name: "Jan Tesař"
gitHubUserName: "tesar-tech"
twitterUserName: "tesar-tech"
---

## Breaking change:

- Use `builder.WebHost.UseStaticWebAssets();` to ensure static assets are copied to the output folder. See [One little catch](#one-little-catch-with-one-liner-solution) for more info.

## Static web assets are always copied

**tl;dr**: It works as expected, just add `builder.WebHost.UseStaticWebAssets();` to your `Program.cs`.

Previously, it wasn't possible to copy static web assets from a Razor class library to the output folder. These assets, residing in the NuGet cache, are served by the framework. Static web assets from RCLs (e.g., CSS files or images) are accessed through the `_content/` path and are copied to the `wwwroot` folder upon publishing. However, BlazorStatic is designed to output the entire website, even during development (without publishing). An addition was made to copy the static web assets from RLCs using `app.Environment.WebRootFileProvider`.

Now, you can use any NuGet package with static web assets (for example, FluentUI; [check how it runs with BlazorStatic](/docs/componentlibs)), and it will work as expected.

This also addresses the lack of support for scoped CSS in BlazorStatic. Use scoped CSS as you normally would.

### One little catch (with one-liner solution)
BlazorStatic now relies on `app.Environment.WebRootFileProvider` to copy static web assets. You need to enable `StaticWebAssets`. In non-dev environments (Staging, Production, etc.), `StaticWebAssets` are turned off. The issue is described [here](https://dev.to/j_sakamoto/how-to-deal-with-the-http-404-content-foo-bar-css-not-found-when-using-razor-component-package-on-asp-net-core-blazor-app-aai) (with older .NET, but the principle is the same):

See it in the `WebHost.cs` file in the [aspnetcore repo](https://github.com/dotnet/aspnetcore/blob/cc9cff31eb828f5849c07afc46b08baeda42b399/src/DefaultBuilder/src/WebHost.cs#L221):

This becomes a problem when switching the `ASPNETCORE_ENVIRONMENT` to anything other than Development, which I recommend doing in GitHub Actions workflows (or similar).

The problem results in missing static web assets (CSS, images, etc.) in the output folder.

How to prevent this? Easily by activating `StaticWebAssets` in your `Program.cs`:

```csharp
var builder = WebApplication.CreateBuilder(args);

builder.WebHost.UseStaticWebAssets(); //👈
```
You might wonder: "Aren't StaticWebAssets turned off in prod for a reason?"

Yes, but: (simply put) for apps that run on a server.

A web app using BlazorStatic is meant for quick static website generation, not server deployment.

If you need to disable `StaticWebAssets`, consider this workaround:

- Add the `wwwroot` folder to `opt.ContentToCopyToOutput`.
- Publish the app before running.

I haven't tested this; let me know if you need it. I am curious about the use case.

## IsDraft property in default FrontMatter is now supported

First merged PR from community! Thanks to [Chris Gonzales](https://github.com/chrisg32) for this contribution.

Default `FrontMatter` has now support for `IsDraft` property.
If you set it to `true` the page will be ignored during generation. A useful feature indeed.

Note: You don't have to use the default FrontMatter at all.
You can tailor the front matter class based on your markdown posts' structure.

## Ignoring files for the generation works

To ignore certain files, configure it in `Program.cs`:

```csharp
builder.Services.AddBlazorStaticService(opt => {
opt.IgnoredPathsOnContentCopy.AddRange(new[] { "app.css" });
});
```

For example, I ignore the `app.css` file used by TailwindCSS to create the final CSS version (`app.min.css`).
There's no need to keep `app.css` in the output.

4 changes: 3 additions & 1 deletion BlazorStaticWebsite/Content/Docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@
- Read about [Deployment](docs/deployment).

- How to produce BlazorStatic app from scratch is described [here](docs/new-start).
- How to produce BlazorStatic app from scratch is described [here](docs/new-start).

- How to use BlazorStatic with FluentUI or any other component library is described [here](docs/componentlibs).
16 changes: 10 additions & 6 deletions BlazorStaticWebsite/Content/Docs/new-start.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ This guide will show you how to create static site using BlazorStatic. It is goo

- Remove `blazor.web.js` from `App.razor` (we don't need it for static site).

- Make necessary changes to your layout. I am using tailwindcss, so everything is accomadated to that.
- Make necessary changes to your layout. I am using tailwindcss, so everything is accommodated to that.

- When you run `dotnet watch` your app should be running.

Expand Down Expand Up @@ -47,7 +47,7 @@ This guide will show you how to create static site using BlazorStatic. It is goo
---
```

These metadata has to match C# class (`BlazorStatic.FronMatter`) that we will use now. You can customize the class to match your own metadata.
These metadata has to match C# class (`BlazorStatic.FrontMatter`) that we will use now. You can customize the class to match your own metadata.

- Mark Content folder to copy to the output:

Expand All @@ -66,7 +66,11 @@ This guide will show you how to create static site using BlazorStatic. It is goo

> dotnet add package BlazorStatic --prerelease

- Register servicies in `Program.cs`
- Turn on `StaticWebAssets`. This will ensure wwwroot and RLCs assets are copied to the output folder. [More info](docs/release-1.0.0-beta.4)
```csharp
builder.WebHost.UseStaticWebAssets();
```
- Register services in `Program.cs`

```csharp
builder.Services.AddBlazorStaticService(opt => {
Expand All @@ -80,7 +84,7 @@ This guide will show you how to create static site using BlazorStatic. It is goo
As you can see `BlazorStaticService` has options you can change. For example you can change the directory structure (where your md files are located), or you can ignore some files (like `app.css` in this case (we have `app.min.css`)).

- Use `BlazorStatic`
Before running the app we need to tell the service to acttually do something:
Before running the app we need to tell the service to actually do something:

```csharp
app.UseBlog<FrontMatter>();
Expand All @@ -89,15 +93,15 @@ This guide will show you how to create static site using BlazorStatic. It is goo

`UseBlog` will parse the markdown files and expose them to the app as Post<FrontMatter> through `BlogService`.

`UseBlazorStaticGenerator` will generate the static files a put them into the `output` folder (also customizable). It will shutdown the app outside of development environment. This is meant for CI/CD pipelines, otherwise the app would run "forever" in particualr job.
`UseBlazorStaticGenerator` will generate the static files a put them into the `output` folder (also customizable). It will shutdown the app outside of development environment. This is meant for CI/CD pipelines, otherwise the app would run "forever" in particular job.

## Scaffold the UI for blog posts

When you run the app right now, it will output the non-parametrized pages (e.g. `@page "/"` into `index.html`) and will copy content of `wwwroot` into the `output`. You can set where to look for non-parametrized pages by `opt.RazorPagesPaths` (default is `Components/Pages` folder).

> File generation is done by using `HttpClient` and saving the result into `.html` file.

We need to scafold the UI for blog posts. BlazorStatic doesn't force you to use any particular UI, but it will help you by prividing `BlogService<FrontMatter>.Posts` collection where your processed posts live.
We need to scaffold the UI for blog posts. BlazorStatic doesn't force you to use any particular UI, but it will help you by providing `BlogService<FrontMatter>.Posts` collection where your processed posts live.

You get get some inspiration for th UI. These pages are important:

Expand Down
8 changes: 4 additions & 4 deletions BlazorStaticWebsite/Program.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
using BlazorStatic;
using BlazorStaticWebsite.Components;
using BlazorStaticWebsite;
using Microsoft.Extensions.FileProviders;

using Microsoft.FluentUI.AspNetCore.Components;

var builder = WebApplication.CreateBuilder(args);

builder.WebHost.UseStaticWebAssets();

builder.Services.AddBlazorStaticService(opt => {
opt.IgnoredPathsOnContentCopy.AddRange(new[] { "app.css" });//pre-build version for tailwind
opt.ContentToCopyToOutput.Add(new("Content/Docs/media", "Content/Docs/media"));
//add docs pages
var docsFiles = Directory.GetFiles(Path.Combine("Content", "Docs"), "*.md")
.Where(x => !x.EndsWith("README.md"));//ignore readme
Expand All @@ -28,6 +27,7 @@

// Add services to the container.
builder.Services.AddRazorComponents();
builder.Services.AddFluentUIComponents();


var app = builder.Build();
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ BlazorStatic:
```csharp
builder.Services.AddBlazorStaticService(opt => {
opt.OutputFolderPath = "output";//root of the output
opt.ContentToCopyToOutput.Add(new("wwwroot",""));//content of root gets copied to the output
//wwwroot and _content are copied by default
opt.IgnoredPathsOnContentCopy.AddRange(new[] { "app.css" }); //don't copy app.css
});
```
Expand All @@ -89,7 +89,7 @@ BlazorStatic:
|Page about BlazorStatic (this repo contains the code itself)|[source](https://github.com/tesar-tech/BlazorStatic/tree/master/BlazorStaticWebsite) | [live](https://tesar-tech.github.io/BlazorStatic/)|
| Minimal blog |[source](https://github.com/tesar-tech/BlazorStaticMinimalBlog)|[live](https://tesar-tech.github.io/BlazorStaticMinimalBlog/)|
|Zodoc - image processing and deep learning sample| [source](https://github.com/tesar-tech/zodoc/)|[live](https://zodoc.tech/)|
| Add your page here!!!||
| Add your page here!!!||

## Contributions

Expand Down
21 changes: 21 additions & 0 deletions src/BlazorStaticExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ public static void UseBlog<TFrontMatter>(this WebApplication app)
public static void UseBlazorStaticGenerator(this WebApplication app, bool shutdownApp = false)
{
var blazorStaticService = app.Services.GetRequiredService<BlazorStaticService>();

AddStaticWebAssetsToOutput(app.Environment.WebRootFileProvider, string.Empty, blazorStaticService);

var lifetime = app.Services.GetRequiredService<IHostApplicationLifetime>();

var logger = app.Services.GetRequiredService<ILogger<BlazorStaticService>>();
Expand All @@ -129,4 +132,22 @@ public static void UseBlazorStaticGenerator(this WebApplication app, bool shutdo
}
);
}
private static void AddStaticWebAssetsToOutput(IFileProvider fileProvider, string subPath, BlazorStaticService blazorStaticService)
{
IDirectoryContents contents = fileProvider.GetDirectoryContents(subPath);

foreach (var item in contents)
{
string fullPath = $"{subPath}{item.Name}";
if (item.IsDirectory)
{
AddStaticWebAssetsToOutput(fileProvider, $"{fullPath}/", blazorStaticService);
}
else
{
if (item.PhysicalPath is not null)
blazorStaticService.Options.ContentToCopyToOutput.Add(new(item.PhysicalPath, fullPath));
}
}
}
}
3 changes: 2 additions & 1 deletion src/BlazorStaticOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,9 @@ public class BlazorStaticOptions
public List<string> IgnoredPathsOnContentCopy { get; } = [];
/// <summary>
/// Paths (files or dirs) relative to project root, that should be copied to output folder
/// Content from RCLs (from _content/) and wwwroot is copied by default
/// </summary>
public List<ContentToCopy> ContentToCopyToOutput { get; } = [new ContentToCopy("wwwroot", "")];
public List<ContentToCopy> ContentToCopyToOutput { get; } = [];

/// <summary>
/// Allows to customize YamlDotNet Deserializer used for parsing front matter
Expand Down
3 changes: 2 additions & 1 deletion src/Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,10 @@ public async Task<string> ParseMarkdownFile(string filePath, (string mediaPathTo
/// </summary>
/// <param name="sourcePath"></param>
/// <param name="targetPath"></param>
/// <param name="ignoredPaths"></param>
/// <param name="ignoredPaths">Target (full)paths that gets ignored.</param>
public void CopyContent(string sourcePath, string targetPath, List<string> ignoredPaths)
{
if(ignoredPaths.Contains(targetPath)) return;
if (File.Exists(sourcePath))//source path is a file
{
string? dir = Path.GetDirectoryName(targetPath);
Expand Down
3 changes: 2 additions & 1 deletion src/Services/BlazorStaticService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,11 @@ internal async Task GenerateStaticPages(string appUrl)
Directory.Delete(options.OutputFolderPath, true);
Directory.CreateDirectory(options.OutputFolderPath);

List<string> ignoredPathsWithOutputFolder = options.IgnoredPathsOnContentCopy.Select(x => Path.Combine(options.OutputFolderPath, x)).ToList();
foreach (var pathToCopy in options.ContentToCopyToOutput)
{
logger.LogInformation("Copying {sourcePath} to {targetPath}", pathToCopy.SourcePath, Path.Combine(options.OutputFolderPath, pathToCopy.TargetPath ));
helpers.CopyContent(pathToCopy.SourcePath, Path.Combine(options.OutputFolderPath, pathToCopy.TargetPath), options.IgnoredPathsOnContentCopy);
helpers.CopyContent(pathToCopy.SourcePath, Path.Combine(options.OutputFolderPath, pathToCopy.TargetPath), ignoredPathsWithOutputFolder);
}


Expand Down

0 comments on commit 0386232

Please sign in to comment.