Présentation des modules Sass

Bonjour, Habr! Je vous présente la traduction de l'article «Présentation des modules Sass» de Miriam Suzanne.

Récemment, une fonctionnalité est apparue dans Sass qui vous est familière dans d'autres langues: un système modulaire . Il s'agit d'un grand pas en avant pour @import , l'une des fonctions les plus couramment utilisées dans Sass. Malgré le fait que la directive @import existante vous permet de connecter des packages tiers et de séparer vos styles en éléments pris en charge, elle a encore plusieurs limitations :

  • @import existe également en CSS, et toute différence dans leur comportement peut prêter à confusion.
  • Si vous effectuez @import plusieurs fois pour un fichier, cela peut ralentir la compilation, provoquer des conflits de redéfinition et vous obtenez du code dupliqué dans la sortie.
  • Tout est de portée mondiale, y compris les packages tiers - c'est ainsi que ma fonction de color peut remplacer votre fonction de color existante ou vice versa.
  • Lorsque vous utilisez une fonction comme la color , il est impossible de savoir exactement où elle est définie. Quel @import connecté?

Les auteurs des packages Sass (comme moi) ont essayé de contourner les problèmes d'espace de noms en définissant manuellement des préfixes pour les variables et les fonctions - mais les modules Sass sont une solution beaucoup plus puissante. En bref, @import est remplacé par des @forward @use et @forward plus explicites. Au cours des prochaines années, @import dans Sass sera obsolète, puis supprimé. Vous pouvez toujours utiliser les CSS Import , mais elles ne seront pas compilées par Sass. Mais ne vous inquiétez pas, il existe un outil de migration qui vous aidera à mettre à niveau.

Importez des fichiers à l'aide de @use


 @use 'buttons'; 

Le nouveau @use est similaire à @import , mais il présente quelques différences notables:

  • Le fichier est importé une fois, quel que soit le nombre de fois que vous utilisez @use dans le projet.
  • Les variables, mixins et fonctions (qui sont appelés «membres» dans Sass) qui commencent par un trait de soulignement ( _ ) ou un trait d'union ( - ) sont considérés comme privés et ne sont pas importés.
  • Les membres du fichier connecté via @use (dans notre cas buttons.scss ) ne sont accessibles que localement et ne sont pas transférés vers l'importation ultérieure.
  • De même, @extends ne s'appliquera qu'en amont; c'est-à-dire que l'extension s'applique uniquement aux styles importés et non aux styles importés.
  • Tous les membres importés ont leur propre espace de noms par défaut.

Lorsque nous attachons le fichier via @use , Sass génère automatiquement un espace de noms basé sur le nom du fichier.

 @use 'buttons'; /*    `buttons`*/ @use 'forms'; /*    `forms`*/ 

Nous avons maintenant accès aux membres du fichier buttons.scss et du fichier forms.scss , mais cet accès n'est pas transféré entre les importations: forms.scss n'a toujours pas accès aux variables définies dans buttons.scss . Étant donné que les entités importées ont un espace de noms, nous devons utiliser la nouvelle syntaxe délimitée par des points pour y accéder:

 /* : <namespace>.$variable */ $btn-color: buttons.$color; $form-border: forms.$input-border; /* : <namespace>.function() */ $btn-background: buttons.background(); $form-border: forms.border(); /* : @include <namespace>.mixin() */ @include buttons.submit(); @include forms.input(); 

Nous pouvons modifier ou supprimer l'espace de noms par défaut en ajoutant en as <name> à l'importation.

 @use 'buttons' as *; /*      */ @use 'forms' as 'f'; $btn-color: $color; /* buttons.$color    */ $form-border: f.$input-border; /* forms.$input-border    */ 

L'utilisation de as * ajoute le module à l'espace de noms racine, donc le préfixe n'est pas nécessaire, mais ses membres sont toujours limités localement par le document actuel.

Importer des modules intégrés Sass


Les capacités internes de Sass ont également été déplacées vers un système modulaire, nous avons donc un contrôle total sur l'espace de noms global. Il existe plusieurs modules intégrés - math , color , string , list , map , selector et meta - qui doivent être importés explicitement dans le fichier avant utilisation.

 @use 'sass:math'; $half: math.percentage(1/2); 

Les modules intégrés peuvent également être importés dans l'espace global:

 @use 'sass:math' as *; $half: percentage(1/2); 

Les fonctions intégrées qui ont déjà des noms de préfixe, comme map-get ou str-index , peuvent être utilisées sans dupliquer ce préfixe:

 @use 'sass:map'; @use 'sass:string'; $map-get: map.get(('key': 'value'), 'key'); $str-index: string.index('string', 'i'); 

Vous pouvez trouver une liste complète des modules intégrés, des fonctions et des changements de nom dans la spécification du module Sass .

Fonctionnalités de base nouvelles et modifiées


Comme avantage supplémentaire, cela signifie que Sass peut ajouter en toute sécurité de nouveaux mixins et fonctions internes sans provoquer de conflits de noms. L'exemple le plus étonnant est le sass:meta load-css du module sass:meta . Il fonctionne de manière similaire à @use , mais ne renvoie que le CSS généré et fonctionne dynamiquement n'importe où dans votre code:

 @use 'sass:meta'; $theme-name: 'dark'; [data-theme='#{$theme-name}'] { @include meta.load-css($theme-name); } 

Le premier argument est l'URL du module (comme dans @use ), mais il peut être modifié dynamiquement en utilisant une variable, même en utilisant l'interpolation, par exemple le theme-#{$name} . Le deuxième argument (facultatif) prend une structure de map avec la configuration:

 /*   $base-color  'theme/dark'   */ @include meta.load-css( 'theme/dark', $with: ('base-color': rebeccapurple) ); 

L'argument $with vous permet de configurer n'importe quelle variable du module chargé à l'aide de la structure de la map , et cette variable doit satisfaire aux conditions:

  • Ce n'est pas une variable privée qui commence par _ ou -
  • Marqué avec la directive !default Default

 /* theme/_dark.scss */ $base-color: black !default; /*    */ $_private: true !default; /*        */ $config: false; /*    ,      !default */ 

Notez que la clé 'base-color' définit la variable $base-color .

Il y a quelques nouvelles fonctions du module sass:meta : module-variables() et module-functions() . Chacun d'eux renvoie une structure de map partir des noms et des valeurs d'un module déjà importé. Ils prennent un argument correspondant à l'espace de noms du module:

 @use 'forms'; $form-vars: module-variables('forms'); /* ( button-color: blue, input-border: thin, ) */ $form-functions: module-functions('forms'); /* ( background: get-function('background'), border: get-function('border'), ) */ 

Plusieurs autres fonctions de sass:meta - global-variable-exists() , function-exists() , mixin-exists() et get-function() - recevront des arguments $module supplémentaires qui nous permettront de vérifier explicitement chaque espace de noms.

Ajuster et mettre à l'échelle les couleurs


Le module sass:color a également quelques réserves intéressantes sur la résolution de certains de nos anciens problèmes. De nombreuses fonctions héritées telles que lighten() ou adjust-hue() ne adjust-hue() plus recommandées pour une utilisation en faveur des fonctions explicites color.adjust() et color.scale() :

 /*  lighten(red, 20%) */ $light-red: color.adjust(red, $lightness: 20%); /*  adjust-hue(red, 180deg) */ $complement: color.adjust(red, $hue: 180deg); 


Certaines de ces fonctions obsolètes (par exemple, adjust-hue ) sont redondantes et inutiles. Autres - comme lighten , darken , saturate , etc. - besoin d'être réimplémenté pour améliorer la logique interne. Les fonctions d'origine étaient basées sur adjust() , qui utilise des mathématiques linéaires: en ajoutant 20% à la luminosité actuelle du red dans notre exemple ci-dessus. Dans la plupart des cas, nous voulons changer ( scale() ) la couleur d'un certain pourcentage par rapport à la valeur actuelle:

 /*        20,   0.2,     */ $light-red: color.scale(red, $lightness: 20%); 

Après avoir été complètement dépréciées et supprimées, ces fonctions réapparaîtront finalement dans sass:color avec un nouveau comportement basé sur color.scale() , et non color.adjust() . Cela se produira progressivement pour éviter les problèmes soudains de rétrocompatibilité. En attendant, je recommande de vérifier manuellement votre code pour voir où color.scale() pourrait être plus utile.

Configurer les bibliothèques importées


Les bibliothèques tierces ou réutilisables sont souvent fournies avec des variables avec des valeurs par défaut que vous pouvez remplacer. Nous l'avons fait avec des variables avant l'importation:

 /* _buttons.scss */ $color: blue !default; /* old.scss */ $color: red; @import 'buttons'; 

Étant donné que lors de l'utilisation de modules, il n'y a plus d'accès aux variables locales, nous avons besoin d'une nouvelle façon de définir des valeurs. Nous pouvons le faire en transmettant les paramètres via la map à @use :

 @use 'buttons' with ( $color: red, $style: 'flat', ); 

Ceci est similaire à l'argument $with dans load-css() , mais au lieu d'utiliser des noms de variables comme clés, nous utilisons les variables elles-mêmes avec le symbole $ .

J'aime à quel point le paramètre est devenu explicite, mais il y a une règle qui m'a dérouté plusieurs fois: un module ne peut être configuré qu'une seule fois lors de la première utilisation . L'ordre de connexion a toujours été important pour Sass, même avec @import , mais ces problèmes sont passés inaperçus. Nous obtenons maintenant une erreur claire, et c'est à la fois bon et un peu inattendu. Assurez-vous de connecter les bibliothèques via @use et de les configurer dans le fichier d'entrée (le document central qui importe tous les autres fichiers) afin que ces paramètres soient compilés avant les autres connexions de bibliothèque via @use .

Il n'est pas possible (pour le moment) de «lier» les configurations ensemble, en les gardant modifiables, mais vous pouvez envelopper le module configuré et le transférer en tant que nouveau module.

Transférer des fichiers avec @forward


Nous n'avons pas toujours besoin d'utiliser le fichier et de faire référence à ses membres. Parfois, nous voulons simplement le transmettre aux importations ultérieures. Supposons que nous ayons plusieurs fichiers associés aux formulaires et que nous voulons les connecter tous ensemble comme un seul espace de noms. Nous pouvons le faire avec @forward :

 /* forms/_index.scss */ @forward 'input'; @forward 'textarea'; @forward 'select'; @forward 'buttons'; 

Les membres de ces fichiers transférés ne sont pas disponibles dans le document actuel et aucun espace de noms n'est créé, mais ces variables, fonctions et mixins seront disponibles lorsqu'un autre fichier les connectera via @use ou @use collection entière via @forward . Si les fichiers individuels soumis contiennent du CSS réel, il sera également transmis sans le générer directement jusqu'à ce que le package lui-même soit utilisé. A ce stade, tout cela sera considéré comme un module avec un espace de noms:

 /* styles.scss */ @use 'forms'; /*        `forms` */ 

Remarque : Si vous demandez à Sass de joindre un dossier, il recherchera le fichier d' index ou _index qu'il _index .

Par défaut, tous les membres publics seront transmis avec le module. Mais nous pouvons être plus sélectifs en utilisant les conditions d' hide et de hide et en spécifiant les membres spécifiques que nous voulons ajouter ou exclure.

 /*    `border()`   `$border-color`   `input` */ @forward 'input' show border, $border-color; /*     `buttons`    `gradient()` */ @forward 'buttons' hide gradient; 

Remarque : lorsque les fonctions et les mixins ont un nom commun, ils sont ajoutés et masqués également ensemble.

Pour clarifier les sources ou éviter les conflits de noms de modules transférés, nous pouvons ajouter des préfixes aux membres du fichier connecté en utilisant as :

 /* forms/_index.scss */ /* @forward "<url>" as <prefix>-*; */ /* ,      `background()` */ @forward 'input' as input-*; @forward 'buttons' as btn-*; /* style.scss */ @use 'forms'; @include forms.input-background(); @include forms.btn-background(); 

Et, si nous en avons besoin, nous pouvons toujours utiliser via @use et @forward le même module via @forward , en ajoutant les deux règles:

 @forward 'forms'; @use 'forms'; 

Cela est particulièrement utile si vous souhaitez préconfigurer la bibliothèque ou ajouter des outils supplémentaires avant de la transférer vers d'autres fichiers. Cela peut aider à simplifier les chemins de connexion:

 /* _tools.scss */ /*        */ @use 'accoutrement/sass/tools' with ( $font-path: '../fonts/', ); /*    */ @forward 'accoutrement/sass/tools'; /* -  ... */ /* _anywhere-else.scss */ /*      */ @use 'tools'; 

@use et @forward doivent être déclarés à la racine du document (non imbriqués) et au début du fichier. Seules @charset et des définitions de variables simples peuvent apparaître avant les directives d'importation.

Transition vers un système modulaire


Pour tester la nouvelle syntaxe, j'ai créé une nouvelle bibliothèque open source Sass ( Cascading Color Systems ) et un nouveau site pour mon groupe - tous deux encore en développement. J'avais besoin de comprendre les modules du point de vue de l'auteur de la bibliothèque et du point de vue du développeur du site. Commençons par l'expérience de "l'utilisateur final" dans l'écriture des styles de site en utilisant la syntaxe du module ...

Styles de support et d'écriture


L'utilisation des modules sur le site a été agréable. La nouvelle syntaxe prend en charge l'architecture de code que j'utilise déjà. Toutes mes importations de paramètres globaux et d'outils sont dans le même répertoire (je l'appelle config ) avec un fichier d'index qui transfère tout ce dont j'ai besoin:

 /* config/_index.scss */ @forward 'tools'; @forward 'fonts'; @forward 'scale'; @forward 'colors'; 

En développant d'autres parties du site, je peux importer ces outils et configurations où j'en ai besoin:

 /* layout/_banner.scss */ @use '../config'; .page-title { @include config.font-family('header'); } 

Il fonctionne même avec mes bibliothèques existantes, telles que Accoutrement et Herman , qui utilisent toujours l'ancienne syntaxe @import . Étant donné que la règle @import ne @import pas remplacée partout à la fois, les développeurs de Sass ont donné du temps pour la transition. Les modules sont disponibles maintenant, mais @import pas avant un an ou deux - et ne sera supprimé de la langue qu'un an après. Dans le même temps, les deux systèmes fonctionneront ensemble de n'importe quelle manière:

  • Si nous @import pour un fichier qui contient la nouvelle syntaxe @use/@forward , seuls les membres publics seront importés sans espace de noms.
  • Si nous @use ou @forward pour un fichier qui contient l'ancienne syntaxe @import , nous avons accès à toutes les importations imbriquées comme un seul espace de noms.

Cela signifie que vous pouvez immédiatement commencer à utiliser la nouvelle syntaxe du module, sans attendre la sortie d'une nouvelle version de vos bibliothèques préférées: et je peux passer un peu de temps à mettre à jour toutes mes bibliothèques!

Outil de migration


La mise à niveau ne prendra pas longtemps si nous utilisons l'outil de migration créé par Jennifer Thakar. Il peut être installé en utilisant NPM, Chocolatey ou Homebrew:

 npm install -g sass-migrator choco install sass-migrator brew install sass/sass/migrator 

Ce n'est pas un outil unique pour migrer vers des modules. Maintenant que Sass est de retour en développement actif (voir ci-dessous), l'outil de migration recevra également des mises à jour régulières pour aider à porter chaque nouvelle fonctionnalité. C'est une bonne idée d'installer cet outil à l'échelle mondiale et de l'enregistrer pour une utilisation future.

Le migrateur peut être lancé à partir de la ligne de commande et, espérons-le, sera ajouté à des applications tierces telles que CodeKit et Scout. Dirigez-le vers un seul fichier Sass, par exemple style.scss et dites-lui quelles migrations appliquer. Pour le moment, il n'y a qu'une seule migration appelée module :

 # sass-migrator <migration> <entrypoint.scss...> sass-migrator module style.scss 

Par défaut, le migrateur met à jour un seul fichier, mais dans la plupart des cas, nous voulons mettre à jour le fichier principal et toutes ses dépendances: tous les éléments connectés via @import , @forward ou @use . Nous pouvons le faire en spécifiant chaque fichier individuellement ou simplement en ajoutant l' --migrate-deps .

 sass-migrator --migrate-deps module style.scss 

Pour un test, nous pouvons ajouter --dry-run --verbose (ou sous forme abrégée -nv ) et regarder les résultats sans changer les fichiers source. Il existe un certain nombre d'autres options que nous pouvons utiliser pour configurer la migration - il y en a même une spécialement conçue pour aider les auteurs de bibliothèques à supprimer les anciens espaces de noms créés manuellement - mais je ne les décrirai pas tous ici. L'outil de migration est entièrement documenté sur le site Web de Sass .

Mise à jour des bibliothèques publiées


J'ai rencontré plusieurs problèmes du côté de la bibliothèque, en particulier, lorsque j'ai essayé de rendre les configurations utilisateur disponibles pour plusieurs fichiers et de trouver une solution pour les configurations «chaîne» manquantes. Les erreurs liées à la commande peuvent être difficiles à déboguer, mais les résultats en valent la peine, et je pense que nous verrons bientôt des correctifs supplémentaires. J'ai encore besoin d'expérimenter l'outil de migration sur des packages complexes, et peut-être d'écrire un article supplémentaire pour les auteurs de bibliothèques.

La chose importante à savoir en ce moment est que Sass nous a fourni une protection pendant la transition. Non seulement les anciens modules d'importation et peuvent fonctionner ensemble, mais nous pouvons créer des fichiers «d' importation uniquement » pour fournir un travail plus pratique aux utilisateurs qui continuent de connecter nos bibliothèques via @import . Dans la plupart des cas, ce sera une version alternative du fichier de package principal, et vous voulez qu'ils soient proches: <name>.scss pour les utilisateurs du module et <name>.import.scss pour les anciens utilisateurs. Chaque fois que l'utilisateur appelle @import <name> , il charge la .import fichier:

 /*  `_forms.scss` */ @use 'forms'; /*  `_forms.import.scss` */ @import 'forms'; 


Ceci est particulièrement utile pour ajouter des préfixes aux développeurs qui n'utilisent pas de modules:

 /* _forms.import.scss */ /*       */ @forward 'forms' as forms-*; 


Mise à jour Sass


Vous vous souvenez peut-être que Sass a gelé l'ajout de nouvelles fonctions il y a plusieurs années, de sorte que ses différentes implémentations (LibSass, Node Sass, Dart Sass) rattrapent l'implémentation d'origine dans Ruby, afin de l' abandonner complètement . Le gel s'est terminé l'année dernière avec plusieurs nouvelles fonctionnalités et des discussions et développements actifs sur GitHub - mais pas si solennellement. Si vous avez manqué ces versions, vous pouvez lire le blog Sass :


Actuellement, Dart Sass est une implémentation canonique et est généralement le premier à introduire de nouvelles fonctionnalités. Je recommande de passer à celui-ci si vous souhaitez recevoir les dernières informations. Vous pouvez installer Dart Sass en utilisant NPM, Chocolatey ou Homebrew. Il fonctionne également très bien avec gulp-sass .

Comme CSS (à partir de CSS3), il n'y a plus de numéro de version unique pour les nouvelles versions. Toutes les implémentations Sass fonctionnent avec la même spécification, mais chacune a un calendrier de publication et une numérotation uniques, qui se reflètent dans les informations de support dans une belle nouvelle documentation conçue par Jina .

image

Les modules Sass sont disponibles à partir du 1er octobre 2019 dans Dart Sass 1.23.0 .

Source: https://habr.com/ru/post/fr471924/


All Articles