Mais conteúdo relacionado
Semelhante a Angular Meetup 04 - Angular PWA 之沒有網路的日子 20190731 (20)
Angular Meetup 04 - Angular PWA 之沒有網路的日子 20190731
- 7. MEETUP
What is PWA
• Progressive web applications
https://developers.google.com/web/progressive-web-apps/
- 10. MEETUP
Service Worker 起手式 (1) – 註冊
if('serviceWorker' in navigator) {
navigator.serviceWorker.register('/my-sw.js')
.then(function(reg) {
// 註冊成功
})
.catch(function(error) {
// 註冊失敗
});
}
- 11. MEETUP
Service Worker 起手式 (2) – 安裝
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open('pomodoro-cdn').then(function(cache) {
return cache.addAll(cacheUrls);
})
);
});
Cache API: https://developer.mozilla.org/en-US/docs/Web/API/Cache
- 13. MEETUP
Service Worker 起手式 (3) – 回應
self.addEventListener('fetch', function(event) {
if (cacheUrls.find(url => url === event.request.url)) {
event.respondWith(caches.match(event.request));
}
});
- 18. MEETUP
加入 Angualr PWA
• ng add @angular/pwa --project *project-name*
• ng build --prod
• http-server -p 8080 -c-1 dist/<project-name>
- 19. MEETUP
Production Build 很慢怎辦?
• 從 angular.json 內加入 build-pwa 的 architect
• 關掉所有最佳化設定
• 確保 fileReplacements 設定使用 envoronment.prod.ts
• 確保 "serviceWorker": true
• 確保 "ngswConfigPath": "ngsw-config.json"
• 注意:在 ng serve 或 ng build --watch 模式下不會產生 ngsw-worker.js
- 20. MEETUP
指定 Service Worker 註冊時機 (1)
• registrationStrategy
• registerWhenStable:預設值,當應用程式穩定時註冊 Service Worker
• registerImmediately:立即註冊 Service Worker
• registerWithDelay:<timeout>:延遲 <timeoute> 時間後,註冊 Service Worker
• 一個回傳 observable 的方法:Service Worker 會在指定的 Observer 有新的事件時註冊
Service Worker
• ex: 立即註冊 Service Worker
ServiceWorkerModule.register('ngsw-worker.js',
{
enabled: environment.production,
registrationStrategy: 'registerImmediately'
}
)
- 21. MEETUP
指定 Service Worker 註冊時機 (2)
• ex: 詢問使用者是否要註冊 Service Worker
export function confirmInstall() {
return from(navigator.serviceWorker.getRegistrations()).pipe(
map(registrations => !!registrations.find(reg => reg.active.scriptURL.endsWith('ngsw-worker.js'))),
filter(installed => !installed),
switchMap(_ => of(confirm('是否要安裝本程式,享受離線使用的快感?'))),
filter(x => !!x)
);
}
@NgModule({
imports: [
ServiceWorkerModule.register('ngsw-worker.js', {
enabled: environment.production,
registrationStrategy: confirmInstall
})
]
})
export class AppModule {}
- 22. MEETUP
更新版本
• 每次 build 完後,會產生 ngsw.json,Angular Service Worker 會透過
ngsw.json 內的 timestamp 屬性判斷是否需要更新
• 可設定 ngsw-config.json 的 appData 屬性,提供相關資料給 Service Worker
constructor(swUpdate: SwUpdate) {
swUpdate.available.subscribe(event => {
const available = event.available.appData as any;
const current = event.current.appData as any;
if(confirm(`Update from ${available.version} to ${current.version}?`)) {
swUpdate.activateUpdate().then(() => document.location.reload());
}
});
}
- 23. MEETUP
定期檢查是否有更新版本
constructor(swUpdate: SwUpdate, appRef: ApplicationRef) {
const appIsStable$ = appRef.isStable
.pipe(first(isStable => isStable === true));
const checkInterval$ = interval(3 * 1000);
const appIsStableOrCheckNeeded$ = concat(appIsStable$, checkInterval$);
appIsStableOrCheckNeeded$.subscribe(() => swUpdate.checkForUpdate());
}
- 25. MEETUP
Cache 資源設定
• 在 ngsw-config.json 中,可以設定要 cache 住哪些檔案
• 在執行建置時,會掃描產出物,將符合要被 cache 住的檔案找出來
• 最終結果會產出 ngsw.json 設定
- 26. MEETUP
Cache 資源設定 (1)
• assetGroups:用來設定哪些靜態資源要被 cache
• name: 群組名稱
• installMode: 一開始的 cache 方式
• prefetch: (default) 將 resources 中的內容立即下載來 cache
• lazy: 需要用到時才下載並 cache
• updateMode: 發現新版本後的 cache 行為
• prefetch: (default) 立即下載並 cache
• lazy: 等待新的 request 發生時才下載
• resources: 群組的資源
• files: 哪些檔案要被 cache
• urls: 哪些網址要被 cache
- 27. MEETUP
Cache 資源設定 (2)
• dataGroups:用來設定哪些請求內容要被 cache (通常用於 API 請求)
• name: 名稱
• urls: 網址路徑
• version: API 版本(選填),可以用來直接決定 API 要重新 cache
• cacheConfig: cache 設定
• maxSize
• maxAge
• timeout (optional): API timeout 後,從 cache 取資料
• strategy (optional):
• performance: cache 優先,maxAge 設定 expire 後則優先抓 API
• freshness: 從網路優先,timeout 後從 cache 抓資料
- 28. MEETUP
載入外部資源的技巧
• Cache CDN 基本方式
• 注意:使用比對的方式一定會是 lazy (因為一開始根本不知道要先去抓什麼檔案)
{
"name": "cdn-fonts",
"installMode": "prefetch",
"updateMode": "prefetch",
"resources": {
"urls": [
"https://fonts.googleapis.com/**",
"https://fonts.gstatic.com/**"
]
}
}
- 29. MEETUP
如何自訂 Service Worker (1)
• sw-cdn.js const cacheUrls = [
'https://fonts.googleapis.com/css?family=Roboto:300,400,500',
'https://fonts.googleapis.com/icon?family=Material+Icons',
];
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open('pomodoro-cdn').then(function(cache) {
return cache.addAll(cacheUrls);
})
);
});
self.addEventListener('fetch', function(event) {
if (cacheUrls.find(url => url === event.request.url)) {
event.respondWith(caches.match(event.request));
}
});
- 30. MEETUP
如何自訂 Service Worker (2)
• sw-main.js
• ngsw-config.json
• app.module.ts
importScripts('sw-cdn.js');
importScripts('ngsw-worker.js');
"files": [..., "!/sw-*.js"]
ServiceWorkerModule.register(
'sw-main.js',
{ enabled: environment.production })