Blazor and Typescript

blazor wasm

Blazor allows us one of the nicest things in the world; write much less JavaScript. What's even better is not to write any more at all! Thanks to Typescript, it is possible to completely eliminate the use of JavaScript from our Blazor projects. Read on to see how!

Comme je mentionnais dans mon dernier article, j’ai eu la chance de participer au Blazor Day en tant que conférencier. Cet article se veut un retour sur un des points que j’ai discuté lors de ma conférence. Aussi, je ne prends aucun crédit sur l’idée, qui vient de cet item de Chris Sainty, une incroyable référence sur Blazor. Par contre, je l’ai légèrement adapté pour permettre autre chose dont je parlerai dans un prochain article.

La première étape pour permettre de faire du TypeScript avec Blazor est d’ajouter un nouveau projet de type Razor Class Library. Ce projet contiendra nos classes TypeScript ainsi que nos classes C# qui vont les utiliser via l’interop. On peut d’ailleurs enlever tous les fichiers créés par défaut et conserver uniquement le dossier wwwroot, comme sur l’image suivante.

Pour mon exemple, j’ai eu le besoin, pour le site du Bracket Show, d’ouvrir un lien dans un nouvel onglet par le code. Malheureusement, ce n’est pas quelque chose qu’on peut présentement faire avec la navigation de Blazor. La première étape est donc d’ajouter une classe TypeScript au niveau du dossier wwwroot du projet. En l’ajoutant, Visual studio devrait vous offrir d’installer le Nuget Microsoft.Typescript.MSBuild. S’il ne le fait pas, installez le manuellement, c’est nécessaire pour la compilation.

export class UrlOpenerService {
    openExternalLink(url: string): void {
        window.open(url, '_blank');
    }

    static load(): void {
        window['UrlOpenerService'] = new UrlOpenerService();
    }
}

UrlOpenerService.load();

La fonction openExternalLink est assez simple dans son comportement, elle utilise window pour ouvrir l’url reçu dans un nouvel onglet. La fonction load elle, qui est statique, permet d’ajouter la classe et ses méthodes dans le window. La touche magique vient de la dernière ligne, où on appelle load. Quand le TypeScript sera transpilé en JavaScript, cela va donc faire que la méthode va être appelée dès qu’on inclut le script dans notre page.

Vous remarquerez à la compilation que des fichiers .js and .js.map sont générés. Ils serviront à l’utilisation et pour déboguer, si nécessaire. Ensuite, il faut ajouter une référence à notre projet Razor Class Library, puis inclure le script au niveau de notre index.html Where _Host.cshtml. Pour l’inclure, la source du script doit débuter par _content, puis le nom de notre projet, suivi du nom du fichier JavaScript généré, comme ceci:

<script src="_content/BlazorTypescript.Client.Typescript/url-opener.service.js">
</script>

Ceci permet donc d’avoir le script au démarrage de l’application, qui va par la suite appeler notre fonction load pour inclure l’objet. On peut ensuite retourner à notre librairie et ajouter une classe C#. Cette classe servira à appeler la fonction openExternalLink via l’interop.

public class UrlOpener
    {
        public static ValueTask OpenExternalLink(
            IJSRuntime jsRuntime, string url)
        {
            return jsRuntime.InvokeVoidAsync(
                "UrlOpenerService.openExternalLink", url);
        }
    }

Un avantage caché

En plus d’éliminer l’écriture de JavaScript, cette configuration nous donne un autre avantage. En isolant complètement le scripting dans un projet, on peut facilement identifier les fonctions utilisées. On peut donc facilement les retirer le jour où une fonction devient accessible via Blazor et C#. Le refactoring pourra se faire tout d’abord en remplaçant le code à l’intérieur de la classe C#. Une fois remplacé, on peut retirer la classe TypeScript sans risques. Et finalement, si nécessaire, on peut déplacer le tout dans notre projet où on utilise la fonction.

La suite

Nous avons donc maintenant résolu un des plus grands problèmes de tout développeur C#; ne plus écrire de JavaScript. Blazor et TypeScript font une excellente équipe en attendant d’être 100% Blazor. Dans un prochain article, je vais amener le tout un peu plus loin, car il y a un gros manque à cette solution qui se doit d’être comblé.

Bruno

Author: Bruno

By day, I am a developer, team leader and co-host of the Bracket Show. By evening, I am a husband and the father of two wonderful children. The time I have left after all of this I spend trying to get moving, playing and writing video game reviews, as well as preparing material for the Bracket Show recordings and for this blog. Through it all, I am also passionate about music and microbreweries.