Construire un mixeur de bûcherons à Sass

Dans ce tutoriel, nous construirons un mixin "logger", qui générera un journal informatif flexible en tant que CSS lors de la compilation de Sass..

La journalisation est le processus d’enregistrement des actions et de l’état de l’application sur une interface secondaire. - Projet de code

L'idée

L’autre jour, la responsable de Neat, Reda Lemedan, et moi parlions de tout ce qui se passait Sass et j’ai vu tout à coup un mélange intéressant de son:

@include -neat-warn ("Quelque chose ne va pas"); 

Je lui ai demandé ce que faisait ce mixin, et il m'a dit que c'était essentiellement une enveloppe pour le @prévenir directive de Sass qui vérifie si l'utilisateur est prêt à imprimer les avertissements de Neat dans la console (en fonction d'une variable globale).

Alors je me suis dit pourquoi s'arrêter là? et a commencé à jouer avec l'idée le même soir. Mon idée était de construire un emballage pour les deux @prévenir et @Erreur (à partir de Sass 3.4) pour aider les développeurs de bibliothèques et d’infrastructures à imprimer différents types de messages (informations, débogage, avertissements, erreurs…) et à suivre tous les journaux.

Ma mise en œuvre actuelle fournit:

  • 5 niveaux de journalisation (DÉBOGUER, INFO, PRÉVENIR, ERREUR et FATAL)
  • un niveau minimum auquel l'enregistreur commence à imprimer;
  • un historique de tous les journaux pouvant être imprimés en tant que CSS;
  • une API conviviale avec des fonctions faciles à utiliser;
  • un assistant pour en savoir plus sur les différents niveaux de journalisation.

Comment ça marche?

Il s'est avéré être assez simple. Nous avons besoin d’une variable globale contenant l’ensemble de la configuration et d’un mixin servant de wrapper pour les directives d’impression de la console..

Parce que nous voulons que notre configuration globale soit personnalisable (dans une certaine mesure), nous emballons sa déclaration dans un mixin. Non seulement c'est plus pratique, mais c'est aussi plus agréable pour l'utilisateur final.

Nous avons donc un mixin, appelons-le enregistreur cela n'a pour but que d'être appelé une seule fois, créant une carte globale contenant notre configuration. Ensuite, nous avons notre emballage, bûche, qui accepte un niveau de journalisation (par exemple PRÉVENIR ou ERREUR) et le message à consigner en tant qu'arguments. C'est à peu près ça.

Pour rendre les choses plus pratiques pour les développeurs, nous allons fournir des fonctions abrégées pour enregistrer différents niveaux. Par exemple, au lieu d'avoir à taper:

@include log ("ERROR", "Il n'y a pas assez de licorne ici."); 

… nous pourrions avoir:

@include ERROR ("Il n'y a pas assez de licorne ici."); 

Vous allez donc vous retrouver avec une API ressemblant à ceci:

// Instancie un enregistreur // qui lance l'impression des journaux au niveau "INFO". // Cela signifie que les journaux 'DEBUG' ne seront pas affichés. @include logger ("INFO"); // Journal des choses. @include ERROR ("Il n'y a pas assez de licorne ici."); 

Nous ajouterons également des mixins pour apporter des fonctionnalités supplémentaires intéressantes:

  • une information d'impression sur chaque niveau de journalisation à titre de rappel;
  • une impression de tous les journaux enregistrés dans la compilation en cours.

Construire l'API

Logger Constructeur

Commençons par le début, allons-nous? Le logger constructeur. Cela devrait accepter un seul paramètre: le niveau auquel l'enregistreur doit commencer à imprimer les journaux dans la console..

C'est un modèle assez courant pour les systèmes de journalisation. Par exemple:

  • Si vous voulez seulement imprimer des erreurs (ERREUR et FATAL), tu écrirais @include logger ("ERROR").
  • Si vous voulez tout imprimer, vous iriez avec @include logger ("ALL"), qui est fondamentalement identique au niveau de journalisation le plus bas (DÉBOGUER).
  • Si vous souhaitez désactiver complètement l’enregistreur, vous exécutez @include logger ("OFF").

Remarque: vous pouvez trouver plus d’informations sur les niveaux de journalisation dans ce thread StackOverflow ou dans la documentation des journaux Apache.

@mixin logger ($ minimum-level) // Liste des niveaux disponibles $ levels: "DEBUG", "INFO", "WARN", "ERROR", "FATAL"; // Assurez-vous que la chaîne donnée est en majuscule $ minimum-level: to-majuscule ($ minimum-level); // Si level est 'ALL', aller au plus bas niveau de tous @if $ minimum-level == "ALL" $ minimum-level: nth ($ level, 1);  // Si le niveau n'est pas valide, sélectionnez 'INFO' à la place de votre choix (@if not index ($ levels "OFF", $ minimum-level) $ minimum-level: "INFO";  // Créer la variable globale $ logger-configuration: (// Liste des niveaux disponibles "niveaux": $ niveaux, // Liste des niveaux imprimés avec '@error' "errors": "FATAL" "ERROR", / / Niveau minimum (en tant qu'index de '$ niveaux') pour imprimer "min": index ($ niveaux, $ minimum-niveau), // Indique si l'enregistreur est activé ou non "activé": $ minimum-niveau! = " OFF ", // Une carte pour garder trace de tous les journaux" historique ": (" DEBUG ": ()," INFO ": ()," WARN ": ()," ERREUR ": ()," FATAL ": () ) ) !global;  

Le code ci-dessus devrait être plutôt explicite, mais j'ai ajouté quelques commentaires pour que tout soit clair. Comme vous pouvez le constater, ce mixin ne fait pas grand chose sauf créer une variable globale. Pas si mal, c'est ça??

Avant d’aller plus loin, créons une petite fonction d’aide qui nous permet d’obtenir facilement une valeur de cette carte globale. Parce que tu sais, en tapant map-get ($ logger-configuration,…) n'est pas amusant à distance. Qu'en est-il de logger-conf (…) au lieu?

@function logger-conf ($ key) @return map-get ($ logger-configuration, $ key);  

Log Wrapper

Bon, passons au réel bûche fonction qui imprime des choses dans la console. Non seulement il devrait afficher les messages donnés dans la console de l'utilisateur, mais il devrait également mettre à jour l'historique afin de garder une trace de ce qui est consigné (ce qui peut être utile ou non).

Cela semble difficile. Eh bien, ne vous inquiétez pas, ça va être aussi lisse que du beurre. Nous savons déjà que ce mixin ne doit accepter que deux paramètres: le niveau de journalisation et le message.

@mixin log ($ level, $ message) // Assurez-vous que le niveau est en majuscule $ level: to-majuscule ($ level); // Sauf si c'est désactivé, continue @if logger-conf ("enabled") // Récupère l'index du niveau actuel // Par exemple, 'DEBUG' serait '1' $ index-current-level: index (logger-conf ( "niveaux"), $ niveau); // Si '$ level' est invalide, // retombe arbitrairement sur 'INFO' @si pas $ index-current-level $ level: "INFO";  // Mettre à jour l'historique du logger @include logger-update-history ($ level, $ message); // Enfin, imprimez le message dans la console // si le niveau actuel est supérieur ou égal au niveau minimum. @if $ index-current-level> = logger-conf ("min") $ print: '[' + $ level + '] ::' + $ message; // Imprimez-le en tant que '@error' s'il s'agit d'un niveau d'erreur @if index (logger-conf ("errors"), $ level) @error $ print;  // Sinon, utilisez '@warn' @else @warn $ print;  

Nous devons maintenant traiter de la mise à jour de l'historique. C’est en fait un peu plus difficile, mais une fois que vous vous êtes habitué à manipuler des cartes, cela devient plus clair..

Avant de regarder le code, laissez-moi vous expliquer comment fonctionne l'histoire. En gros, il s’agit d’une carte dans laquelle les clés représentent les niveaux de journalisation et les valeurs, les listes de messages consignés. Par exemple, vous pourriez avoir quelque chose comme:

$ _: ("DEBUG": (), "INFO": (), "WARN": ("Vous devriez faire attention à cela.", "Cela pourrait être amélioré."), "ERREUR": ("Quelque chose est cassé ." ), "FATAL": () ) 

D'accord. Allons-y.

@mixin logger-update-history ($ level, $ message) // Obtenir la carte de l'historique de la configuration $ history: logger-conf ("history"); // Obtenir la liste de l'historique pour le niveau actuel $ current-level-history: map-get ($ history, $ level); // Ajoute le nouveau journal à la liste $ current-level-history: append ($ current-level-history, $ message); // Créer une variable temporaire contenant le nouvel historique map $ logger-history: map-merge ($ history, ($ level: $ current-level-history)); // Met à jour la mappe d'historique à partir de la configuration avec notre variable temporaire $ logger-configuration: map-merge ($ logger-configuration, ("history": $ logger-history))! Global;  

Cela implique pas mal de lignes peu amicales, mais quand vous expliquez chaque ligne individuellement, tout est finalement logique..

Nous avons terminé, mais nous avons parlé d'ajouter des fonctions de sténographie. Faisons-le maintenant avant d'oublier:

@mixin FATAL ($ message) @include log ("FATAL", $ message);  @mixin ERROR ($ message) @include log ("ERROR", $ message);  @mixin WARN ($ message) @include log ("WARN", $ message);  @mixin INFO ($ message) @include log ("INFO", $ message);  @mixin DEBUG ($ message) @include log ("DEBUG", $ message);  

C'est tout. Une dernière chose que nous pourrions faire, mais qui n’est pas vraiment obligatoire, est de vérifier si enregistreur a été inclus avant d'essayer d'utiliser la carte globale. Non seulement nous évitons les erreurs stupides, mais nous pouvons également rendre l'instanciation de l'enregistreur facultative en le faisant à la volée..

@mixin log ($ level, $ message) // Vérifie si la variable globale 'logger-configuration' existe. // Si ce n'est pas le cas, cela signifie que "consignateur" n'a pas été inclus, // nous l'incluons donc, en définissant arbitrairement le niveau minimal sur "INFO". @si pas globale-variable-existe ("logger-configuration") @include logger ("INFO");  @if logger-conf ("activé") //… 

Ajout d'Extras

Nous allons commencer par le premier (et le moins utile) des deux mixins supplémentaires, l’assistant. C’est vraiment un gadget à ce stade puisque tout ce qu’il fait est d’imprimer une règle CSS avec des niveaux de journalisation comme sélecteurs et des explications comme valeurs..

Ceci est destiné à aider les développeurs quand ils ne savent pas vraiment quel niveau de journalisation ils doivent utiliser. Cela aurait pu être écrit sous forme de commentaire, mais je voulais essayer cette aide imprimante.

@mixin logger-help // Ouvre un nouveau sélecteur 'logger-help' logger-help OFF: "Désactiver le logger."; FATAL: "Erreurs graves entraînant une résiliation prématurée."; ERREUR: "Autres erreurs d'exécution ou conditions inattendues."; WARN: "Utilisation d’API obsolètes, mauvaise utilisation de l’API," presque "erreurs" + "autres situations d’exécution indésirables ou inattendues, mais pas nécessairement erronées."; INFO: "Événements d’exécution intéressants (démarrage / arrêt)."; DEBUG: "Informations détaillées sur le flux dans le système.";  

Vous l'utilisez comme ceci:

@include logger-help; 

… Et il se compile comme:

logger-help OFF: "Désactiver le logger."; FATAL: "Erreurs graves entraînant une résiliation prématurée."; ERREUR: "Autres erreurs d'exécution ou conditions inattendues."; WARN: "Utilisation d’API obsolètes, mauvaise utilisation de l’API, erreurs" presque ", autres situations d’exécution indésirables ou inattendues, mais pas nécessairement erronées."; INFO: "Événements d’exécution intéressants (démarrage / arrêt)."; DEBUG: "Informations détaillées sur le flux dans le système."; 

Rien de spécial. L'autre mixin supplémentaire est bien plus intéressant. Il utilise l'historique pour imprimer tous les journaux enregistrés lors de la compilation..

@mixin logger-print-logs // Ouvre un nouveau sélecteur 'logger-logs' logger-logs // Boucle sur l'historique @each $ level, $ logs dans logger-conf ("history") // Vérifie si Le niveau de consignation actuel de la boucle // doit être affiché ou non en fonction du niveau minimal // et de la longueur de sa valeur (pas de journal, pas d'impression). @if index (logger-conf ("niveaux"), $ niveau)> = logger-conf ("min") et longueur ($ journaux)> 0 // Faites une boucle sur les journaux enregistrés et imprimez-les. @each $ log in $ logs # $ level: $ log;  

Encore une fois, simple utilisation:

@include logger-print-logs; 

… Qui produirait (d'après notre exemple précédent):

logger-logs WARN: "Faites attention à cela."; WARN: "Cela pourrait être amélioré."; ERREUR: "Quelque chose est cassé";  

Exemple

// Instanciez un nouvel enregistreur avec 'INFO' comme niveau minimum pour l'enregistrement. // Si non inclus, cela se fera automatiquement sur le premier journal. @include logger ("INFO"); // aide du logger (facultatif, évidemment) @include logger-help; // Log stuff @include INFO ("Hey, regarde ça."); @include INFO ("Apportez les licornes!"); @include WARN ("Mec, fais attention."); // Celui-ci n'est pas imprimé mais reste suivi dans les journaux. @include DEBUG ("Debug and stuff."); // Historique de sortie (optionnel) particulièrement utile pour le débogage @include logger-print-logs; 

Dernières pensées

Comme vous pouvez le constater, le code est assez léger à la fin, et la majeure partie de son volume est constitué de commentaires. Je pense que cela fournit une belle API propre permettant de garder une trace de ce qui est enregistré dans un projet donné.

Cet outil est destiné aux développeurs de bibliothèques et de framework. Si vous en êtes un, essayez ceci si vous pensez que cela pourrait être utile et donnez-moi vos commentaires..

N'hésitez pas à récupérer le mixin de GitHub, ou à jouer directement sur SassMeister.