Come far funzionare un blog Jekyll offline utilizzando i Service Workers

Pubblicato: 2017-01-26

Byte brevi: lo sapevi che con l'avvento dei Service Workers, si potrebbe iniziare a far funzionare i siti Web offline! Tali app Web sono chiamate PWA (Progressive Web Apps). In questo tutorial, ti aiuterò a utilizzare un addetto ai servizi per far funzionare offline un blog/sito Web basato su Jekyll e alcune cose interessanti che ne derivano.

(NOTA : i frammenti di codice nell'articolo sono presi dal repository di codice del mio blog. Se necessario, può essere indirizzato. Se non conosci Jekyll, puoi leggere l'articolo della serie 3 sui trucchi CSS.)

SFONDO

In precedenza c'era una cache app basata su file YAML yuk, che era di natura molto codificata e non poteva essere utilizzata per memorizzare nella cache risorse e pagine Web in modo dinamico. Entrate, addetti ai servizi. Semplice API Javascript basata su eventi per eseguire il caching dinamico del lavoratore del servizio per archiviare le risorse, in modo che possano essere utilizzate per servire le pagine Web quando non c'è rete.

Gli addetti all'assistenza sono approdati in Chrome Canary nel 2014, ma le sue specifiche sono ancora in fase di revisione/aggiunta e progettazione. Nel 2015 e nel 2016, il team Chrome di Google ha diffuso ampiamente la voce di questa nuova tecnologia nei browser. Solo Apple non ha supportato questo (anche al momento della stesura di questo articolo) sui propri dispositivi (per ragioni sconosciute) [non partecipano attivamente a nessuna discussione sulle specifiche anche sui lavoratori dei servizi].

Che cos'è un lavoratore di servizio? Fondamentalmente, è un web worker con steroidi. Una caratteristica di un web worker è che tutte le attività di un web worker vengono eseguite separatamente (in modo asincrono) dal thread di esecuzione JavaScript principale (event loop). Questa funzione consente di eseguire attività ad alta intensità di CPU o memoria, ad esempio calcoli complicati senza compromettere le prestazioni dell'interfaccia utente dell'app Web.

Service Worker ci consente di memorizzare nella cache (memorizza a lungo) risorse, come JavaScript, CSS, HTML, immagini, file di caratteri nella cache di Service Worker del browser, quindi la prossima volta che l'utente carica quella pagina, viene caricata quasi istantaneamente . Inoltre, poiché in questa strategia di memorizzazione nella cache, il browser cerca prima la disponibilità delle risorse dalla cache del service worker, la pagina Web viene servita anche quando una è offline! Se una risorsa non è presente nella cache, viene inviata una richiesta di rete per recuperarla.

Service worker abilita anche le notifiche push che sono comuni da vedere su molti siti Web in questi giorni, inclusi Facebook, Whatsapp sul Web e Twitter. Parleremo principalmente della funzione offline. Questa procedura è specifica di Jekyll, tuttavia, la maggior parte del codice del service worker può essere generalmente applicato a qualsiasi sito Web.

Poiché Jekyll offre contenuti statici ( è un generatore di siti statici, duh! ), il nostro codice di service worker sarebbe molto semplice e facile da capire.

DIAMOCI DENTRO:

In tutte le pagine rilevanti, viene eseguito il seguente pezzo di script. Sta facendo le seguenti cose:

  1. Verifica dell'esistenza dell'API del lavoratore del servizio nel browser e registrazione del lavoratore del servizio.
  2. Quando l'operatore del servizio è stato attivato, metti un piccolo messaggio di brindisi/chip all'utente che il sito Web è pronto per essere utilizzato offline ora.
 funzione mostraOfflineToast() {
  let offlineToast = document.querySelector('.offline-ready');
  offlineToast.classList.add('attivo');
  setTimeout(funzione(){ 
    offlineToast.className = offlineToast.className.replace("active", "").trim();
  }, 5500);
}

// (1)
se (navigator.serviceWorker) {
  navigator.serviceWorker.register('/sw.js').then(function(reg) {
      se (!reg.installazione) ritorna;
      console.log("[*] ServiceWorker sta installando...");

      var lavoratore = reg.installazione;

      worker.addEventListener('statechange', function() {
          if (worker.state == 'ridondante') {
              console.log('[*] Installazione non riuscita');
          }
          if (worker.state == 'installato') {
              console.log('[*] Installazione riuscita!');
          }
          // (2)
          if (worker.state == 'attivato' && !navigator.serviceWorker.controller) {
            showOfflineToast();
          }
      });
  });
} 

gdad-s-river.github.io-(iPhone 6)

Puoi aggiungere questo pezzo di codice in un file ad esempio serviceWorker.html all'interno della directory include del tuo codice Jekyll e includerlo in default.html usando il motore di modelli liquidi di Jekyll

 <!DOCTYPE html>
<html>

  {% include head.html %}

  <corpo>
    {% include header.html %}

    <div class="page-content">
      <div class="wrapper">
        {{ contenuto }}
      </div>
    </div>

    {% include footer.html %}

    <!-- Contiene il codice sopra in un tag di script-->
    {% includi serviceWorker.html %} 

    <div class="offline-ready">Il sito è pronto per l'uso offline</div>
  </corpo>

</html>

Passiamo ora al codice dell'operatore di servizio effettivo che fa la magia. Questo codice risiede in sw.js nella radice del tuo codice Jekyll.

 //sw.js
---
disposizione: nullo
---

const staticCacheName = "gdad-s-river-static-v61";

console.log("installazione di service worker");

const filesToCache = [
  "/",
  {% per pagina in site.html_pages %}
    '{{ page.url }}',
  {% fine per %}
  {% per post in site.posts %}
    '{{ post.url }}',
  {% fine per %}

  // può essere automatizzato anziché manualmente
  "/assets/images/bhavri-github-callbacks.png",
  "/assets/images/bhavri-github-issues.png",
  "/assets/images/jakethecake-svg-line-anime.png",
  "/assets/images/svg-animated-mast-text-shapes-tweet.png",
  "css/main.css",
  "/di/",
  "/indice.html"
];

staticCacheName è la versione della cache che deve essere aggiornata ogni volta che apporto alcune modifiche alle risposte memorizzate nella cache (ad esempio apporto una modifica in un file CSS o in un post di blog). E sto solo definendo quali richieste voglio intercettare e memorizzare nella cache in un array (usato nel prossimo frammento).

 //sw.js

self.addEventListener("installa", funzione(e){
  self.skipWaiting();
  e.waitUntil(
    caches.open(staticCacheName).then(function(cache){
      return cache.addAll(filesToCache);
    })
  )
});

self.skipWaiting , vale a dire che ogni volta che questo file sw.js cambia, la versione più recente del service worker non dovrebbe essere accodata, ma resa attiva immediatamente (si potrebbe chiedere all'utente di aggiornare la pagina dando un messaggio come La pagina Web è stata aggiornata/modificata, fare clic su Aggiorna per caricare nuovi post o altro. ), buttando via la versione precedente.

java-e-android-square-ad-1

e.waitUntil citando dal sito Web MDN:

“Il metodo ExtendableEvent.waitUntil() estende la durata dell'evento. Nei service worker, prolungare la vita di un evento impedisce al browser di terminare il service worker prima che le operazioni asincrone all'interno dell'evento siano state completate.

Apro una cache denominata gdad-s-river-static-v61 , che restituisce una promessa con il mio nome cache, quindi chiamo cache.addAll (che utilizza l'API fetch in background), che recupera tutte le richieste nel array fornito e li memorizza nella cache.

Al prossimo frammento!

 //sw.js

self.addEventListener("activate", function(e){
  e.waitUntil(
    caches.keys().then(function(cacheNames){
      return Promise.all(
        cacheNames.filter(function(cacheName){
          return cacheName.startsWith("gdad-s-river-static-")
            && nomecache != staticCacheName;
        }).map(funzione(nomecache){
          restituisce cache.delete(nomecache);
        })
      )ß
    })
  )
});

Quando l'operatore del servizio si attiva, mi assicuro che qualsiasi lavoratore del servizio che non sia l'ultima versione venga eliminato. Ad esempio, se la mia ultima versione della cache è say gdad-s-river-static-v61 , e qualcuno è ancora su gdad-s-river-static-v58 , alla sua prossima visita, voglio che quel client non si preoccupi di pompare una versione alla volta, ma eliminare immediatamente quella versione per installare quella più recente.

 //sw.js

self.addEventListener("fetch", funzione(e){
  e.respondWith(
     caches.match(e.request).then(function(risposta) {
       risposta di ritorno || recuperare (e.richiesta);
     })
   )
});

Nell'evento di recupero, sto semplicemente dicendo al lavoratore del servizio come rispondere a una richiesta particolare fatta (dal momento che stiamo dirottando la risposta dando potere, i lavoratori del servizio lavorano solo su siti Web di origine https sicuri). Gli dico di abbinare la richiesta a quelle memorizzate nella cache nel browser e, se non trova quella particolare risposta alla richiesta, recuperala attraverso la rete, altrimenti servila dalla cache.

Tada! L'addetto ai servizi ha reso offline il blog basato su Jekyll!

SORPRESA! LA COSA BELLA:

Peccato: non funzionerebbe sui dispositivi iOS.

Se aggiungi un file manifest.json dell'app Web nella radice del progetto in questo modo:

 {
  "name": "gdad-s-river",
  "short_name": "gdad-s-river",
  "theme_color": "#2196f3",
  "background_color": "#2196f3",
  "display": "autonomo",
  "Scopo": "/",
  "start_url": "/",
  "icone": [
    {
     "src": "assets/images/favicon_images/android-icon-36x36.png",
     "misure": "36x36",
     "tipo": "immagine\/png",
     "densità": "0,75"
    },
    {
     "src": "assets/images/favicon_images/android-icon-48x48.png",
     "misure": "48x48",
     "tipo": "immagine\/png",
     "densità": "1.0"
    },
    {
     "src": "assets/images/favicon_images/android-icon-72x72.png",
     "misure": "72x72",
     "tipo": "immagine\/png",
     "densità": "1,5"
    },
    {
     "src": "assets/images/favicon_images/android-icon-96x96.png",
     "misure": "96x96",
     "tipo": "immagine\/png",
     "densità": "2.0"
    },
    {
     "src": "assets/images/favicon_images/android-icon-144x144.png",
     "misure": "144x144",
     "tipo": "immagine\/png",
     "densità": "3.0"
    },
    {
     "src": "assets/images/favicon_images/android-icon-192x192.png",
     "misure": "192x192",
     "tipo": "immagine\/png",
     "densità": "4.0"
    }
  ]
}

e aggiungilo nel file head.html all'interno del tag head,

 <testa>
 <!-- alcune cose -->
	<link rel="manifest" href="/manifest.json">
 <!-- alcune cose -->
</testa>

Quindi, alla seconda visita del tuo sito Web (entro 5 minuti), verrà chiesto all'utente di aggiungere il tuo sito Web alla schermata iniziale (per risiedere con un'icona, proprio come le altre app native), con cui sarai coinvolto proprio come una app.

Screenshot_20170123-232947

RISORSE

  • I dettagli delle funzionalità offline e delle strategie di memorizzazione nella cache del lavoratore dei servizi possono essere trovati nel ricettario offline di Jake Archibald di questo fantastico.
  • Un corso Udacity gratuito molto dettagliato su tutto ciò che avresti mai bisogno di sapere sugli addetti ai servizi e su IndexDB.

Hai trovato questo articolo su Jekyll Blog interessante e utile? Non dimenticare di condividere le tue opinioni e feedback.

Leggi anche : Ecosia — Il motore di ricerca che pianta alberi