วิธีรับบล็อก Jekyll ทำงานแบบออฟไลน์โดยใช้พนักงานบริการ

เผยแพร่แล้ว: 2017-01-26

ไบต์สั้น: คุณรู้หรือไม่ว่า ด้วยการถือกำเนิดของ Service Workers เราสามารถเริ่มทำให้เว็บไซต์ทำงานแบบออฟไลน์ได้! เว็บแอปดังกล่าวเรียกว่า PWAs (Progressive Web Apps) ในวิธีการนี้ ฉันจะช่วยให้คุณใช้พนักงานบริการเพื่อทำให้บล็อก/เว็บไซต์ที่ใช้ Jekyll ทำงานแบบออฟไลน์และมีสิ่งเจ๋งๆ ที่มาพร้อมกับมัน

(หมายเหตุ : ตัวอย่างโค้ดในบทความนำมาจากที่เก็บโค้ดในบล็อกของฉัน สามารถอ้างอิงได้หากต้องการ หากคุณยังใหม่กับ Jekyll คุณสามารถอ่าน 3 Series Article ใน CSS Tricks ได้)

พื้นหลัง

ก่อนหน้านี้เคยเป็น App Cache ที่ใช้ไฟล์ yuk YAML ซึ่งมีการเข้ารหัสที่ยากมากในธรรมชาติ และไม่สามารถใช้เพื่อแคชเนื้อหาและหน้าเว็บแบบไดนามิกได้ เข้ามา พนักงานบริการ. Javascript API แบบธรรมดาที่ใช้เหตุการณ์ธรรมดาเพื่อแคชพนักงานบริการแบบไดนามิกเพื่อจัดเก็บสินทรัพย์ เพื่อให้สามารถใช้เพื่อให้บริการหน้าเว็บเมื่อไม่มีเครือข่าย

พนักงานบริการลงจอดใน Chrome Canary ในปี 2014 แต่ข้อมูลจำเพาะยังคงได้รับการปรับปรุง/เพิ่มเติมและออกแบบ ในปี 2015 และ 2016 ทีมงาน Chrome ของ Google ได้เผยแพร่เทคโนโลยีใหม่นี้ในเบราว์เซอร์อย่างหนัก มีเพียง Apple เท่านั้นที่ไม่รองรับสิ่งนี้ (แม้ในขณะที่เขียนบทความนี้) บนอุปกรณ์ของพวกเขา (ด้วยเหตุผลที่ไม่ทราบสาเหตุ) [พวกเขาไม่ได้เข้าร่วมในการอภิปรายข้อมูลจำเพาะเกี่ยวกับพนักงานบริการด้วยเช่นกัน]

พนักงานบริการคืออะไร? โดยพื้นฐานแล้วมันเป็นพนักงานเว็บเกี่ยวกับสเตียรอยด์ คุณลักษณะหนึ่งของผู้ปฏิบัติงานบนเว็บคือ งานทั้งหมดของผู้ปฏิบัติงานเว็บทำงานแยกจากกัน (แบบอะซิงโครนัส) จากเธรดการเรียกใช้ JavaScript หลัก (วนรอบเหตุการณ์) ฟีเจอร์นี้ช่วยเรียกใช้งานที่ใช้ CPU หรือหน่วยความจำสูง เช่น การคำนวณที่ซับซ้อนโดยไม่กระทบต่อประสิทธิภาพของอินเทอร์เฟซผู้ใช้ของเว็บแอป

Service Worker ให้เราแคช (เก็บไว้นาน) ทรัพย์สิน เช่น JavaScript, CSS, HTML, รูปภาพ, ไฟล์ฟอนต์ในแคชของผู้ให้บริการแคชของเบราว์เซอร์ ดังนั้นครั้งต่อไปที่ผู้ใช้โหลดหน้านั้นจะถูกโหลดแทบจะในทันที . และเนื่องจากในกลยุทธ์การแคชนี้ เบราว์เซอร์จะค้นหาความพร้อมใช้งานของสินทรัพย์ก่อนจากแคชของเจ้าหน้าที่บริการ หน้าเว็บจึงใช้งานได้แม้ในขณะที่ออฟไลน์! หากไม่มีเนื้อหาในแคช คำขอเครือข่ายจะถูกส่งเพื่อดึงข้อมูล

พนักงานบริการยังเปิดใช้งานการแจ้งเตือนแบบพุชที่เห็นได้ทั่วไปในหลายเว็บไซต์ในทุกวันนี้ รวมถึง Facebook, Whatsapp บนเว็บและ Twitter เราจะพูดถึงคุณลักษณะออฟไลน์เป็นหลัก วิธีการนี้ใช้เฉพาะกับ Jekyll อย่างไรก็ตาม โดยทั่วไปแล้วรหัสพนักงานบริการส่วนใหญ่ใช้กับเว็บไซต์ใดก็ได้

เนื่องจาก Jekyll ให้บริการเนื้อหาแบบสแตติก ( เป็นเครื่องสร้างไซต์แบบคงที่ duh! ) รหัสพนักงานบริการของเราจึงเป็นพื้นฐานและเข้าใจง่าย

มากันเถอะ:

ในเพจที่เกี่ยวข้องทั้งหมด สคริปต์ต่อไปนี้จะถูกดำเนินการ มันทำสิ่งต่อไปนี้:

  1. ตรวจสอบการมีอยู่ของ API พนักงานบริการในเบราว์เซอร์และการลงทะเบียนพนักงานบริการ
  2. เมื่อพนักงานบริการเปิดใช้งานแล้ว ให้ส่งข้อความสั้นๆ สั้นๆ ว่า toast/chip ไปยังผู้ใช้ว่าเว็บไซต์พร้อมใช้งานแบบออฟไลน์แล้ว
 ฟังก์ชัน showOfflineToast() {
  ให้ offlineToast = document.querySelector('.offline-ready');
  offlineToast.classList.add('ใช้งานอยู่');
  setTimeout(ฟังก์ชัน(){ 
    offlineToast.className = offlineToast.className.replace("ใช้งานอยู่", "").trim();
  }, 5500);
}

// (1)
ถ้า (navigator.serviceWorker) {
  navigator.serviceWorker.register ('/sw.js').then (ฟังก์ชัน (reg) {
      ถ้า (!reg.installing) กลับมา;
      console.log("[*] ServiceWorker กำลังติดตั้ง...");

      var worker = reg.installing;

      worker.addEventListener ('statechange', ฟังก์ชัน () {
          if (worker.state == 'ซ้ำซ้อน') {
              console.log('[*] การติดตั้งล้มเหลว');
          }
          ถ้า (worker.state == 'ติดตั้ง') {
              console.log('[*] ติดตั้งสำเร็จ!');
          }
          // (2)
          ถ้า (worker.state == 'เปิดใช้งาน' && !navigator.serviceWorker.controller) {
            showOfflineToast();
          }
      });
  });
} 

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

คุณสามารถเพิ่มโค้ดชิ้นนี้ในไฟล์ที่บอกว่า serviceWorker.html ภายในไดเร็กทอรี include ของโค้ด Jekyll ของคุณและ รวม ไว้ใน default.html โดยใช้เอ็นจินการสร้างเทมเพลตเหลวของ Jekyll

 <!DOCTYPE html>
<html>

  {% รวม head.html %}

  <body>
    {% รวม header.html %}

    <div class="page-content">
      <div class="wrapper">
        {{ เนื้อหา }}
      </div>
    </div>

    {% รวม footer.html %}

    <!-- มีโค้ดด้านบนในแท็กสคริปต์-->
    {% รวม serviceWorker.html %} 

    <div class="offline-ready">ไซต์พร้อมใช้งานแบบออฟไลน์แล้ว</div>
  </body>

</html>

ตอนนี้เป็นรหัสพนักงานบริการจริงที่ทำมายากล รหัสนี้อยู่ใน sw.js ที่รูทของ Jekyll Code ของคุณ

 //sw.js
---
เลย์เอาต์: null
---

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

console.log("กำลังติดตั้งพนักงานบริการ");

const filesToCache = [
  "/",
  {% สำหรับหน้าใน site.html_pages %}
    '{{ page.url }}',
  {% สิ้นสุดสำหรับ %}
  {% สำหรับการโพสต์ใน site.posts %}
    '{{ post.url }}',
  {% สิ้นสุดสำหรับ %}

  // เป็นแบบอัตโนมัติแทนการป้อนด้วยตนเอง
  "/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",
  "/เกี่ยวกับ/",
  "/index.html"
];

staticCacheName คือเวอร์ชันแคชที่จะอัปเดตทุกครั้งที่ฉันทำการเปลี่ยนแปลงบางอย่างกับการตอบสนองที่แคชไว้ (เช่น ฉันทำการเปลี่ยนแปลงในไฟล์ CSS หรือโพสต์ในบล็อก) และฉันแค่กำหนดคำขอที่ฉันต้องการสกัดกั้นและแคชในอาร์เรย์ (ใช้ในตัวอย่างถัดไป)

 //sw.js

self.addEventListener ("ติดตั้ง", ฟังก์ชัน (e){
  self.skip รอ ();
  e. waitUntil(
    caches.open (staticCacheName) จากนั้น (ฟังก์ชัน (แคช){
      ส่งคืน cache.addAll (filesToCache);
    })
  )
});

self.skipWaiting กล่าวคือทุกครั้งที่ไฟล์ sw.js นี้เปลี่ยนแปลง เวอร์ชันใหม่กว่าของผู้ปฏิบัติงานบริการไม่ควรเข้าคิว แต่เปิดใช้งานทันที (อาจมีผู้ใช้แจ้งให้รีเฟรชหน้าเว็บโดยให้ข้อความเช่น หน้าเว็บได้รับการปรับปรุง/เปลี่ยนแปลง คลิก รีเฟรช เพื่อโหลดโพสต์ใหม่หรืออะไรก็ตาม ) เวอร์ชันเก่าทิ้งไป

java-and-android-square-ad-1

e.waitUntil อ้างจากเว็บไซต์ MDN:

“The ExtendableEvent.waitUntil() วิธีการขยายอายุของเหตุการณ์ สำหรับผู้ปฏิบัติงานบริการ การยืดอายุของเหตุการณ์จะป้องกันไม่ให้เบราว์เซอร์ยุติพนักงานบริการก่อนที่การดำเนินการแบบอะซิงโครนัสภายในเหตุการณ์จะเสร็จสิ้น”

ฉันเปิดแคชชื่อ gdad-s-river-static-v61 ซึ่งส่งคืนสัญญาด้วยชื่อแคชของฉัน จากนั้นฉันเรียก cache.addAll (ซึ่งใช้การดึงข้อมูล API ในพื้นหลัง) ซึ่งจะดึงคำขอทั้งหมดใน อาร์เรย์ที่จัดเตรียมไว้และแคชไว้

มาชมคลิปต่อไป!

 //sw.js

self.addEventListener ("เปิดใช้งาน", ฟังก์ชั่น (e){
  e. waitUntil(
    caches.keys().then(ฟังก์ชัน(cacheNames){
      กลับ Promise.all(
        cacheNames.filter (ฟังก์ชัน (ชื่อแคช){
          ส่งคืน cacheName.startsWith("gdad-s-river-static-")
            && cacheName != staticCacheName;
        }).map(ฟังก์ชัน(ชื่อแคช){
          ส่งคืน cache.delete (ชื่อแคช);
        })
      )ß
    })
  )
});

เมื่อพนักงานบริการเปิดใช้งาน ฉันมั่นใจว่าพนักงานบริการที่ไม่ใช่เวอร์ชันล่าสุดจะถูกลบ ตัวอย่างเช่น หากเวอร์ชันแคชล่าสุดของฉันคือ gdad-s-river-static-v61 และมีคนยังคงอยู่ใน gdad-s-river-static-v58 ในการเยี่ยมชมครั้งต่อไปของเขา/เธอ ฉันต้องการให้ไคลเอนต์นั้นไม่สนใจ ปั๊มทีละเวอร์ชัน แต่ให้ลบเวอร์ชันนั้นออกอย่างตรงไปตรงมาเพื่อติดตั้งเวอร์ชันล่าสุด

 //sw.js

self.addEventListener ("ดึงข้อมูล", ฟังก์ชัน (e){
  e.respondWith(
     caches.match (e.request) จากนั้น (ฟังก์ชั่น (ตอบสนอง) {
       ตอบกลับ || ดึงข้อมูล (e.request);
     })
   )
});

ในการดึงข้อมูล ฉันแค่บอกพนักงานบริการถึงวิธีการตอบสนองต่อคำขอเฉพาะที่ทำขึ้น (เนื่องจากเรากำลังแย่งชิงการตอบสนองที่ให้อำนาจ พนักงานบริการจะทำงานบนเว็บไซต์หรือที่รู้จักว่า https ที่ปลอดภัยเท่านั้น) ฉันบอกให้จับคู่คำขอกับคำขอที่แคชไว้ในเบราว์เซอร์ และหากไม่พบการตอบสนองต่อคำขอนั้นโดยเฉพาะ ให้ดึงข้อมูลผ่านเครือข่าย มิฉะนั้นจะให้บริการจากแคช

ธาดา! พนักงานบริการทำให้บล็อกขับเคลื่อน Jekyll ออฟไลน์!

เซอร์ไพรส์! สิ่งดีๆ:

คนเกียจคร้าน: สิ่งนี้จะไม่ทำงานบนอุปกรณ์ iOS

หากคุณเพิ่มไฟล์ web app manifest.json ที่รูทของโปรเจ็กต์ดังนี้:

 {
  "name": "gdad-s-river",
  "short_name": "gdad-s-แม่น้ำ",
  "theme_color": "#2196f3",
  "background_color": "#2196f3",
  "display": "แบบสแตนด์อโลน",
  "ขอบเขต": "/",
  "start_url": "/",
  "ไอคอน": [
    {
     "src": "assets/images/favicon_images/android-icon-36x36.png",
     "ขนาด": "36x36",
     "type": "image\/png",
     "ความหนาแน่น": "0.75"
    },
    {
     "src": "assets/images/favicon_images/android-icon-48x48.png",
     "ขนาด": "48x48",
     "type": "image\/png",
     "ความหนาแน่น": "1.0"
    },
    {
     "src": "assets/images/favicon_images/android-icon-72x72.png",
     "ขนาด": "72x72",
     "type": "image\/png",
     "ความหนาแน่น": "1.5"
    },
    {
     "src": "assets/images/favicon_images/android-icon-96x96.png",
     "ขนาด": "96x96",
     "type": "image\/png",
     "ความหนาแน่น": "2.0"
    },
    {
     "src": "assets/images/favicon_images/android-icon-144x144.png",
     "ขนาด": "144x144",
     "type": "image\/png",
     "ความหนาแน่น": "3.0"
    },
    {
     "src": "assets/images/favicon_images/android-icon-192x192.png",
     "ขนาด": "192x192",
     "type": "image\/png",
     "ความหนาแน่น": "4.0"
    }
  ]
}

และเพิ่มลงในไฟล์ head.html ภายในแท็ก head

 <head>
 <!-- ของบางอย่าง -->
	<link rel="manifest" href="/manifest.json">
 <!-- ของบางอย่าง -->
</head>

จากนั้น ในการเข้าชมเว็บไซต์ของคุณครั้งที่สอง (ภายใน 5 นาที) ผู้ใช้จะแจ้งให้เพิ่มเว็บไซต์ของคุณไปที่หน้าจอหลัก (เพื่อให้มีไอคอนอยู่ เช่นเดียวกับแอปที่มาพร้อมเครื่องอื่นๆ) ซึ่งคุณจะมีส่วนร่วมได้เช่นเดียวกัน แอพ

ภาพหน้าจอ_20170123-232947

ทรัพยากร

  • รายละเอียดของคุณสมบัติออฟไลน์ของพนักงานบริการและกลยุทธ์การแคชสามารถพบได้ในตำราอาหารออฟไลน์ของ Jake Archibald ที่ยอดเยี่ยมนี้
  • หลักสูตร Udacity ฟรีที่มีรายละเอียดมากเกี่ยวกับทุกสิ่งที่คุณจำเป็นต้องรู้เกี่ยวกับพนักงานบริการและ IndexDB

คุณพบว่าบทความนี้ในบล็อก Jekyll น่าสนใจและเป็นประโยชน์หรือไม่ อย่าลืมแบ่งปันมุมมองและข้อเสนอแนะของคุณ

อ่าน เพิ่มเติม : Ecosia — เครื่องมือค้นหาที่ปลูกต้นไม้