jsakamoto / BlazingStory

The clone of "Storybook" for Blazor, a frontend workshop for building UI components and pages in isolation.
https://jsakamoto.github.io/BlazingStory/
Mozilla Public License 2.0
319 stars 15 forks source link

[How to] BlazingStory with MudBlazor using ServerMode #40

Open Fronix opened 6 months ago

Fronix commented 6 months ago

So I finally figured out why MudBlazor was seemingly having random issues in BlazingStories. More specifically

System.InvalidOperationException: JavaScript interop calls cannot be issued at this time. This is because the component is being statically rendered. When prerendering is enabled, JavaScript interop calls can only be performed during the OnAfterRenderAsync lifecycle method.
   at Microsoft.AspNetCore.Components.Server.Circuits.RemoteJSRuntime.BeginInvokeJS(Int64 asyncHandle, String identifier, String argsJson, JSCallResultType resultType, Int64 targetInstanceId)
   at Microsoft.JSInterop.JSRuntime.InvokeAsync[TValue](Int64 targetInstanceId, String identifier, CancellationToken cancellationToken, Object[] args)
   at Microsoft.JSInterop.JSRuntime.InvokeAsync[TValue](Int64 targetInstanceId, String identifier, Object[] args)
   at BlazingStory.Internals.Extensions.IJSExtensions.ImportAsync(IJSRuntime jsRuntime, String modulePath)
   at BlazingStory.Internals.Services.JSModule.GetModuleAsync()
   at BlazingStory.Internals.Services.JSModule.InvokeVoidAsync(String identifier, Object[] args)
   at BlazingStory.Internals.Pages.Canvas.CanvasFrame.EventTArgMonitorHandler[TArgs](String name, TArgs eventArgs)
   at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
   at IVO.Ui.Components.Picker`1.SetTextAsync(String value, Boolean callback) in D:\Git\BlazingStoryTest\MudBlazor\Components\Picker\Picker.razor.cs:line 294
   at IVO.Ui.Components.DatePicker.SetDateAsync(Nullable`1 date, Boolean updateValue) in D:\Git\BlazingStoryTest\MudBlazor\Components\DatePicker\DatePicker.cs:line 67
   at IVO.Ui.Core.TaskExtensions.AndForget(Task task, Boolean ignoreExceptions) in D:\Git\BlazingStoryTest\MudBlazor\Core\Extensions\TaskExtensions.cs:line 12System.InvalidOperationException: JavaScript interop calls cannot be issued at this time. This is because the component is being statically rendered. When prerendering is enabled, JavaScript interop calls can only be performed during the OnAfterRenderAsync lifecycle method.

The fix

Use @InteractiveServerNoPreRender

In your IndexPage.razor and IFramePage.razor replace all @InteractiveServer with @InteractiveServerNoPreRender

Remove the blazor.web.js script tag in IFramePage.razor

Example IndexPage.razor:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <!--
    If you need to add <link> or <script> elements to include CSS or JavaScript files
    for canvas views of your Stories,
    YOU SHOULD DO THAT IN THE "IFramePage.razor" FILE, NOT HERE.
    -->
    <title>StoriesTester</title>
    <base href="/" />
    <link rel="stylesheet" href="css/blazor-ui.css" />
    <HeadOutlet @rendermode="@InteractiveServerNoPreRender" />
</head>

<body>
    <StoriesTester.Components.App @rendermode="@InteractiveServerNoPreRender" />

    <div id="blazor-error-ui">
        An unhandled error has occurred.
        <a href="" class="reload">Reload</a>
        <a class="dismiss">šŸ—™</a>
    </div>

    <!--
    If you need to add <script> elements to include JavaScript files for canvas views of your Stories,
    YOU SHOULD DO THAT IN THE "IFramePage.razor" FILE, NOT HERE.
    -->
    <script src="_framework/blazor.web.js"></script>
</body>

</html>

Example IFramePage.razor:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>StoriesTester</title>
    <base href="/" />
    <!--
    If you need to add <link> or <script> elements to include CSS or JavaScript files
    for canvas views of your Stories,
    YOU SHOULD PLACE THEM HERE, not in the "IndexPage.razor" file.
    -->
    <link rel="stylesheet" href="css/blazor-ui.css" />
    <link rel="stylesheet" href="IVO.Ui.Stories.styles.css" />
    <!-- MudBlazor -->
    <link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
    <HeadOutlet @rendermode="@InteractiveServerNoPreRender" />
</head>

<body>
    <component type="typeof(App)" render-mode="Server" />
    <StoriesTester.Components.App @rendermode="@InteractiveServerNoPreRender" />

    <div id="blazor-error-ui">
        An unhandled error has occurred.
        <a href="" class="reload">Reload</a>
        <a class="dismiss">šŸ—™</a>
    </div>

    <!--
    If you need to add <script> elements to include JavaScript files for canvas views of your Stories,
    YOU SHOULD PLACE THEM HERE, not in the "index.html" file.
    -->
    <!-- This script shouldn't be here if using serverrender -->
    <!--     <script src="_framework/blazor.web.js"></script> -->
    <script src="_framework/blazor.server.js"></script>
    <script src="_content/MudBlazor/MudBlazor.min.js"></script>
</body>

</html>