Einführung in Sass-Module

Hallo Habr! Ich präsentiere Ihnen die Übersetzung des Artikels „Introducing Sass Modules“ von Miriam Suzanne.

Kürzlich wurde in Sass eine Funktion veröffentlicht, die Ihnen in anderen Sprachen bekannt ist: ein modulares System . Dies ist ein großer Fortschritt für @import , eine der am häufigsten verwendeten Funktionen in Sass. Trotz der Tatsache, dass Sie mit der vorhandenen @import Direktive Pakete von Drittanbietern verbinden und Ihre Stile in unterstützte Elemente unterteilen können, gibt es immer noch einige Einschränkungen ::

  • @import auch in CSS vorhanden, und Unterschiede in ihrem Verhalten können verwirrend sein.
  • Wenn Sie @import mehrmals für eine Datei @import , kann dies die Kompilierung verlangsamen, Neudefinitionskonflikte verursachen und Sie erhalten doppelten Code in der Ausgabe.
  • Alles ist im globalen Bereich, einschließlich Paketen von Drittanbietern - so kann meine Farbfunktion Ihre vorhandene color überschreiben oder umgekehrt.
  • Wenn Sie eine Funktion wie color , ist es unmöglich, genau zu wissen, wo sie definiert ist. Welcher @import verbunden?

Die Autoren von Sass-Paketen (wie ich) haben versucht, Namespace-Probleme zu umgehen, indem sie Präfixe für Variablen und Funktionen manuell festgelegt haben - aber Sass-Module sind eine viel leistungsfähigere Lösung. Kurz gesagt, @import wird durch explizitere @use und @forward . In den nächsten Jahren wird @import in Sass nicht mehr unterstützt und dann entfernt. Sie können weiterhin CSS Import , diese werden jedoch nicht von Sass kompiliert. Aber keine Sorge, es gibt ein Migrationstool , mit dem Sie ein Upgrade durchführen können.

Importieren Sie Dateien mit @use


 @use 'buttons'; 

Die neue @use ähnelt @import , weist jedoch einige bemerkenswerte Unterschiede auf:

  • Die Datei wird einmal importiert, unabhängig davon, wie oft Sie @use im Projekt verwenden.
  • Variablen, Mixins und Funktionen (die in Sass als "Mitglieder" bezeichnet werden), die mit einem Unterstrich ( _ ) oder einem Bindestrich ( - ) beginnen, werden als privat betrachtet und nicht importiert.
  • Mitglieder aus der über @use verbundenen @use (in unserem Fall buttons.scss ) sind nur lokal zugänglich und werden nicht zum nachfolgenden Import übertragen.
  • Ebenso gilt @extends nur für Upstreams. Das heißt, die Erweiterung gilt nur für importierte Stile und nicht für importierte Stile.
  • Alle importierten Mitglieder haben standardmäßig einen eigenen Namespace .

Wenn wir die Datei über @use , generiert Sass automatisch einen Namespace basierend auf dem Dateinamen.

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

Jetzt haben wir Zugriff auf die Mitglieder sowohl der Datei buttons.scss als auch der Datei forms.scss , aber dieser Zugriff wird nicht zwischen Importen übertragen: forms.scss weiterhin keinen Zugriff auf die in buttons.scss definierten buttons.scss . Da importierte Entitäten einen Namespace haben, müssen wir die neue durch Punkte getrennte Syntax verwenden, um auf sie zuzugreifen:

 /* : <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(); 

Wir können den Standard-Namespace ändern oder entfernen, indem wir dem Import as <name> hinzufügen.

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

Wenn Sie as * das Modul dem Root-Namespace hinzugefügt, sodass das Präfix nicht benötigt wird, seine Mitglieder jedoch durch das aktuelle Dokument lokal begrenzt sind.

Importieren Sie eingebettete Sass-Module


Die internen Funktionen in Sass wurden ebenfalls in ein modulares System verschoben, sodass wir die volle Kontrolle über den globalen Namespace haben. Es gibt mehrere integrierte Module - math , color , string , list , map , selector und meta -, die vor der Verwendung explizit in die Datei importiert werden müssen.

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

Eingebettete Module können auch in den globalen Raum importiert werden:

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

Integrierte Funktionen, die bereits Präfixnamen haben, wie z. B. map-get oder str-index , können verwendet werden, ohne dieses Präfix zu duplizieren:

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

Eine vollständige Liste der integrierten Module, Funktionen und Namensänderungen finden Sie in der Sass-Modulspezifikation .

Neue und geänderte Kernfunktionen


Als zusätzlichen Vorteil bedeutet dies, dass Sass sicher neue interne Mixins und Funktionen hinzufügen kann, ohne Namenskonflikte zu verursachen. Das erstaunlichste Beispiel ist das load-css sass:meta aus dem sass:meta Modul. Es funktioniert ähnlich wie @use , gibt jedoch nur das generierte CSS zurück und funktioniert dynamisch an einer beliebigen Stelle in Ihrem Code:

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

Das erste Argument ist die Modul-URL (wie in @use ), sie kann jedoch mithilfe einer Variablen dynamisch geändert werden, auch durch Interpolation, z. B. theme-#{$name} . Das zweite (optionale) Argument nimmt eine map mit der Konfiguration an:

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

$with Argument $with können Sie jede Variable im geladenen Modul mithilfe der map konfigurieren. Diese Variable muss die folgenden Bedingungen erfüllen:

  • Es ist keine private Variable, die mit _ oder - beginnt
  • Markiert mit der !default Default-Direktive

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

Beachten Sie, dass der Schlüssel 'base-color' die Variable $base-color 'base-color' festlegt.

Es gibt noch ein paar neue Funktionen aus dem sass:meta Modul sass:meta : module-variables() und module-functions() . Jeder von ihnen gibt eine map aus Namen und Werten eines bereits importierten Moduls zurück. Sie nehmen ein Argument an, das dem Modul-Namespace entspricht:

 @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'), ) */ 

Einige andere Funktionen von sass:meta - global-variable-exists() , function-exists() , mixin-exists() und get-function() - erhalten zusätzliche $module , mit denen wir jeden Namespace explizit überprüfen können.

Passen Sie die Farben an und skalieren Sie sie


Das Modul sass:color hat auch einige interessante Vorbehalte gegen die Lösung einiger unserer alten Probleme. Viele der älteren Funktionen wie lighten() oder adjust-hue() nicht mehr für die expliziten Funktionen color.adjust() und color.scale() :

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


Einige dieser veralteten Funktionen (z. B. adjust-hue ) sind redundant und unnötig. Andere - wie lighten , darken , saturate usw. - müssen erneut implementiert werden, um die interne Logik zu verbessern. Die ursprünglichen Funktionen basierten auf adjust() , das lineare Mathematik verwendet: Hinzufügen von 20% zur aktuellen Helligkeit von red in unserem obigen Beispiel. In den meisten Fällen möchten wir die Farbe um einen bestimmten Prozentsatz gegenüber dem aktuellen Wert ändern ( scale() ):

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

Nachdem diese Funktionen vollständig veraltet und entfernt wurden, werden sie schließlich in sass:color mit einem neuen Verhalten color.scale() das auf color.scale() und nicht auf color.scale() color.adjust() . Dies geschieht schrittweise, um plötzliche Abwärtskompatibilitätsprobleme zu vermeiden. In der Zwischenzeit empfehle ich, Ihren Code manuell zu überprüfen, um color.scale() wo color.scale() möglicherweise nützlicher ist.

Konfigurieren Sie importierte Bibliotheken


Bibliotheken von Drittanbietern oder wiederverwendbaren Bibliotheken enthalten häufig Variablen mit einigen Standardwerten, die Sie überschreiben können. Wir haben dies mit Variablen vor dem Import gemacht:

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

Da bei Verwendung von Modulen kein Zugriff mehr auf lokale Variablen besteht, benötigen wir eine neue Methode zum Festlegen von Werten. Wir können dies tun, indem wir die Einstellungen per map an @use :

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

Dies ähnelt dem Argument $with in load-css() , aber anstatt Variablennamen als Schlüssel zu verwenden, verwenden wir die Variablen selbst mit dem Symbol $ .

Mir gefällt, wie explizit die Einstellung geworden ist, aber es gibt eine Regel, die mich mehrmals verblüfft hat: Ein Modul kann bei der ersten Verwendung nur einmal konfiguriert werden . Die Verbindungsreihenfolge war für Sass auch bei @import immer wichtig, aber diese Probleme @import unbemerkt. Jetzt erhalten wir einen klaren Fehler, der sowohl gut als auch ein wenig unerwartet ist. @use Sie sicher, dass Sie die Bibliotheken über @use und in der Eintragsdatei (dem zentralen Dokument, das alle anderen Dateien importiert) konfigurieren, damit diese Einstellungen vor anderen Bibliotheksverbindungen über @use .

Es ist (im Moment) nicht möglich, die Konfigurationen zusammenzubinden, damit sie bearbeitet werden können. Sie können das konfigurierte Modul jedoch umschließen und als neues Modul übertragen.

Übertragen von Dateien mit @forward


Wir müssen die Datei nicht immer verwenden und auf ihre Mitglieder verweisen. Manchmal wollen wir es nur an nachfolgende Importe weitergeben. Angenommen, wir haben mehrere Dateien mit Formularen verknüpft und möchten sie alle als einen Namespace miteinander verbinden. Wir können dies mit @forward tun:

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

Mitglieder solcher weitergeleiteten Dateien sind im aktuellen Dokument nicht verfügbar und es wird kein Namespace erstellt. Diese Variablen, Funktionen und Mixins sind jedoch verfügbar, wenn eine andere Datei sie über @use oder @use gesamte Sammlung über @forward . Wenn die übermittelten Einzeldateien tatsächlich CSS enthalten, wird es auch übertragen, ohne es direkt zu generieren, bis das Paket selbst verwendet wird. In dieser Phase wird dies alles als ein Modul mit einem Namespace betrachtet:

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

Hinweis : Wenn Sie Sass bitten, einen Ordner anzuhängen, sucht er nach dem index oder der _index Datei darin.

Standardmäßig werden alle öffentlichen Mitglieder zusammen mit dem Modul weitergeleitet. Wir können jedoch selektiver hide , indem wir die show und hide verwenden und bestimmte Mitglieder angeben, die wir hinzufügen oder ausschließen möchten.

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

Hinweis : Wenn Funktionen und Mixins einen gemeinsamen Namen haben, werden sie auch zusammen hinzugefügt und ausgeblendet.

Um die Quellen zu klären oder Namenskonflikte von weitergeleiteten Modulen zu vermeiden, können wir den Mitgliedern der verbundenen Datei Präfixe hinzufügen, indem wir Folgendes verwenden:

 /* 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(); 

Und wenn nötig, können wir immer über @use und dasselbe Modul über @forward , wobei @forward beide Regeln hinzufügen:

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

Dies ist besonders nützlich, wenn Sie die Bibliothek vorkonfigurieren oder zusätzliche Tools hinzufügen möchten, bevor Sie sie in andere Dateien übertragen. Dies kann helfen, Verbindungspfade zu vereinfachen:

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

Sowohl @use als auch @forward müssen im Stammverzeichnis des Dokuments (nicht verschachtelt) und am Anfang der Datei deklariert werden. Vor Importanweisungen können nur @charset und einfache Variablendefinitionen @charset .

Übergang zu einem modularen System


Um die neue Syntax zu testen, habe ich eine neue Open-Source-Sass-Bibliothek ( Cascading Color Systems ) und eine neue Site für meine Gruppe erstellt - beide befinden sich noch in der Entwicklung. Ich musste die Module aus Sicht des Autors der Bibliothek und aus Sicht des Site-Entwicklers verstehen. Beginnen wir mit der Erfahrung des "Endbenutzers" beim Schreiben von Site-Stilen mithilfe der Modulsyntax ...

Support- und Schreibstile


Die Verwendung der Module auf der Website hat Spaß gemacht. Die neue Syntax unterstützt die bereits verwendete Codearchitektur. Alle meine Importe von globalen Einstellungen und Tools befinden sich im selben Verzeichnis (ich nenne es config ) mit einer Indexdatei, die alles überträgt, was ich brauche:

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

Durch die Entwicklung anderer Teile der Site kann ich diese Tools und Konfigurationen überall dort importieren, wo ich sie benötige:

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

Es funktioniert sogar mit meinen vorhandenen Bibliotheken wie Accoutrement und Herman , die immer noch die alte @import Syntax verwenden. Da die @import Regel nicht überall auf einmal ersetzt wird, haben die Sass-Entwickler etwas Zeit für den Übergang @import . Die Module sind ab sofort verfügbar, aber @import läuft noch ein oder zwei Jahre nicht ab - und wird erst ein Jahr später aus der Sprache entfernt. Gleichzeitig arbeiten die beiden Systeme auf folgende Weise zusammen:

  • Wenn wir @import für eine Datei ausführen, die die neue @use/@forward Syntax enthält, werden nur öffentliche Mitglieder ohne Namespace importiert.
  • Wenn wir @use oder @forward für eine Datei ausführen, die die alte @import Syntax enthält, erhalten wir Zugriff auf alle verschachtelten Importe als einen einzigen Namespace.

Dies bedeutet, dass Sie sofort mit der Verwendung der neuen Modulsyntax beginnen können, ohne auf die Veröffentlichung einer neuen Version Ihrer Lieblingsbibliotheken warten zu müssen: und ich kann einige Zeit damit verbringen, alle meine Bibliotheken zu aktualisieren!

Migrationstool


Das Upgrade dauert nicht lange, wenn wir das von Jennifer Thakar erstellte Migrationstool verwenden. Es kann mit NPM, Chocolatey oder Homebrew installiert werden:

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

Dies ist kein einmaliges Tool für die Migration zu Modulen. Nachdem sich Sass wieder in der aktiven Entwicklung befindet (siehe unten), erhält das Migrationstool auch regelmäßige Updates, um die Portierung jeder neuen Funktion zu unterstützen. Es ist eine gute Idee, dieses Tool global zu installieren und für die zukünftige Verwendung zu speichern.

Der Migrator kann über die Befehlszeile gestartet werden und wird hoffentlich Anwendungen von Drittanbietern wie CodeKit und Scout hinzugefügt. style.scss auf eine einzelne Sass-Datei, z. B. style.scss und teilen Sie ihm mit, welche Migrationen style.scss . Derzeit gibt es nur eine Migration namens module :

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

Standardmäßig aktualisiert der @import nur eine Datei. In den meisten Fällen möchten wir jedoch die Hauptdatei und alle ihre Abhängigkeiten aktualisieren: alle Elemente, die über @import , @forward oder @use . Wir können dies tun, indem wir jede Datei einzeln --migrate-deps oder einfach das --migrate-deps hinzufügen.

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

Für einen Testlauf können wir --dry-run --verbose (oder in abgekürzter Form -nv ) -nv und die Ergebnisse -nv ohne die Quelldateien zu ändern. Es gibt eine Reihe anderer Optionen, mit denen wir die Migration konfigurieren können - es gibt sogar eine, die speziell entwickelt wurde, um Bibliotheksautoren beim Löschen alter manuell erstellter Namespaces zu helfen -, aber ich werde hier nicht alle beschreiben. Das Migrationstool ist vollständig auf der Sass-Website dokumentiert .

Veröffentlichte Bibliotheken aktualisieren


Ich bin auf der Bibliotheksseite auf einige Probleme gestoßen, insbesondere als ich versuchte, Benutzerkonfigurationen für mehrere Dateien verfügbar zu machen und eine Lösung für fehlende "Ketten" -Konfigurationen zu finden. Das Debuggen von auftragsbezogenen Fehlern kann schwierig sein, aber die Ergebnisse sind die Mühe wert, und ich denke, wir werden bald einige zusätzliche Korrekturen sehen. Ich muss noch mit dem Migrationstool für komplexe Pakete experimentieren und möglicherweise einen zusätzlichen Artikel für Bibliotheksautoren schreiben.

Das Wichtigste, was Sie jetzt wissen müssen, ist, dass Sass uns während des Übergangs Schutz gewährt hat. Die alten Importe und Module können nicht nur zusammenarbeiten, @import wir können auch Nur-Import- Dateien erstellen, um Benutzern, die unsere Bibliotheken weiterhin über @import verbinden, eine bequemere Arbeit zu ermöglichen. In den meisten Fällen handelt es sich um eine alternative Version der <name>.scss , und Sie möchten, dass sie sich in der Nähe befinden: <name>.scss für <name>.scss und <name>.import.scss für alte Benutzer. Jedes Mal, wenn der Benutzer @import <name> , lädt er die .import Datei:

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


Dies ist besonders nützlich, um Präfixe für Entwickler hinzuzufügen, die keine Module verwenden:

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


Sass Update


Sie erinnern sich vielleicht, dass Sass vor einigen Jahren die Hinzufügung neuer Funktionen eingefroren hat, so dass seine verschiedenen Implementierungen (LibSass, Node Sass, Dart Sass) die ursprüngliche Ruby-Implementierung einholen, um sie vollständig aufzugeben . Das Einfrieren endete letztes Jahr mit mehreren neuen Funktionen und aktiven Diskussionen und Entwicklungen auf GitHub - aber nicht so feierlich. Wenn Sie diese Veröffentlichungen verpasst haben, können Sie den Sass-Blog lesen:


Derzeit ist Dart Sass eine kanonische Implementierung und führt normalerweise als erster neue Funktionen ein. Ich empfehle, darauf zu wechseln, wenn Sie die neuesten Informationen erhalten möchten. Sie können Dart Sass mit NPM, Chocolatey oder Homebrew installieren . Es funktioniert auch gut mit Schluck-Sass .

Wie bei CSS (beginnend mit CSS3) gibt es für neue Versionen keine einzige Versionsnummer mehr. Alle Sass-Implementierungen arbeiten mit derselben Spezifikation, aber jede von ihnen verfügt über einen eindeutigen Release-Zeitplan und eine eindeutige Nummerierung, die sich in den Support-Informationen in einer schönen neuen Dokumentation von Jina widerspiegeln.

Bild

Sass-Module sind ab dem 1. Oktober 2019 in Dart Sass 1.23.0 verfügbar .

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


All Articles