javascriptblazor

How do I put together a Blazor Page that will call a javascript file that needs to import an ESModule?


There is the following application called Fantastic Dice that is a javascript module. It can be loaded as such from the example provided here from this page.

https://codesandbox.io/p/sandbox/dice-es6-module-cdn-lhbs99?file=%2Fsrc%2Findex.js%3A1%2C1-2%2C1

I have tried doing this in a Blazor page with no success.

I have the following javascript file called dice.js

import DiceBox from "https://unpkg.com/@3d-dice/dice-box@1.0.8/dist/dice-box.es.min.js";

export function DiceBoxCall() {
    let Box = new DiceBox("#dice-box", {
        assetPath: "assets/",
        origin: "https://unpkg.com/@3d-dice/dice-box@1.0.8/dist/",
        theme: "default",
        themeColor: "#feea03",
        offscreen: true,
        scale: 6
    });

    Box.init().then(async (world) => {
        Box.roll(["4d20", "4d12", "4d10", "4d8", "4d6", "4d4"]);
    });
}

I call it from Blazor using the JSRuntime library

await JSRuntime.InvokeVoidAsync("DiceBoxCall");

This loads, but It cannot find DiceBoxCall. I'm pretty sure its the import but that import is vital to everything. The library fantastic dice uses is an ESModule and the import call is loading the library into a class object. I cannot find any other example that would help me here.

Edit:

I tried using in the following way with no success.

<HeadContent>
    <script type="module">
        import DiceBox from "@3d-dice/dice-box"
    </script>
</HeadContent>

Solution

  • Just tried the approach similar to what I described in this post and it seems to be working.

    I have three files:

    1. DiceRoller.razor page layout
        @page "/DiceRoller"
        <h3>DiceRoller</h3>
        <div id="dice-box"></div>
    
    1. DiceRoller.razor.cs page code-behind (partial class)
    using Microsoft.AspNetCore.Components;
    using Microsoft.JSInterop;
    
    namespace BlazorServerJS.Pages;
    
    public partial class DiceRoller : ComponentBase
    {
        [Inject]
        private IJSRuntime JS { get; set; } = default!;
        private IJSObjectReference? _jsModule;
     
        protected override async Task OnAfterRenderAsync(bool firstRender)
        {
            _jsModule ??= await JS.InvokeAsync<IJSObjectReference>(
                "import", "./Pages/DiceRoller.razor.js");
    
            await _jsModule.InvokeVoidAsync("DiceBoxCall");
    
            await base.OnAfterRenderAsync(firstRender);
        }
    }
    
    1. DiceRoller.razor.js (just because I like to store .js and .css next to respective pages).
    import DiceBox from "https://unpkg.com/@3d-dice/dice-box@1.0.8/dist/dice-box.es.min.js";
    
    export function DiceBoxCall() {
        let Box = new DiceBox("#dice-box", {
            assetPath: "assets/",
            origin: "https://unpkg.com/@3d-dice/dice-box@1.0.8/dist/",
            theme: "default",
            themeColor: "#feea03",
            offscreen: true,
            scale: 6
        });
    
        Box.init().then(async (world) => {
            Box.roll(["4d20", "4d12", "4d10", "4d8", "4d6", "4d4"]);
        });
    }