SlideShare uma empresa Scribd logo
1 de 34
Baixar para ler offline
ANGULAR '19
技術在我們手上 世界就在我們手上
礁溪老爺酒店 11/2 - 3, 2019
https://2019.angular.tw
Angular PWA
Mike 黃升煌
Service Worker
全端開發人員天梯:https://www.facebook.com/fullstackledder/
Angular PWA
Mike 黃升煌
沒有網路的日子
全端開發人員天梯:https://www.facebook.com/fullstackledder/
今天的 Sample Code
https://github.com/wellwind/ng-tw-meetup-04-pwa-service-worker
What is PWA?
MEETUP
What is PWA
• Progressive web applications
https://developers.google.com/web/progressive-web-apps/
讓離線使用得以實現的關鍵
Service Worker
Service Worker 起手式
MEETUP
Service Worker 起手式 (1) – 註冊
if('serviceWorker' in navigator) {
navigator.serviceWorker.register('/my-sw.js')
.then(function(reg) {
// 註冊成功
})
.catch(function(error) {
// 註冊失敗
});
}
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
MEETUP
Service Worker 起手式 (3) – 啟動
self.addEventListener('activate', function(event){
// 判斷哪些資源過期並清除
});
MEETUP
Service Worker 起手式 (3) – 回應
self.addEventListener('fetch', function(event) {
if (cacheUrls.find(url => url === event.request.url)) {
event.respondWith(caches.match(event.request));
}
});
一切的重點在於如何
cache
常見的 cache 策略
MEETUP
常見的 Cache 策略
• The Offline Cookbook
• 兩個重點
• 優先透過網路
• 優先透過 cache
Angular PWA 之
Service Worker
(DEMO)
MEETUP
加入 Angualr PWA
• ng add @angular/pwa --project *project-name*
• ng build --prod
• http-server -p 8080 -c-1 dist/<project-name>
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
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'
}
)
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 {}
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());
}
});
}
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());
}
MEETUP
檢查是否離線狀態
window.addEventListener('online', () => {
console.log('online');
});
window.addEventListener('offline', () => {
console.log('offline');
});
MEETUP
Cache 資源設定
• 在 ngsw-config.json 中,可以設定要 cache 住哪些檔案
• 在執行建置時,會掃描產出物,將符合要被 cache 住的檔案找出來
• 最終結果會產出 ngsw.json 設定
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
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 抓資料
MEETUP
載入外部資源的技巧
• Cache CDN 基本方式
• 注意:使用比對的方式一定會是 lazy (因為一開始根本不知道要先去抓什麼檔案)
{
"name": "cdn-fonts",
"installMode": "prefetch",
"updateMode": "prefetch",
"resources": {
"urls": [
"https://fonts.googleapis.com/**",
"https://fonts.gstatic.com/**"
]
}
}
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));
}
});
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 })
MEETUP
如何自訂 Service Worker (3)
• angular.json
"assets": [
...,
"src/sw-main.js",
"src/sw-cdn.js"
]
Resources
MEETUP
Resources
• Progress Web Apps
• Angular Service Worker Introduction
• Progress Web App Checklist
• Using Service Workers
THANK YOU

Mais conteúdo relacionado

Semelhante a Angular Meetup 04 - Angular PWA 之沒有網路的日子 20190731

The Evolution of Async Programming (GZ TechParty C#)
The Evolution of Async Programming (GZ TechParty C#)The Evolution of Async Programming (GZ TechParty C#)
The Evolution of Async Programming (GZ TechParty C#)
jeffz
 
利用 ASP.NET MVC 提升您的 Web 應用程式
利用 ASP.NET MVC 提升您的 Web 應用程式利用 ASP.NET MVC 提升您的 Web 應用程式
利用 ASP.NET MVC 提升您的 Web 應用程式
Chui-Wen Chiu
 
行動商務實務 - PhoneGap Advance
行動商務實務 - PhoneGap Advance行動商務實務 - PhoneGap Advance
行動商務實務 - PhoneGap Advance
My own sweet home!
 
通行证项目技术分享
通行证项目技术分享通行证项目技术分享
通行证项目技术分享
Tony Deng
 

Semelhante a Angular Meetup 04 - Angular PWA 之沒有網路的日子 20190731 (20)

輕鬆上手Asp.net web api 2.1-twMVC#14
輕鬆上手Asp.net web api 2.1-twMVC#14輕鬆上手Asp.net web api 2.1-twMVC#14
輕鬆上手Asp.net web api 2.1-twMVC#14
 
twMVC#14 | 輕鬆上手ASP.NET Web API 2
twMVC#14 | 輕鬆上手ASP.NET Web API 2twMVC#14 | 輕鬆上手ASP.NET Web API 2
twMVC#14 | 輕鬆上手ASP.NET Web API 2
 
AngularJS training in Luster
AngularJS training in LusterAngularJS training in Luster
AngularJS training in Luster
 
Supersonic Subatomic Quarkus accelerate cloud native development
Supersonic Subatomic Quarkus accelerate cloud native developmentSupersonic Subatomic Quarkus accelerate cloud native development
Supersonic Subatomic Quarkus accelerate cloud native development
 
The Evolution of Async Programming (GZ TechParty C#)
The Evolution of Async Programming (GZ TechParty C#)The Evolution of Async Programming (GZ TechParty C#)
The Evolution of Async Programming (GZ TechParty C#)
 
利用 ASP.NET MVC 提升您的 Web 應用程式
利用 ASP.NET MVC 提升您的 Web 應用程式利用 ASP.NET MVC 提升您的 Web 應用程式
利用 ASP.NET MVC 提升您的 Web 應用程式
 
twMVC#32應用 ASP.NET WebAPI2 Odata 建置高互動性 APIS
twMVC#32應用 ASP.NET WebAPI2 Odata 建置高互動性 APIStwMVC#32應用 ASP.NET WebAPI2 Odata 建置高互動性 APIS
twMVC#32應用 ASP.NET WebAPI2 Odata 建置高互動性 APIS
 
ASP.NET Core MVC 2.2從開發到測試 - Development & Unit Testing
ASP.NET Core MVC 2.2從開發到測試 - Development & Unit TestingASP.NET Core MVC 2.2從開發到測試 - Development & Unit Testing
ASP.NET Core MVC 2.2從開發到測試 - Development & Unit Testing
 
利用Signalr打造即時通訊@Tech day geek
利用Signalr打造即時通訊@Tech day geek利用Signalr打造即時通訊@Tech day geek
利用Signalr打造即時通訊@Tech day geek
 
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
 
行動商務實務 - PhoneGap Advance
行動商務實務 - PhoneGap Advance行動商務實務 - PhoneGap Advance
行動商務實務 - PhoneGap Advance
 
Asp.net mvc 培训
Asp.net mvc 培训Asp.net mvc 培训
Asp.net mvc 培训
 
Html5移动web应用开发(PhoneGap)
Html5移动web应用开发(PhoneGap)Html5移动web应用开发(PhoneGap)
Html5移动web应用开发(PhoneGap)
 
Html5移动web应用开发(PhoneGap)
Html5移动web应用开发(PhoneGap)Html5移动web应用开发(PhoneGap)
Html5移动web应用开发(PhoneGap)
 
使用 ASP.NET 5 實戰開發雲端應用程式
使用 ASP.NET 5 實戰開發雲端應用程式使用 ASP.NET 5 實戰開發雲端應用程式
使用 ASP.NET 5 實戰開發雲端應用程式
 
Browser vs. Node.js Jackson Tian Shanghai
Browser vs. Node.js   Jackson Tian ShanghaiBrowser vs. Node.js   Jackson Tian Shanghai
Browser vs. Node.js Jackson Tian Shanghai
 
以HTML5和COIMOTION打造跨平台App
以HTML5和COIMOTION打造跨平台App以HTML5和COIMOTION打造跨平台App
以HTML5和COIMOTION打造跨平台App
 
通行证项目技术分享
通行证项目技术分享通行证项目技术分享
通行证项目技术分享
 
容器驅動開發 - .NET Conf 2017 @ 台中
容器驅動開發 - .NET Conf 2017 @ 台中容器驅動開發 - .NET Conf 2017 @ 台中
容器驅動開發 - .NET Conf 2017 @ 台中
 
I os 07
I os 07I os 07
I os 07
 

Mais de 升煌 黃

Mais de 升煌 黃 (15)

使用 Passkeys 打造無密碼驗證服務
使用 Passkeys 打造無密碼驗證服務使用 Passkeys 打造無密碼驗證服務
使用 Passkeys 打造無密碼驗證服務
 
陽明交大 - 跟著 AI 學習 Angular
陽明交大 - 跟著 AI 學習 Angular陽明交大 - 跟著 AI 學習 Angular
陽明交大 - 跟著 AI 學習 Angular
 
用 Standalone Component 來寫 Angular 吧! - STUDY4.TW 2023 小聚 - 聊前端
用 Standalone Component 來寫 Angular 吧! - STUDY4.TW 2023 小聚 - 聊前端 用 Standalone Component 來寫 Angular 吧! - STUDY4.TW 2023 小聚 - 聊前端
用 Standalone Component 來寫 Angular 吧! - STUDY4.TW 2023 小聚 - 聊前端
 
.NET Conf Taiwan 2022 - Tauri - 前端人員也能打造小巧快速的 Windows 應用程式
.NET Conf Taiwan 2022 - Tauri -前端人員也能打造小巧快速的 Windows 應用程式.NET Conf Taiwan 2022 - Tauri -前端人員也能打造小巧快速的 Windows 應用程式
.NET Conf Taiwan 2022 - Tauri - 前端人員也能打造小巧快速的 Windows 應用程式
 
DevFest 2022 Taipei 使用 Standalone Component 來寫 Angular 吧!
DevFest 2022 Taipei 使用 Standalone Component 來寫 Angular 吧!DevFest 2022 Taipei 使用 Standalone Component 來寫 Angular 吧!
DevFest 2022 Taipei 使用 Standalone Component 來寫 Angular 吧!
 
gRPC - 打造輕量、高效能的後端服務
gRPC - 打造輕量、高效能的後端服務gRPC - 打造輕量、高效能的後端服務
gRPC - 打造輕量、高效能的後端服務
 
Modern web 2020 - 使用 Nx 管理超大型前後端專案
Modern web 2020 - 使用 Nx 管理超大型前後端專案Modern web 2020 - 使用 Nx 管理超大型前後端專案
Modern web 2020 - 使用 Nx 管理超大型前後端專案
 
Angular Taiwan 2019 - Schematics Workshop
Angular Taiwan 2019 - Schematics WorkshopAngular Taiwan 2019 - Schematics Workshop
Angular Taiwan 2019 - Schematics Workshop
 
Angular Taiwan 2019 - 大型 Angular 專案的的管理心得與技巧
Angular Taiwan 2019 - 大型 Angular 專案的的管理心得與技巧Angular Taiwan 2019 - 大型 Angular 專案的的管理心得與技巧
Angular Taiwan 2019 - 大型 Angular 專案的的管理心得與技巧
 
Angular Taiwan 2018 - Angular CDK
Angular Taiwan 2018 - Angular CDKAngular Taiwan 2018 - Angular CDK
Angular Taiwan 2018 - Angular CDK
 
玩轉 Schematics - Modern Web 2018
玩轉 Schematics - Modern Web 2018玩轉 Schematics - Modern Web 2018
玩轉 Schematics - Modern Web 2018
 
OAuth2介紹
OAuth2介紹OAuth2介紹
OAuth2介紹
 
Docker - 30秒生出100台伺服器
Docker - 30秒生出100台伺服器Docker - 30秒生出100台伺服器
Docker - 30秒生出100台伺服器
 
敏捷開發與Scrum
敏捷開發與Scrum敏捷開發與Scrum
敏捷開發與Scrum
 
Test Driven Development
Test Driven DevelopmentTest Driven Development
Test Driven Development
 

Angular Meetup 04 - Angular PWA 之沒有網路的日子 20190731

  • 1.
  • 3. Angular PWA Mike 黃升煌 Service Worker 全端開發人員天梯:https://www.facebook.com/fullstackledder/
  • 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
  • 12. MEETUP Service Worker 起手式 (3) – 啟動 self.addEventListener('activate', function(event){ // 判斷哪些資源過期並清除 });
  • 13. MEETUP Service Worker 起手式 (3) – 回應 self.addEventListener('fetch', function(event) { if (cacheUrls.find(url => url === event.request.url)) { event.respondWith(caches.match(event.request)); } });
  • 16. MEETUP 常見的 Cache 策略 • The Offline Cookbook • 兩個重點 • 優先透過網路 • 優先透過 cache
  • 17. Angular PWA 之 Service Worker (DEMO)
  • 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()); }
  • 24. MEETUP 檢查是否離線狀態 window.addEventListener('online', () => { console.log('online'); }); window.addEventListener('offline', () => { console.log('offline'); });
  • 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 })
  • 31. MEETUP 如何自訂 Service Worker (3) • angular.json "assets": [ ..., "src/sw-main.js", "src/sw-cdn.js" ]
  • 33. MEETUP Resources • Progress Web Apps • Angular Service Worker Introduction • Progress Web App Checklist • Using Service Workers