คู่มือเริ่มใช้งานฉบับย่อแบบออฟไลน์

Codelab นี้เป็นส่วนหนึ่งของหลักสูตรการฝึกอบรม Progressive Web App ที่พัฒนาโดยทีมการฝึกอบรมของ Google Developers คุณจะได้ประโยชน์สูงสุดจากหลักสูตรนี้หากคุณทํางานผ่าน Codelab ตามลําดับ

โปรดดูรายละเอียดทั้งหมดเกี่ยวกับหลักสูตรที่หัวข้อการพัฒนา Progressive Web App

บทนำ

ในห้องทดลองนี้ คุณจะใช้ Lighthouse เพื่อตรวจสอบมาตรฐาน Progressive Web App (PWA) ของเว็บไซต์ นอกจากนี้ คุณยังเพิ่มฟังก์ชันการทํางานออฟไลน์ด้วย Service Worker API ได้ด้วย

สิ่งที่คุณจะได้เรียนรู้

  • วิธีตรวจสอบเว็บไซต์ด้วย Lighthouse
  • วิธีเพิ่มความสามารถออฟไลน์ลงในแอปพลิเคชัน

สิ่งที่ควรทราบ

  • HTML, CSS และ JavaScript พื้นฐาน
  • ทําความคุ้นเคยกับสัญญา ES2015

สิ่งที่ต้องมี

  • คอมพิวเตอร์ที่มีสิทธิ์เข้าถึงเทอร์มินัล/Shell
  • การเชื่อมต่ออินเทอร์เน็ต
  • เบราว์เซอร์ Chrome (สําหรับ Lighthouse)
  • เครื่องมือแก้ไขข้อความ
  • ไม่บังคับ: Chrome ในอุปกรณ์ Android

ดาวน์โหลดหรือโคลนที่เก็บ pwa-training-labs จาก github และติดตั้ง Node.js เวอร์ชัน LTS

ไปที่ไดเรกทอรี offline-quickstart-lab/app/ แล้วเริ่มต้นเซิร์ฟเวอร์การพัฒนาในเครื่อง:

cd offline-quickstart-lab/app
npm install
node server.js

คุณจะยกเลิกเซิร์ฟเวอร์ได้ตลอดเวลาด้วย Ctrl-c

เปิดเบราว์เซอร์แล้วไปที่ localhost:8081/ คุณควรเห็นว่าเว็บไซต์นั้นเป็นหน้าเว็บที่ไม่ซับซ้อนและคงที่

หมายเหตุ: ยกเลิกการลงทะเบียน Service Worker และล้างแคชของ Service Worker ทั้งหมดสําหรับ Localhost เพื่อไม่ให้รบกวนห้องทดลอง ใน Chrome DevTools คุณจะดําเนินการได้โดยการคลิกล้างข้อมูลเว็บไซต์จากส่วนล้างพื้นที่เก็บข้อมูลของแท็บแอปพลิเคชัน

เปิดโฟลเดอร์ offline-quickstart-lab/app/ ในเครื่องมือแก้ไขข้อความที่ต้องการ โฟลเดอร์ app/ คือที่ที่คุณจะสร้างห้องทดลอง

โฟลเดอร์นี้มีสิ่งต่อไปนี้

  • โฟลเดอร์ images/ มีรูปภาพตัวอย่าง
  • styles/main.css เป็นสไตล์ชีตหลัก
  • index.html เป็นหน้า HTML หลักสําหรับเว็บไซต์ตัวอย่างของเรา
  • package-lock.json และ package.json ขึ้นอยู่กับทรัพยากร Dependency (การขึ้นต่อกันเพียงอย่างเดียวในกรณีนี้คือเซิร์ฟเวอร์การพัฒนาภายใน)
  • server.js เป็นเซิร์ฟเวอร์การพัฒนาในเครื่องสําหรับการทดสอบ
  • service-worker.js คือไฟล์ Service Worker (ปัจจุบันว่างเปล่า)

ก่อนที่จะเริ่มทําการเปลี่ยนแปลงกับเว็บไซต์ เราไปตรวจสอบกับ Lighthouse เพื่อดูว่ารายการไหนที่ปรับปรุงได้บ้าง

กลับไปที่แอป (ใน Chrome) แล้วเปิดแท็บการตรวจสอบของเครื่องมือสําหรับนักพัฒนาซอฟต์แวร์ คุณควรเห็นไอคอน Lighthouse และตัวเลือกการกําหนดค่า เลือก "Mobile" สําหรับอุปกรณ์ เลือกการตรวจสอบทั้งหมด เลือกตัวเลือกการควบคุม แล้วเลือกล้างพื้นที่เก็บข้อมูล ดังนี้

คลิกเรียกใช้การตรวจสอบ การตรวจสอบจะใช้เวลาสักครู่เพื่อดําเนินการให้เรียบร้อย

คำอธิบาย

คุณควรเห็นรายงานที่มีคะแนนในเครื่องมือสําหรับนักพัฒนาซอฟต์แวร์เมื่อการตรวจสอบเสร็จสมบูรณ์ คะแนนควรแสดงในลักษณะนี้ (คะแนนอาจไม่ตรงกันทุกประการ)

หมายเหตุ: คะแนนของ Lighthouse เป็นค่าโดยประมาณและอาจได้รับอิทธิพลจากสภาพแวดล้อมของคุณ (เช่น ในกรณีที่คุณเปิดหน้าต่างเบราว์เซอร์จํานวนมาก) ทั้งนี้คะแนนของคุณอาจไม่ตรงกับคะแนนที่แสดงที่นี่

และในส่วน Progressive Web App ควรมีลักษณะดังนี้

รายงานจะมีคะแนนและเมตริกใน 5 หมวดหมู่ ดังนี้

  • Progressive Web App
  • ประสิทธิภาพ
  • การช่วยเหลือพิเศษ
  • แนวทางปฏิบัติแนะนำ
  • SEO

จะเห็นได้ว่าแอปของเรามีคะแนนไม่ดีในหมวดหมู่ Progressive Web App (PWA) มาปรับปรุงคะแนนของเรากัน

โปรดใช้เวลาสักครู่เพื่อดูส่วน PWA ของรายงาน และดูว่าสิ่งใดขาดหายไป

ลงทะเบียน Service Worker

หนึ่งในความล้มเหลวที่ระบุในรายงานคือไม่มีการลงทะเบียน Service Worker ขณะนี้เรามีไฟล์ Service Worker ที่ว่างเปล่าที่ app/service-worker.js

เพิ่มสคริปต์ต่อไปนี้ที่ด้านล่างของ index.html ก่อนแท็กปิด </body>

<script>
if ('serviceWorker' in navigator) {
  window.addEventListener('load', function() {
    navigator.serviceWorker.register('service-worker.js')
      .then(reg => {
        console.log('Service worker registered! 😎', reg);
      })
      .catch(err => {
        console.log('😥 Service worker registration failed: ', err);
      });
  });
}
</script>

คำอธิบาย

โค้ดนี้จะลงทะเบียนไฟล์ Service Worker ของ sw.js ที่ว่างเปล่าเมื่อหน้าเว็บโหลดแล้ว แต่ไฟล์ Service Worker ปัจจุบันว่างเปล่าและจะไม่ดําเนินการใดๆ มาเพิ่มรหัสบริการในขั้นตอนถัดไปกัน

แคชทรัพยากรล่วงหน้า

ความล้มเหลวอีกอย่างที่ระบุในรายงานคือแอปไม่ตอบสนองด้วยรหัสสถานะ 200 เมื่อออฟไลน์ เราต้องอัปเดต Service Worker เพื่อแก้ปัญหานี้

เพิ่มโค้ดต่อไปนี้ในไฟล์ Service Worker (sw.js)

const cacheName = 'cache-v1';
const precacheResources = [
  '/',
  'index.html',
  'styles/main.css',
  'images/space1.jpg',
  'images/space2.jpg',
  'images/space3.jpg'
];

self.addEventListener('install', event => {
  console.log('Service worker install event!');
  event.waitUntil(
    caches.open(cacheName)
      .then(cache => {
        return cache.addAll(precacheResources);
      })
  );
});

self.addEventListener('activate', event => {
  console.log('Service worker activate event!');
});

self.addEventListener('fetch', event => {
  console.log('Fetch intercepted for:', event.request.url);
  event.respondWith(caches.match(event.request)
    .then(cachedResponse => {
        if (cachedResponse) {
          return cachedResponse;
        }
        return fetch(event.request);
      })
    );
});

จากนั้นกลับไปที่เบราว์เซอร์และรีเฟรชเว็บไซต์ ตรวจสอบคอนโซลเพื่อดูว่า Service Worker มีลักษณะดังนี้

  • ลงทะเบียนแล้ว
  • ติดตั้งแล้ว
  • เปิดอยู่

หมายเหตุ: หากลงทะเบียน Service Worker ไว้ก่อนหน้านี้หรือพบปัญหาในการทําให้เหตุการณ์ทั้งหมดเริ่มทํางาน ให้ยกเลิกการลงทะเบียน Service Worker และรีเฟรชหน้า หากไม่สําเร็จ ให้ปิดอินสแตนซ์ทั้งหมดของแอปแล้วเปิดอีกครั้ง

ต่อไป ให้ยุติเซิร์ฟเวอร์การพัฒนาในเครื่องในบรรทัดคําสั่งโดยการเรียกใช้ Ctrl + c รีเฟรชเว็บไซต์อีกครั้งและสังเกตว่าเว็บไซต์โหลดแม้ว่าเซิร์ฟเวอร์จะออฟไลน์อยู่ก็ตาม

หมายเหตุ: คุณอาจเห็นข้อผิดพลาดในคอนโซลที่ระบุว่าการดึงข้อมูลบริการไม่ได้: An unknown error occurred when fetching the script. service-worker.js Failed to load resource: net::ERR_CONNECTION_REFUSED ระบบแสดงข้อผิดพลาดนี้เนื่องจากเบราว์เซอร์ดึงข้อมูลสคริปต์ Service Worker ไม่ได้ (เนื่องจากเว็บไซต์ออฟไลน์อยู่) แต่ตามที่คาดไว้เพราะเราใช้ Service Worker เพื่อแคชตัวเองไม่ได้ ไม่เช่นนั้นเบราว์เซอร์ของผู้ใช้จะค้างกับ Service Worker รายเดียวกันตลอดไป

คำอธิบาย

เมื่อสคริปต์บริการลงทะเบียนโดยสคริปต์การลงทะเบียนใน index.html เหตุการณ์ install Service Worker จะเกิดขึ้น ระหว่างเหตุการณ์นี้ Listener เหตุการณ์ install จะเปิดแคชที่มีชื่อและแคชไฟล์ที่ระบุด้วยเมธอด cache.addAll การดําเนินการนี้เรียกว่า "precaching" ซึ่งมักจะเกิดขึ้นในช่วงเหตุการณ์ install ซึ่งโดยทั่วไปจะเป็นครั้งแรกที่ผู้ใช้เข้าชมเว็บไซต์

หลังจากติดตั้ง Service Worker แล้ว และหาก Service Worker รายอื่นไม่ได้ควบคุมหน้าอยู่ Service Worker ใหม่จะ "เปิดใช้งาน" (Listener เหตุการณ์ activate จะทริกเกอร์ใน Service Worker) และเริ่มควบคุมหน้า

เมื่อมีการขอทรัพยากรจากหน้าเว็บที่ Service Worker ควบคุม คําขอจะส่งผ่าน Service Worker เช่น พร็อกซีเครือข่าย เหตุการณ์ fetch จะทริกเกอร์สําหรับแต่ละคําขอ ใน Service Worker ของเรา Listener เหตุการณ์ของ fetch จะค้นหาแคชและตอบกลับด้วยทรัพยากรที่แคชไว้หากมีอยู่ในแคช หากระบบไม่ได้แคชทรัพยากรไว้ ระบบจะขอทรัพยากรตามปกติ

การแคชทรัพยากรจะช่วยให้แอปทํางานแบบออฟไลน์ได้เพื่อหลีกเลี่ยงคําขอเครือข่าย ตอนนี้แอปสามารถตอบกลับได้ด้วยรหัสสถานะ 200 เมื่อออฟไลน์

หมายเหตุ: เหตุการณ์การเปิดใช้งานจะไม่ได้ใช้เพื่อจุดประสงค์ใดๆ นอกเหนือจากการบันทึกในตัวอย่างนี้ เหตุการณ์นี้เกิดขึ้นเพื่อช่วยแก้ปัญหาเกี่ยวกับวงจรการทํางานของ Service Worker

ไม่บังคับ: คุณยังดูทรัพยากรที่แคชไว้ในแท็บแอปพลิเคชันของเครื่องมือสําหรับนักพัฒนาซอฟต์แวร์ได้โดยขยายส่วนพื้นที่เก็บข้อมูลแคช ดังนี้

รีสตาร์ทเซิร์ฟเวอร์การพัฒนาด้วย node server.js และรีเฟรชเว็บไซต์ จากนั้นเปิดแท็บการตรวจสอบในเครื่องมือสําหรับนักพัฒนาซอฟต์แวร์อีกครั้ง แล้วเรียกใช้การตรวจสอบ Lighthouse อีกครั้งโดยเลือกการตรวจสอบใหม่ (เครื่องหมายบวกในมุมซ้ายบน) เมื่อการตรวจสอบเสร็จสิ้นแล้ว คุณควรเห็นว่าคะแนน PWA ของเราดีกว่ามาก แต่ยังคงปรับปรุงได้ We&#39 จะปรับปรุงคะแนนในส่วนต่อไป

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

คะแนน PWA ของเรายังไม่ดีนัก ข้อผิดพลาดที่เหลืออยู่บางส่วนที่แสดงในรายงานคือ ผู้ใช้จะไม่ได้รับข้อความแจ้งให้ติดตั้งเว็บแอปของเรา และเราไม่ได้กําหนดค่าหน้าจอแนะนําหรือสีแบรนด์ในแถบที่อยู่ เราแก้ปัญหาเหล่านี้และดําเนินการเพิ่มลงในหน้าจอหลักอย่างต่อเนื่องได้โดยปฏิบัติตามเกณฑ์เพิ่มเติม สิ่งสําคัญที่สุดคือเราต้องสร้างไฟล์ Manifest

สร้างไฟล์ Manifest

สร้างไฟล์ใน app/ ชื่อ manifest.json และเพิ่มโค้ดต่อไปนี้

{
  "name": "Space Missions",
  "short_name": "Space Missions",
  "lang": "en-US",
  "start_url": "/index.html",
  "display": "standalone",
  "theme_color": "#FF9800",
  "background_color": "#FF9800",
  "icons": [
    {
      "src": "images/touch/icon-128x128.png",
      "sizes": "128x128"
    },
    {
      "src": "images/touch/icon-192x192.png",
      "sizes": "192x192"
    },
    {
      "src": "images/touch/icon-256x256.png",
      "sizes": "256x256"
    },
    {
      "src": "images/touch/icon-384x384.png",
      "sizes": "384x384"
    },
    {
      "src": "images/touch/icon-512x512.png",
      "sizes": "512x512"
    }
  ]
}

รูปภาพที่อ้างอิงในไฟล์ Manifest มีอยู่ในแอปแล้ว

จากนั้นเพิ่ม HTML ต่อไปนี้ที่ด้านล่างของแท็ก <head> ใน index.html

<link rel="manifest" href="manifest.json">

<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="application-name" content="Space Missions">
<meta name="apple-mobile-web-app-title" content="Space Missions">
<meta name="theme-color" content="#FF9800">
<meta name="msapplication-navbutton-color" content="#FF9800">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="msapplication-starturl" content="/index.html">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<link rel="icon" sizes="128x128" href="/images/touch/icon-128x128.png">
<link rel="apple-touch-icon" sizes="128x128" href="/images/touch/icon-128x128.png">
<link rel="icon" sizes="192x192" href="icon-192x192.png">
<link rel="apple-touch-icon" sizes="192x192" href="/images/touch/icon-192x192.png">
<link rel="icon" sizes="256x256" href="/images/touch/icon-256x256.png">
<link rel="apple-touch-icon" sizes="256x256" href="/images/touch/icon-256x256.png">
<link rel="icon" sizes="384x384" href="/images/touch/icon-384x384.png">
<link rel="apple-touch-icon" sizes="384x384" href="/images/touch/icon-384x384.png">
<link rel="icon" sizes="512x512" href="/images/touch/icon-512x512.png">
<link rel="apple-touch-icon" sizes="512x512" href="/images/touch/icon-512x512.png">

กลับไปที่เว็บไซต์ ในแท็บแอปพลิเคชันของเครื่องมือสําหรับนักพัฒนาซอฟต์แวร์ ให้เลือกส่วนล้างพื้นที่เก็บข้อมูล แล้วคลิกล้างข้อมูลเว็บไซต์ จากนั้นให้รีเฟรชหน้าเว็บ เลือกส่วนไฟล์ Manifest คุณควรเห็นไอคอนและตัวเลือกการกําหนดค่าที่กําหนดค่าไว้ในไฟล์ manifest.json หากไม่เห็นการเปลี่ยนแปลงของคุณ ให้เปิดเว็บไซต์ในหน้าต่างที่ไม่ระบุตัวตนแล้วตรวจสอบอีกครั้ง

คำอธิบาย

ไฟล์ manifest.json จะบอกเบราว์เซอร์ว่าต้องจัดรูปแบบและจัดรูปแบบแบบต่อเนื่องอย่างไรให้แอปของคุณ เช่น เบราว์เซอร์ Chrome, ไอคอนหน้าจอหลัก และหน้าจอแนะนํา นอกจากนี้ยังใช้กําหนดค่าเว็บแอปให้เปิดในโหมด standalone ได้เช่นเดียวกับโฆษณาเนทีฟ (กล่าวคือ นอกเบราว์เซอร์) ก็ได้

เบราว์เซอร์นี้ยังคงอยู่ในระหว่างการพัฒนาสําหรับเบราว์เซอร์บางตัว และแท็ก <meta> กําหนดค่าฟีเจอร์บางส่วนเหล่านี้สําหรับเบราว์เซอร์บางตัวที่ยังไม่รองรับอย่างเต็มรูปแบบ

เราจําเป็นต้องล้างข้อมูลเว็บไซต์เพื่อนํา index.html เวอร์ชันแคชเก่าออก (เนื่องจากเวอร์ชันดังกล่าวไม่มีลิงก์ไฟล์ Manifest) ลองทําการตรวจสอบของ Lighthouse อีกครั้งเพื่อดูว่าคะแนน PWA เพิ่มขึ้นเท่าใด

กําลังเปิดใช้งานข้อความแจ้งให้ติดตั้ง

ขั้นตอนถัดไปเพื่อติดตั้งแอปของเราคือการแสดงข้อความเตือนผู้ใช้ให้ติดตั้ง Chrome 67 จะแจ้งผู้ใช้โดยอัตโนมัติ แต่ตั้งแต่ Chrome 68 เป็นต้นไป พรอมต์การติดตั้งควรเปิดใช้งานแบบเป็นโปรแกรมเพื่อตอบสนองต่อท่าทางสัมผัสของผู้ใช้

เพิ่มปุ่มโควต้า & ติดตั้งแอปและแบนเนอร์ที่ด้านบนของ index.html (อยู่หลังแท็ก <main>) ด้วยรหัสต่อไปนี้

<section id="installBanner" class="banner">
    <button id="installBtn">Install app</button>
</section>

จากนั้นจัดรูปแบบแบนเนอร์โดยการเพิ่มรูปแบบต่อไปนี้ใน styles/main.css

.banner {
  align-content: center;
  display: none;
  justify-content: center;
  width: 100%;
}

บันทึกไฟล์ สุดท้ายให้เพิ่มแท็กสคริปต์ต่อไปนี้ลงใน index.html

  <script>
    let deferredPrompt;
    window.addEventListener('beforeinstallprompt', event => {

      // Prevent Chrome 67 and earlier from automatically showing the prompt
      event.preventDefault();

      // Stash the event so it can be triggered later.
      deferredPrompt = event;

      // Attach the install prompt to a user gesture
      document.querySelector('#installBtn').addEventListener('click', event => {

        // Show the prompt
        deferredPrompt.prompt();

        // Wait for the user to respond to the prompt
        deferredPrompt.userChoice
          .then((choiceResult) => {
            if (choiceResult.outcome === 'accepted') {
              console.log('User accepted the A2HS prompt');
            } else {
              console.log('User dismissed the A2HS prompt');
            }
            deferredPrompt = null;
          });
      });

      // Update UI notify the user they can add to home screen
      document.querySelector('#installBanner').style.display = 'flex';
    });
  </script>

บันทึกไฟล์ เปิดแอปใน Chrome บนอุปกรณ์ Android โดยใช้การแก้ไขข้อบกพร่องจากระยะไกล เมื่อโหลดหน้าเว็บแล้ว คุณจะเห็นปุ่ม "Install app" (คุณจะไม่เห็นบนเดสก์ท็อป) ดังนั้นคุณต้องทดสอบในอุปกรณ์เคลื่อนที่) คลิกปุ่มแล้วข้อความแจ้ง "เพิ่มลงในหน้าจอหลัก" จะปรากฏขึ้น ทําตามขั้นตอนเพื่อติดตั้งแอปในอุปกรณ์ หลังจากติดตั้ง คุณจะสามารถเปิดเว็บแอปในโหมดสแตนด์อโลน (นอกเบราว์เซอร์) ได้โดยแตะไอคอนหน้าจอหลักที่สร้างขึ้นใหม่

คำอธิบาย

โค้ด HTML และ AMP จะเพิ่มแบนเนอร์และปุ่มที่ซ่อนอยู่ซึ่งเราสามารถใช้เพื่อให้ผู้ใช้เปิดใช้งานข้อความแจ้งให้ติดตั้งได้

เมื่อเหตุการณ์ beforeinstallprompt เริ่มทํางาน เราจะป้องกันไม่ให้ประสบการณ์การใช้งานเริ่มต้น (โดยที่ Chrome 67 และเวอร์ชันก่อนหน้าจะแจ้งให้ผู้ใช้ติดตั้งโดยอัตโนมัติ) และจับภาพ beforeinstallevent ในตัวแปร deferredPrompt ส่วนกลาง จากนั้นปุ่ม "Install app" มีการกําหนดค่าให้แสดงข้อความแจ้งด้วยเมธอด prompt() ของ beforeinstallevent&#39 เมื่อผู้ใช้ตัดสินใจแล้ว (ต้องการติดตั้งหรือไม่) สัญญา userChoice จะตกลงเป็นตัวเลือกของผู้ใช้ (outcome) สุดท้าย เราจะแสดงปุ่มติดตั้งเมื่อทุกอย่างพร้อมแล้ว

คุณได้ดูวิธีตรวจสอบเว็บไซต์ด้วย Lighthouse และวิธีใช้งานฟังก์ชันการทํางานแบบออฟไลน์พื้นฐานแล้ว หากกรอกข้อมูลในส่วนที่ไม่บังคับแล้ว คุณก็ได้เรียนรู้วิธีติดตั้งเว็บแอปลงในหน้าจอหลักแล้วด้วย

แหล่งข้อมูลเพิ่มเติม

Lighthouse เป็นโอเพนซอร์ส คุณสามารถแยก เพิ่มการทดสอบของคุณเอง และยื่นข้อบกพร่องได้ Lighthouse ยังเป็นเครื่องมือบรรทัดคําสั่งสําหรับผสานรวมกับกระบวนการบิลด์ได้ด้วย

ดู Codelab ทั้งหมดในหลักสูตรการฝึกอบรม PWA ที่หัวข้อยินดีต้อนรับ Codelab ของหลักสูตร/