- Build a simple webapp with API
- Add PWA features to enhance user experience
- Deploy to firebase and test it on a real device
- get a free api key at https://newsapi.org
- create empty directory
- add
index.html
- add
index.js
as module - add
index.css
- use google fonts: https://fonts.google.com/?selection.family=Manjari
- add bootstrap: https://getbootstrap.com/docs/4.3/getting-started/introduction/
index.js
function getNews() {
fetch('https://newsapi.org/v2/top-headlines?country=us&apiKey=<YOUR_API_KEY>')
.then(response => response.json())
.then(results => renderNews(results.articles))
}
function renderNews(news) {
const cols = document.getElementById('cardContainer');
news.map(article => {
cols.innerHTML += buildCard(article.title, article.urlToImage, article.publishedAt)
})
}
function buildCard(title, imgLink, date) {
return `
<div class="card">
<img src=${imgLink} class="card-img-top" alt="...">
<div class="card-body">
<h5 class="card-title">${title}</h5>
<p class="card-text"><small class="text-muted">${date}</small></p>
</div>
</div>
`;
}
window.addEventListener('DOMContentLoaded', () => {
getNews();
});
index.html
<div class="container-fluid p-5">
<h1 class="display-1">Top News</h1>
<div class="row">
<div class="card-columns" id="cardContainer">
<!-- Generated by JS -->
</div>
</div>
</div>
<script src="index.js" type="module"></script>
- run
firebase-login
- run
firebase-init
(usebuild
for build folder) - run
npm run build
- run
filrebase deploy
- check with lighthouse
- should be added the public root
<link rel="manifest" href="manifest.json"/>
manifest.json
{
"name": "TopNews",
"short_name": "TopNews",
"icons": [
{
"src": "/images/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/images/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"start_url": "/index.html",
"display": "standalone",
"background_color": "#3E4EB8",
"theme_color": "#2F3BA2"
}
- add images (freepik + preview)
- ios metatags
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="TopNews PWA">
<link rel="apple-touch-icon" href="/images/icons/icon-152x152.png">
- Can be inspected in caro dev-tools
<meta name="theme-color" content="#2F3BA2" />
- create a service worker file
news-sw.js
- check and register the service worker on
index.js
index.js
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/news-sw.js')
.then((reg) => console.log('Service worker registered.', reg));
});
}
- create cache name and array of files to cache:
news-sw.js
const CACHE_NAME = 'NEWS_CACHE_V1';
const CACHED_FILES = [
'/',
'/index.html',
'/index.js',
'/index.css',
];
self.addEventListener('install', function (event) {
event.waitUntil(
caches.open(CACHE_NAME)
.then(function (cache) {
return cache.addAll(CACHED_FILES);
})
);
});
self.addEventListener('fetch', function (event) {
event.respondWith(
caches.open(DATA_CACHE_NAME).then((cache) => {
return cache.match(event.request)
.then((response) => {
return response || fetch(event.request).then(response => {
if(response.status === 200) {
cache.put(event.request.url, response.clone());
}
})
});
})
);
});
- load workbox
importScripts('https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js');
if (workbox) {
console.log(`Workbox is loaded`);
}
- cache api
workbox.routing.registerRoute(
new RegExp('^https://newsapi.org'),
new workbox.strategies.CacheFirst({
cacheName: 'api-cache',
plugins: [
new workbox.cacheableResponse.Plugin({
statuses: [0, 200],
})
]
})
);
- cache static files
workbox.routing.registerRoute(
/\.(?:js|css|html)$/,
new workbox.strategies.NetworkFirst()
);
- cache fonts with options
workbox.routing.registerRoute(
/^https:\/\/fonts\.gstatic\.com/,
new workbox.strategies.CacheFirst({
cacheName: 'google-fonts-webfonts',
plugins: [
new workbox.cacheableResponse.Plugin({
statuses: [0, 200],
}),
new workbox.expiration.Plugin({
maxAgeSeconds: 60 * 60 * 24 * 365,
maxEntries: 30,
}),
],
})
);
- add some UI to
index.html
index.html
<div class="d-flex justify-content-between">
<h1 class="display-1">Top News</h1>
<div class="lead ">
You like my app? Gee, thanks, just build it<br/>
I want it, I got it, you want it?,
<button class="btn btn-primary" id="btnAdd">you got it!</button>
<br/>
</div>
</div>
- ad to index.js
let deferredPrompt;
window.addEventListener('beforeinstallprompt', (event) => {
deferredPrompt = event;
});
const btnAdd = document.getElementById('btnAdd');
btnAdd.addEventListener('click', () => deferredPrompt.prompt());
- test install and uninstall
- Deploy to firebase
- Try to install on your macOS or Android phone