Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Progressive Angular apps
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
Ciro Nunes
November 22, 2016
Technology
960
3
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Progressive Angular apps
20 minutes talk about Progressive Web Apps with Angular 2
Ciro Nunes
November 22, 2016
More Decks by Ciro Nunes
See All by Ciro Nunes
Rust Front-end with Yew
cironunes
0
110
Type safe CSS with Reason
cironunes
0
160
What I've learned building automated docs for Ansarada's design system
cironunes
0
110
Beyond ng new
cironunes
2
260
Animate your Angular apps
cironunes
0
470
Sweet Angular, good forms never felt so good
cironunes
0
120
Sweet Angular, good forms never felt so good
cironunes
0
330
Angular: Um framework. Mobile & desktop.
cironunes
1
620
Firebase & Angular
cironunes
0
310
Other Decks in Technology
See All in Technology
Claude Codeから見る、エンジニアの世界の変容とその先
oikon48
7
4.3k
AI時代、つくる力を自分たちの手に。 ──電通×KAG、アジャイルとAI駆動開発で挑む開発の変革
yuukiyo
3
390
日本AIベンチャーレポート2026
kentarofujii
0
240
Agent 活用環境の構築・運用のための AWS サービスのご紹介/agentcore-for-building-and-operating-agents
ren8k
1
150
【データ横丁主催】AI エージェント時代のTranslytical Data Platform
shisyu_gaku
0
300
「作れる」と「リリースできる」の間にあったもの── PdMを外して見えた、PdMがやるべき仕事/Buildable ≠ Shippable: What Removing the PM Taught Me About the PM’s Job
yappli_developers
0
290
BacklogのRAG 今ならこう作る - S3 Vectorsと自前パイプラインの勘所
revsystem
0
140
How we choose session proposals
kawaguti
PRO
0
170
Draft AIエージェントの トークン消費を最小化する 8つの原則
kinopeee
5
1.8k
Filter What the LLM Reads: RAG Governance with AgentCore Gateway
yakumo
0
110
背中から、背中へ ー 社外コミュニティで学んだ「雑に背中を押す」という恩送り ー / easygoing encouragement and pay forward to community
naitosatoshi
0
330
LLM-as-a-Judgeは本当に信頼できるのか――評価器を評価する話
taka_aki
3
1.1k
Featured
See All Featured
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
4.6k
Collaborative Software Design: How to facilitate domain modelling decisions
baasie
1
350
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
Writing Fast Ruby
sferik
630
63k
Thoughts on Productivity
jonyablonski
76
5.4k
Are puppies a ranking factor?
jonoalderson
2
4.1k
AI Search: Where Are We & What Can We Do About It?
aleyda
0
8.1k
Color Theory Basics | Prateek | Gurzu
gurzu
1
500
What the history of the web can teach us about the future of AI
inesmontani
PRO
2
750
Conquering PDFs: document understanding beyond plain text
inesmontani
PRO
4
3.2k
First, design no harm
axbom
PRO
2
1.4k
SEOcharity - Dark patterns in SEO and UX: How to avoid them and build a more ethical web
sarafernandez
0
310
Transcript
Progressive WEB APPS
@cironunesdev
None
None
None
Progressive Web App
Progressive Web App Enhancement
Progressive Web App Enhancement Like
http://alistapart.com/article/understandingprogressiveenhancement
http://alistapart.com/article/understandingprogressiveenhancement
App Like
RESPONSIVE CONNECTIVITY INDEPENDENT DISCOVERABLE ENGAGEABLE INSTALLABLE SAFE LINKABLE
App Like, but…
Service Workers Cache API Fetch API Notification API HTTPS ❤
}
How to build a PWA?
1. Web Application Manifest 2. App Shell 3. Cache (SW)
{ "name": "Ali Express", "short_name": "AliExpress", "icons": [{ "src": "images/icons/icon-128x128.png",
"sizes": "128x128", "type": "image/png" }], "start_url": "/index.html", "display": "standalone", "background_color": "#3E4EB8", "theme_color": "#2F3BA2" } manifest.webapp
Splash Screen
1. Web Application Manifest 2. App Shell 3. Cache (SW)
None
None
None
1. Architect & implement your app shell 2. Cache via
service workers
<link rel="stylesheet" href="inline.css"> <div> <header> <h1>App shell</h1> <button>Menu</button> <menu>...</menu> </header>
<main class="content"> ... </main> </div>
1. Architect & implement your app shell 2. Cache via
service workers
if ('serviceWorker' in navigator) { navigator['serviceWorker'] .register('./service-worker.js') .then(() => console.log('Service
Worker Registered')); } main.ts REGISTER
var cacheName = 'myApp'; var filesToCache = [...]; self.addEventListener('install', function(e)
{ e.waitUntil( caches.open(cacheName).then(function(cache) { return cache.addAll(filesToCache); }) ); }); service-worker.js ADD TO CACHE
self.addEventListener('activate', (e) => { e.waitUntil(self.clients.claim()); e.waitUntil( caches.keys().then((keyList) => { return
Promise.all(keyList.map((key) => { if (key !== cacheName) { return caches.delete(key); } })); }) ); }); service-worker.js CLEAR CACHE
self.addEventListener('fetch', (e) => { e.respondWith( caches.match(e.request).then((response) => { return response
|| fetch(e.request); }) ); }); service-worker.js READING FROM CACHE
1. Web Application Manifest 2. App Shell 3. Cache (SW)
self.addEventListener('fetch', function(e) { var dataUrl = 'https://sample-api.com'; if (e.request.url.indexOf(dataUrl) >
-1) { e.respondWith( caches.open(dataCacheName).then(function(cache) { return fetch(e.request).then(function(response){ cache.put(e.request.url, response.clone()); return response; }); }) ); } else { e.respondWith( caches.match(e.request).then(function(response) { return response || fetch(e.request); }) ); } }); service-worker.js
self.addEventListener('fetch', function(e) { var dataUrl = 'https://sample-api.com'; if (e.request.url.indexOf(dataUrl) >
-1) { e.respondWith( caches.open(dataCacheName).then(function(cache) { return fetch(e.request).then(function(response){ cache.put(e.request.url, response.clone()); return response; }); }) ); } else { e.respondWith( caches.match(e.request).then(function(response) { return response || fetch(e.request); }) ); } }); service-worker.js
self.addEventListener('fetch', function(e) { var dataUrl = 'https://sample-api.com'; if (e.request.url.indexOf(dataUrl) >
-1) { e.respondWith( caches.open(dataCacheName).then(function(cache) { return fetch(e.request).then(function(response){ cache.put(e.request.url, response.clone()); return response; }); }) ); } else { e.respondWith( caches.match(e.request).then(function(response) { return response || fetch(e.request); }) ); } }); service-worker.js
self.addEventListener('fetch', function(e) { var dataUrl = 'https://sample-api.com'; if (e.request.url.indexOf(dataUrl) >
-1) { e.respondWith( caches.open(dataCacheName).then(function(cache) { return fetch(e.request).then(function(response){ cache.put(e.request.url, response.clone()); return response; }); }) ); } else { e.respondWith( caches.match(e.request).then(function(response) { return response || fetch(e.request); }) ); } }); service-worker.js
None
caches.match(e.request.clone()).then((response) => { return response || fetch(e.request.clone()).then((theResponse) => { return
caches.open(dataCacheName).then((cache) => { cache.put(e.request.url, theResponse.clone()); return theResponse.clone(); }); }); }); service-worker.js
Profit!
Profit! What about a protip?
Lighthouse
None
None
None
Bootstrap App shell Service worker Notifications
None
None
Bootstrap App shell Service worker Notifications
None
~ $ npm i --save @angular/app-shell
~ $ npm i --save @angular/app-shell // App code import
{ AppShellModule } from '@angular/app-shell'; @NgModule({ bootstrap: [AppComponent], imports: [ BrowserModule, AppShellModule.runtime(), AppModule })
@Component({ selector: 'app-root-component', template: ` <!-- Only show loading indicator
in the shell --> <loading-indicator *shellRender> </loading-indicator> <!-- Hide a dynamic view until runtime --> <dynamic-view *shellNoRender> </dynamic-view> ` }) export class AppRootComponent {}
Can we be faster?
None
@NgModule({ bootstrap: [AppComponent], imports: [ AppShellModule.prerender(), AppModule, UniversalModule.withConfig({...}) })
Bootstrap App shell Service worker Notifications
~ $ npm i --save @angular/service-worker
~ $ npm i --save @angular/service-worker // worker-basic.min.js is copied
from // node_modules/@angular/service-worker/bundles if (navigator.serviceWorker) { navigator.serviceWorker.register('/worker-basic.min.js'); }
{ "routing": { "routes": { "/": { "prefix": false }
}, "index": "/index.html" } } ngsw-manifest.json
Bootstrap App shell Service worker Notifications
self.addEventListener('push', function(e) { e.waitUntil( fetch('http://localhost:8090/pushdata').then(function(response) { return response.json(); }).then(function(data) {
return self.registration.showNotification(title, { body: body, icon: icon, tag: tag }); }, function(err) { err(err); }) ); }); worker-push.js
self.addEventListener('push', function(e) { e.waitUntil( fetch('http://localhost:8090/pushdata').then(function(response) { return response.json(); }).then(function(data) {
return self.registration.showNotification(title, { body: body, icon: icon, tag: tag }); }, function(err) { err(err); }) ); }); worker-push.js
None
pwa.rocks Go get inspired and create something great!
@cironunesdev Dzięki!