📜 ⬆️ ⬇️

PWA is easy. Hello Habr

Continuing familiarity with Progressive Web Applications. After the theoretical last part, it 's time to move on to practice.

Today we will build a simple, but full PWA "Hello Habr".


')

The application is available at https://altrusl.imtqy.com/habr-pwa/hello-habr/ . When you open in a browser on a mobile device, you can add a shortcut to your home screen and launch it in full screen mode.

If anyone wants to try this example on his computer, then Chrome allows you to work locally with simple PWA applications without installing third-party web servers with SSL certificates.
Instructions for running "Hello Habr" locally
You need to install this or a similar extension from the Chrome web store, which is a local web server. Without PHP support, naturally.



“Hello Habr” files can be downloaded from GitHub -a - https://github.com/altrusl/habr-pwa/tree/master/hello-habr

Put everything in one directory and point it to the web server.


"Hello Habr" consists of one page. He shows on it a picture (logo) and an animated inscription.

"Hello Habr" code

index.html


<html> <head> <title>Hello Habr</title> <script src="hh.js"></script> <link rel="stylesheet" href="hh.css" /> <script type="text/javascript"> if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw.js') .then(function(registration) { console.log('Registration successful, scope is:', registration.scope); }) .catch(function(error) { console.log('Service worker registration failed, error:', error); }); } </script> </head> <body> <div class="center"> <p id="text"></p> </div> <div id="logo"></div> </body> </html> 

hh.css


 @font-face { font-family: Zaplyv-Heavy; src: url(Zaplyv-Heavy.otf); } body { display: flex; align-items: center; align-content: center; justify-content: center; overflow: auto; } .center { font-family: Zaplyv-Heavy; font-size: 8vmax; } #logo { background-image: url(logo.jpg); background-size: 100%; width: 100px; height: 100px; position: absolute; top: 0; right: 0; margin: 10px; } 

hh.js


 window.onload = function() { fetch("hh.txt?mode=nocache").then(data => data.text()).then(data => { animateText(data) }); } function animateText(data) { var ele = document.getElementById("text"), txt = data.split(""); var interval = setInterval(function(){ if(!txt[0]){ return clearInterval(interval); }; ele.innerHTML += txt.shift(); }, 150); } 

hh.txt


 Hello Hubr 


There is also a custom font. Total - the minimum full set of average web site resources. If you open index.html in the browser, a picture and an inscription will appear. The inscription is loaded with javascript via fetch from the hh.txt file - the simplest model of a common PWA application.

If you open without sw.js, then this will be a regular web site. Add Service Worker to our files.

sw.js
 // Caches var CURRENT_CACHES = { font: 'font-cache-v1', css:'css-cache-v1', js:'js-cache-v1', site: 'site-cache-v1', image: 'image-cache-v1' }; self.addEventListener('install', (event) => { self.skipWaiting(); console.log('Service Worker has been installed'); }); self.addEventListener('activate', (event) => { var expectedCacheNames = Object.keys(CURRENT_CACHES).map(function(key) { return CURRENT_CACHES[key]; }); // Delete out of date caches event.waitUntil( caches.keys().then(function(cacheNames) { return Promise.all( cacheNames.map(function(cacheName) { if (expectedCacheNames.indexOf(cacheName) == -1) { console.log('Deleting out of date cache:', cacheName); return caches.delete(cacheName); } }) ); }) ); console.log('Service Worker has been activated'); }); self.addEventListener('fetch', function(event) { console.log('Fetching:', event.request.url); event.respondWith(async function() { const cachedResponse = await caches.match(event.request); if (cachedResponse) { console.log("\tCached version found: " + event.request.url); return cachedResponse; } else { console.log("\tGetting from the Internet:" + event.request.url); return await fetchAndCache(event.request); } }()); }); function fetchAndCache(request) { return fetch(request) .then(function(response) { // Check if we received a valid response if (!response.ok) { return response; // throw Error(response.statusText); } var url = new URL(request.url); if (response.status < 400 && response.type === 'basic' && url.search.indexOf("mode=nocache") == -1 ) { var cur_cache; if (response.headers.get('content-type') && response.headers.get('content-type').indexOf("application/javascript") >= 0) { cur_cache = CURRENT_CACHES.js; } else if (response.headers.get('content-type') && response.headers.get('content-type').indexOf("text/css") >= 0) { cur_cache = CURRENT_CACHES.css; } else if (response.headers.get('content-type') && response.headers.get('content-type').indexOf("font") >= 0) { cur_cache = CURRENT_CACHES.font; } else if (response.headers.get('content-type') && response.headers.get('content-type').indexOf("image") >= 0) { cur_cache = CURRENT_CACHES.image; } else if (response.headers.get('content-type') && response.headers.get('content-type').indexOf("text") >= 0) { cur_cache = CURRENT_CACHES.site; } if (cur_cache) { console.log('\tCaching the response to', request.url); return caches.open(cur_cache).then(function(cache) { cache.put(request, response.clone()); return response; }); } } return response; }) .catch(function(error) { console.log('Request failed for: ' + request.url, error); throw error; }); } 


As you can see, we create five caches for each type of resource. Cache site - for html files. All resources are cached, with the exception of those who have “mode = nocache” in the GET query - and this is our query to the hh.txt file with the line for the label.
Sometimes you can see that the resource is taken from the disk cache. This is a frequent problem when developing applications with the Service Worker, therefore it is better to disable the disk cache (browser cache). And not in my browser, but on the server — for example, in
.htaccess
 # Cache-Control Headers <ifModule mod_headers.c> <FilesMatch (\.css|\.js|sprites\.png)$> Header unset ETag Header unset Expires Header set Cache-Control "no-cache" </FilesMatch> </IfModule> 

The logic of sw.js is simple - “Cache falling back to the network”. First, the requested resource is checked in the cache, if it is there, it is taken and returned to the browser from there. If not, it is obtained from the network, returned to the browser, and a copy of the resource is placed in the cache.

After the first opening of the index.html page in the Chrom-a console, you can see the records about the installation and activation of the Service Worker. After the second opening in the repository, our caches are created and our resources are placed in them. It also shows that at subsequent discoveries, only requests to hh.txt go to the web server, all other resources are taken from the Service Worker.

Screenshot


Locally stored index.html, hh.css, hh.js, hh.otf, logo.jpg - this is the very same application shell, a shell of static resources and data that acts as the shell of the program on the client. All the dynamic information necessary for the operation of the site is obtained by javascript requests to the server and displaying the received data in the shell-e app. In our case, this is a request for text.txt.

In order to be called a functionally full PWA, “Hello Habr” lacks one thing - the icons on the home screen of smartphones and launch in full screen mode.

To do this, you need to connect the application manifest to index.html:
manifest.json
 { "short_name": "Hello Habr", "name": "Hello Habr - PWA example", "icons": [ { "src": "logo3.jpg", "type": "image/jpg", "sizes": "192x192" }, { "src": "logo2.jpg", "type": "image/jpg", "sizes": "512x512" } ], "start_url": "index.html", "background_color": "#3367D6", "display": "standalone", "scope": "/habr-pwa/hello-habr/", "theme_color": "#3367D6" } 

It connects to index.html:
 <link rel="manifest" href="manifest.json"> 


After that, mobile browsers (each in its own way) will offer to create a shortcut for the application on the home screen. When launched by shortcut, the application will open in standalone mode - without browser controls. More on the manifest options - on Google Developers .

The “Hello Habr” application minimally possesses all the properties of PWA and is in fact it. As you can see, in order to translate a simple site into PWA, you just need to connect the manifest and the Service Worker file. The sw.js used is fairly universal.

Next time we will transfer to PWA a ready site on CMS Joomla (site out of the box with the original demo data). Moreover, sw.js will remain almost the same.

Source: https://habr.com/ru/post/419585/


All Articles