# Getting Started with SpawnDev.BlazorJS This guide covers everything you need to start using SpawnDev.BlazorJS in your Blazor WebAssembly application. --- ## Installation Install from NuGet: ```bash dotnet add package SpawnDev.BlazorJS ``` Or add directly to your `.csproj`: ```xml ``` **Supported frameworks:** .NET 8, .NET 9, .NET 10 --- ## Program.cs Setup Two changes are required in `Program.cs`: 1. Register `BlazorJSRuntime` with `AddBlazorJSRuntime()` 2. Replace `RunAsync()` with `BlazorJSRunAsync()` ### Minimal Setup ```csharp using SpawnDev.BlazorJS; using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components.WebAssembly.Hosting; var builder = WebAssemblyHostBuilder.CreateDefault(args); builder.RootComponents.Add("#app"); builder.RootComponents.Add("head::after"); // Add BlazorJSRuntime singleton service builder.Services.AddBlazorJSRuntime(); // IMPORTANT: Use BlazorJSRunAsync instead of RunAsync await builder.Build().BlazorJSRunAsync(); ``` ### Setup with Worker Scope Detection (out var JS) The `AddBlazorJSRuntime` method has an overload that outputs the `BlazorJSRuntime` instance immediately. This lets you detect the current scope (Window, Worker, etc.) before the app finishes building - critical for apps that run in both Window and Worker contexts. ```csharp using SpawnDev.BlazorJS; using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components.WebAssembly.Hosting; var builder = WebAssemblyHostBuilder.CreateDefault(args); // Get BlazorJSRuntime immediately via out parameter builder.Services.AddBlazorJSRuntime(out var JS); // Only add root components when running in a Window scope // Workers do not have a DOM - adding components there would fail if (JS.IsWindow) { builder.RootComponents.Add("#app"); builder.RootComponents.Add("head::after"); } // Register your services builder.Services.AddSingleton(); await builder.Build().BlazorJSRunAsync(); ``` This is the standard pattern used across all SpawnDev projects. The same `Program.cs` runs in both the browser Window and any Web Worker contexts. `BlazorJSRunAsync()` handles the difference automatically - in a Window it calls `RunAsync()` to start the Blazor renderer, in a Worker it enters a service-only mode. ### Setup with WebWorkerService When using [SpawnDev.BlazorJS.WebWorkers](https://github.com/LostBeard/SpawnDev.BlazorJS.WebWorkers) for multi-threaded workers: ```csharp using SpawnDev.BlazorJS; using SpawnDev.BlazorJS.WebWorkers; using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components.WebAssembly.Hosting; var builder = WebAssemblyHostBuilder.CreateDefault(args); builder.Services.AddBlazorJSRuntime(out var JS); if (JS.IsWindow) { builder.RootComponents.Add("#app"); builder.RootComponents.Add("head::after"); } // Add WebWorkerService for spawning workers from .NET builder.Services.AddWebWorkerService(); // Register services - these are available in both Window and Worker scopes builder.Services.AddSingleton(); await builder.Build().BlazorJSRunAsync(); ``` ### Loading a JavaScript Library Before App Start Some JS libraries need to be loaded before the app starts. You can do this using the `BlazorJSRuntime` instance from `out var JS`: ```csharp var builder = WebAssemblyHostBuilder.CreateDefault(args); builder.Services.AddBlazorJSRuntime(out var JS); if (JS.IsWindow) { builder.RootComponents.Add("#app"); builder.RootComponents.Add("head::after"); // Load a JS library before the app starts await JS.LoadScript("_content/MyLibrary/my-library.js"); } await builder.Build().BlazorJSRunAsync(); ``` --- ## Injecting BlazorJSRuntime ### In Razor Components ```csharp @inject BlazorJSRuntime JS

Window Height: @windowHeight

@code { int windowHeight; protected override void OnInitialized() { windowHeight = JS.Get("window.innerHeight"); } } ``` Or using the `[Inject]` attribute in code-behind: ```csharp [Inject] BlazorJSRuntime JS { get; set; } ``` ### In Services ```csharp public class MyService { private readonly BlazorJSRuntime _js; public MyService(BlazorJSRuntime js) { _js = js; } public string GetUserAgent() { return _js.Get("navigator.userAgent"); } } ``` ### Static Access from JSObject Classes Inside any class that inherits from `JSObject`, you can access `BlazorJSRuntime` via the protected static `JS` property: ```csharp public class MyWrapper : JSObject { public MyWrapper(IJSInProcessObjectReference _ref) : base(_ref) { } // JS.New calls the BlazorJSRuntime static instance public MyWrapper(string url) : base(JS.New("MyClass", url)) { } } ``` --- ## Basic Operations ### Get and Set Global Properties ```csharp // Get a property value (supports dot notation) var height = JS.Get("window.innerHeight"); var title = JS.Get("document.title"); var userAgent = JS.Get("navigator.userAgent"); // Set a property value JS.Set("document.title", "My Blazor App"); JS.Set("myGlobalVar", 42); // Get a typed JSObject wrapper using var window = JS.Get("window"); using var document = JS.Get("document"); using var navigator = JS.Get("navigator"); ``` ### Call Synchronous Methods Use `Call` for methods that return a value, `CallVoid` for void methods: ```csharp // Call a method that returns a value var item = JS.Call("localStorage.getItem", "myKey"); // Call a void method JS.CallVoid("localStorage.setItem", "myKey", "myValue"); JS.CallVoid("console.log", "Hello from Blazor!"); // Call with multiple arguments var sum = JS.Call("Math.max", 10, 20); ``` ### Call Asynchronous Methods (Promise-returning) Use `CallAsync` for JavaScript methods that return a Promise: ```csharp // Fetch API - returns a Promise using var response = await JS.CallAsync("fetch", "/api/data"); var text = await response.Text(); // Any Promise-returning method var result = await JS.CallAsync("myAsyncFunction", arg1, arg2); ``` **CRITICAL:** Using `CallAsync` on a synchronous JS method will THROW. Using `Call` on an async/Promise method will return a `Promise` object, not the resolved value. Match the call type to the JS method type. ### Create New JavaScript Objects ```csharp // Create a new JS object using the constructor name using var audio = JS.New