Tools Frontend

Bower spiegato ai back end developer

Lettura 12 minuti

Bower è un gestore di pacchetti per il web, che comprende, tra gli altri, librerie JS e CSS, come Composer lo è per PHP.

Perché usare Bower?

Se utilizziamo spesso librerie di terzi nei nostri progetti, che vengono rilasciate con nuove versioni periodicamente, è utile avere un gestore di pacchetti perché ci consente di tenere aggiornate le nostre librerie all’ultima versione oppure di tornare indietro a specifiche versioni. Inoltre è molto utile usato insieme ad un task runner come Grunt o Gulp perché è possibile specificare tutte le librerie dipendenti all’interno del file bower.json per il progetto in essere in modo che sia sufficiente questo file per allineare il progetto su vari computer.

Anche nell’ipotesi di utilizzare un sistema di controllo di versione, basterà mettere sotto versione il solo file bower.json che ha tutti i riferimenti alle librerie utilizzate che verrano tirate giù in locale tramite un comando specifico che vedremo di seguito.

Come funziona Bower?

Un po’ come Composer, si compone di due parti:

  • il file bower.json, equivalente a composer.json, che contiene le specifiche del progetto
  • la cartella bower_components, equivalente alla vendor di composer, in cui vengono scaricate le dipendenze

Le dipendenze sono appunto i pacchetti (librerie/framework js/css etc..) contenuti nel registro di Bower che è possibile installare tramite gli appositi comandi Bower.

Vediamo ora come generare il bower.json ma prima assicuriamoci di aver installato Bower. Se avete già node.js installato (sennò scaricate ed installate) sarà sufficiente lanciare il comando:

$ npm install -g bower

(sintassi piuttosto autoesplicativa, la -g sta per global e va utilizzata la prima volta soltanto per installare Bower a livello globale sulla macchina in modo che il comando bower sia poi disponibile ovunque nel sistema).

Fatto ciò, ovunque nel terminale digitando bower -v dovremmo ottenere il numero di versione. Anche questo è bene ogni tanto aggiornarlo.

Ora siamo pronti per configurare Bower. Ci portiamo nella cartella del progetto (poi starà a voi scegliere in quale posizione è meglio collocare i file, ma mediamente si mette allo stesso livello del task runner e delle cartelle di output dei JS e CSS compilati per non dover digitare URL infinitamente lunghe o complicate come vedremo poi).

Per generare il file bower.json ci viene in aiuto un suo comando nativo (molto comodo):

$ bower init

Questo lancia la procedura di compilazione del file, ci verranno chieste un po’ di informazioni:

  1. name (proposta di nome): tra parentesi viene proposto un nome di default, che poi è il nome della cartella in cui ci troviamo. Se ci piace possiamo premere invio, altrimenti digitate il nome del progetto. Il nome dovrebbe rispettare le regole per un URL, quindi essere in lettere minuscole, senza spazi o comunque sostituiti da ‘-’, può contenere lettere e numeri, può contenere trattini e punti, ma non può iniziare o finire con questi. Inoltre punti e trattini consecutivi non sono ammessi. Il tutto per un massimo di 50 caratteri. Questo è l’unico ‘campo’ obbligatorio.
  2. description: descrizione del progetto per un massimo di 140 caratteri (è utile compilarlo nel caso il vostro sia un progetto pubblico condiviso altrimenti è a vostra discrezione)
  3. main file: specifica un file principale per tipo, necessari affinché il pacchetto funzioni. Es. abbiamo molteplici file .less che vengono importati tutti in style.less? Allora quest’ultimo sarà il file principale per il tipo less. Stessa cosa per JS: se poniamo il caso di avere script1.js e script2.js uniti in un unico js chiamato scripts.js, allora questo sarà il file principale JS. Questi file non vengono usati direttamente da Bower, ma sono messi in questo modo a disposizione di terzi. Ci sono degli strumenti, infatti, che estrapolano queste informazioni per copiarli od utilizzarli all’interno di script, come bower-installer che copia tutti i main file delle dipendenze nella cartella specificata o il modulo per task runner main-bower-files che permette di chiamarli con una funzione che li unisca tutti (è possibile che unisca a cascata anche tutti i main file delle dipendenze delle dipendenze, qualcuno suggerisce di risolverla con regole di overrides). Questi due sono per fare un esempio, probabilmente là fuori ci sono altre funzionalità.
  4. what types of modules does this package expose?, specifica il tipo di modulo definito nel file principale JS. Può essere una o più voci delle seguenti:
    1. amd, modulo javascript compatibile con AMD, come require.js, usa define() nella sintassi
    2. es6, modulo javascript compatibile con ECMAScript 6 modules, usa import ed export nella sintassi
    3. globals, modulo javascript che si aggiunge al namespace globale, usando la sintassi window.namespace o this.namespace
    4. node, modulo javascript compatibile con node e common.js, usa module.exports nella sintassi
    5. yui, modulo javascript compatibile con YUI modules, usa YUI.add() nella sintassi

Per sapere cosa sono i moduli Javascript qui una lettura in inglese che lo spiega molto bene, ma in buona sostanza significa scrivere codice riutilizzabile e distribuibile, dove ogni modulo è costituito da un gruppo di file che insieme implementano una specifica funzionalità. Quindi qui si tratta di definire quale “metodo di scrittura codice” verrà utilizzato.

  1. keywords: le parole chiave che descrivono il progetto, rispettano le stesse regole del nome pacchetto
  2. authors (proposta): tra parentesi viene proposto un nome di default + email, si può confermare con invio o specificare a fianco. È possibile inserire più coppie autore-email-url separandoli con una virgola, l’output sarà il seguente:
"authors": [
  "Bitbull",
  "Bitbull <info@bitbull.it>",
  "Bitbull <info@bitbull.it>; (http://bitbull.it)"
]

Oppure si può scrivere anche in questo modo:

"authors": [
  { "name": "Bitbull" },
  { "name": "Bitbull", "email": "info@bitbull.it" },
  { "name": "Bitbull", "email": "info@bitbull.it", "homepage": "http://bitbull.it" }
]
  1. license (MIT): tipo di licenza, scegliere la più adatta per il progetto (scegliere una licenza, inserire un identificatore di licenza SPDX oppure un URL)
  2. homepage: url del progetto in cui sono contenute informazioni per l’utilizzo del pacchetto, utile se si tratta di un progetto pubblico che verrà aggiunto al registro
  3. set currently installed components as dependencies? (Y/n): chiede se installare come dipendenza tutto il contenuto di bower_components. Essendo questa la prima volta che lo lanciamo la nostra cartella sarà vuota per cui la risposta è indifferente. Può essere utile rispondere Y in caso fossimo certi che in bower_components ci siano solo elementi inerenti il progetto, che magari per distrazione non sono stati aggiunti come dipendenze (omettendo insomma il flag --save), perché così facendo provvederà lui ad aggiornare il bower.json
  4. add commonly ignored files to ignore list? (Y/n): aggiunge alla lista degli ignore file comuni, sono in pratica quei file o cartelle che si vuole evitare vengano scaricati da chi utilizzerà il vostro pacchetto (per esempio è inutile far installare tutta la bower_components di un pacchetto ai fini dell’utilizzo dello stesso)
  5. would you like to mark this package as private which prevents it from being accidentally published to the registry? (y/N): nel caso il nostro progetto non debba essere pubblicato nel registro dei pacchetti, si risponderà Y a questa domanda, altrimenti (indovina un po’?) N. Con private settato a true il comando per la pubblicazione del pacchetto, che vedremo in seguito, non funzionerà.

L’intervista è finita. Bower ti propone ora la bozza di quanto generato sulla base delle tue risposte. Se è tutto corretto puoi confermare con Y.

Ecco un esempio di un bower.json completo:

{
  "name": "bower-spiegato-ai-backend",
  "authors": [
    "Bitbull <info@bitbull.it> (http://bitbull.it)"
  ],
  "description": "Un bower.json di esempio",
  "main": [
    "js/script.js",
    "src/less/style.less"
  ],
  "moduleType": [
    "amd",
    "globals",
    "node"
  ],
  "keywords": [
    "for",
    "dummies",
    "bower",
    "bitbull"
  ],
  "license": "MIT",
  "homepage": "http://bitbull.it",
  "private": true,
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components",
    "test",
    "tests"
  ]
}

A queste info è possibile aggiungere il riferimento al repository se presente:

"repository": {
  "type": "git",
  "url": "git://github.com/bitbull-team/bower-spiegato-ai-backend.git"
}

Ora si può passare all’installazione dei pacchetti che ci servono, prendiamo per esempio il classico jQuery.

Se conosciamo già il nome del repo possiamo installarlo direttamente altrimenti è possibile fare una ricerca direttamente da terminale con:

$ bower search jquery

Ne verrà fuori una sfilza che non finisce più, normalmente quello corretto/ufficiale si trova in alto, ma verifichiamo sempre che il repo sia giusto:

jQuery https://github.com/jquery/jquery.git
jquery https://github.com/jquery/jquery-dist.git
jquery.x https://github.com/jljLabs/jquery.x.git
jquery.Q https://github.com/jsbuzz/jQuery_Q.git
jt_jquery https://github.com/vicanso/jt_jquery.git
jquery-m https://github.com/meetup/jquery.git
[..]

Installiamo perciò il primo ricordandoci di usare la dicitura --save che ci assicura che venga inserito nelle dipendenze richieste in produzione:

$ bower install jQuery --save

Il nostro bower.json avrà in fondo ora un blocco in più:

"dependencies": {
  "jQuery": "^3.1.0"
}

con la specifica della nostra dipendenza e relativa versione installata. Per installare un componente in una specifica versione bisogna scrivere:

$ bower install bootstrap#2.0.0 --save

Possiamo continuare ad aggiungere dipendenze tramite riga di comando oppure se conosciamo già nome e versione elencarli direttamente in questo blocco:

"dependencies": {
  "jQuery": "^3.1.0",
  "bootstrap": "~3",
  "font-awesome": "~4"
}

e installarli tutti assieme con:

$ bower install

I simboli ^ e ~ che precedono le versioni sono dei vincoli di versione e significano rispettivamente:

  • ^: consente cambiamenti che non modificano la cifra (che non sia uno zero) più a sinistra. In altre parole, questo permette aggiornamenti di PATCH e MINORI per le versioni 1.0.0 e superiori, aggiornamenti di PATCH per le versioni 0.x> = 0.1.0, e nessun aggiornamento per le versioni 0.0.X. Nel caso di jQuery ^ 3.1.0 significa che accetta tutte le versione tra la 3.1.0 compresa e la 4.0.0. esclusa (altri esempi)
  • ~: consente modifiche a livello di PATCH se è specificata una versione MINORE sul comparatore. Consente lievi modifiche a livello MINORE, se invece non lo è. Nel caso di bootstrap ~3 vuol dire che accetta tutte le versioni tra la 3.0.0 compresa alla 4.0.0 esclusa (altri esempi)

considerando la regola di Semantic Versioning per la scrittura del numero di versione che prevede sia MAJOR.MINOR.PATCH. Si possono poi usare anche i simboli di comparazione >, <, >=, <=.

Vi sono poi altri due modi di installare i componenti tramite riga di comando, una è quella di omettere il flag --save:

$ bower install jQuery

questo installerà normalmente la libreria nella cartella bower_components ma non aggiornerà il bower.json con questa dipendenza. È utile se si vuol testare un componente ma non si sa ancora se farà parte o meno del progetto.

L’altra è quella di usare il flag --save-dev che installa il componente come dipendenza delegata al solo sviluppo:

$ bower install jasmine --save-dev

Utile per installare componenti che servono soltanto durante la fase di sviluppo e che non devono andare in produzione. Un esempio fra tutti, gli script di unit test:

"devDependencies": {
  "jasmine-core": "jasmine#^2.4.1"
}

Qualora si volesse solo installare le dipendenze di produzione basterà aggiungere il flag -p:

$ bower install -p

Un altro modo per configurare tutti i componenti utili al progetto è di installare tutti i pacchetti necessari tramite bower install e successivamente lanciare bower init per la creazione del bower.json assicurandoci di rispondere Y alla domanda: set currently installed components as dependencies?.

Come già detto, il bower.json è indispensabile ed è l’unico che va messo sotto versione (tralasciando quindi la cartella bower_components). Quando viene scaricato il repo del nostro progetto, basterà portarsi tramite terminale nella cartella contenente il bower.json e lanciare bower install affinché crei e popoli la cartella bower_components di tutte le dipendenze specificate nel json. È errore comune lanciare una compilazione gulp o grunt che si basa su tali dipendenze senza aver prima lanciato bower install.

E adesso? Come si usa?

Installate tutte le librerie utili al progetto, possiamo finalmente servircene in pagina. Ci si può collegare direttamente ai file nella cartella bower_components:

<script src=”bower_components/jquery/dist/jquery.min.js”></script>

però non è molto consigliabile perché comporta dover pubblicare in produzione anche tutta questa cartella che contiene di fatto molti file, tra cui gli originali, che occuperebbero spazio inutile.

Oppure inserirli nel nostro task runner affinché li unisca e minifichi nell’unico file di output pronto per la produzione. Vediamo un esempio con Gulp:

gulp.task('js', function() {
  var scripts = [
    'bower_components/jquery/dist/jquery.js',
    'src/js/mio-script.js'
  ];

  var stream = gulp
    .src(scripts)
    .pipe(concat('script.js'));

  if (config.uglifyJS === true) {
    stream.pipe(uglify());
  }

  return stream
    .pipe(gulp.dest('js'));
});

Gli esempi si riferiscono alla libreria JS di jQuery, ma possono essere anche applicati nel caso di file css o less/sass ovviamente.

Utilizzando Bower in questo modo è facile intuire che nel momento in cui lanciamo un aggiornamento all’ultima versione di un componente questo si aggiornerà per il progetto poiché gli URL ai sorgenti di norma non cambiano. Questo ci evita i vecchi metodi dello andare sul sito ufficiale del plugin, scaricare il sorgente, caricarlo nella cartella progetto, nominarlo correttamente affinché coincida con l’URL usato nel codice e rifarlo ogni volta.

Ma come si aggiorna un componente?

Facile.

$ bower update jQuery

dove jQuery è il nome esatto del pacchetto (il nome è case sensitive).

Vi sono poi altri comandi utili da sapere:

$ bower info jQuery

restituisce info sul componente, tra cui url del progetto, versione presente in locale e tutte le versioni disponibili.

$ bower home jQuery

apre l’URL del componente nel browser

$ bower uninstall jQuery

disinstalla il componente cancellando la sua cartella da bower_components però non aggiorna il bower.json (che pecca!) quindi andrà corretto a mano.

$ bower prune

ripulisce bower_components di tutti i componenti che non risultano come dipendenze (sia di produzione che di sviluppo) nel bower.json.

$ bower lookup jQuery

restituisce l’URL del progetto per un rapido confronto.

E se volessi registrare un pacchetto?

Se volessimo mettere a disposizione una nostra libreria o framework ed aggiungerli così al registro Bower, in modo da poterla installare tramite i semplici comandi da terminale appena visti, bisogna assicurarsi innanzitutto che il nostro modulo rispetti alcune regole:

  1. deve contenere un bower.json conforme alle regole di scrittura viste durante bower init e che sono riassunte qui
  2. il pacchetto deve utilizzare i tag git secondo la semantica di versione (è ammesso il prefisso ‘v’)
  3. dev’essere pubblicamente disponibile ad un github end point (URL), tipo git://github.com/{{proprietario}}/{{pacchetto}}.git

Fatto questo si può caricare tramite questo comando:

$ bower register bower-spiegato-ai-backend git://github.com/bitbull-team/bower-spiegato-ai-backend.git

dove bower-spiegato-ai-backend è il nome del pacchetto contenuto nel nostro bower.json e il link è quello al repository.

Ora chiunque potrà installare il nostro pacchetto semplicemente digitando:

$ bower install bower-spiegato-ai-backend

Figo no?

Esiste anche un modo per cancellare il pacchetto dal registro, previa autenticazione su Github per confermare di essere un contributore del repository:

$ bower login

che vi chiederà di digitare user e pass e solo dopo avvenuta autenticazione sarà possibile eseguire:

$ bower unregister bower-spiegato-ai-backend

La cancellazione del pacchetto dal registro è però, al momento, disabilitato, sicché.

Per concludere, è possibile abbinare al bower.json un file di configurazione per cambiare alcune impostazioni, tra cui il percorso della cartella bower_components.

Per fare ciò, bisogna creare un file chiamato .bowerrc contenente al suo interno un json, di seguito la specifica per cambiare cartella alla bower_components:

{
  "directory": "app/bower-files"
}

Si possono specificare moltissime altre configurazioni che sono spiegate qui.

E con questo finisce il tour nel fantastico mondo di Bower. Ora è tutto chiaro, collega?

Articolo scritto da