public class Blazor in WordPress – Multiple Components

{

In my previous post, I showed how to simply embed a single Blazor Component inside a WordPress page or post. However, what I really want is the chance to willy-nilly throw in as many components as I want, wherever I want. This runs into some problems. If you try to just copy/paste my code from the first post multiple times, and run it with your dev tools open, you’ll see multiple errors.

 

The first issue is with the line <script src="_framework/blazor.webassembly.js"></script>. As with any javascript file, you should only import blazor.webassembly one time, not multiple times. Sure, I could remember just to do that the first time, but it would be even nicer to have it built into my WordPress blog, and never have to worry about adding that line. It’s also more “correct” for websites to import scripts and other files in the head or at the bottom of the body (footer area), rather than in the midst of the content.

 

If this were a custom website, I would just add the tag to index.html. But with WordPress, there’s lots of warnings about interfering scripts, loading order, and so forth, so they don’t recommend you do this yourself. Instead, I installed a plugin, Header and Footer Scripts, which gives you WP UI-level control over custom tags in a header and/or footer.

 

After installing the plugins, I moved the blazor.webassembly script to the header, and reloaded to make sure everthing still worked. I discovered that I also had to move <base href="/" /> to make it still work. But again, this is something you would only want to do once per page. (And, side note, it’s the biggest failing of this whole setup, as redirecting all url calls can interfere with other WP plugins.)

 

Finally, if we’re going to move scripts, we should also move any stylesheet link tags. With all those moved out of the way, now the in-post html looks much more concise and neat:

 

<div id="app">Loading...</div>

 

Great! But now…I want two different components. OK, so, obviously, I should replace the id="app" with some other ids. Let’s look again at what the reference looks like in our Blazor Web Assembly Program.cs file:

 

public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");

builder.Services.AddScoped(
sp => new HttpClient {BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)});

await builder.Build().RunAsync();
}

[Program.Main]

 

We already mentioned in the last post that you can replace <App> and "#app" with your own razor component file and id tag. So I tried adding two.

 

builder.RootComponents.Add<DataGrid>("#grid");
builder.RootComponents.Add<MusicKeyboard>("#keyboard");

 

And this definitely worked with two Id’ed div elements in a page! Unfortunately…if you happen to only want to use one of your two components, then Blazor throws an error that it can’t find the matching div for the other one!

 

My first attempt to fix this was to revert back to just loading the App razor component, and using logic inside that to decide which other component to show. This turned out to work for single components, but Blazor would get confused if it saw two "app" divs!

 

Luckily, after some more Google-fu, I stumbled on this GitHub issue: Unable to use RootComponents twice on same page, where the original poster, Ecroyd, came up with a clever workaround of using a custom element tag (type) for each component, looking up which components are on the page with JSInterop, and then only adding the RootComponents that are found!

 

You can see Ecroyd’s version on the link above, but I did some more tweaking. I decided I would rather keep these div elements, and instead add a class="blazor-component" to identify each.

 

var jsRuntime = builder.Services.BuildServiceProvider().GetRequiredService<IJSRuntime>();
var module = await jsRuntime.InvokeAsync<IJSObjectReference>("import", "/componentFinder.js");
var json = await module.InvokeAsync<JsonElement>("getBlazorComponents");
foreach(var id in json.EnumerateArray())
{
switch (id.ToString())
{
case "blazor-data-grid":
builder.RootComponents.Add<BdGridDemo>("#blazor-data-grid");
break;
case "blazor-music-keyboard":
builder.RootComponents.Add<MusicKeyboardDemo>("#blazor-music-keyboard");
break;
}
}

[Program.Main changed code]

 

export function getBlazorComponents() {
return Array.from(document.querySelectorAll('.blazor-component')).map(a => a.id);
}

[componentFinder.js lookup module]

 

Now, for each component I want to embed, I add the following (some styling added for layout):

 

<div class="blazor-component" style="height: 550px; background: white; padding: 10px; overflow-x: scroll;" id="blazor-music-keyboard">Loading Blazor Music Keyboard ... </div>

 

 

Loading Blazor Music Keyboard …

 

Or

 

<div class="blazor-component" style="height: 800px; overflow-y: scroll; width: 100%; background: white; color: black; padding: 20px; font-family: arial;" id="blazor-data-grid">Loading Blazor Data Grid ... </div>

 

 

Loading Blazor Data Grid …
}

public class Embedding Blazor Components in WordPress

{

In my previous post, Blazor Data Grid, I showed off a new Blazor web component, and at the bottom of the post, I actually had a demo version of the component right here in this blog, which is running on WordPress. Hat tip to Virtual Dan at http://dano.vfsystems.net/2020/03/blazor-and-wordpress/ for getting me pointed in the right direction!

 

The gist of it is, since Blazor components can run in WebAssembly, all you need for a functioning embedded component is a Blazor WebAssembly project with a single component, published up to a folder in your WordPress (or other site) directory, a script tag to load blazor’s runtime, and a div with a pre-determined Id.

 

I started with the default Blazor Web Assembly template in Rider (my IDE of choice, but VS or VS Code work fine as well). In Program.Main, you see the following line:

 

builder.RootComponents.Add<App>("#app");

 

This defines the key div as having id="app", and points to a blazor component or razor file named App.razor. You can of course change both the Id string value and the razor file loaded. In my case, I decided that I didn’t need all the routing logic in App.razor for an embedded component project, so I deleted this (and many other files). At first, I just pointed to the component I wanted to render. Note that if you change the Id, you will also want to update your index.html file to match, so you can test your application. Running in debug, you get a simple rendering of your component in a blank page.

 

Loading Blazor Music Keyboard …

[Demo Musical Keyboard (Xylophone) Component]

 

Now that we have a working Blazor Wasm component, we want to get it up to our WordPress server. I recommend setting up some form of automated deployment on git commit, so that you don’t have to manually copy files every time you make a change (I use Azure DevOps Pipelines, but there are many solutions). Basically, you want everything in the /wwwroot folder of your publishing step to be directly copied into your root WordPress folder, like say /etc/wordpress/. This should be the same folder as wp-config.php.

 

That “everything” mentioned above includes two important folders, _content and _framework. _framework is the .NET Runtime and Wasm assemblies. We will discuss _content later. You should also see your index.html (although we won’t be using this), and any css or javascript files you created in your wwwroot.

 

Once the files are in place, load up the WordPress post or page editor, and add a “Custom HTML” block. Add the following code (I’m reverting back to the default “app” id here):

 

<div>
  <base href="/" />
<link href="YourApplication.styles.css" rel="stylesheet" />
  <div id="app">Loading...</div>
<script src="_framework/blazor.webassembly.js"></script>
</div>

 

This is based on Virtual Dan’s version, (thanks again). Let’s break it down.

 

The stylesheet link is only important if you actually created any styles for your component. We’ve already mentioned that we need a div with the correct Id. Whatever you put inside the div (e.g., “Loading…”) will show for a second or two while blazor boots up. Then it gets overwritten by the contents of your component. Below this is the script that loads Blazor Web Assembly.

 

I noticed the <base href="/" /> in Virtual Dan’s source code on his site. He doesn’t mention it in the explanations, but I figured out the reason for this. Without re-setting the base url, I would get errors with looking for blazor.webassembly.js at whatever the page url is, like https://tocode.software/2021/03/04/Blazor/_framework/blazor.webassembly.js. Obviously, I don’t want to put my framework at this location on disk, if I want to share it with multiple pages in the future, and prevent it from breaking if the url ever changes. I did tinker around with starting the script src with and without the forward slash, but it didn’t seem to work either way, until I discovered what Dan was doing with the base href.

 

If you’ve successfully followed thus far, publish or preview your wordpress page, and give yourself a high five for running Blazor in WordPress! I will follow up in the next few days with another post about refactoring and supporting multiple components.

}