Ingruz's Blog

Gestire assets CSS con npm, gulp e postcss

September 13, 2016

Npm è ormai diventato lo standard de-facto per la gestione delle librerie javascript. Nato inizialmente come package manager per nodejs (la parte “server” di javascript), negli ultimi anni ha iniziato ad attrarre sempre più sviluppatori di librerie anche per il frontend, sostituendosi al jquery plugin registry e scalzando bower dalla posizione di package manager più utilizzato per dagli sviluppatori frontend.

Per quanto npm funzioni egregiamente per gestire le librerie javascript (in fondo è nato per questo) ho sempre trovato un po’ di difficoltà a gestire librerie che hanno anche delle parti di styling o addirittura riguardano esclusivamente lo styling (come ad esempio le famose librerie bootstrap o font-awesome). Entrambi sono presenti nel registro di npm e quindi il loro download è distante un semplice npm install, ma una volta che abbiamo i files nella nostra cartella node_modules come possiamo utilizzarli senza perderci il sonno? Oltre ai files css spesso ci sono anche altri assets come immagini, fonts etc. che spesso sono referenziati in maniera relativa nei rispettivi fogli di stile, creando non pochi problemi una volta che questi vengono importati dai nostri scripts di building.

La tentazione di spostare questi files a mano o addirittura gestire queste dipendenze in maniera manuale e separata da npm è forte ma grazie a moderni tools come gulpjs e postcss è possibile risolvere questo problema in maniera automatizzata.

Di gulpjs abbiamo già trattato ampiamente, mentre postcss è un tool modulare, scritto sempre in javascript, che si prefigge come scopo quello di trasformare e manipolare il CSS attraverso decine di plugins, che permettono di eseguire le operazioni più disparate, dalla semplice minificazione, all’applicazione automatica dei vendor prefixes, alla possibilità di utilizzare sintassi future previste dallo standard CSS ma non ancora implementate da tutti i browsers. In sostanza permette di scrivere CSS in maniera più “flat” possibile e lasciare che i vari plugins si occupino di renderlo il più efficente e compatibile possibile.

Setup

Questo tutorial suppone che abbiate già installato nel vostro sistema nodejs (e quindi npm), nonchè il pacchetto gulp-cli globalmente (npm install --global gulp-cli).

Ora posizionatevi nella cartella dove risiede il vostro progetto e inizializzate npm (se non l’avete già fatto) tramite il comando npm init.

Installiamo ora le dipendenze di sviluppo:

$ npm install gulp gulp-postcss postcss-copy postcss-import --save-dev

E poi un paio di dipendenze che contengono assets CSS:

$ npm install bootstrap font-awesome --save

Prima di poter iniziare a lavorare al nostro script di building creiamo un file css di prova in src/styles/style.css, nel quale vogliamo importare i fogli di stile di bootstrap e font-awesome e aggiungere qualche nostro style custom o eventuali overrides. Si noti come i paths ai fogli di style di bootstrap e font-awesome siano relativi alla cartella node_modules, che è quella usata di default da npm per salvare i pacchetti installati.

@import "bootstrap/dist/css/bootstrap.css";
@import "font-awesome/css/font-awesome.css";

.logo {
    background: url('../assets/logo.png');
    height: 100px;
    width: 200px;
}

Task Gulp

Creiamo il nostro file gulpfile.js e importiamo tutti i pacchetti necessari:

var gulp = require('gulp');
var postcss = require('gulp-postcss');
var cssCopy = require('postcss-copy');
var cssImport = require('postcss-import');

Iniziamo a scrivere il task che si occuperà di generare il nostro css, supponendo che il nostro entry point sia src/styles/style.css mentre il foglio di stile definitivo sarà salvato in public/styles/style.css.

gulp.task('styles', function() {
    return gulp.src('src/styles/style.css')
        .pipe(postcss([
            cssImport({
                path: ['node_modules']
            }),
            cssCopy({
                src: ['node_modules', 'src'],
                dest: 'public/assets',
                relativePath: function() {
                    return 'public/styles';
                }
            })
        ]))
        .pipe(gulp.dest('public/styles'))
});

Essendo postcss completamente modulare non esegue alcuna operazione in sè, ma si occupa di applicare una serie di plugin ai files passati come input, in questo caso tramite gulp (ma è perfettamente possibile utilizzarlo stand-alone). Innanzitutto utilizziamo il plugin postcss-import (cssImport) per risolvere le direttive @import e concatenare i fogli di stile esterni all’interno del nostro file style.css, specificando nel parametro path che vogliamo utilizzare la cartella node_modules come root per risolvere gli import.

Successivamente applichiamo il plugin postcss-copy (cssCopy) per copiare fisicamente gli assets dalle cartelle di origine ad una cartella di destinazione designata, public/assets, attraverso il parametro dest. Nel parametro src invece specifichiamo quali sono le cartelle di root in cui sono presenti i files css. Infine attraverso la funzione relativePath indichiamo al plugin relativamente a quale cartella dovranno essere riscritti gli url degli assets nel foglio di stile, specificando quindi la cartella di destinazione del file style.css.

Lanciamo ora il task tramite shell:

$ gulp styles

Se non ci sono stati errori dovremmo trovarci tutti gli assets referenziati nella cartella public/assets, mentre nella cartella public/styles troveremo il file style.css compilato con gli url degli assets riscritti per puntare ai files copiati nella cartella public/assets! Da notare come anche i nostri assets presenti nella cartella src saranno importati esattamente come quelli delle librerie di terze parti, a patto che siano referenziati con il corretto path relativo nei nostri fogli di stile.

N.B.: di default postcss-copy rinomina i files copiati nel loro hash md5, ma è possibile modificare questo comportamento attraverso il parametro template, per maggiori informazioni consulare la documentazione.

Tirando le somme

Grazie a questo semplice task gulp e a postcss possiamo ora gestire e includere il nostro datepicker o la nostra gallery preferita tramite npm, senza dover ogni volta copiare a mano i fogli di stile o i relativi assets. L’unica cosa che potrebbe risultare un po’ tediosa è il dover andare a cercare il path relativo al file CSS per ogni libreria, ma questa è un’operazione che di solito và eseguita una volta sola, a meno che gli sviluppatori della libreria non modifichino il path o nome interno del foglio di stile.

Sarà inoltre molto semplice applicare ulteriori plugins tra lo sterminato catalogo proposto da postcss, aggiungendoli semplicemente all’array all’interno del task gulp!

Per concludere, sebbene questa procedura funzioni senza problemi con CSS liscio, richiede ulteriori elaborazioni (e tribolazioni) nel caso si dedica di utilizzarla in congiunzione a pre-processori quali SASS o LESS. Nel caso ce ne fosse l’interesse potrebbe essere l’argomento per un futuro post.


Emanuele Ingrosso, sviluppatore web full-stack dal 2011, appassionato di videogames, Lego e libri fantasy. Seguimi su Twitter