Isolation CSS et JavaScript sous Blazor

Blazor offre la possibilité de réaliser des composants autonomes et facilement réutilisables notamment avec la diffusion en paquet NuGet.

Cependant, jusqu’à présent il était nécessaire d’ajouter le CSS dans la partie header du fichier _Host.cshtml ou index.html sous la forme :

<link href="_content/Mycomponent/my_component.css" rel="stylesheet" />

Il en va de même pour les scripts JavaScript qui devaient être ajoutés dans le body :

<script src="_content/ Mycomponent / my_component.js"></script>

Il fallait donc, lors de la diffusion du composant, préciser à l’utilisateur de bien penser à ajouter ces éléments. La sortie de .Net5 apporte une évolution significative permettant d’améliorer le côté autonome en supprimant cette obligation. Il s’agit de l’isolation CSS et JavaScript !

Isolation CSS

Implémentation

Pour commencer à utiliser l’isolation CSS, il faut créer un projet Blazor et utiliser .Net5. Vous pouvez indifféremment utiliser Blazor server ou Blazor webassembly. La mise en place de l’isolation CSS est extrêmement simple. Il suffit d’ajouter une feuille de style portant le même nom que le composant. Par exemple, si l'on souhaite ajouter un style à l’index n’ayant comme portée que l’index lui-même, il suffit d’ajouter le fichier Index.razor.css :

 

 

 

Et pour modifier la balise h1, ajouter le css suivant :

h1 { color: blue; }

Nous pouvons constater que le h1 de l’index est bien bleu.

 

 

 

Alors que le h1 du composant counter est resté noir.

 

 

 

Fonctionnement

Au moment de la génération, Blazor combine tous les styles dans un fichier CSS unique nommé myblazorcomponent.style.css, où myblazorcomponent est bien sûr le nom de l'application. Dans le cas d’un projet appelé BlazorCSSJsisolation, nous obtiendrons le fichier BlazorCSSJsisolation.styles.css que nous pouvons retrouver en ouvrant la console de développeur.

 

 

 

Autre point important, si nous analysons l’élément h1, nous remarquons l’ajout d’un attribut.

 

 

 

Et dans le fichier de style, nous retrouvons ce même attribut.

 

 

 

C’est ainsi que Blazor peut isoler le rendu css pour chaque composant, chacun disposant de son propre attribut généré.  

Isolation CSS et composants enfants

1. Style différent

Posons-nous la question du fonctionnement avec les composants enfant. En effet, il n’est pas rare d’avoir des composants imbriqués les uns dans les autres. Par exemple, lors de la création d’un projet Blazor, nous avons par défaut un composant SurveyPrompt. Maintenant que nous avons observé comment fonctionne l’isolation, nous comprenons facilement qu’il faut ajouter un fichier css pour le composant enfant si nous souhaitons un style différent et spécifique.

 2. Style identique au parent

Par défaut, l’isolation CSS s’applique uniquement au composant auquel elle est liée. Ainsi dans le fichier Index.razor, le h1 en bleu s’applique à l’index, mais pas au composant SurveyPrompt inclus dans la page. C’est le style général qui s’applique. Il est malgré tout possible de propager le style isolé aux composants enfants. Il faut pour cela utiliser l’attribut ::deep dans le fichier de style.

::deep h1 { color: blue; }

Puis, encapsulons les éléments parents et enfants dans une même balise (div par exemple). Un attribut sera alors ajouté sur la balise div et le style sera appliqué au parent et à l’enfant.  

Migration d’un projet .net Core 3.x vers .Net5

Si vous migrez depuis un projet en .Net Core 3.x vers .Net5, il est possible que l’isolation CSS ne fonctionne pas comme attendu. En effet, lors de la création d’un projet en .Net5 directement, le fichier de style BlazorCSSJsisolation.styles.css est automatiquement ajouté dans le fichier _Host.cshtml ou index.html. Ce fichier est la clé du fonctionnement de l’isolation CSS. Cependant lors de la migration depuis un projet antérieur, ce fichier n’est pas ajouté. Vous devrez inclure manuellement la ligne <link href="BlazorCSSJsisolation.styles.css" rel="stylesheet" /> dans le header afin de faire fonctionner l’isolation CSS.  

Isolation Javascript

L’isolation JavaScript fonctionne un peu différemment de l’isolation CSS. Il n’est pas possible de faire comme pour le CSS en créant un fichier composant.razor.js. Cette fois, il est nécessaire de créer un fichier js contenant les scripts et le placer dans le dossier wwwroot.

 

 

 

Dans l’exemple ci-dessus, le fichier se trouve à la racine de wwwroot, mais il est tout à fait possible de créer un sous-dossier (wwwroot/js). C’est dans ce fichier, tools.js (le nom est libre), qu’il faut écrire les différentes fonctions JavaScript qui seront ensuite appelées dans l’application. Prenons comme exemple une fonction simple qui affiche Hello World.

export function HelloWorld() { alert('Hello World!'); }

Il est important de préfixer la fonction par le mot clé export. Nous allons ensuite ajouter un bouton sur la page d’accueil qui servira de déclencheur pour cette fonction JavaScript (Il s’agit bien sûr d’un exemple, vous n’êtes pas obligé de lier la fonction à un bouton). Dans le fichier Index.razor, ajoutez :

<button class="btn btn-primary">Appel du JS</button>

En l’état, le bouton ne fait pas grand-chose. Nous allons donc créer la fonction associée puis l’appeler pour déclencher le JavaScript. La suite se passe dans la partie code de notre Index (pour ma part Index.razor.cs). Servons-nous de IJSRuntime et de JSObjectReference. IJSRuntime.InvokeAsync appelle la fonction importée et JSObjectReference garde un objet JavaScript en mémoire, en conservant une référence vers le module ES chargé. Nous injectons le service IJSRuntime.

[Inject] IJSRuntime JSRuntime { get; set; } Puis nous créons une instance de IJSObjectReference. private Task<IJSObjectReference> _module; private Task<IJSObjectReference> Module => _module ??= JSRuntime.InvokeAsync<IJSObjectReference>("import", "./tools.js").AsTask();

Le premier argument est la fonction import qui importe un module JavaScript. Le deuxième argument est le chemin vers le fichier contenant les fonctions JavaScript à importer. La variable module contient maintenant notre module JavaScript. Nous utilisons par ailleurs le .AsTask() pour convertir la ValueTask en Task car elle peut être attendue plusieurs fois.   Il ne reste plus maintenant qu’à créer la fonction à associer à notre bouton dans laquelle nous appelons la fonction JavaScript qui nous intéresse.

protected async Task SayHello() { var module = await Module; await module.InvokeVoidAsync("HelloWorld"); }

Modifier le bouton pour ajouter la fonction.

<button class="btn btn-primary" @onclick="@(async () => await SayHello())">Appel du JS</button>

Quand nous cliquons, nous recevons bien l’alerte JavaScript qui se déclenche.

 

 

 

 

Code source Le code servant d’illustration pour cet article se trouve sur Github. Vous souhaitez en savoir plus sur Blazor ?