Una guida per smettere di dipendere da una vecchia libreria e usare la nuova sintassi JavaScript restando compatibili con il maggior numero di browser.
Recentemente ho iniziato una nuova collaborazione con un’azienda che ha un sito WordPress in piedi da diversi anni e dato che copro il ruolo di Front End Developer uno dei primi task che mi sono stati assegnati è stato rifattorizzare il codice jQuery presente.
Il sito sul quale sto lavorando è in piedi da moltissimi anni, il tema ha visto il suo primo commit nel 2015, e in casi come questo generalmente è preferibile sviluppare un nuovo tema da zero.
Ma non sempre è possibile.
Il team è composto da decine di sviluppatori e molte sono state le funzionalità aggiunte nel tempo che, senza l’appropriata documentazione, sono difficili da duplicare in un nuovo progetto.
In molti casi l’approccio migliore è rifattorizzare il codice esistente con l’obiettivo di diminuire le dipendenze rendendo il codice più performante e facile da comprendere.
Ed è quello che mi hanno chiesto di fare.
Il primo step è stato proprio quello di identificare la dipendenza più vecchia e lenta per rifattorizzare quella.
Oggi possiamo fare a meno di jQuery?
jQuery è stato una libreria che ha guadagnato moltissima popolarità perché, oltre a offrire una sintassi più semplice da comprendere, rendeva il nostro codice compatibile con molti browser.
Ai tempi, stiamo parlando dei primi anni 2000, il mercato dei browser era molto “confuso”.
Ciascuno implementava nuove funzionalità come meglio credeva e i JavaScript engine non erano performanti come quelli di oggi perché, diciamoci la verità, JavaScript era visto soltanto come un linguaggio di ripiego.
jQuery ha il merito di aver standardizzato molto del codice che scrivevano gli sviluppatori e molti approcci che sono stati proposti in questa libreria sono stati implementati nella nuova sintassi JavaScript che scriviamo tutti i giorni.
Quello che voglio fare in questo articolo è mostrarti che oggi si lavora bene anche senza jQuery.
Tutte gli esempi che ti mostrerò con questo articolo sono compatibili da IE8+, considerando che jQuery supporta IE9+ il tuo codice sarà ancora più compatibile.
Generalmente utilizzare codice vanilla JS rispetto a jQuery ci permette di avere un codice che è molto più performante, in molti casi il codice JavaScript batte in performance quello di jQuery 10 a 1.
Quindi se sei interessato a scrivere codice più performante e compatibile per i tuoi progetti continua a leggere.
Rifattorizzare codice jQuery in JavaScript
Rifattorizzare il codice è una pratica nella scrittura di applicazioni che ha lo scopo di modificare il codice sorgente per renderlo più semplice da leggere, più performante e generalmente più moderno.
Non sempre è possibile ottenere tutti e tre i benefici, magari una certa struttura è più performante ma meno leggibile, ma diciamo che in generale dovremmo cercare di raggiungerli tutti.
Per il resto di questo articolo ti presenterò alcuni dei codici che ho sostituito, rifattorizzato quindi, partendo dall’esempio in jQuery per arrivare a quello con puro ES6+.
Spero che le informazioni che troverai saranno tanto utili quanto lo sono state per il sottoscritto.
Smetti di usare il $
Sicuramente una delle caratteristiche più apprezzate nella libreria jQuery è la selezione degli elementi resa incredibilmente semplice grazie al $
.
Prima di jQuery selezionare un elemento era sempre stato complicato, JavaScript offriva diversi approcci ma richiedevano tanti caratteri e ricordarsi il funzionamento di ciascuna era semplicemente doloroso.
getElementById()
, getElementsByClassName()
, getElementsByName()
, getElementsByTagName()
erano le funzioni principali che ci permettevano di muoverci nel DOM, ma erano anche molto lontane dalla sintassi dei selettori CSS.
Grazie a jQuery è diventato possibile selezionare un elemento con la stessa naturalezza con la quale si scrive un selettore CSS.
Scrivere $('h2.tit')
era diventato una seconda natura per selezionare i titoli di secondo livello con classe tit
. E via dicendo per qualsiasi altro selettore CSS ti passi per la testa.
Tutto quello che viene inserito in $()
viene considerato come un selettore CSS.
$('#box'); // Seleziono elemento con id box $('li.even'); // Seleziono tutti i li con classe even $('.cards p').first(); // Selezione il primo paragrafo in un .cards
Questo approccio è stato tanto efficace che è stato introdotto nella sintassi ES6 attraverso i metodi querySelector()
e querySelectorAll()
:
document.getElementById('box'); // Seleziono elemento con id box document.querySelectorAll('li.even'); // Seleziono tutti i li con classe even document.querySelector('.cards p'); // Selezione il primo paragrafo in un .cards
Nell’esempio precedente ho mantenuto getElementById()
perchè risulta essere ancora molto performante quando dobbiamo selezionare un elemento dal suo id
.
Se senti già la mancanza del $
girando in rete ho trovato qualche funzione che potrebbe aiutarti.
// Seleziona da document var $ = function (selector) { return document.querySelector(selector); };
Con questa prima utility function puoi rivivere l’esperienza di scrivere $()
utilizzando querySelector
dietro le quinte senza dover caricare ~30kb di libreria jQuery che sarebbe utilizzata solo per quello.
Attenzione a quello che fai
Poco fa ti ho suggerito un approccio che ti permette di creare il tuo querySelector
richiamandolo come $
ma fai molta attenzione perché se nel tuo progetto usi jQuery o altre librerie che usano questo carattere potresti incontrare diversi problemi.
La funzione $()
utilizzata in questo modo avvia la ricerca degli elementi sempre da document
, l’oggetto che contiene tutta la pagina. querySelector
e querySelectorAll
sono metodi molto utili perché possiamo anche dichiarare un elemento conteitore.
const cardsContainer = document.querySelectorAll('.card'); const cardTitle = cardsContainer.querySelectorAll('.card--title');
Questo esempio mostra come utilizzare un insieme di elementi già selezionati come base di partenza per un nuovo querySelectorAll
.
Per imitare questa caratteristica e utilizzare comunque il $()
basta avere le seguenti funzioni:
// Seleziona un singolo elemento con contenitore var $ = function (selector, parent) { return (parent ? parent : document).querySelector(selector); }; // Semplice funzione per avere un array di tutti gli elementi var $$ = function (selector, parent) { return Array.prototype.slice.call((parent ? parent : document).querySelectorAll(selector)); };
Adesso hai $()
per selezionare un singolo elemento e $$()
per selezionare tutti quelli corrispondenti.
Se puoi vuoi fare una personalizzazione ancora più accurata e lasciare che sia JavaScript a decidere quando richiamare la funzione migliore in base al selettore potresti utilizzare questo esempio.
// Funzione che decide in automatico cosa fare function $(selector, context) { var context = context || document var selectorType = 'querySelectorAll' var is_single_element = selector.indexOf('#') === 0 if (is_single_element) { selectorType = 'getElementById' selector = selector.substr(1, selector.length) } var results = context[selectorType](selector) if (is_single_element) { return results } else { return [].slice.call(results) } }
Inserire elementi nel DOM
Spesso capita di avere la necessità di aggiungere dinamicamente degli elementi all’interno di una pagina. Con jQuery il lavoro era molto semplificato perché erano state create diversi metodi specifici.
Prendiamo il seguente codice HTML come base per questo esperimento.
<div id="comments"> <p class="comment">Primo commento.</p> <p class="comment">Secondo commento.</p> </div> <form> <textarea id="commentContent"></textarea> <button>Pubblica commento</button> </form>
In questo caso vogliamo mostrare il commento inserito in #commentContent
all’interno della lista di elementi presente sopra.
Con jQuery uno dei tanti approcci potrebbe essere:
var commentContent = $('#commentContent').val() $('#comments').append('<p class="comment">' + commentContent + '</p>')
Il codice è abbastanza semplice da leggere e il metodo append()
ci permette di aggiungere il nuovo .comment
come ultimo elemento della lista, anche in ES6 si può scrivere qualcosa di molto simile.
const commentContent = document.getElementById('commentContent').value; const comments = document.getElementById('comments'); comments.insertAdjacentHTML('beforeend', `<p class="comment">${commentContent}</p>`);
A prima vista questo codice risulta meno intuitivo ma stiamo soltanto usando un nuovo approccio.
Le stringhe template per restituire in un colpo solo codice HTML e il valore contenuto nella variabile commentContent
e il metodo insertAdjacentHTML()
che offre molte opzioni per inserire i nostri elementi.
Ricorda sempre, lo scopo di rifattorizzare il codice è quello di renderlo semplice, veloce e moderno. Non sempre si raggiungono tutti gli obiettivi ma si familiarizza presto con la nuova sintassi ?
Lavorare con le classi
Lavorare con le classi è essenziale per rendere le nostre pagine web dinamiche. Aggiungere o rimuovere una classe è una pratica incredibilmente comune in JavaScript e spesso viene usato per mostrare una parte di contenuto che prima era nascosto.
Anche in questo caso jQuery ci ha abituato male mettendoci a disposizione i seguenti metodi:
$(selector).addClass('bold'); $(selector).removeClass('bold'); $(selector).toggleClass('bold');
Fare la stessa cosa con JavaScript qualche anno fa avrebbe richiesto un sacco di codice in più e in effetti non avrebbe neanche avuto molto senso, in fin dei conti bastava aggiungere jQuery.
Oggi però esiste una valida alternativa che è nativa nel linguaggio e non ci sono più scuse per non eliminare questa dipendenza:
element.classList.add('bold') element.classList.remove('bold') element.classList.toggle('bold')
classList
è un DOMTokenList
che contiene tutte le classi definite in element
che puoi modificare grazie ai diversi metodi che mette a disposizione come visto qua sopra.
Lavorare con gli eventi
Gli eventi in JavaScript sono tutto e definiscono gran parte del nostro codice. Anche in questo caso jQuery è stato in grado di standardizzare la selezione dell’evento per il quale siamo in ascolto, magari un click
, ed eseguire la callback quando questo evento si presentava nel DOM.
jQuery rendeva questo compito ancora più semplice perché per la selezione di qualsiasi evento era richiesto un unico metodo:on()
.
$('#btn').on('click', function(evt) { alert('Grazie per aver cliccato!'); });
Abbiamo scritto un codice jQuery che in tre righe:
- seleziona l’elemento con id
btn
, - resta in ascolto di un evento
click
per l’elemento selezionato, - crea una funzione anonima che viene eseguita quando l’elemento viene cliccato
Oggi con JavaScript possiamo fare qualcosa di molto simile grazie a addEventListener()
:
const button = document.getElementById('btn'); button.addEventListener('click', (evt) => { alert('Grazie per aver cliccato!'); });
Mostra/nascondi un elemento
Continuiamo l’avventura nella manipolazione degli elementi presenti nel DOM andando ad analizzare un altro approccio molto comune in jQuery.
$(el).hide(); // Nascondi. $(el).show(); // Mostra.
Anche in questo caso sembra che la sintassi jQuery sia diretta al punto e ci siano pochi sprechi anche in termini di caratteri, ma il JavaScript che possiamo scrivere oggi non se la cava poi male:
// Compatibile IE8+ el.style.display = 'none'; // Nascondi. el.style.display = ''; // Mostra.
Questo è possibile perché puoi selezionare qualsiasi attributo di un elemento presente nel DOM con il carattere .
Nell’esempio precedente abbiamo selezionato l’attributo style
e impostato il valore della proprietà display
a none
(per nasconderlo) e poi abbiamo rimosso il valore per utilizzare quello originale definito nei CSS.
Aggiungi elemento prima/dopo
Hai già visto parte di questo codice precedentemente ma giusto per essere chiari voglio ricordarti come puoi aggiungere degli elementi con jQuery:
$(target).before(element); $(target).after(element); $(parent).append(element);
Tutti i metodi precedenti permettono di inserire l’elemento element
in target
con before()
che lo inserisce prima e after()
dopo.
append()
si occupa maggiormente della posizione dell’elemento ma inserisce sempre element
come ultimo elemento all’interno di parent
.
Con JavaScript vanilla si può fare in questo modo:
// Compatibile IE8+ target.insertAdjacentElement('beforebegin', element); target.insertAdjacentElement('afterend', element); parent.appendChild(el);
insertAdjacentElement()
racchiude al suo interno le funzionalità di before()
e after()
, basta cambiare il primo parametro e se poi vogliamo sfruttare la gerarchia dei nostri elementi possiamo sempre usare appendChild()
.
Lavorare con il contenuto
Ultimo aspetto che voglio trattare in questo articolo quando dobbiamo rifattorizzare del codice jQuery con JavaScript è la possibilità di lavorare con il contenuto presente all’interno degli elementi che selezioniamo.
jQuery ci ha permesso di ottenere questo tipo di contenuto in diversi modi:
// Ottieni il testo $(el).text(); // Ottieni Outer HTML $(el).prop('outerHTML'); // Ottieni Inner HTML $(el).html();
Allo stesso modo il codice JavaScript è molto semplice da scrivere:
// Compatibile IE9+ // Ottieni il testo el.textContent // Compatibile IE8+ // Ottieni Outer HTML el.outerHTML // Ottieni Inner HTML el.innerHTML
Con ES6 la situazione sembra ancora più semplice perché tutto quello che possiamo fare è accedere direttamente alle proprietà dell’elemento.
Conclusioni
In questo articolo abbiamo visto sette modi differenti per rifattorizzare vecchio codice jQuery con JavaScript moderno cosa che ci permette di ottenere diversi benefici.
Questi non sono gli unici approcci che possiamo prendere quando dobbiamo rifattorizzare codice jQuery, infatti gli ingegnieri di HubSpot hanno anche pubblicato You Might Not Need jQuery come riferimento.
Io ho preso diversi spunti da questo documento ma non tutti perché il mio obiettivo era mostrare la sintassi JavaScript che ci permette di sostituire in modo molto simile funzionalità che erano state introdotte con jQuery.
In diversi casi la sintassi jQuery è ancora molto più semplice rispetto alle soluzioni in JavaScript ma se il tuo obiettivo è quello di rimuovere completamente jQuery dai tuoi progetti potresti sostituire le funzionalità con altre librerie più leggere.
Per esempio, ajax()
è ancora un metoto più semplice da gestire in jQuery rispetto al classico codice JavaScript (almeno se non usi transpiler come Babel) e se pensi di caricare jQuery per questo singolo metodo potresti usare Axios per le tue chiamate AJAX.
Se hai trovato altri modi per sostituire jQuery nei tuoi progetti e vuoi condividerli con noi non esitare a commentare questo articolo. In alternativa potresti condividere questo articolo in modo che anche altri sviluppatori potranno scoprire come scrivere codice JavaScript più performante e moderno.
Una piccola azione per la creazione di un Web migliore per tutti.
Lascia un commento