開發一個漸進式Web應用程序(PWA)前都須要瞭解什麼?

轉載請註明出處:葡萄城官網,葡萄城爲開發者提供專業的開發工具、解決方案和服務,賦能開發者。javascript

原文出處:https://dzone.com/articles/how-to-build-a-progressive-web-app-pwa-with-javasccss

 

自蘋果推出了iPhone應用商店以來,App成爲了咱們生活中不可或缺的一部分,而對於實體業務也是如此,如今各行業都在推出本身的App,但有沒有人想過這樣一種場景,若是本身的潛在客戶尚未安裝你的App亦或是即使安裝但由於客戶的手機存儲空間緊張而卸載掉了你的App?那有沒有使App更輕量,更易安裝的技術實現呢?答案是「有的」。html

漸進式Web應用程序就是爲此而生的,它同時具有了Web應用功能和之前只有在原生應用纔有的功能的特色,漸進式Web應用程序經過從主屏幕上的圖標啓動,也能夠根據推送通知啓動,加載時間幾乎能夠忽略不計,並且除了能夠在線使用外,也能夠打包成可離線使用。java

最重要的是,漸進式Web應用程序在手機上建立方式也很簡單,由於它們只是對你網站的加強,當有人在第一次訪問你的網站時,PWA的功能在通過你受權後就會自動爲你建立在手機上。node

下面, 咱們會一塊兒來看看如何來建立一個屬於本身的PWA應用。git

要求

要開始學習本教程,您必須安裝如下軟件:github

  • node  8.9 版本及以上 (https: // nodejs.org/en/download/).web

  • Yarn (https://yarnpkg.com)chrome

  • Gitnpm

做爲本教程初始的工程,你能夠clone如下Github庫:

1
git clone https: //github .com /petereijgermans11/progressive-web-app

而後,到如下目錄中  

1
cd  pwa-article / pwa-app-manifest-init

經過如下命令安裝依賴並啓動工程

1
npm i && npm start

經過如下地址打開應用: http:// localhost:8080

 

 

應用的網址

有許多方法能夠訪問個人本地主機:爲了從遠程訪問發佈在你機器上的8080端口的地址。爲此,您可使用ngrok。請參閱:https://ngrok.com/

使用如下命令安裝ngrok: 

1
npm  install  -g ngrok

在終端中運行如下命令。該命令爲您生成一個可供外部訪問的URL

1
ngrok http 8080

而後在Chrome中的移動設備上瀏覽至生成的網址。

PWA須要的技術組件是什麼?

PWA有三個重要的技術組件協調工做,包括:

Manifest清單文件,Service Worker和在https下運行。

 

 

Manifest清單文件

清單文件是一個JSON配置文件,其中包含了PWA的基礎信息,例如應用的icon,Web應用程序名稱及背景顏色。若是瀏覽器檢測到網站存在PWA清單文件,Chrome會自動出現「添加到主屏幕」按鈕。若是用戶點擊贊成,該圖標將被添加到主屏幕,而且將安裝PWA。

 

 

建立一個Manifest.json

PWA的Manifest.json文件以下所示:

JSON格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
   "name" "Progressive Selfies" ,
   "short_name" "PWA Selfies" ,
   "icons" : [
     {
       "src" "/src/images/icons/app-icon-192x192.png" ,
       "type" "image/png" ,
       "sizes" "192x192"
     },
     {
       "src" "/src/images/icons/app-icon-512x512.png" ,
       "type" "image/png" ,
       "sizes" "512x512"
     }
   ],
   "start_url" "/index.html" ,
   "scope" "." ,
   "display" "standalone" ,
   "background_color" "#fff" ,
   "theme_color" "#3f51b5"
}

告訴瀏覽器你應用的清單

在與index.html 文件相同的級別的目錄中建立Manifest.json文件。清單文件建立後,將清單文件引用連接添加到index.html中。

1
< link  rel=」manifest」 href=」/manifest.json」>

Manifest 屬性介紹

Manifest有不少配置屬性,接下來咱們會對其中的屬性作一個簡單的介紹

  • nameshort_name:指定Web應用的名稱,short_name是該應用的簡稱,當沒有足夠空間展現應用的name屬性時,系統就會使用short_name 。

  • l  display:display屬性指定Web應用的顯示模式,它有四個值可供配置:fullscreen、standalone、minimal-ui和browser,但通常經常使用的屬性就是fullscreen和standalone。

    • fullscreen:全屏顯示

    • standalone:這種模式下打開的應用不會出現瀏覽器的地址欄,因此所以看起來更像是一個原生應用

    • minimal-uibrowser:和使用瀏覽器訪問區別不大。

  • l  orientation:控制Web應用的顯示的方向及禁止手機轉屏。

  • l  iconsbackground_color:icon用於指定應用圖標,background_color是應用加載完成前的背景色,經過設置這兩個屬性,可組合成應用的Splash Screen。

  • l  theme_color:定義應用程序的默認主題顏色。

  • l  description:設置應用的一段描述內容。


以上是pwa 清單文件屬性的一些說明,咱們經過將設置完成的清單文件並將其放置在與index.html 文件同級的目錄中便可完成清單文件的添加。

打開Chrome開發者工具 – Application - Manifest,查看添加的清單文件是否加載完成,若是沒有下圖的信息,咱們能夠經過從新啓動服務器  npm start來從新加載。

 

 

 

什麼是Service Worker

Service Worker(SW) 是一段JavaScript,它做爲瀏覽器和網絡服務器間的代理。Service Worker能夠在基於瀏覽器的 web 應用中實現如離線緩存、消息推送、靜默更新等 native 應用常見的功能,以給 web 應用提供更好更豐富的使用體驗。

另外,這個API還容許利用緩存來支持離線體驗,從而使開發人員能夠徹底控制用戶的使用體驗  

 

 

 

Service Worker生命週期

對於Service Worker,基本設置的步驟以下:

  • 首先應註冊SW,若是SW已註冊,瀏覽器會根據於安裝事件自動開始安裝。

  • 安裝SW後,它將收到激活事件。此激活事件可用於清理SW早期版本的中使用的資源。

 

 

 

 

實際操做應該首先建立一個和index.html同級,名爲sw.js的空文件。而後再index.html文件中,添加一個base標籤,以下:

1
< base  href=」/」>

最後,在src/js/app.js中添加如下代碼註冊SW。此代碼將在頁面 「 加載 」 過程當中被激活。

你能夠打開Chrome DevTools – Application - Service Worker 中檢查SW是否已經啓用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
window.addEventListener( 'load' , () => {
     const base = document.querySelector( 'base' );
     let  baseUrl = base && base.href ||  '' ;
     if  (!baseUrl.endsWith( '/' )) {
         baseUrl = `${baseUrl}/`;
    
   
     if  ( 'serviceWorker'  in  navigator) {
         navigator.serviceWorker.register(`${baseUrl}sw.js`)
             .then( registration => {
             // Registration was successful
             console.log( 'ServiceWorker registration successful with scope: ' , registration.scope);
         })
         . catch (err => {
             // registration failed :(
             console.log( 'ServiceWorker registration failed: ' , err);
         });
     }
});

以上這段代碼主要的做用是檢查SW的API 在window對象的navigator 屬性中是否可用。window對象表明瀏覽器窗口。若是SW在navigator 中可用,則在頁面加載時當即註冊SW。

雖然註冊一個SW很簡單,但在有些狀況下咱們依然會遇到沒法註冊Service Worker的問題,咱們來簡單看看沒法註冊SW的緣由都有什麼並如何解決:

  • 您的應用程序沒法在HTTPS下運行。在開發過程當中,你能夠經過localhost使用SW 。但若是將其部署在網站上時,則須要啓用HTTPS。

  • SW的路徑不正確。

沒有勾選Update on reload。  

 

 

Service Worker 事件

除了install和activate事件外,其餘事件還有message、fetch、sync和push事件。

 

 

將如下代碼添加到你的SW中以監聽生命週期事件(安裝和激活):

 

1
2
3
4
5
6
7
8
self.addEventListener( 'install' , event => {
     console.log( '[Service Worker] Installing Service Worker ...' , event);
     event.waitUntil(self.skipWaiting());
});
self.addEventListener( 'activate' , event => {
     console.log( '[Service Worker] Activating Service Worker ...' , event);
     return  self.clients.claim();
});

install回調調用skipWaiting()函數來觸發activate事件,並告訴Service Worker當即開始工做,而無需等待用戶瀏覽或從新加載頁面。

skipWaiting()函數強制等待中的Service Worker成爲活動的Service Worker。self.skipWaiting()函數也能夠和self.clients.claim()函數一塊兒使用,以確保對底層Service Worker的更新當即生效。

在這種狀況下,self-property 表明窗口對象(即你的瀏覽器窗口)。

添加到主屏幕按鈕

"添加到主屏幕按鈕" 容許用戶在其設備上安裝PWA。爲了真正用這個按鈕安裝PWA,你必須在SW中定義一個fetch事件處理程序。讓咱們在sw.js中解決這個問題。

1
2
3
4
5
6
7
8
self.addEventListener( 'fetch' , event => {
     console.log( '[Service Worker] Fetching something ....' , event);
     // This fixes a weird bug in Chrome when you open the Developer Tools
     if  (event.request.cache ===  'only-if-cached'  && event.request.mode !==  'same-origin' ) {
         return ;
     }
     event.respondWith(fetch(event.request));
});

Service Worker緩存

Service Worker的強大之處在於其攔截HTTP請求的能力。在這一步中,咱們使用這個選項來攔截HTTP請求和響應,直接從緩存爲用戶提供閃電般快速的響應。

Service Worker安裝期間進行預緩存 

當用戶第一次訪問你的網站時,SW會開始自行安裝。在這個安裝階段,你能夠將PWA使用的全部頁面、腳本和樣式文件下載並緩存起來,如下是完成這項工做的sw.js文件代碼:  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const CACHE_STATIC_NAME =  'static' ;
const URLS_TO_PRECACHE = [
     '/' ,
     'index.html' ,
     'src/js/app.js' ,
     'src/js/feed.js' ,
     'src/lib/material.min.js' ,
     'src/css/app.css' ,
     'src/css/feed.css' ,
     'src/images/main-image.jpg' ,
     'https://fonts.googleapis.com/css?family=Roboto:400,700' ,
     'https://fonts.googleapis.com/icon?family=Material+Icons' ,
];
self.addEventListener( 'install' , event => {
     console.log( '[Service Worker] Installing Service Worker ...' , event);
     event.waitUntil(
         caches.open(CACHE_STATIC_NAME)
             .then(cache => {
                 console.log( '[Service Worker] Precaching App Shell' );
                 cache.addAll(URLS_TO_PRECACHE);
             })
             .then(() => {
                 console.log( '[ServiceWorker] Skip waiting on install' );
                 return  self.skipWaiting();
             })
     );
});

這段代碼使用安裝事件,並在安裝階段添加了一個URLS_TO_PRECACHE數組。一旦調用開啓緩存函數(caches.open),你就可使用cache.addAll()函數來緩存數組中的文件。經過event.waitUntil()方法使用JavaScript promise來知道安裝須要多長時間以及是否成功。

安裝事件會調用self.skipWaiting()直接激活SW。若是全部文件都已被成功緩存,SW就會被安裝。但若是其中一個文件沒法下載,則安裝步驟將會失敗。在Chrome開發者工具中,你能夠檢查緩存(在Cache Storage中)是否被URLS_TO_PRECACHE數組中的靜態文件填充。

 

 

可是,若是你查看Network選項卡,文件仍然是經過網絡獲取的。緣由是雖然緩存已經準備就緒了,但咱們並無從緩存中讀取引用資源。因此爲了完成這部分工做,咱們首先要監聽應用的fetch事件,而後攔截並從緩存中獲取資源,讓咱們看看下面的代碼吧: 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
self.addEventListener( 'fetch' , event => {
     console.log( '[Service Worker] Fetching something ....' , event);
     event.respondWith(
         caches.match(event.request)
             .then(response => {
                 if  (response) {
                     console.log(response);
                     return  response;
                 }
                 return  fetch(event.request);
             })
     );
});

咱們使用caches.match()函數檢查傳入的URL是否與當前緩存中可能存在的資源匹配。若是匹配,咱們就返回該緩存資源,但若是該資源不存在於緩存中,咱們就像正常狀況下同樣繼續獲取請求的資源。

在Service Worker安裝並激活後,刷新頁面並再次檢查網絡選項卡。如今,Service Worker將攔截HTTP請求,並從緩存中即時加載相應的資源,而不是向服務器發出網絡請求。

如今,若是咱們在網絡選項卡中設置離線模式,咱們的應用也依然能正常訪問。

後臺傳輸

Background Fetch API是SW的後臺功能,它容許用戶在後臺下載大文件、視頻和音樂等資源。在獲取/傳輸過程當中,你的用戶即使關閉標籤,乃相當閉整個瀏覽器,也不會清除傳輸任務。當用戶再次打開瀏覽器後,傳輸過程將恢復。這個API也能夠將傳輸的進度能夠顯示給用戶,用戶能夠取消或暫停這個過程。

 

 

 

默認狀況下,後臺傳輸功能是不可用的,你必須經過url(chrome://flags/#enable-experimental-web-platform-features)容許chrome的「Experimental Web Platform features」選項

 

 

如下是如何實現此類後臺傳輸的示例。

在你的index.html文件中添加ID爲「 bgFetchButton」 的按鈕

1
< button  id=」bgFetchButton」>Store assets locally</ button >

而後,在加載事件處理程序中的app.js中添加用於執行後臺傳輸的代碼

1
2
3
4
5
6
7
8
9
10
11
12
13
window.addEventListener(‘load’, () => {
...
        bgFetchButton = document.querySelector(‘ #bgFetchButton’);
        bgFetchButton.addEventListener(‘click’, async event => {
          try  {
             const registration = await navigator.serviceWorker.ready;
             registration.backgroundFetch.fetch(‘my-fetch’, [ new               Request(`${baseUrl}src/images/main-image-lg.jpg`)]);
          catch  (err) {
             console.error(err);
          }
      });
...
});

上面的代碼在如下條件下開始執行後臺傳輸:

  • 用戶點擊ID爲bgFetchButton的按鈕

  • SW已註冊

後臺傳輸必須在異步函數中執行,由於傳輸過程不能阻塞用戶界面。

傳輸完成後放入緩存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
self.addEventListener(‘backgroundfetchsuccess’, event => {
   console.log(‘[Service Worker]: Background Fetch Success’, event.registration);   event.waitUntil(
    (async  function () {
      try  {
      // Iterating the records to populate the cache
        const cache = await caches.open(event.registration.id); const records =          await event.registration.matchAll(); const promises = records.map(async          record => {
          const response = await record.responseReady;
          await cache.put(record.request, response);
        });
        await Promise.all(promises);
      catch  (err) {
        console.log(‘[Service Worker]: Caching error’);
      }
    })()
   );
});

這段代碼由如下步驟組成:

  • l  當Background Fetch傳輸完成,你的SW將收到Background Fetch成功事件。

  • l  建立並打開一個與registration.id同名的新緩存。

  • l  經過registration.matchAll()獲取全部記錄並遍歷。

最後,經過Promise.all(),執行全部的承諾。  

 

總結 

在本文中咱們討論了PWA的基礎組成部分的其中兩部分:Manifest、Service Worker的基礎功能介紹,由於HTTPS以前咱們已經有過一些討論了https://www.cnblogs.com/powertoolsteam/p/http2https.html

後面若是你們感興趣,咱們可用一塊兒討論一些PWA的高級功能,這些功能能夠爲你的應用提供調用硬件的能力。若是有任何問題,歡迎經過評論區留言告訴我。 

相關文章
相關標籤/搜索