Angular 學習筆記 ( PWA + App Shell )


更新 : 2019-06-29 

自從 pwa 一推出開始玩了一把,一直到現在才真的有項目需求...

重新整理了一下. 

https://angular.io/guide/service-worker-getting-started

跟着 get start 走,基本上 3 個 command 就搞定了. 真實方便呢

下面提一提需要留意的東西 

Hash Mismatch 問題

如果我們用 live server 來測試, 你會發現 pwa 跑不起來, 

如果我們用 iis 也很有可能出現這種情況 

其中的關鍵就是, ng build 的時候 angular 會拿 index.html 來 hash 

然后以這個判斷內容是否有修改. 這個是很常用的技術. 比如 html content security policy 在保護 script 執行時也有對比 hash 的概念

live server 和 iis 或者 cdn 經常會幫我們 minify html, 所以會生成的 hash 與 ng build 的時候不吻合 (ng build 的時候沒有 minify)

官方的例子很巧妙的使用了 http-server 避開了這件事兒... 也留些了坑 /.\

https://github.com/angular/angular/issues/21636 (很多人踩進去了...)

當然你也不能怪誰啦... 

期望以后 angular 會幫我們 minify 咯

https://github.com/angular/angular-cli/issues/11360

https://github.com/angular/angular/issues/23613

https://www.willpeavy.com/tools/minifier/

目前我的解決方法就是手動提前 minify index.html 才 ng build. 

如果是開發階段,還是用 http-server 吧. 

npm i g http-server 

http-server -p 4200 -a localhost ./dist/project-name -o http://localhost:4200/index.html

 

另一個要注意的是 cache dataGroups 機制. 

data groups 通常用來 cache api 返回的資料. 

它有 2 個 mode 

一個是 freshness, 另一個是 performance

先說 performance,它就好像一般的 js 的 cache 一樣,有 cache 就不會去 server, 等到 max age 到為止. 

freshness 比較特別, 在 network 好的情況下, 它總是去 server 拿回來,然后存一份 cache 

當 offline 時它會馬上使用 cache, 或者時 network 超時的時候它會立刻返回 cache,

然后繼續等待 network 把資料拿回來后更新 cache, 注意它只是更新 cache 並不會通知 app 哦, 所以 app 這時候用的是之前 cache 的資料。

這個體驗就不是很好了,但是一個請求是無法獲得 2 個 response 的,如果拿了 cache 那么就獲取不到新的了. 

我們也無法精准的判斷 response 是 from cache or server. (最多只能判斷 timeout 時間來猜測而已.)

一般上我們的需求是, offline 用 cache, online 用 server. 沒有超不超時的概念. 

所以我通常的做法時 set 一個很長的超時, 如果用戶不是 offline 而是超時的話也不會用 cache, 而是報錯之類的處理. 

 

還有一個好的功能是, by pass 

To bypass the service worker you can set ngsw-bypass as a request header, or as a query parameter. (The value of the header or query parameter is ignored and can be empty or omitted.)

在請求 header 加上 ngsw-bypass 就可以 skip 掉 service worker 的 fetch 了. 

 

最后在說說 notification click 的問題.

https://github.com/angular/angular/issues/20956

這個 issue 被關掉了, ng 提供了一個監聽的方法

this.swPush.notificationClicks.subscribe(v => {
  console.log('done');
});

這個只有在 app 打開着的狀態下才有用, ng 並沒有實現 action open window ...

如果我們要實現依然需要修改 ngsw-worker.js

真的是啊....

https://github.com/angular/angular/issues/21197

也沒有給我們好的方式去擴展 

目前用到一個做法是 ..

https://medium.com/@smarth55/extending-the-angular-cli-service-worker-44bfc205894c

//my-service-worker.js
self.addEventListener('notificationclick', (event) => {
  console.log('notification clicked!')
});


//app.module.ts
ServiceWorkerModule.register('my-service-worker.js', { enabled: environment.production })


"assets": {
  ...,
  "src/my-service-worker.js"
}


//my-service-worker.js
importScripts('./ngsw-worker.js');
self.addEventListener('notificationclick', (event) => {
  console.log('notification clicked!')
});

做法就是 extends + override 咯。這樣就可以實現了咯

一個好得體驗應該是這樣子,到用戶在線時,我們不應該發 notification,而應該用 web socket 去同步資料

只有當用戶不在線時,我們才需要通過 notification... 不然你想,用戶就在屏幕前,notification 一直發... 人家會不喜歡嘛。

 

 

PWA (Progressive Web Apps) 是未來網頁設計的方向. 漸進式網站.

Angular v5 開始支持 pwa 網站 (所謂支持意思是說有一些 build in 的方法和規范去實現它) 。

就目前來說 pwa 有幾個特點 : 

1.https 

2.Service work 

3.Cache API

4.攔截 Fetch (任何游覽器發出的請求, 包括 index.html)

5.Push API

6.Share API

 

主要的用途是 : 

1. offline view (通過 service work + cache + 攔截 fetch 實現)

2. push notification (通過 service work + Push API + Notification API 實現)

3. AMP 網站預加載 service-work.js (在 amp page 出發 service worker 預加載整個頁面需要的 html,js.css)

 

參考 : 

https://blog.angular-university.io/service-workers/

https://blog.angular-university.io/angular-service-worker/

實現我就不說了,人家已經是 step by step 了. 我就講一些重點吧.

service work 比較復雜的地方是 life cycle. 

當你訪問一個網站后 www.domain.com 

當頁面渲染好后, ng 會找到一個好的時間點去 register service worker 也就是加載 "/ngsw-worker.js".

ng 有自己的方式(比如對比文件的 hash 等等)去管理 life cycle (如果你知道怎么自己實現 service worker 的話,你會發現 ng 完全自己控制了 life cycle 而沒有使用 default 的)

service work 開啟后, 就是一般的預加載 css, js, html 等等. 然后統統都會 cache 起來. 

完成后, 你 offline 就可以看到效果了. 你 refresh 的話會發現所有的請求都是從 cache 返回的,包括 index.html 

連 index.html 都 cache 起來了,那要怎樣更新網站呢 ? 

每一次更新, ng 在 cli build 的時候都會生產一個 hash 放進 ngsw-worker.js,

網站每一次刷新雖然會先使用 cache 版本,但是它也會馬上去加載 ngsw-worker.js 然后進行判斷看 hash 是否一樣。

如果發現有新的 js,css 那么就會去加載,等到下一次 refresh 就會使用新版本了. 如果你希望用戶馬上使用新版本, ng 也開放了一個 API

可以通過 subscribe 的方式監聽這個 update event, 然后可以 alert 用戶叫用戶馬上 refresh.

所以流程是  cache first -> check update -> notify user and update now Or wait for user next refresh 

我建議在網站比較穩定后才設置 service work, 而

而且網頁必須向后兼容, 或至少要有錯誤處理在版本過久的情況下。

因為不管怎樣,用戶一定會先獲取到 cache 的版本,如果你的 cache 版本運行失敗(比如你的 Ajax response 已經換了, 而之前的 js 版本無法處理, 甚至 error, 這樣用戶可能非常的難升級到新版本,而且體驗也會很糟. 所以要用 pwa 要注意這個哦)

 

除了 cache, ng 也封裝了 push notification。

之前寫過一篇關於 push 的原生實現. 

http://www.cnblogs.com/keatkeat/p/7503615.html 

ng 的實現看這個 

https://medium.com/google-developer-experts/a-new-angular-service-worker-creating-automatic-progressive-web-apps-part-2-practice-3221471269a1

目前還不支持 notification click 時間,這個還蠻糟糕的,非常重要的功能丫。怎么會沒有實現呢 ? https://github.com/angular/angular/issues/20956

而且也沒有擴展的方式,如果硬要就需要直接改 ngsw-worker.js  源碼了。

 

最后說說 App-shell 

這個和 skeleton 類似的概念, 取代單調的 loading bar.

step by step :  https://blog.angular-university.io/angular-app-shell/

ng 的實現手法是通過 cli build 時運行 server render, 然后把渲染好的 skeleton page 插入到 index.html. 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM