Der folgende Beitrag ist ein Gastbeitrag von Marcus Tisäter. Ich denke, es gibt viele von uns, die PostCSS faszinierend finden. Besonders aus der Perspektive, dass wir möglicherweise eigene Plugins in JavaScript schreiben können, die CSS beliebig transformieren. Aber wo soll man anfangen? Wie macht man das gut? Marcus erklärt.
Sie haben vielleicht Leute sagen hören, dass das Erstellen eines PostCSS-Plugins einfach ist. Aber wie fängt man an? Keine Sorge, genau das werden wir in diesem Artikel durchgehen. Danach zeigen wir Ihnen, was Sie tun können, sobald Sie mit Ihrem Plugin fertig sind, und wie ein verantwortungsbewusster PostCSS-Plugin-Entwickler aussieht.
Best Practices, wir kommen.
Wie fange ich an?
Alles, was es braucht, sind ein paar Zeilen JavaScript, um etwas Magisches in PostCSS geschehen zu lassen. Der beste Weg, um zu beginnen, ist das offizielle PostCSS-plugin-boilerplate. Dieses Starter-Kit enthält ein initiales Setup-Skript, ein paar npm-Abhängigkeiten und Boilerplate-Code für Ihr PostCSS-Plugin. Außerdem stellt es Ihnen eine Datei zum Schreiben von Tests in AVA (einem Test-Runner) und einige Dokumentationen zur Verfügung, um Ihnen den Einstieg zu erleichtern.
Der unten stehende Ausschnitt ist der wichtigste Teil, den Sie vom Plugin verstehen müssen. Es ist eine Wrapper-Funktion in einer Methode, die Sie in die Plugin-API einklinken.
// You have to require the shell itself, PostCSS.
var postcss = require('postcss');
module.exports = postcss.plugin('pluginname', function (opts) {
opts = opts || {};
// Work with options here
return function (css, result) {
// Transform the CSS AST
};
});
Zuerst müssen wir verstehen, was PostCSS uns standardmäßig bietet. PostCSS selbst tut nichts; es ist nur ein umgebender Wrapper für Ihr Plugin. Der PostCSS-Kern enthält einen Parser, der einen CSS AST (Abstract Syntax Tree) generiert, eine Darstellung eines Knotenbaums, der CSS-Strings parst. Wenn wir etwas innerhalb des CSS Abstract Syntax Tree ändern, wird PostCSS es immer noch als Wurzelknoten darstellen, aber den Syntaxbaum zurück in einen CSS-String stringifizieren.

Schreiben wir ein wirklich einfaches PostCSS-Plugin. Wir können es PostCSS-backwards nennen. PostCSS-backwards erlaubt es Ihnen, CSS-Deklarationswerte rückwärts zu drehen. color: dlog würde zu color: gold umgekehrt und umgekehrt.
var postcss = require('postcss');
module.exports = postcss.plugin('postcss-backwards', function (opts) {
opts = opts || {};
return function (css, result) {
// Runs through all of the nodes (declorations) in the file
css.walkDecls(declaration => {
declaration.value = declaration.value.split('').reverse().join('');
});
};
});
Natürlich ist dies nur ein albernes Beispiel. Es ist nicht nützlich und niemand würde es jemals verwenden. Wichtiger noch, das wäre schlecht für das PostCSS-Plugin-Ökosystem. Wir werden später mehr darüber sprechen.
Bevor wir uns mit der eigentlichen PostCSS-API befassen, möchte ich Sie bitten, einen meiner absoluten Lieblings-PostCSS-Plugins anzuschauen: PostCSS Focus. PostCSS Focus fügt jedem :hover in Ihrem Stylesheet einen :focus-Selektor hinzu. Das ist großartig zur Verbesserung der Barrierefreiheit, da :focus-Stile oft vergessen werden und fast immer mit :hover-Stilen gepaart werden sollten.
Werfen Sie einen Blick auf den Code, der mit einigen Kommentaren versehen ist, wie dieses Plugin erstellt wurde.
var postcss = require('postcss');
module.exports = postcss.plugin('postcss-focus', function () {
return function (css) {
// Callback for each rule node.
css.walkRules(function (rule) {
// Match the individual rule selector
if ( rule.selector.indexOf(':hover') !== -1 ) {
// Array to contain the rule’s individual selector.
var focuses = [];
rule.selectors.forEach(function (selector) {
// Passes all declaration values within the match of hover replacing those values with the returned result of focus.
if ( selector.indexOf(':hover') !== -1 ) {
focuses.push(selector.replace(/:hover/g, ':focus'));
}
});
// Checks if array contain values
if ( focuses.length ) {
// Concat the original rules with the new duplicated :focus rules
// Groups of selectors are automatically split with commas.
rule.selectors = rule.selectors.concat(focuses);
}
}
});
};
});
Lernen Sie die PostCSS API kennen
Die PostCSS API ist der schnellste und genaueste CSS-Parser, den ich je verwendet habe. Die Dokumentation dazu ist sehr gut geschrieben und deckt alles ab, was Sie wissen müssen, um sie zu beherrschen. Die API bietet verschiedene Funktionen, Klassen, gängige Methoden und Module zur Verwendung. Es gibt Methoden, die Ihnen vielleicht schon bekannt sind, wie prepend, append, clone, cloneAfter oder replaceWith. Sie können sie mit der DOM (Document Object Model) API vergleichen, um CSS manipulieren zu können. Es ist die gleiche Ideologie.
Wenn Sie mit der PostCSS API nicht weiterkommen, können Sie Ihr Plugin mit sogenannten Hilfswerkzeugen erweitern. Werkzeuge wie Selektor-, Wert- und Dimensions-Parser oder Funktions- und Eigenschafts-Resolver. Der Funktions-Resolver ist einer der beliebtesten. Er ist ein Werkzeug, das dazu dient, JavaScript-Funktionen verfügbar zu machen.
Andere erweiterbare Werkzeuge zur Nutzung
- Value parser – Wandelt CSS-Deklarationswerte und @-Regel-Parameter in einen Knotenbaum um.
- Property resolver – Hilfsmethode zum Auflösen eines Regels-Eigenschaftswertes
- Selector parser – Selektor-Parser mit integrierten Methoden zur Arbeit mit Selektor-Strings.
- Dimension parser for number, length and percentage. – Parsen Sie eine CSS-Dimension in ein JavaScript-Objekt.
Was macht mich zu einem verantwortungsbewussten PostCSS-Plugin-Entwickler?
Tun Sie eine Sache und tun Sie sie gut.
PostCSS-Plugins sollten dafür erstellt werden, eine bestimmte Sache zu tun; das kann so einfach sein wie das Hinzufügen eines :focus-Selektors zu jedem :hover in Ihrem Stylesheet oder das Umwandeln einer Einheitsgröße wie Pixel in ems. Wichtig ist, dass Sie vermeiden, ein Multifunktions-Plugin zu schreiben, das viele Dinge tut. PostCSS-Benutzer wählen gerne ihre einzigartige Sammlung von Plugins aus, um die Dinge zu erledigen, die sie tun müssen.
Wenn Sie ein Multifunktions-Plugin erstellen möchten, können Sie eine Reihe einzelner PostCSS-Plugins zu einem Paket bündeln. Sie haben vielleicht schon von Plugins gehört, die so erstellt wurden, wie cssnext für zukünftige CSS-Syntax oder cssnano für moderne CSS-Minifizierung. Das wird von PostCSS-Benutzern oft geschätzt. Es erspart ihnen, ihre eigenen Sätze von Hand auswählen zu müssen.
Keep it Simple, Stupid
Das alte gute Designprinzip KISS (Keep It Simple, Stupid) der US-Marine ist ein perfektes Prinzip, dem man beim Erstellen eines PostCSS-Plugins folgen sollte. Nehmen Sie PostCSS-focus als Beispiel, es ist eine sehr einfache Idee, aber dennoch ein sehr nützliches PostCSS-Plugin zur Korrektur der Barrierefreiheit. Die Unix-Philosophie passt auch in Bezug auf den Code perfekt dazu.
Erstellen Sie Code, der kurz, einfach, klar und modular ist.
Ich habe eine coole Idee für ein PostCSS-Plugin
Es gibt mehr als 200 registrierte PostCSS-Plugins. Bevor Sie Ihre Plugin-Idee ausarbeiten, suchen Sie sie im PostCSS-Plugin-Register. Es besteht eine hohe Wahrscheinlichkeit, dass es bereits von jemand anderem erstellt wurde und Sie es nicht unbedingt neu erstellen müssen. Stattdessen ist gegenseitige Hilfe das, was ein gutes Plugin-Ökosystem ausmacht. Jeder PostCSS-Plugin-Autor, den ich kenne, schätzt Unterstützung, Ideen und Pull Requests.
PostCSS hat kürzlich eine Vorschlagsbox für Benutzer geöffnet, um Ideen für PostCSS-Plugins einzureichen.
Denk außerhalb der Box
Das Erstaunliche an PostCSS ist, dass Sie etwas bauen können, das sehr einfach und dennoch effizient, einzigartig und futuristisch ist. Erstaunliche und beliebte Werkzeuge wie Autoprefixer, uncss, CSS Modules und Stylelint werden alle von PostCSS angetrieben. Sie sind großartige Beispiele dafür, über den Tellerrand hinaus zu denken.
Was ist eine schlechte Idee für ein PostCSS-Plugin?
Ich rate Ihnen davon ab, ein "syntactic sugar"-Plugin zu schreiben.
Zum Beispiel Kurzschreibweisen für nicht standardmäßige Deklarationseigenschaften oder -werte, wie ein Plugin, das font: 10px 700 in font-size: 10px; font-weight: 700 umwandelt. Es sieht aus wie Standard-CSS, ist es aber nicht. Stellen Sie sich vor, Sie übergeben Ihren CSS-Code, der dies verwendet, an einen anderen Entwickler. Das würde zu Verwirrung und Frustration führen, wäre schwerer zu warten und hätte eine unnötig schlechte Lernkurve.
Ich denke, deshalb sind einige Entwickler immer noch sehr skeptisch gegenüber PostCSS, es ermöglicht uns, diese Möglichkeiten zu schaffen. Dennoch können diese "syntactic sugar"-Plugins recht beliebt werden. Wir haben gesehen, wie diese Mixin-Bibliotheken viral gingen. Ein besserer Weg, diese zu erstellen, ist, das Deklarieren der Eigenschaft auf andere Weise zu verlangen. Vielleicht _font oder etwas anderes, das natives CSS nicht auf inkompatible Weise überschreibt und unwahrscheinlich ist, jemals Teil von nativem CSS zu werden.
Schaffen Sie etwas Neues mit den Möglichkeiten von PostCSS und bewahren Sie den Geist von CSS.
– Andrey Sitnik, Schöpfer von PostCSS
JavaScript ist beängstigend?!
Viele Entwickler (wie ich selbst) fühlen sich beim Arbeiten mit JavaScript immer noch nicht sehr wohl. Wir glauben nicht, dass wir genug Erfahrung haben, um uns mit der Erstellung eines PostCSS-Plugins zu beschäftigen. PostCSS hat das für mich tatsächlich umgedreht. Es ist unglaublich zu sehen, wie viel Sie mit nur wenigen Zeilen Code erreichen können und wie einfach es ist, ein funktionierendes PostCSS-Plugin zu erstellen.
PostCSS-Plugins, die sehr wenig Code verwenden
Und doch etwas Einzigartiges und Nützliches erschaffen. Schauen Sie sich das an
- postcss-will-change – Fügt einen 3D-Hack vor die
will-change-Eigenschaft ein. - postcss-at-root – Platziert Regeln direkt am Wurzelknoten.
- postcss-calc – Reduziert
calc()-Referenzen, wann immer es möglich ist. - postcss-z-index – Reduziert
z-index-Werte. - postcss-alias – Erstellt benutzerdefinierte Aliase für CSS-Eigenschaften mit einer
@alias-Regel. - postcss-easings – Ersetzt Ease-Namen von easings.net durch
cubic-bezier(). - postcss-verthorz – Fügt eine Kurzschreibweise für vertikalen und horizontalen Abstand hinzu.
Lassen Sie uns über Best Practices sprechen
Ihr PostCSS-Plugin sollte den CSS AST (Abstract Syntax Tree) *nur einmal* durchlaufen und einen Cache von Regeln beibehalten, anstatt mehrere Iterationsschritte. Die Verwendung einer String-Darstellung eines Knotens ist recht teuer, also tun Sie das nur, wenn Sie es benötigen, und stellen Sie vor allem sicher, dass PostCSS-Plugins mit TDD (Test Driven Development) entwickelt werden.
Es gibt eine Methode aus der PostCSS API, bei der Sie vorsichtig sein sollten: die node.raws-Methode. node.raws enthält Informationen zur Erzeugung von Byte-zu-Byte-Knoten-Strings. Das kann schlecht sein, da es Leerzeichen und Codeformatierungsdaten aus dem Stylesheet speichert. Da jeder Parser unterschiedliche Daten speichern kann, wird dies sehr teuer.
- Verwenden Sie nach Möglichkeit asynchrone Methoden
- Setzen Sie
node.sourcefür neue Knoten (erzeugt eine genaue Source Map) - Verwenden Sie
node.errorfür CSS-relevante Fehler (erzeugt eine Quellposition) - Verwenden Sie
result.warnfür Warnungen (geben Sie keineconsole.log()s aus)
Machen Sie sich keine Sorgen, wenn das alles keinen Sinn ergibt. Wenn die Zeit reif ist, schauen Sie sich die offizielle Plugin-Richtlinien-Seite für weitere Details an.
Sourcemapping
PostCSS verfügt über eine hervorragende Sourcemaps-Unterstützung und -Integration. Es kann das erwartete Format automatisch erkennen, sowohl Inline- als auch externe Maps lesen und ausgeben. Als Plugin-Entwickler müssen Sie vorsichtig sein, die Sourcemapping-Funktionalität nicht zu beeinträchtigen.
Jede Knoteneigenschaft setzt standardmäßig node.source (enthält eine Ursprungsposition im geparsten Input). PostCSS stringify berechnet die neue Position dieses Knotens und verwendet node.source, um eine Zuordnung zwischen der neuen und der alten Position zu erstellen. Der häufige Fehler ist, dass PostCSS-Plugin-Autoren vergessen, einfach source beim Erstellen des Knotens hinzuzufügen, was dazu führt, dass das Plugin nicht zugeordnet wird. Die beste und einzige Empfehlung für Plugin-Autoren ist, die PostCSS API clone(), cloneBefore() oder cloneAfter() zu verwenden, da dies die Quellknotenquelle kopiert oder die Quelle manuell setzt.
Was mache ich, wenn ich fertig bin?
Jeder darf ein PostCSS-Plugin schreiben und es auf GitHub und npm veröffentlichen. Am Ende geht es darum, Verantwortung für etwas zu übernehmen, das man veröffentlicht hat.
Mit großer Macht kommt große Verantwortung.
Aber bevor wir uns Hals über Kopf in die Dinge stürzen, gibt es ein paar zwingende Regeln für einen PostCSS-Plugin-Autor. Sie finden sie alle hier. Lassen Sie uns einige der wichtigsten Regeln durchgehen.
TDD (Test Driven Development)
Beim Schreiben von Code ist es auch wichtig, Tests zu schreiben. Ich denke, Entwickler sollten den Zweck eines Tests kennen und auch in der Lage sein, einen zu schreiben. Es gibt so viele Gründe, warum Sie Tests schreiben sollten. Die Qualität Ihres Endergebnisses ist oft viel besser, da Sie beim Erstellen und Ausführen von Tests viele "Aha-Momente" erleben werden. Aus persönlicher Erfahrung verbessert sich mein Code drastisch, wenn ich lerne, aus Testfehlern zu refaktorieren.
Ich empfehle, Tests in AVA zu schreiben, da es eine sehr einfache Syntax hat und auch am häufigsten in PostCSS-Plugins verwendet wird. Das ist hilfreich, um die meisten Mitwirkenden für Ihr Plugin zu gewinnen. AVA hat auch promise-Unterstützung, was großartig für asynchrone Plugins ist, sowie weitere Vorteile wie Geschwindigkeit, keine impliziten Globale, ES2015-Unterstützung und dass es alle Tests parallel ausführt. Wenn Sie nicht lieber mit AVA arbeiten möchten, können Sie sich Chai oder Mocha ansehen.
Schreiben wir einen einfachen Test für unser PostCSS-backwards-Plugin in AVA.
// Function helper to make our tests cleaner
// This runs our plugin
function run(t, input, output, opts = {}){
return postcss([ plugin(opts) ]).process(input)
.then( result => {
t.same(result.css, output);
t.same(result.warnings().length, 0);
});
}
// This test passed.
test('reverse color value from dlog to gold', t => {
return run(t, 'a{ color: dlog }', 'a{ color: gold }');
});
CI-Service
Die Verwendung eines CI-Dienstes wie Travis zum Testen von Code in verschiedenen Node-Umgebungen wird empfohlen, da Sie testen können, ob Ihr Code die Anforderungen direkt von Node erfüllt. Ich mag Travis auch, da es konfigurierbar ist und Sie alle Tests automatisch ausführen können, wenn Sie Änderungen in Ihr Repository committen, und Sie Pass/Fail-Benachrichtigungen erhalten. Probieren Sie es aus!
Benennung Ihres Plugins
Der Name Ihres PostCSS-Plugins sollte mit "postcss-" beginnen, um anzuzeigen, dass es sich tatsächlich um ein PostCSS-Plugin handelt und auch den Zweck klarzustellen, indem man den Namen liest. Es ist auch vorzuziehen, den Namen kleinzuschreiben.
- Bevorzugt: postcss-my-cool-plugin
- Nicht bevorzugt: PostCSS-My-Cool_Plugin
Dokumentation
Sie müssen nicht unbedingt viel Dokumentation schreiben, aber es ist wichtig zu beschreiben, was Ihr PostCSS-Plugin tut, indem Sie im README Eingabe- und Ausgabecodebeispiele zeigen. Das macht es dem Benutzer klarer, was der Zweck des Plugins ist.
Führen Sie ein Changelog
Es ist wichtig, eine Changelog-Datei zu führen, die bei jeder Veröffentlichung, die Sie für Ihr PostCSS-Plugin veröffentlicht haben, aktualisiert wird. Das ist sowohl für Sie (eine Historie, auf die Sie zurückblicken können) als auch für die Benutzer Ihres Plugins (eine Referenz für Updates und Änderungen) sehr vorteilhaft. Ich würde einen npm-Publisher wie npmpub empfehlen und weitere Informationen auf keepachangelog.com/ für Tipps und Tricks zur Pflege einer guten Changelog-Datei lesen.
Letzte weise Worte
Ich denke, der beste Weg, um zu lernen, wie man ein PostCSS-Plugin erstellt, ist, sich hineinzustürzen, sich Zeit zu nehmen, um die PostCSS API kennenzulernen und im AST Explorer herumzuspielen.
Denken Sie daran, dass Sie auf dieser Reise nicht allein sind; Sie haben die PostCSS-Community, die Ihnen hilft. Das Schöne an PostCSS ist seine Community. Es klingt klischeehaft, aber ich möchte betonen, dass Sie oft mit den Experten hinter dem PostCSS-Kern sprechen und jede Menge Hilfe erhalten können.
Wenn Sie Fragen haben, hinterlassen Sie diese gerne im Kommentarbereich oder twittern Sie mir und ich werde mein Bestes tun, um Ihnen eine Antwort zu geben. Schauen Sie sich die Dokumentation auf der offiziellen Website postcss.org an.
Ich möchte Ben Briggs, Andrey Sitnik, Dan Gamble, Chris Coyier und Malin Gernandt dafür danken, dass sie diesen Artikel durch Korrekturlesen und Ideen ermöglicht haben.
Gute Arbeit, Marcus!
Schöner Artikel. Ich mochte die Idee von PostCSS schon immer, habe aber nie die Zeit gefunden, mich damit zu beschäftigen. Um ehrlich zu sein, hat Sass meine Probleme bereits gelöst und ich habe keine anderen Probleme, bei denen ich sehe, dass PostCSS im Moment Lösungen anbietet.
PS: Die Formulierung ist "syntactic sugar", nicht "syntax sugar" :)
Ja, es gibt keinen Grund, Sass-Mixins durch PostCSS-Mixins in aktuellen Projekten zu ersetzen.
Aber nicht alle Probleme können nicht durch Mixins gelöst werden. Ich denke, Sie sollten bereits PostCSS mit Autoprefixer verwenden, um das Problem mit Präfixen zu lösen.
Danke Scott. Sass ist immer noch eine sehr nützliche Sprache und muss nicht unbedingt komplett durch PostCSS ersetzt werden. Sie können damit beginnen, einfach ein paar Plugins wie autoprefixer für Vendor-Präfixe oder pixrem, das Pixel-Fallbacks für rem-Einheiten hinzufügt, zu integrieren. Es gibt unzählige Plugins, die helfen, Probleme zu lösen oder uns Zeit zu sparen. Ich bin sicher, Sie können etwas finden, das Sie davon überzeugt, PostCSS hinzuzufügen, was innerhalb von Sass nicht möglich wäre.
Toller Beitrag #marcus.. Ja, Sie haben Recht, Sass ist bereits etabliert und es gibt viele nützliche Werkzeuge und Funktionen. Daher können wir PostCSS für einige zusätzliche Funktionen wie pixrem, rtlcss, svg usw. verwenden.
Tolle Einführung Marcus Tisäter. Ich hatte schon immer die Idee, eine zu schreiben, wusste aber nicht wirklich, wo ich anfangen sollte. Problem gelöst :) Nochmals vielen Dank!