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'; @use '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:
$btn-color: buttons.$color; $form-border: forms.$input-border; $btn-background: buttons.background(); $form-border: forms.border(); @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; $form-border: f.$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:
@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
$base-color: black !default; $_private: true !default; $config: false;
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'); $form-functions: module-functions('forms');
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()
:
$light-red: color.adjust(red, $lightness: 20%); $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()
):
$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:
$color: blue !default; $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:
@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:
@use '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.
@forward 'input' show border, $border-color; @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:
@forward 'input' as input-*; @forward 'buttons' as btn-*; @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:
@use 'accoutrement/sass/tools' with ( $font-path: '../fonts/', ); @forward 'accoutrement/sass/tools'; @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:
@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:
@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
:
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:
@use 'forms'; @import 'forms';
Dies ist besonders nützlich, um Präfixe für Entwickler hinzuzufügen, die keine Module verwenden:
@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.

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