PostCSS Deep Dive crea il tuo plugin personale

Come sono sicuro che hai già raccolto bene a questo punto, ciò che rende PostCSS sorprendente è il suo fiorente ecosistema di plugin. E un'enorme ragione per cui ci sono così tanti ottimi plugin, con altri che escono sempre, è che PostCSS rende la creazione di un proprio plugin così accessibile per chiunque abbia qualche esperienza con JavaScript.

Non hai bisogno di permessi speciali per creare un plugin PostCSS; se vuoi farne uno, vai avanti e fallo. Attraverso questa libertà hai la possibilità di trasformare i tuoi processi di sviluppo CSS in qualsiasi cosa tu voglia che siano, senza menzionare l'opportunità di condividere il tuo lavoro con altri membri della comunità PostCSS in rapida crescita.

In questo tutorial imparerai come creare un plugin di base per PostCSS. Non entreremo troppo nell'API del plugin e non useremo alcuna codifica super hardcore. Io stesso sono uno sviluppatore front-end e le mie competenze JavaScript sono al livello che ti aspetteresti che fossero per una persona front-end, ma ciò non mi ha impedito di creare il mio primo plug-in PostCSS in poche ore.

Segui e scopri di persona quanto può essere accessibile lo sviluppo di plugin PostCSS!

Cosa stiamo andando a costruire

Creeremo un plug-in che consente di inserire facilmente pile di font in famiglia di font dichiarazioni tramite la seguente sintassi:

h1 font-family: "Open Sans", fontstack ("Arial"); 

Dopo la compilazione, il codice sopra si trasformerà in:

h1 font-family: "Open Sans", Arial, "Helvetica Neue", Helvetica, sans-serif; 

Impostare un progetto per lavorare all'interno

Anche se stai creando il tuo plugin, dovrai comunque iniziare creando un progetto Gulp o Grunt vuoto. Caricherete il vostro plug-in in questo progetto nello stesso modo in cui avete usato i plugin di altre persone in questa serie.

Puoi leggere come configurare i progetti Gulp o Grunt per PostCSS nelle esercitazioni precedenti:

  • Guida rapida su PostCSS: Gulp Setup
  • Guida rapida per PostCSS: installazione Grunt

Se non si desidera configurare manualmente il progetto da zero, è possibile scaricare i file sorgente allegati a questo tutorial ed estrarre il progetto di avviamento Gulp o Grunt in una cartella di progetto vuota. Quindi, con un terminale o un prompt dei comandi puntato sulla cartella, eseguire il comando installazione di npm.

Creare una shell plugin di base

Crea una cartella in "node_modules" chiamata "postcss-myplugin". È comune usare il prefisso postcss- per chiarire che il tuo plugin è per PostCSS.

Tutti i plugin PostCSS sono moduli di nodo, quindi sarà necessario trasformare la nuova cartella in una sola. Apri un terminale / prompt dei comandi, punta alla cartella appena creata ed esegui npm init. Questo eseguirà l'impostazione di base di un modulo nodo, quindi segui semplicemente le istruzioni che appaiono nel tuo terminale, lasciando il campo "entry point" come predefinito "index.js".

Quando questo è fatto, con il terminale ancora puntato verso la cartella, esegui il comando npm install postcss --save. Questo installerà PostCSS come una dipendenza per questo modulo, qualcosa che tutti i plugin PostCSS devono fare.

Creare un file denominato "index.js" nella cartella "postcss-myplugin". Aggiungi questo codice per caricare il modulo postcss principale:

var postcss = require ('postcss');

Poi sotto aggiungi questo wrapper di base che circonderà il codice di elaborazione del nostro plugin:

var postcss = require ('postcss'); module.exports = postcss.plugin ('myplugin', funzione myplugin (opzioni) funzione di ritorno (css) opzioni = opzioni || ; // codice di elaborazione verrà aggiunto qui);

Carica il tuo nuovo plugin

Ora siamo pronti per caricare il tuo plug-in appena creato nel tuo progetto. Non farà nulla ancora, ma vogliamo solo ottenere la configurazione essenziale in atto.

Carica il plugin via Gulp

Se stai usando Gulp, aggiungi questa variabile sotto quella già presente nel file:

var myplugin = require ('postcss-myplugin');

Ora aggiungi il nuovo nome della variabile nel tuo processori array:

 processori var = [myplugin];

Fai un rapido test per verificare che tutto funzioni eseguendo il comando gulp css e controllando che un nuovo file "style.css" sia apparso nella cartella "dest" del tuo progetto.

Carica il plugin via Grunt

Se stai usando Grunt, aggiorna il processori oggetto, che è annidato sotto il opzioni oggetto, al seguente:

 processori: [require ('postcss-myplugin') ()]

Fai un rapido test per verificare che tutto funzioni eseguendo il comando grunt postcss e controllando che un nuovo file "style.css" sia apparso nella cartella "dest" del tuo progetto.

Aggiungi la funzionalità del plugin

Aggiungi test CSS

Prima di iniziare ad aggiungere codice di elaborazione al nostro plug-in, aggiungeremo del codice di prova al nostro foglio di stile su cui il plugin può lavorare.

Al tuo file "src / style.css" aggiungi questo CSS:

h1 font-family: "Open Sans", fontstack ("Arial"); 

In questo momento, perché il nostro plugin non sta ancora facendo nulla, se compilate il vostro CSS vedrete esattamente lo stesso codice copiato direttamente nel file "style.css" della cartella "dest"..

Passa attraverso le regole e le dichiarazioni

Ora vogliamo iniziare la scansione del CSS del nostro file in modo che possiamo trovare qualsiasi istanza di fontstack () e elaborarli. Per iniziare, aggiungi il seguente codice dopo il opzioni = opzioni || ; linea:

 css.walkRules (function (rule) rule.walkDecls (function (decl, i) ););

L'uso di walkRules () nella prima riga consente di scorrere tutte le regole del tuo CSS; una regola è fondamentalmente il tuo selettore e gli stili che hai impostato tra le parentesi graffe. Nel nostro test CSS una regola sarebbe:

h1 font-family: "Open Sans", fontstack ("Arial"); 

Quindi, all'interno di ogni regola, walkDecls () scorre attraverso ogni dichiarazione; una dichiarazione è essenzialmente ogni riga nello stile. Nel precedente CSS, una dichiarazione sarebbe:

font-family: "Open Sans", fontstack ("Arial");

Controlla se fontstack () Si usa la sintassi

Mentre ripetiamo ogni dichiarazione usando il codice che abbiamo appena aggiunto, la dichiarazione corrente è rappresentata da decl, che ci consente di accedere sia alla proprietà della dichiarazione sia al suo valore tramite decl.prop e decl.value rispettivamente.

Con il nostro esempio CSS, decl.prop ci darebbe famiglia di font e decl.value ci darebbe  "Open Sans", fontstack ("Arial").

Vogliamo controllare tutti decl.value nel nostro foglio di stile per vedere se contiene la stringa fontstack (. Se lo fa, sappiamo che qualcuno sta cercando di utilizzare il nostro plugin per aggiungere uno stack di font al proprio CSS.

Dentro il walkDecl () loop, aggiungi:

 var value = decl.value; if (value.indexOf ('fontstack (')! == -1) console.log ("found fontstack");

Per prima cosa stiamo prendendo decl.value e memorizzandolo nella variabile valore. Qualsiasi modifica a decl.value sarà inviato nel foglio di stile compilato; stiamo memorizzando il suo contenuto nella variabile valore quindi possiamo giocarci.

Quindi stiamo usando il metodo indexOf () per cercare il nostro nuovo valore variabile per la stringa fontstack (. Se viene trovato, stiamo registrando "found fontstack" sulla console in modo che possiamo controllare se tutto sta funzionando finora.

Correre gulp css o grunt postcss e dovresti vedere l'output "found fontstack" una volta nel tuo terminale / prompt dei comandi.

Definire alcuni tipi di carattere

Ora che il nostro plugin è in grado di individuare istanze di fontstack () nel nostro foglio di stile, possiamo prepararci a convertire quell'istanza in uno stack di font, ad esempio un elenco di nomi di font. Ma prima di poterlo fare, dobbiamo prima definire questi stack di font.

Nella parte superiore del tuo file, sotto l'esistente postcss variabile, crea una variabile chiamata fontstacks_config. Trasformeremo questa variabile in un oggetto contenente coppie chiave-valore.

Per ogni voce nell'oggetto, la chiave dovrebbe essere il primo carattere nello stack di caratteri, ad es. 'Arial'. Sarà la stringa passata da un utente a specificare lo stack di caratteri che desidera utilizzare, ad es. fontstack ( "Arial") o fontstack ("Times New Roman").

Il valore in ogni coppia dovrebbe essere una stringa dell'elenco completo di caratteri contenuti nello stack di caratteri, ad es. 'Arial, "Helvetica Neue", Helvetica, sans-serif'.

Aggiungi due voci al tuo fontstacks_config oggetto, uno per 'Arial' e uno per 'Times New Roman', utilizzando gli stack di font forniti da CSS Font Stack.

Il tuo fontstacks_config la variabile dovrebbe apparire così:

// Stack di font da http://www.cssfontstack.com/ var fontstacks_config = 'Arial': 'Arial,' Helvetica Neue ', Helvetica, sans-serif', 'Times New Roman': 'TimesNewRoman', Times New Roman ", Times, Baskerville, Georgia, serif '

Verifica quale tipo di carattere è richiesto

La prima cosa che dobbiamo fare quando troviamo un'istanza di fontstack () essere usato è capire quale stack di font l'utente ha richiesto, cioè quale stringa hanno impostato tra le parentesi. 

Ad esempio, se un utente è entrato fontstack ( "Arial") vorremmo estrarre la stringa Arial. Il motivo per cui vogliamo questa stringa è che ci darà una chiave che possiamo usare per cercare la pila di font corrispondente dalla nostra fontstacks_config oggetto.

Aggiungi questo codice immediatamente dentro Se dichiarazione che abbiamo aggiunto in precedenza, in sostituzione del console.log ("found fontstack"); linea:

// Ottieni il nome della stringa di caratteri richiesta facendo corrispondere la stringa all'interno delle parentesi di fontstack (). // Quindi sostituisci eventuali virgolette doppie o singole al suo interno. var fontstack_requested = value.match (/ \ (([^)] +) \) /) [1] .replace (/ ["'] / g," ");

Stiamo eseguendo due passaggi qui per estrarre il nome del fontstack come stringa.

Per prima cosa usiamo il metodo match () per trovare qualsiasi stringa tra parentesi nel nostro valore. Questo ci darebbe una stringa simile "Arial" o 'Arial'.

Vogliamo solo il nome del font, senza virgolette doppie o singole, quindi usiamo il metodo replace () per eliminarle dalla stringa, lasciandoci con una stringa non quotata come Arial.

Questa stringa è memorizzata nel fontstack_requested variabile.

Titolo Indicare la Fontstack richiesta

Useremo il nostro nuovo creato fontstack_requested variabile per cercare uno stack di font dal nostro fontstack_config opzione. La parte difficile è che le chiavi in ​​questo oggetto sono case sensitive, quindi se proviamo a cercare il Arial entrata con la chiave arial fallirà.

Per risolvere questo, andremo a "Title Case" la stringa, quindi per esempio tempi nuovi romani sarebbe convertito a Times New Roman. Lo faremo tramite una breve funzione personalizzata.

Sotto il tuo fontstacks_config variabile aggiungi questo ToTitleCase () funzione:

// Credito per questa funzione a http://stackoverflow.com/questions/196972/convert-string-to-title-case-with-javascript/196991#196991 function toTitleCase (str) return str.replace (/ \ w \ S * / g, function (txt) return txt.charAt (0) .toUpperCase () + txt.substr (1) .toLowerCase ();); 

Ora applicheremo questa funzione al nostro fontstack_requested variabile. Sotto la linea in cui hai creato il fontstack_requested variabile, aggiungi questo codice:

// Titolo case le parole nel nome del font, nel caso in cui l'utente non lo facesse da solo fontstack_requested = toTitleCase (fontstack_requested);

Questo passa il fontstack_requested variabile attraverso il nostro ToTitleCase () funzione, aggiornando il suo valore.

Cerca Fontstack From Config

Ora abbiamo il nostro fonstack_requested variabile impostata correttamente, possiamo usarla per cercare la pila di font corrispondente. Dopo la riga che hai appena aggiunto, inserisci questo codice:

// Cerca la fontstack richiesta nell'oggetto fontstack_config var fontstack = fontstacks_config [fontstack_requested];

Questo trova il valore nel fontstacks_config oggetto che ha una chiave corrispondente alla stringa contenuta nel nostro fontstack_requested variabile. 

Ad esempio, se fontstack_requested contiene la stringa Arial, la voce in fontstacks_config con la chiave Arial sarà trovato e il valore 'Arial, "Helvetica Neue", Helvetica, sans-serif' sarà restituito.

Questo valore restituito viene quindi memorizzato nella variabile fontstack.

Controlla i caratteri impostati prima di fontstack ()

Ora abbiamo recuperato la nostra stringa di stack dei caratteri e pronta per essere inserita nel CSS, ma c'è ancora un'altra cosa che dobbiamo fare. Ricorderai nel nostro codice di test che abbiamo incluso il font "Open Sans" come font preferito, con lo stack di font che funge da fallback. Abbiamo anche bisogno di recuperare questo nome di carattere dal valore in modo che possa essere aggiunto al CSS che inseriamo nel foglio di stile elaborato.

Sotto il fontstack riga variabile, aggiungi questo codice:

// Trova e memorizza qualsiasi nome di carattere che potrebbe essere già nel valore, prima della chiamata a fontstack () var first_font = value.substr (0, value.indexOf ('fontstack ('));

Questo codice utilizza il metodo substr () per trovare qualsiasi contenuto tra l'inizio del nostro valore, (rappresentato da 0), e il nostro fontstack () istanza (che si trova usando il metodo indexOf ()). Qualunque contenuto sia trovato è memorizzato nella variabile first_font.

Ad esempio, nel nostro codice di test valore è uguale a  "Open Sans", fontstack ("Arial"), così la first_font la variabile sarà impostata come  "Apri Sans", .

Crea un nuovo valore

Ora abbiamo tutti i pezzi di cui abbiamo bisogno per creare un nuovo valore con cui sostituire il valore originale del nostro codice di prova  "Open Sans", fontstack ("Arial").

Dopo l'ultimo codice che hai aggiunto, inserisci questo codice:

// Crea il nuovo valore per questa regola combinando le variabili first_font e fontstack var new_value = first_font + fontstack;

Qui stiamo unendo il nostro first_font e fontstack variabili in una singola stringa e memorizzarle nella variabile NEW_VALUE

Nel nostro codice di test, ciò significherebbe la combinazione  "Apri Sans",  e Arial, "Helvetica Neue", Helvetica, sans-serif.

Nostro NEW_VALUE la variabile quindi manterrebbe la stringa  "Open Sans", "Arial", Helvetica Neue ", Helvetica, sans-serif".

Questo ora ci dà il valore completo che vogliamo aggiungere al foglio di stile elaborato in modo che: 

font-family: "Open Sans", fontstack ("Arial"); 

... si trasforma in:

font-family: "Open Sans", "Arial", Helvetica Neue ", Helvetica, sans-serif";

Invia il nuovo valore al foglio di stile

Ora che abbiamo il nostro nuovo valore pronto per essere inserito nel foglio di stile elaborato, tutto ciò che dobbiamo fare è aggiornare decl.value. PostCSS si occuperà del resto, aggiungendo il nuovo valore nel CSS elaborato per noi.

Aggiungi questo codice dopo l'ultima riga che hai aggiunto:

// Reimposta il nuovo valore nel foglio di stile decl.value = new_value;

Questo set decl.value per eguagliare il contenuto del nostro NEW_VALUE variabile.

Prova il tuo plugin

Il tuo plug-in è ora disponibile. Dagli un vortice compilando il tuo foglio di stile con gulp css o grunt postcss (con il terminale puntato verso la cartella del progetto, non la cartella dei plugin).

Il tuo file "dest / style.css" dovrebbe ora mostrare una pila di font completa:

h1 font-family: "Open Sans", Arial, "Helvetica Neue", Helvetica, sans-serif; 

(Facoltativo) Aggiungi opzioni di caratteri opzionali configurabili dall'utente

Potresti voler consentire agli utenti del tuo plug-in di impostare le proprie opzioni, nello stesso modo in cui hai impostato le opzioni come hai usato i plugin PostCSS in questa serie.

Vogliamo che gli utenti siano in grado di impostare a fontstacks opzione, aggiungendo stack di font aggiuntivi o ridefinendo stack di font esistenti, ad esempio:

fontstacks: 'Extra Stack': '"Extra Stack", "Moar Fonts", Extra, serif', 'Arial': 'Arial, "Comic Sans"'

Nota: questo passaggio è facoltativo. Se lo desideri, puoi saltarlo e il tuo plugin funzionerà perfettamente, senza alcuna configurazione di set utente.

Abbiamo già la parte essenziale di abilitare le opzioni di set di utenti sul nostro plug-in. Nel nostro module.exports linea noterai un opzioni argomento è passato. 

module.exports = postcss.plugin ('myplugin', function (options) 

Riceveremo tutte le opzioni utente impostate dall'utente.

Vedrai anche che abbiamo la linea:

opzioni = opzioni || ;

Questo controlla se opzioni ha qualsiasi valore e, in caso contrario, lo imposta su un oggetto vuoto. Questo ci assicura che non ci siano errori quando iniziamo a lavorare opzioni ciò potrebbe derivare dall'essere indefinito.

Per iniziare, installeremo Underscore.js nel nostro progetto, poiché utilizzeremo il suo pratico metodo extend (). Esegui questo comando per installarlo nel plug-in che stai creando:

npm install underscore --save

Ora carica Underscore nel tuo plugin aggiungendo un _ variabile per richiederlo, sotto il tuo esistente postcss variabile:

var postcss = require ('postcss'); var _ = require ('underscore');

Quindi quello che faremo è prendere il fontstacks_config oggetto che abbiamo già creato all'interno del plugin e lo "estendiamo" con qualsiasi stack di font che l'utente ha impostato attraverso la configurazione delle opzioni.

Aggiungi questo codice direttamente sotto il opzioni = opzioni || ; linea:

 // Estende l'opzione predefinita fontstacks_config con qualsiasi set di caratteri personalizzati impostato nelle opzioni del plugin fontstacks_config = _.extend (fontstacks_config, options.fontstacks);

Il fontstacks l'opzione che è stata impostata dall'utente è rappresentata da options.fontstacks.

Usando Underscore estendere() metodo, tutti i font stack in options.fontstacks sono aggiunti a quelli già in fontstacks_config. Ovunque ci sia una chiave corrispondente, il valore da options.fontstacks sovrascriverà quello in fontstacks_config. Ciò consente agli utenti di ridefinire qualsiasi stack di font esistente.

Nel tuo Gulpfile o Gruntfile, imposta a fontstacks opzione e passa un nuovo stack di font e ridefinisce uno esistente:

/ * Gulpfile * / var processors = [myplugin (fontstacks: 'Extra Stack': '"Extra Stack", "Moar Fonts", Extra, serif', 'Arial': 'Arial, "Comic Sans"' )]; / * Gruntfile * / processori: [require ('postcss-myplugin') (fontstacks: 'Extra Stack': '"Extra Stack", "Moar Fonts", Extra, serif', 'Arial': 'Arial,' Comic Sans"'  ) ]

Ora aggiungi alcuni CSS aggiuntivi al tuo file "src / style.css" in modo da poter testare il nuovo stack di font che abbiamo appena aggiunto tramite le nostre opzioni:

h2 font-family: "Droid Sans", fontstack ("Extra Stack"); 

Ricompila il tuo CSS e dovresti vedere che il tuo stack di font "Arial" ora ha un output diverso e che lo stack di font "Extra Stack" è stato stampato correttamente:

h1 font-family: "Open Sans", Arial, "Comic Sans";  h2 font-family: "Droid Sans", "Extra Stack", "Moar Fonts", Extra, serif; 

Il tuo plugin completo

Questo è tutto! Hai finito. Hai completato il tuo primo plug-in PostCSS.

Ecco l'intera cosa su GitHub se dovessi aver bisogno di confrontare il tuo codice come riferimento.

Riassumiamo

Hai appena creato un intero plug-in PostCSS e spero che ti vengano in mente alcune idee sugli altri plug-in che ti piacerebbe creare. Forse c'è quella piccola cosa che ti infastidisce sempre quando scrivi CSS, e forse ora puoi trovare la tua soluzione per sbarazzartene definitivamente. O forse c'è qualcosa in più che pensi davvero che il CSS dovrebbe avere fuori dagli schemi, beh, ora puoi aggiungerlo da solo!

Per riassumere ciò che abbiamo coperto:

  • Inizia a sviluppare un nuovo plugin impostando un progetto Gulp o Grunt su cui lavorare.
  • Crea un nuovo modulo nodo all'interno del tuo progetto, che diventerà il tuo plugin.
  • Carica il tuo nuovo plugin nel tuo progetto.
  • Aggiungi alcuni CSS di test nella sintassi che desideri venga utilizzata dal tuo plug-in.
  • Utilizzare i metodi dell'API PostCSS per eseguire la scansione attraverso un foglio di stile.
  • Individua le istanze della sintassi del tuo plug-in in uso.
  • Scrivi JavaScript e utilizza l'API PostCSS per apportare le trasformazioni appropriate (e / o aggiunte) al codice originale e inviarlo al CSS elaborato.

Per utenti TypeScript

Come parte della versione 5.0 di PostCSS, Jed Mao ha contribuito con un gran numero di definizioni TypeScript che possono aiutare molto nello sviluppo di plugin attraverso il completamento automatico e la documentazione integrata durante la digitazione.

Se ti ritrovi nello sviluppo di plug-in PostCSS, questo è davvero qualcosa che vale la pena di integrare nel tuo flusso di lavoro. Io stesso non sono una mano di tipo Script, ma ho intenzione di inserire comunque il codice, quasi puramente per sfruttare questa funzionalità.

Se vuoi provare questo non è necessario essere su Windows o utilizzare Visual Studio, poiché puoi utilizzare il codice di Visual Studio open source gratuito, che gira su Windows, Mac e Linux ed è basato su Electron , la stessa shell che alimenta l'Editor di Atom.

Per un esempio su come incorporare queste definizioni TypeScript nel progetto, controlla il plugin postcss-font-pack. Forchetta e gioca in Visual Studio Code per vedere come funziona il completamento automatico e la documentazione in linea.

PostCSS Deep Dive: Wrapping Up

Grazie mille per aver seguito questa serie Deep Dive PostCSS. Spero che ti sia piaciuto leggerlo tanto quanto mi è piaciuto crearlo! Ancora più importante, spero che tu abbia una testa piena di idee su come puoi far funzionare PostCSS nella tua vita quotidiana di sviluppo web.

PostCSS è davvero un'incredibile nuova aggiunta al mondo del front-end, poiché il modo in cui facilita i plugin apre le porte a possibilità mai viste prima nello sviluppo di CSS. La gamma di plug-in disponibili al momento è già sufficiente per rimodellare completamente i flussi di lavoro giornalieri di una persona, e questo è solo ciò che è stato creato nello spazio di un paio d'anni. 

Suggerirei che PostCSS non abbia ancora raggiunto il massimo, e che quando comincerà a essere qualcosa di cui la maggior parte degli sviluppatori CSS almeno conoscerà, se non lo giuro, vedremo che arriverà davvero al suo massimo. E con l'arrivo di altri sviluppatori front-end, vedremo più contributi all'ecosistema dei plugin, aggiungendo nuovi plugin e aiutandoci a creare quelli esistenti.

!