Modernizr.load aka yepnope.js

Lo sviluppo delle tecnologie web sta attraversando una fase decisamente caotica. Nell’attesa che i nuovi standard raggiungano uno stadio di maggior maturità, nella speranza che i browser vadano a supportarli tutti allo stesso modo, e nell’attesa snervante che vengano abbandonate le vecchie versioni di Internet Explorer, sviluppare un sito o una webapp non è impresa da poco.

HTML5 fornisce nuovi elementi; CSS3 dispone di nuove proprietà e selettori; e che dire delle nuove API: geolocation, drag & drop, IndexedDB, Web Workers, local storage, ecc. ecc.
Strumenti eccezionali, che pian piano trasformeranno alla radice il web, ma che al momento creano perplessità per le notevoli differenze di supporto tra i browser.

Applicazioni e siti che facciano uso delle nuove tecnologie, allora, dovranno essere progettati in modo da garantire a chiunque l’accesso alle informazioni, anche a chi non dispone di un browser evoluto. Diventano indispensabili strumenti come Modernizr e yepnope.js.

Partiamo dal secondo e diciamo subito che si tratta di un loader di risorse, ossia di script e fogli di stile esterni al documento principale. Ma non si tratta di un loader qualunque: yepnope.js è un loader asincrono e condizionale. Le risorse non vengono caricate in ordine sequenziale, sebbene vengano eseguite in ordine sequenziale, e ciò può portare ad un notevole miglioramento nei tempi di caricamento ed esecuzione delle nostre webapp. E inoltre, è un loader condizionale, ossia permette di caricare una risorsa o un’altra a seconda dell’esito di un test.

Facciamo un esempio. Supponiamo di voler caricare la libreria jQuery dal Google CDN. Ma supponiamo pure di non fidarci al 100% di Google e quindi prevediamo una soluzione di fallback: se il Google CDN è giù, carichiamo la nostra versione locale della libreria:

yepnope([{
  load: 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js',
  callback: function (url, result, key) {
    if (!window.jQuery) {
      yepnope('js/libs/jquery-1.7.2.min.js');
    }
  }
}]);

La proprietà load carica la risorsa, mentre callback esegue la funzione anonima solo quando la risorsa sarà disponibile. Nell’esempio, la funzione di callback verifica l’esistenza dell’oggetto jQuery: in caso contrario, ossia nella remota eventualità che il CDN non sia disponibile, si provvede a caricare la versione locale richiamando ancora yepnope.

Ovviamente, qui non abbiamo la pretesa di fornire una guida al loader yepnope.js, e dunque rinviamo alla documentazione online per ogni approfondimento.

Passiamo a Modernizr e, in particolare, al metodo Modernizr.load, che fa esattamente la stessa cosa: carica risorse esterne. E lo fa esattamente allo stesso modo, dato che la libreria incorpora lo stesso codice di yepnope.js. E allora perché scegliere l’uno al posto dell’altro? In generale direi che, se nelle nostre app si fa ricorso a Modernizr, non vale la pena caricare yepnope.js.

Facciamo un esempio un po’ più complesso, in cui si faccia ricorso a Modernizr.load. Testiamo il supporto del tipo di input date: in caso negativo, offriremo all’utente il datepicker di jQuery UI; dunque il browser dovrà caricare le librerie jQuery e jQuery UI, oltre che il template lightness e il nostro script:

Modernizr.load([{
  test: Modernizr.inputtypes && Modernizr.inputtypes.date,
  // Grab Google CDN's jQuery, with a protocol relative URL; fall back to local if offline
  nope: [
    'timeout=2000!https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js',
    'css/ui-lightness/jquery-ui-1.8.21.custom.css',
    'js/libs/jquery-ui-1.8.21.min.js',
    'js/script.js'
  ],
  callback: {
    "jquery.min.js": function(url, result, key){
      if( !window.jQuery ){
        Modernizr.load('js/libs/jquery-1.7.2.min.js');
        console.log('local copy of jQuery loaded');
      }else{
        console.log('Google CDN copy of jQuery loaded');
      }
      console.log(url);
    },
    "jquery-ui-1.8.21.custom.css": function(url, result, key){
      console.log('jQuery UI template loaded');
      console.log(url);
    }, 
    "jquery-ui-1.8.21.min.js": function(url, result, key){
      if( window.jQuery.ui ){
        console.log('jQuery UI loaded');
      }
      console.log(url);
    },
    "script.js": function(url, result, key){
      console.log('script loaded');
      console.log(url);
    }
  }
}]);

Ed ecco la funzione principale di Modernizr: il test sul supporto di features proprie di HTML5. Nell’esempio si tratta del tipo di input date. Nel caso il test sia negativo, ossia il browser non supporti il tipo date, andremo a caricare le quattro risorse indicate nella proprietà nope. La prima URL punta alla versione 1.7.2 di jQuery ospitata dal Google CDN; timeout=2000! impone un timeout di due secondi, scaduti i quali viene eseguita comunque la callback (il timeout predefinito è di 10 secondi). La seconda URL punta al template lightness di jQuery UI, ospitato sul nostro server. La terza URL punta alla versione 1.8.21 di jQuery UI, preferita alla versione 1.8.17 al momento presente sul CDN. Infine, l’ultima URL punta al nostro script.

Il campo input type=date come reso da Opera. Opera non carica le librerie jQuery e jQuery UI

Esattamente come yepnope.js, il caricamento delle risorse è asincrono, sebbene l’esecuzione sia sincrona: lo script successivo viene quindi eseguito solo dopo l’esecuzione del precedente.

E poi le callback. Come yepnope, Modernizr.load permette di associare una chiave ad ogni funzione di callback, in modo da renderla facilmente individuabile. La chiave non è obbligatoria, e le callback sono eseguite in successione, ma quando le risorse si moltiplicano, conviene assegnare una chiave che permetta di capire a cosa si riferisca ognuna delle funzioni anonime. La chiave è data dal nome del file caricato.

La prima funzione viene eseguita al caricamento di jQuery dal CDN. Il suo unico compito è di verificare l’esistenza dell’oggetto jQuery e, in caso negativo, di caricare la versione locale della libreria.

La seconda callback viene eseguita solo alla conclusione dell’esecuzione della prima. Qui non ha uno scopo preciso, se non di mandare un messaggio alla console. Lo stesso accade con la terza e la quarta callback.

Firefox, Chrome e Safari non supportano il campo input di tipo date. Modernizr, quindi, procede al caricamento delle librerie e dello script JS, e il browser manda a video il datepicker di jQuery UI

Ora scaricate Modernizr e yepnope.js e provate lo script. Questo non verrà eseguito in Opera, che supporta il campo di tipo date, e le librerie non verranno caricate. Al contrario, Firefox, Chrome e Safari eseguiranno l’intero script e caricheranno le librerie.

Annunci