Isoliertes JavaScript in Blazor mit zusammengestellten JS-Dateien

· 3 Min. Lesezeit

Wenn Sie schon einmal mit Blazor und JS Interop gearbeitet haben, haben Sie wahrscheinlich eine riesige app.js-Datei voller Zufallsfunktionen für verschiedene Komponenten erhalten. Es funktioniert, aber es wird schnell chaotisch. Glücklicherweise gibt es einen viel saubereren Ansatz: zusammengestellte JavaScript-Dateien.

Die Idee

Genau wie bei der CSS-Isolation können Sie mit Blazor eine .razor.js-Datei neben Ihrer Komponente platzieren. Das JavaScript-Modul wird bei Bedarf nur dann geladen, wenn die Komponente es tatsächlich benötigt. Keine globalen Skripte, keine Umweltverschmutzung.

Einrichten

Nehmen wir an, wir haben eine Clipboard.razor-Komponente, die Text in die Zwischenablage kopiert. Erstellen Sie direkt daneben eine Datei mit dem Namen Clipboard.razor.js:

export function copyToClipboard(text) {
    navigator.clipboard.writeText(text).then(() => {
        console.log("Copied to clipboard!");
    });
}

Beachten Sie das Schlüsselwort export – das ist wichtig. Blazor lädt es als Standard-ES-Modul.

Laden des Moduls in Blazor

In Ihrer Komponente verwenden Sie IJSRuntime, um das Modul zu importieren. Der Pfad folgt einer Konvention: ./_content/{ASSEMBLY_NAME}/{COMPONENT_PATH}.razor.js für Bibliotheken oder einfach der relative Pfad für das aktuelle Projekt.

@inject IJSRuntime JS
@implements IAsyncDisposable

<button @onclick="Copy">Copy to clipboard</button>

@code {
    [Parameter]
    public string Text { get; set; }

    private IJSObjectReference? module;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            module = await JS.InvokeAsync<IJSObjectReference>(
                "import", "./Components/Clipboard.razor.js");
        }
    }

    private async Task Copy()
    {
        if (module is not null)
        {
            await module.InvokeVoidAsync("copyToClipboard", Text);
        }
    }

    public async ValueTask DisposeAsync()
    {
        if (module is not null)
        {
            await module.DisposeAsync();
        }
    }
}

Hier ein paar Dinge zu beachten:

– Wir laden das Modul in OnAfterRenderAsync, da JS Interop während des serverseitigen Vorrenderns nicht verfügbar ist

  • Wir behalten einen Verweis auf das Modul bei IJSObjectReference – Wir implementieren IAsyncDisposable, um das Modul zu bereinigen, wenn die Komponente zerstört wird

Warum das besser ist

Früher habe ich alles in einem einzigen wwwroot/js/app.js abgelegt. Es funktionierte, aber das Finden von Funktionen war mühsam und jede Seite lud JavaScript, das sie nicht brauchte. Mit zusammengestellten JS-Dateien:

  • Jede Komponente besitzt ihr eigenes JavaScript
  • Module werden nur bei Bedarf langsam geladen
  • Keine globalen Funktionsnamenkonflikte
  • Einfacher zu warten und zu löschen – wenn Sie die Komponente löschen, löschen Sie auch das JS

Ein Problem mit dem Pfad

Der Pfad, den Sie an import übergeben, hängt davon ab, ob Sie sich in einer eigenständigen Blazor-App oder einer Razor-Klassenbibliothek befinden. Bei einer regulären Blazor-App ist der Pfad relativ zu wwwroot. Die Datei .razor.js wird zur Erstellungszeit dorthin kopiert, sodass Sie sie vom Speicherort der Komponente im Projekt aus referenzieren.

Wenn Sie beim Laden des Moduls eine 404 erhalten, überprüfen Sie den Pfad noch einmal und stellen Sie sicher, dass die Datei mit .razor.js und nicht nur mit .js endet.

Ich hoffe, Ihnen hat der Beitrag gefallen! Sie können mich gerne in den sozialen Medien unter @emimontesdeoca kontaktieren.

Ressourcen