- 00:00:01 welcome to this video where I want to
- 00:00:03 build a basic progressive web app with
- 00:00:05 you now I already do have a video about
- 00:00:08 progressive web apps on my channel you
- 00:00:10 can find a link in the video description
- 00:00:11 of course and this our video it's
- 00:00:14 basically taken from my complete
- 00:00:16 progressive web of course I host an
- 00:00:17 udemy of course you can also find a link
- 00:00:19 to Disney video description now in this
- 00:00:22 video here I want to build a progressive
- 00:00:24 weather with you which works offline and
- 00:00:27 which we can install on the device home
- 00:00:29 screen of an Android device so let's do
- 00:00:32 that let's dive into that and let's
- 00:00:34 learn what it takes to create a basic
- 00:00:36 progressive web app
- 00:00:40 so in the video description you can find
- 00:00:43 a link to a starting project which I
- 00:00:45 already opened in webstorm it's a very
- 00:00:48 basic project and as you can see in the
- 00:00:50 readme of that file you'll need no js'
- 00:00:52 to run this development server this
- 00:00:55 project uses and you'll also need to
- 00:00:57 install the dependencies though their
- 00:00:59 dependency is really just as one
- 00:01:01 dependency here at HTTP server and then
- 00:01:04 we have to start command which spins up
- 00:01:06 the HTTP server so let's do that let's
- 00:01:08 first of run an NPM install to install
- 00:01:11 that server and once we did this we can
- 00:01:13 start it with NPM start and of course
- 00:01:16 keep that process running because we
- 00:01:17 want to keep our development server
- 00:01:19 running you'll then find the addresses
- 00:01:21 under which you can visit the project in
- 00:01:23 the console but you can also simply
- 00:01:25 wizard localhost 8080 1 now this page is
- 00:01:30 a very simple web application it's not a
- 00:01:32 progressive web app at all and all we
- 00:01:34 can do right now is we have this huge
- 00:01:36 card here which you can click and when
- 00:01:38 we click it then the text down here
- 00:01:40 changes with a little animation and we
- 00:01:42 can go back and forth between the
- 00:01:44 different content so obviously the
- 00:01:46 application here might not blow your
- 00:01:48 minds but the cool thing is that it's a
- 00:01:51 nice application where we can add
- 00:01:52 progressive features or features of
- 00:01:54 progressive web apps to make it a
- 00:01:56 progressive web app I strongly recommend
- 00:01:59 checking out that other video I
- 00:02:00 mentioned which I took from my complete
- 00:02:02 guide to get you into the basics of
- 00:02:05 progressive weather app so that you
- 00:02:06 learn why you might want to build them
- 00:02:07 and what makes a progressive web apps
- 00:02:09 now with that let's turn this
- 00:02:12 application into a progressive web app
- 00:02:14 by first of all adding a manifest file a
- 00:02:18 manifest file is a file which is read by
- 00:02:21 the browser's by browsers supporting it
- 00:02:23 at least and this file then allows the
- 00:02:26 browser to get some extra information
- 00:02:28 about your page something like the icon
- 00:02:31 it should use or for example the name
- 00:02:33 description of the page things like
- 00:02:36 these which allow the browser to display
- 00:02:38 your page correctly and very important
- 00:02:41 to install it on the home screen with
- 00:02:44 your own icon and so on so that's the
- 00:02:47 idea behind the manifest file in general
- 00:02:50 though we need to understand which
- 00:02:52 browsers do some
- 00:02:53 word which progressive web app features
- 00:02:55 let's have a look at that on the web app
- 00:02:58 manifest page of the Mozilla developer
- 00:03:00 Network you can not only find some
- 00:03:03 information about how this file should
- 00:03:04 be structured and which properties you
- 00:03:06 can add I strongly recommend this
- 00:03:08 article but of course I will also walk
- 00:03:09 you through the most important
- 00:03:10 properties in this video but you can
- 00:03:12 also found if you scroll down you can
- 00:03:15 also find some information about the
- 00:03:17 browser support now what you see here
- 00:03:20 browser compatibility that it's not
- 00:03:22 supported at all that's not entirely
- 00:03:24 true many features like installing it on
- 00:03:27 the home screen simply doesn't work on
- 00:03:28 desktop like that but if you check out
- 00:03:31 mobile that's the more interesting part
- 00:03:32 because that is what we want to add our
- 00:03:35 application to the device screen and
- 00:03:36 there you see how it gets how it is
- 00:03:39 supported and support is pretty well on
- 00:03:41 Android now iOS Safari the support is
- 00:03:45 not there yet but Safari is also working
- 00:03:49 on progressive web as we see some
- 00:03:51 development there so chances are that
- 00:03:53 this file will also be readable by
- 00:03:55 Safari on iOS or other browsers on iOS
- 00:03:58 in the future so for now let's focus on
- 00:04:01 Chrome for Android and all the other
- 00:04:03 Android browsers and then we see it's
- 00:04:05 pretty good so this is the web app
- 00:04:07 manifest and to use such a file we
- 00:04:10 should add it to our project now the
- 00:04:12 application is actually served from the
- 00:04:15 public folder this is where all the
- 00:04:17 source code of the web app you saw lives
- 00:04:19 now if we have a look at it the river
- 00:04:21 index.html file and then we have our
- 00:04:24 source folder with the different asset
- 00:04:26 scripts images and so on now important
- 00:04:29 here I only got one HTML file I'm not
- 00:04:32 creating a single page application ship
- 00:04:34 though well it is only a single page so
- 00:04:36 I guess technically it is one but I'm at
- 00:04:38 least not using any framework I'm not
- 00:04:40 using angular react or view here if you
- 00:04:43 check out my JavaScript file it's a very
- 00:04:45 simple file using vanilla JavaScript and
- 00:04:47 this is important you can turn a single
- 00:04:50 page application driven by react angular
- 00:04:53 and so on into a progressive web app you
- 00:04:56 can also turn any other application into
- 00:04:58 a progressive weather also multi page
- 00:05:01 applications and the course I mentioned
- 00:05:03 at the beginning my udemy course
- 00:05:05 actually uses a mult
- 00:05:06 Paige application to show you how
- 00:05:08 versatile this concept is and that you
- 00:05:10 can apply to any web app that's really
- 00:05:12 important to me that you understand this
- 00:05:14 any web app so back to that manifesto
- 00:05:18 chase have folded the right place to add
- 00:05:21 it is right next or index.html file so
- 00:05:23 there I'll create a new file and I'll
- 00:05:25 name it manifest Jason it has to be
- 00:05:28 adjacent file now with that added
- 00:05:31 without any content in it yet I'll go to
- 00:05:34 the index.html file and there at the end
- 00:05:37 of the head section I'll now add a new
- 00:05:39 link it won't be of type stylesheet
- 00:05:43 though instead it should be relating to
- 00:05:45 a manifest and the link should simply
- 00:05:48 point to slash many faster Jason so to
- 00:05:51 this manifest file once you did this we
- 00:05:55 can start filling this file with life
- 00:05:56 and since it's a JSON file we should of
- 00:05:59 course write jason code in there so what
- 00:06:02 goes into such a manifesto Jason fall
- 00:06:05 first of all you can give your
- 00:06:07 application a name like a basic
- 00:06:10 progressive web app whatever you want
- 00:06:13 this name will be used in some places
- 00:06:15 for example on the splash screen which
- 00:06:18 Android will automatically show you if
- 00:06:20 you start your application after you
- 00:06:23 installed it on the home screen however
- 00:06:25 there are all the places like below the
- 00:06:27 icon where this name is simply too long
- 00:06:29 that's why there's also a short name
- 00:06:32 property and this showed us the name
- 00:06:34 indicate be a short name like basic PWA
- 00:06:38 this will be used below the icon on your
- 00:06:40 home screen and to make sure it's not
- 00:06:42 getting cut off you should pick a short
- 00:06:44 while string a short text here now
- 00:06:47 beside that we also have a start URL
- 00:06:50 because all lowercase by the way because
- 00:06:54 if you think about your app being added
- 00:06:57 to the home screen and the important
- 00:06:59 part about this installation thing which
- 00:07:01 I'll later show you is of course that
- 00:07:03 all the time when I say install it's
- 00:07:05 still a web app it's not a native
- 00:07:09 Android app you're running then it is a
- 00:07:11 web app in its core it's going to wizard
- 00:07:13 your web page which gets served from
- 00:07:15 your servers so this is why we have to
- 00:07:17 specify a start URL here
- 00:07:20 you could just say dot to simply use
- 00:07:22 this folder where the manifesto Jason
- 00:07:24 for lies in as a start URL which makes
- 00:07:27 sense for me here because that's the
- 00:07:28 public folder and that is our route web
- 00:07:30 folder but you could of course also say
- 00:07:32 slash index.html or whatever it is so
- 00:07:36 I'll go back to dot though because I
- 00:07:37 simply want to serve my root folder
- 00:07:39 whenever the user taps this icon on the
- 00:07:42 home screen now there's also another
- 00:07:44 important property that's the display
- 00:07:46 property here we can control how our
- 00:07:49 progressive web app runs in the end if
- 00:07:52 we open it if we open it from the home
- 00:07:54 screen I mean does it should look like
- 00:07:56 it's running the browser with the
- 00:07:58 browser toolbar at the top or does it
- 00:08:00 look like a real native app still again
- 00:08:03 it will always be a web app but we can
- 00:08:05 change the way it looks and to really
- 00:08:07 create an immersive feeling we might
- 00:08:10 want to pick standalone here our
- 00:08:13 alternatives would be fullscreen or
- 00:08:17 browser so here I'll pick standalone to
- 00:08:21 really make it look like a standalone
- 00:08:23 application and therefore reassembling
- 00:08:26 this native app look we also have
- 00:08:30 orientation now orientation allows us to
- 00:08:33 control how the user should view our
- 00:08:36 application now we can't rely on the
- 00:08:38 browser and forcing this actually or the
- 00:08:41 device but here we could say portrait to
- 00:08:44 make sure that this app can only be
- 00:08:46 viewed in portrait mode if started from
- 00:08:48 the home screen so I'll add this here
- 00:08:51 too and now the nice thing is the
- 00:08:54 background color and this is again all
- 00:08:56 lowercase here the background colors for
- 00:09:00 example used on the splash screen which
- 00:09:02 is created automatically which will be
- 00:09:04 the background color and your app icon
- 00:09:06 now I'll come back to the icon thing but
- 00:09:09 that is for example reset the background
- 00:09:11 color
- 00:09:11 what the background color here is not
- 00:09:13 it's the background color of your
- 00:09:15 general page so it's not this white
- 00:09:18 background here this is not controlled
- 00:09:20 for the manifest and I'm really talking
- 00:09:22 about the background during startup of
- 00:09:24 the application for example so here why
- 00:09:26 don't we pick some greyish color we also
- 00:09:30 have a theme color and the theme color
- 00:09:33 now for example Styles the toolbar
- 00:09:35 already when your application runs in
- 00:09:38 the browser the browser toolbar color
- 00:09:40 should change but also especially if we
- 00:09:43 started our app through tapping the icon
- 00:09:45 and then for example we open the tasks
- 00:09:48 which are on our mobile device we will
- 00:09:50 see that our application runs as a
- 00:09:52 separate task colored in our theme color
- 00:09:54 so that is where we can see that now you
- 00:09:57 can pick any color I'll simply pick a
- 00:10:00 color from this image here so maybe this
- 00:10:03 blue here which is the following hex
- 00:10:06 code 5f AAA e5 and that again will be
- 00:10:11 used in some places for example the task
- 00:10:14 switcher now with that we can go to
- 00:10:18 another important part the icons and
- 00:10:20 this is I cans not I can and I can say
- 00:10:24 is an array because you can specify
- 00:10:26 multiple icons in different sizes
- 00:10:28 basically each icon is defined as a
- 00:10:31 JavaScript object here in this JSON file
- 00:10:33 and then has free properties the source
- 00:10:36 pointing to the I can file now in this
- 00:10:39 project you are using you already will
- 00:10:41 find this images folder and in there
- 00:10:43 this icons folder where I prepared some
- 00:10:45 icons for you and here we can simply
- 00:10:47 point to them so we can say source
- 00:10:50 images icons and then for example app I
- 00:10:53 can – 96 by 96 dot PNG that is the path
- 00:10:59 to the I can I wanna use we also have to
- 00:11:03 explicitly set these sizes of that icon
- 00:11:05 because we can probably guess that it's
- 00:11:07 96 by 96 but of course we could have
- 00:11:10 named this file anything we want so we
- 00:11:12 clearly have to tell the browser what
- 00:11:14 the size of that icon is and here it's
- 00:11:16 96 by 96 and this is how we should
- 00:11:18 specify this format this value here now
- 00:11:21 why do we need to tell the browser the
- 00:11:23 size of the icon because the browser
- 00:11:25 should pick the right icon for the
- 00:11:27 different devices where this application
- 00:11:29 might run on and depending on the
- 00:11:31 density of the screen and the resolution
- 00:11:33 of the screen of the device it should
- 00:11:34 pick a well-fitting icon the last
- 00:11:37 property for each icon is the type and
- 00:11:40 here this is image PNG and it should be
- 00:11:43 a PNG image if you want to use it
- 00:11:46 as a home screen icon as a splash screen
- 00:11:48 icon theoretically other formats are
- 00:11:51 supported to hurt you but to have an
- 00:11:53 installable application where chrome
- 00:11:55 actively prompts the user whether he
- 00:11:58 wants to install it add a to the home
- 00:12:00 screen or not you should set this at
- 00:12:02 least this is the case right now
- 00:12:04 now this is one icon but we got more I
- 00:12:06 can store it so I'll specify them all
- 00:12:09 the next one we'll check ft dimensions
- 00:12:12 144 by 144 and this is actually an icon
- 00:12:16 which you should always provide this
- 00:12:18 dimension 144 by 144 this is an icon
- 00:12:21 which is required so that chrome shows
- 00:12:24 this do you want to install this app
- 00:12:27 pop-up to the user basically 144 by 144
- 00:12:30 has to be provided if you don't provide
- 00:12:33 any other icons provide this size so the
- 00:12:36 next icon I want to add here is of
- 00:12:39 course the the next I can – that folder
- 00:12:42 so 2 5 6 by 2 5 6 and then let's add the
- 00:12:46 last icon this last I can here is pretty
- 00:12:48 important for the splash screen display
- 00:12:51 though it will work without it
- 00:12:53 now this is a basic app manifest a basic
- 00:12:57 manifest adjacent fall now with that
- 00:12:59 let's save all of that and let's go back
- 00:13:02 to this application let's reload it and
- 00:13:04 let's open the developer tools now I'm
- 00:13:06 using Chrome here and I strongly
- 00:13:08 recommend using Chrome because they have
- 00:13:10 awesome developer tools when it comes to
- 00:13:12 debugging or working with progressive
- 00:13:14 web apps there you can visit the
- 00:13:16 application tab and let me increase this
- 00:13:21 so there you can visit the application
- 00:13:22 tab and there you'll find this manifest
- 00:13:25 area if you click on it you should see
- 00:13:28 the information the browser could get
- 00:13:30 from the manifest you specified so the
- 00:13:33 name the short name the color and all
- 00:13:35 the icons you specified here so that's
- 00:13:38 awesome this seems all to work fine now
- 00:13:41 we could already manually add it to the
- 00:13:43 home screen we could go to a mobile
- 00:13:45 device an Android device simply open
- 00:13:48 this application if it were to run on a
- 00:13:50 server and then tap deep Add to Home
- 00:13:52 screen I can manually D add to
- 00:13:55 homescreen menu option we should then
- 00:13:57 already use this icon ansan but
- 00:14:00 Jerome won't actively prompt us to do
- 00:14:02 that to install it however there are
- 00:14:05 some criteria and a link to the criteria
- 00:14:07 can be found in the video description
- 00:14:09 which to find when Chrome will show you
- 00:14:12 this actively so when it actively asks
- 00:14:15 the user whether he wants to add the
- 00:14:17 page the user is currently on QT a home
- 00:14:19 screen or not now right now when I
- 00:14:22 record this video the criteria are that
- 00:14:24 you have a manifesto JSON file with 144
- 00:14:28 by 144 PNG icon that you of course
- 00:14:32 should specify a name and so on short
- 00:14:34 name and that you also have a
- 00:14:37 serviceworker
- 00:14:38 we don't have dead yet that you also
- 00:14:41 visited the page with a five-minute
- 00:14:44 pause in between budget that you came
- 00:14:46 back basically because you probably
- 00:14:48 liked the page and that's important that
- 00:14:51 your page has served over HTTP now
- 00:14:54 during development localhost is actually
- 00:14:56 an exception but you should serve it
- 00:14:59 over HTTP because service workers
- 00:15:01 require HTTPS and service workers are a
- 00:15:04 requirement for the app manifest again
- 00:15:06 localhost is the single exception that
- 00:15:10 exists where you can also serve your
- 00:15:12 progressive web app over localhost and
- 00:15:14 see all the features of course that's
- 00:15:15 not available when serving it on a real
- 00:15:17 server so there make sure you're serving
- 00:15:20 your page over HTTPS so what did we get
- 00:15:23 the manifest let's now add a service
- 00:15:26 worker and for that I'll add a
- 00:15:29 JavaScript file because a service worker
- 00:15:31 is just using javascript you could be
- 00:15:33 inclined to add it in the JavaScript
- 00:15:35 folder in the source folder but here's
- 00:15:38 an important thing a service worker
- 00:15:40 always has a scope scope defines which
- 00:15:43 pages a service worker can control
- 00:15:45 because a service worker is JavaScript
- 00:15:48 but not like your normal JavaScript like
- 00:15:51 here in the app dot J's file a service
- 00:15:54 worker isn't attached to a single page a
- 00:15:56 single file this app dot J's file is it
- 00:15:59 gets loaded by the index.html file here
- 00:16:01 at the bottom and it is attached to this
- 00:16:04 fall this is the reason why in app dot
- 00:16:06 ajs we can access the Dom off this
- 00:16:09 index.html file now a service worker is
- 00:16:12 also rich
- 00:16:14 through your pages but I'm deliberately
- 00:16:16 saying page s because you could add it
- 00:16:18 on any page but then it runs in the
- 00:16:22 background on a separate fret so not on
- 00:16:25 your main UI thread like this script
- 00:16:27 file runs but on a separate fret this
- 00:16:30 also means that for example on Android
- 00:16:33 it will keep on running even if your
- 00:16:35 page is closed which is amazing for
- 00:16:37 getting push messages for example
- 00:16:39 something I do show in my udemy course
- 00:16:41 so this is a serviceworker it runs on a
- 00:16:44 separate fret it's not connected to a
- 00:16:47 single page but instead it has a scope
- 00:16:50 which could be your entire domain all
- 00:16:52 the pages on the domain or a subset if
- 00:16:55 you limit the scope to a given folder in
- 00:16:57 your domain on your web page here so to
- 00:17:00 say and that's the important thing if I
- 00:17:02 were to add my serviceworker in this
- 00:17:04 javascript file the serviceworker could
- 00:17:07 only interact with pages stored in the
- 00:17:11 javascript file or in sub pages that of
- 00:17:14 course isn't helpful because we haven't
- 00:17:16 any pages in there so we should create
- 00:17:18 the serviceworker on the public folder
- 00:17:20 here so I'll create a new file and you
- 00:17:22 can name this file whatever you want
- 00:17:24 I'll name it s wjs this is a file which
- 00:17:29 will hold my serviceworker related
- 00:17:31 javascript code and again it's not
- 00:17:33 attached to a single page it is
- 00:17:35 event-driven and it can list is to
- 00:17:37 events fired by any of your pages or
- 00:17:40 other events not even coming from your
- 00:17:42 pages like incoming push notifications
- 00:17:44 now here I want Q react to some events
- 00:17:50 triggered by my index.html fault though
- 00:17:52 and first of all we should register this
- 00:17:56 serviceworker this is done in JavaScript
- 00:17:59 and of course in your normal JavaScript
- 00:18:01 because you have to tell the browser hey
- 00:18:04 here's a serviceworker related to my
- 00:18:06 page or a subset of my pages please
- 00:18:09 register it and if the browser doesn't
- 00:18:12 notice serviceworker yet or the
- 00:18:14 serviceworker file changed so if the
- 00:18:16 file size changed the browser will take
- 00:18:19 the serviceworker
- 00:18:20 and register it override the old one or
- 00:18:23 register it as a new one to code to
- 00:18:26 register a service program
- 00:18:27 therefore as I said has to be added in
- 00:18:29 the app dot JS file or directly in a
- 00:18:32 script part in the index.html file and
- 00:18:34 in there
- 00:18:36 I'll now simply add navigator that
- 00:18:39 refers to the browser Service Worker dot
- 00:18:43 register now here's an important thing
- 00:18:46 you should make sure that this code
- 00:18:48 where you register a serviceworker gets
- 00:18:50 executed on every page in your
- 00:18:52 application so that the user if he
- 00:18:56 Wizards a different page and not your
- 00:18:57 main page if you had multiple ones so
- 00:19:00 that even if the user wizard at some
- 00:19:02 other page like slash about that he
- 00:19:04 still installs the serviceworker and
- 00:19:06 then again you have one serviceworker
- 00:19:08 for all the pages so it's always the
- 00:19:10 same one you register but the user might
- 00:19:12 enter a different place a different path
- 00:19:14 in your app so you should be prepared
- 00:19:15 for this back to the registration code
- 00:19:19 there you pass an argument to register
- 00:19:22 and that simply skip off to the
- 00:19:23 serviceworker file so in this case it's
- 00:19:26 /s wjs pointing to the root folder and
- 00:19:30 then s wjs this is the serviceworker i
- 00:19:32 want to register now we have one issue
- 00:19:35 here though this code will work phone
- 00:19:37 will work fine on Chrome on the latest
- 00:19:39 version however what if the user uses a
- 00:19:42 browser which doesn't support service
- 00:19:44 workers we can check serviceworker
- 00:19:47 support on his serviceworker ready this
- 00:19:50 is a page on check our cobalt github do
- 00:19:52 link can be found in the video
- 00:19:54 description and on this page you see the
- 00:19:56 different serviceworker features and
- 00:19:58 which browsers supported or are working
- 00:20:01 on it and you see that Chrome and
- 00:20:03 Firefox support is decent but that
- 00:20:05 Safari and AD are working on
- 00:20:07 serviceworker features the general
- 00:20:10 features or some special features so if
- 00:20:13 the user uses Safari or edge right now
- 00:20:16 the code we wrote here this one will
- 00:20:19 throw an error because the browser can't
- 00:20:22 handle this
- 00:20:23 there is no serviceworker object on the
- 00:20:25 browser so what we should do is we
- 00:20:27 should wrap this into AF check where we
- 00:20:29 say if service worker in navigator so if
- 00:20:35 this object exists in the navigator then
- 00:20:37 we want to execute this code otherwise
- 00:20:39 we won't register a service worker
- 00:20:42 that of course means we don't have
- 00:20:43 access to the features we are about to
- 00:20:45 add but that doesn't matter because the
- 00:20:47 browser doesn't support it anyways so
- 00:20:50 with that we were just sir to Service
- 00:20:51 Worker now we can fill the service
- 00:20:54 worker with some life let's go to the
- 00:20:56 service worker and I said that the
- 00:20:58 service worker is event driven you
- 00:21:00 always react to events in there so what
- 00:21:03 you can do is you can add an event
- 00:21:05 listener you add it on self this refers
- 00:21:08 to the service worker process so to say
- 00:21:11 and then you call add event listener and
- 00:21:13 now there is no click event or something
- 00:21:16 like that because we're not reacting to
- 00:21:18 Dom events here because the service
- 00:21:20 worker is decoupled from the Dom you
- 00:21:22 can't access the Dom in a service worker
- 00:21:24 but there are other events or events
- 00:21:26 available for example the install event
- 00:21:29 this will be fired when a service worker
- 00:21:31 is you guessed it installed which is the
- 00:21:34 case as I mentioned if it's brand-new or
- 00:21:36 if it's an updated version and the
- 00:21:38 browser replaces the existing one for
- 00:21:41 the given scope for the given domain in
- 00:21:42 this case so if the install event fires
- 00:21:45 then I want to execute a function here
- 00:21:48 and in this function of first of all
- 00:21:51 simply log service worker installed this
- 00:21:55 is something I can do here
- 00:21:56 now we'll soon add more code to the
- 00:21:58 install event though let's also listen
- 00:22:01 to the activate event here now in the
- 00:22:04 activate event we know that it has been
- 00:22:07 activated and the difference between
- 00:22:09 installing and activating is that
- 00:22:12 installation happens instantly if the
- 00:22:14 browser detects a new service worker but
- 00:22:16 it will keep it waiting until it
- 00:22:18 activates until you or the user using
- 00:22:21 your page closed all tabs in his browser
- 00:22:24 where your page was open the reason for
- 00:22:26 it is is simple if you install a new
- 00:22:28 service worker and you overwrite the old
- 00:22:30 one if you would immediately activate
- 00:22:33 and replace the old one then you might
- 00:22:35 break the air page the user is currently
- 00:22:37 visiting because maybe your page is
- 00:22:39 firing somebody went to which the
- 00:22:41 service worker should react and you
- 00:22:42 suddenly push a new version onto this
- 00:22:45 page now existing processes might get
- 00:22:48 interrupted the page might not work
- 00:22:50 anymore that is why we have two separate
- 00:22:52 steps here
- 00:22:53 it will only activate after user closed
- 00:22:56 all tabs and then open it again then the
- 00:22:59 installed service worker will get
- 00:23:01 activated so these are two events we can
- 00:23:03 see here now let me also go back to the
- 00:23:06 app dot JS file and chain something to
- 00:23:09 the registration the register method
- 00:23:11 returns a promise and therefore here I
- 00:23:14 can execute a function where I can
- 00:23:16 simply log service worker registered now
- 00:23:21 with all that added let's see this in
- 00:23:24 action so the server is still running
- 00:23:26 I'll go back to my application here and
- 00:23:29 I'll reload it now if you go to service
- 00:23:32 workers here you should see that a
- 00:23:34 service worker was registered and this
- 00:23:37 is the scope of your service worker this
- 00:23:39 domain here's the service worker file
- 00:23:41 you see it's activated and it is running
- 00:23:43 and this is your first service worker
- 00:23:46 added now the service worker like this
- 00:23:50 doesn't do too much though you typically
- 00:23:53 the most basic use that you can do you
- 00:23:55 typically use it for caching caching
- 00:23:58 means that you can actively add some
- 00:24:00 files to your cache a special cache not
- 00:24:03 the default browser cache and you can
- 00:24:06 also define when these assets should be
- 00:24:08 served so that you make sure that your
- 00:24:10 page even works if you're offline let's
- 00:24:14 add such a functionality in the service
- 00:24:15 worker and the best place to catch some
- 00:24:18 files which you know will not change
- 00:24:20 that often you always want to be able to
- 00:24:22 access them is in the installed step
- 00:24:24 here because there you can pre cache the
- 00:24:27 static assets off your page you do this
- 00:24:30 by simply reaching out to the cache API
- 00:24:34 a special web API which allows you to
- 00:24:37 access this special cache I was talking
- 00:24:39 about not the default browser cache but
- 00:24:41 a cache you can manage you can use
- 00:24:44 caches open to open a cache there next
- 00:24:48 you pass a name and this could be static
- 00:24:51 or whatever you like if it doesn't exist
- 00:24:53 yet like it does for the first time you
- 00:24:55 execute this it will simply create it
- 00:24:57 and thereafter it will open this cache
- 00:24:59 caches open returns a promise and in the
- 00:25:03 function which gets executed once the
- 00:25:05 promise resolves we get access to the
- 00:25:07 opened cache so let's pass this as an
- 00:25:09 argument now in this open cache we can
- 00:25:12 call the add method to now add an asset
- 00:25:16 for caching now the add method is pretty
- 00:25:18 cool we can simply add a path to an
- 00:25:21 asset here and the browser will
- 00:25:23 automatically make an HTTP request to
- 00:25:26 the browser and store the incoming
- 00:25:28 response in the cache it will actually
- 00:25:30 store a key value pair in the cache
- 00:25:32 where the key is your request and the
- 00:25:35 response is well excuse me and the value
- 00:25:37 is the response you got back so here we
- 00:25:40 can simply specify a path like for
- 00:25:42 example let's say we want to cache the
- 00:25:44 app.js file so we could cache source J s
- 00:25:49 AB dot J s we also might want to just
- 00:25:53 cache slash so that if we wizard just
- 00:25:56 localhost:8080 1 nothing else we have
- 00:25:59 this response cached we should also
- 00:26:01 cache slash index.html because that's
- 00:26:03 not the same as just slash both load the
- 00:26:06 same file and yet but is these are
- 00:26:08 different requests to different
- 00:26:10 endpoints now with that we would already
- 00:26:13 cache quite some files we wouldn't cache
- 00:26:16 any images and CSS and so on though and
- 00:26:18 you can see that you're calling cache
- 00:26:20 add a lot now that's fine but I'll
- 00:26:22 comment it out there is another function
- 00:26:25 which is cache at all cash add all takes
- 00:26:28 an array of strings and simply does all
- 00:26:30 these individual additions automatically
- 00:26:33 in one turn so here again you can now
- 00:26:36 cache slash slash index.html so this is
- 00:26:40 just an area of strings as I said source
- 00:26:42 JSF J's and what else we have
- 00:26:45 like for example source CSS and in there
- 00:26:49 we have the app CSS file now we also
- 00:26:53 might want to store an image so here we
- 00:26:55 could now store source image as PW a dot
- 00:27:00 JPEG you could also store the icons here
- 00:27:03 now I will store something else though
- 00:27:06 if we have a look at the index.html file
- 00:27:08 there you will see that we're also
- 00:27:11 reaching out to a CDN to fetch this font
- 00:27:14 so what I'll do is I'll also try to
- 00:27:17 catch this so I'll copy this URL you can
- 00:27:20 cash assets from Abra service – it's not
- 00:27:23 just from your server you can enter any
- 00:27:25 URL into the cache add method so I'll
- 00:27:29 reach out to this CDN here by simply
- 00:27:32 adding this URL here queue and keep in
- 00:27:35 mind these are all just you are else
- 00:27:37 these are relative URLs on your own
- 00:27:40 server and this is a URL reaching out to
- 00:27:43 an average server in the end the browser
- 00:27:45 will make these requests and store the
- 00:27:48 response for you
- 00:27:49 this code won't work though service
- 00:27:53 workers are only idle working for an
- 00:27:57 unknown period of time and then they
- 00:27:59 will shut down to make sure that the
- 00:28:01 service worker doesn't shut down before
- 00:28:03 cashing is done we can take advantage of
- 00:28:06 the event which we get passed into this
- 00:28:07 function for the installation event
- 00:28:10 automatically this event has a wait
- 00:28:14 until method and we should execute this
- 00:28:17 to make sure that this recruit waits for
- 00:28:19 a certain process to finish before it
- 00:28:21 possibly shuts down and shutting down
- 00:28:23 doesn't mean instead it's just passed so
- 00:28:26 to say and it will wake up the next time
- 00:28:28 it receives an event now we can take
- 00:28:31 cache open which returns a promise and
- 00:28:33 pass it to wait until wait until
- 00:28:36 conveniently expects to get a promise so
- 00:28:38 this is just fine now with that it will
- 00:28:41 wait for this process here to finish
- 00:28:44 before it possibly goes into idle mode
- 00:28:46 again now let's try this out let's save
- 00:28:49 this keep in mind we now change the
- 00:28:51 serviceworker file so the fault size
- 00:28:53 changed so the browser should install
- 00:28:55 the new one the next time we refresh the
- 00:28:58 page so let's do that let's refresh the
- 00:29:00 page and there you now see if you go to
- 00:29:03 applications service workers then we get
- 00:29:06 a new service worker waiting to activate
- 00:29:08 in the console we therefore see that it
- 00:29:11 was registered that it was installed but
- 00:29:14 that it wasn't activated yet to activate
- 00:29:17 it we have to close this page and reopen
- 00:29:21 it close all active tabs with the page
- 00:29:24 and the next time you visit your
- 00:29:25 developer tools
- 00:29:26 you see it's activated and running
- 00:29:28 you'll also see also under application
- 00:29:31 if you go to cache storage
- 00:29:33 and right-click it to refresh you'll see
- 00:29:36 there is a static cashier this static
- 00:29:39 cash actually cashed all the requests
- 00:29:42 you specified in your service worker you
- 00:29:45 also see the response here and the date
- 00:29:47 and time when twas cashed now with that
- 00:29:50 we haven't gotten offline support yet
- 00:29:52 though all these things are cached but
- 00:29:55 we never try to fetch them so what we
- 00:29:57 can do is we can add a new event
- 00:29:59 listener to this service worker and this
- 00:30:02 is for the fetch event now the fetch
- 00:30:04 event is for example triggered whenever
- 00:30:06 you fetch something in the index.html
- 00:30:08 file like through this link or fruit
- 00:30:10 desolating to the apt osseous follow or
- 00:30:13 through this line link pointing to the
- 00:30:14 script file whenever this is the case a
- 00:30:17 fetch event is registered in the service
- 00:30:20 worker now for the fetch event we can
- 00:30:23 now react with a function where we also
- 00:30:26 get an event as an argument and now
- 00:30:28 there we can decide what we want to do
- 00:30:30 if we don't do anything the default will
- 00:30:33 happen the browser will go ahead reach
- 00:30:35 out to the network and make that request
- 00:30:37 but we can change that behavior we can
- 00:30:40 basically use our service worker like a
- 00:30:42 network proxy here we can use event and
- 00:30:47 now not wait until but respond with to
- 00:30:50 make sure we respond with something
- 00:30:52 different than the default Network
- 00:30:54 request now here we could respond with
- 00:30:57 our own fetch request to some other URL
- 00:31:00 or we simply reach out to their cache
- 00:31:02 and try to find the given network data
- 00:31:06 from that cache get it from the cache
- 00:31:08 the data we wanted to get I mean we can
- 00:31:12 do this with the caches API again and
- 00:31:14 there we have a match method this allows
- 00:31:17 us to match the incoming requests with
- 00:31:20 some resource in our in our cache so we
- 00:31:25 should simply pass event requests there
- 00:31:27 is a request up a request object on an
- 00:31:30 event object and now the cache API will
- 00:31:33 have a look if in any of its caches in
- 00:31:35 this case we only have one but it could
- 00:31:37 have multiple ones if in any of the
- 00:31:39 caches it finds this request and for
- 00:31:42 some assets it should indeed do that if
- 00:31:46 that's the case or actually always it
- 00:31:49 will then execute a function where we
- 00:31:52 get their response from the cash from
- 00:31:55 the cash not from the network back now
- 00:31:58 this will also be executed if it doesn't
- 00:32:01 find something in the cache so it will
- 00:32:03 not fail it will not throw an error
- 00:32:04 response will then just be null if
- 00:32:07 response is set though we can simply
- 00:32:11 return the response so we return the
- 00:32:13 response from the cache if we have it in
- 00:32:15 there else
- 00:32:17 we can simply do something well else we
- 00:32:20 can reach out to the network so we can
- 00:32:21 then make the fetch with the fetch API
- 00:32:24 this is supported by all more modern
- 00:32:27 browsers and since we're in a
- 00:32:28 serviceworker which only runs on modern
- 00:32:30 browsers we can safely access this so
- 00:32:33 fetch is now available and fetch will
- 00:32:35 now make a network request to event
- 00:32:39 request for example and there we can
- 00:32:41 then simply return fetch which is of
- 00:32:43 course a promise but we can return a
- 00:32:47 promise or directly response both will
- 00:32:50 work here in caches match and this code
- 00:32:52 should make sure that if we have the
- 00:32:54 request in the cache we get the response
- 00:32:57 from the cache if we don't find it in
- 00:32:59 there we go ahead and make that Network
- 00:33:01 request let's see if that works
- 00:33:04 let's save this and let's reload the app
- 00:33:06 to install the new serviceworker now as
- 00:33:09 before it's waiting to activate so let's
- 00:33:11 simply close that tap and reopen it and
- 00:33:14 let's have a look it was activated now
- 00:33:17 let's see if this works if I reload this
- 00:33:19 all works but now under a serviceworker
- 00:33:21 here an application
- 00:33:23 let's go offline and let's reload the
- 00:33:25 app again and even though I'm offline
- 00:33:28 I am offline this is simulating that I'm
- 00:33:31 offline the app looks like before and
- 00:33:33 it's the works like before I can still
- 00:33:35 tap this the reason for it is this and
- 00:33:38 we can confirm this if we have a look at
- 00:33:39 the network tab that we're getting these
- 00:33:42 assets from the serviceworker here you
- 00:33:44 see that from the serviceworker we're
- 00:33:46 fetching it from there that's of course
- 00:33:48 the cool thing because now we got an
- 00:33:50 offline ready application with a
- 00:33:53 serviceworker
- 00:33:54 now you can find whom this whole caching
- 00:33:57 and get something from the cache thing
- 00:34:00 way more there are different strategies
- 00:34:02 you can use to get something from the
- 00:34:04 cache first but then reach out to the
- 00:34:06 network to get a more up-to-date version
- 00:34:08 of that asset but to go to the cache
- 00:34:10 first to show something on the screen
- 00:34:12 immediately and so on and I will walk
- 00:34:14 through all these strategies in my udemy
- 00:34:17 course which I mentioned at the
- 00:34:18 beginning linked in the video
- 00:34:19 description this basic caching here the
- 00:34:22 spree caching we're doing here
- 00:34:24 already is a huge first step though now
- 00:34:27 with that let's see how that looks like
- 00:34:29 on a real device it should actually all
- 00:34:32 work on an Android emulator for example
- 00:34:35 a one you create through the Android
- 00:34:37 studio so feel free to do that if you
- 00:34:39 don't have a real Android device I'll
- 00:34:42 quickly connect my real device with my
- 00:34:44 computer though and then I'll try to see
- 00:34:46 this run on the device and see how the
- 00:34:49 application looks there now I connected
- 00:34:52 my real Android phone with my Mac here
- 00:34:54 and the cool thing is on Chrome which
- 00:34:57 you have Chrome on your Android device
- 00:34:59 again should also work on an emulator
- 00:35:01 and you have Chrome on your Mac and
- 00:35:04 somewhere on your Windows machine – as
- 00:35:06 your default browser you can go to the
- 00:35:09 developer tools on Chrome for desktop
- 00:35:11 these free dots you see in the top right
- 00:35:13 corner and then more tools and then
- 00:35:16 remote devices now if you expand this
- 00:35:19 here this a simple window you actually
- 00:35:22 see all connected Android devices now
- 00:35:25 there you should also make sure that you
- 00:35:27 check port forwarding so that you can
- 00:35:29 visit a port which a server I should say
- 00:35:33 running on your local machine on your
- 00:35:35 desktop machine here also from your
- 00:35:37 mobile device because by default if you
- 00:35:39 enter localhost 8080 one on your real
- 00:35:42 mobile device or the emulator this will
- 00:35:45 not be your page on your machine here
- 00:35:48 this will be localhost on the device
- 00:35:51 which is the device itself but with port
- 00:35:53 forwarding you can make sure that you
- 00:35:55 could enter localhost 8080 1 on your
- 00:35:57 device and wizard the server running on
- 00:35:59 your Mac or Windows machine so with that
- 00:36:03 let's now simply go to that connect
- 00:36:06 device my oneplus here and there I now
- 00:36:10 will simply open a new tab so let me
- 00:36:13 quickly do that
- 00:36:14 so now here in Chrome for my desktop
- 00:36:17 machine I can inspect this tap I opened
- 00:36:21 and I now got the same developer tools I
- 00:36:23 have on my Mac Chrome here on my Mac
- 00:36:28 still this window is running on the Mac
- 00:36:29 but it's referring to the page running
- 00:36:32 on my mobile device which I can show by
- 00:36:35 tapping here and so on
- 00:36:36 and you see I already get this
- 00:36:38 installation banner here you can also
- 00:36:41 manually trigger it by going to manifest
- 00:36:44 and then clicking add to homescreen any
- 00:36:46 developer tools connected to your device
- 00:36:48 now I'll click Add here and now it's
- 00:36:51 again well as I just said adding it to
- 00:36:53 my home screen we now have a look at
- 00:36:56 that here it is quite a bit here it
- 00:37:00 opens and this is now opened through the
- 00:37:03 icon on the home screen now right now at
- 00:37:06 the point of time I'm recording this
- 00:37:07 this is a bit buggy at least for a
- 00:37:10 localhost
- 00:37:10 testing there you see it still looks
- 00:37:13 like it's running on the browser even
- 00:37:15 though I opened it from this icon and I
- 00:37:18 promised you that it would look like as
- 00:37:20 like a standalone app at least since we
- 00:37:22 displayed a set display to stand alone
- 00:37:25 in the manifest now on localhost we get
- 00:37:28 this back we don't get it if we surf
- 00:37:30 this from HTTP though so why don't we
- 00:37:33 quickly do that as an extra bonus task
- 00:37:36 to make sure to really shift us to a
- 00:37:38 real page so we can see how it would
- 00:37:41 work if we were to serve it from HTTPS
- 00:37:45 now you can upload it to any of your
- 00:37:47 favorite hosting providers as long as
- 00:37:50 you ensure that your application or your
- 00:37:52 hosting your server – ship the app
- 00:37:55 through HTTP I will use firebase because
- 00:37:57 it's super simple to setup and super
- 00:37:59 simple to get started so I'll quickly
- 00:38:01 head over to firebase and there I'll go
- 00:38:04 to the console to create a new project
- 00:38:06 for that and again you can use any other
- 00:38:08 hosting provider as long as your app is
- 00:38:10 served over HTTP so here I will name
- 00:38:14 this basic PWA
- 00:38:17 and region can be whichever region you
- 00:38:20 want Germany and create this project now
- 00:38:23 firebase also offers a lot of other
- 00:38:26 features like database which
- 00:38:28 she was at all here I'm just interested
- 00:38:29 in their hosting so once it is finished
- 00:38:33 I want you well host my app here so if I
- 00:38:37 click on hosting and click on get
- 00:38:39 started you get instructions on how to
- 00:38:41 host your application and first of all
- 00:38:44 you should install the firebase tools
- 00:38:46 again of course only relevant if you are
- 00:38:48 using firebase so I'll quit my local
- 00:38:51 development server and I'll quickly
- 00:38:53 install the firebase tools globally on
- 00:38:55 my machine with sudo and people install
- 00:38:58 – gee firebase tools does basically a
- 00:39:01 seal i buy firebase which allows us to
- 00:39:03 do some things like easily deploying it
- 00:39:06 to our web server now once this is
- 00:39:08 finished we can simply click continue
- 00:39:10 here in this window to see the next
- 00:39:12 tasks we should sign in and then initiai
- 00:39:16 initiate our project now I already am
- 00:39:19 signed in so I'll type firebase init
- 00:39:21 here to put this project folder under
- 00:39:23 control of firebase and I'll simply just
- 00:39:26 check posting here by hitting the tab
- 00:39:28 bar in this drop-down in this menu and
- 00:39:30 then hit enter and this will now set us
- 00:39:33 up to be a host of a project now I have
- 00:39:36 to pick the project and its basic PWA
- 00:39:38 for me the project just to create it
- 00:39:41 I'll confirm that my route web directory
- 00:39:44 should be the public directory which is
- 00:39:46 the default
- 00:39:47 I will check no here it's not a single
- 00:39:50 page application though that
- 00:39:51 theoretically would theoretically would
- 00:39:52 be one and you could write Y for yes
- 00:39:55 here but I'll write no and I don't want
- 00:39:58 to override the public index.html file
- 00:40:00 so I'll enter n here for no to with that
- 00:40:03 it's initialized and the last step is Q
- 00:40:06 enter firebase deploy so let's run this
- 00:40:09 deployed to ship this project to a
- 00:40:13 server and once this is done we'll also
- 00:40:16 get the URL under which we can wizard
- 00:40:18 this here Q so let's wait for this to
- 00:40:21 finish real quick and now that it
- 00:40:23 finished des is the URL where we can
- 00:40:25 wizard our project let's quickly check
- 00:40:27 it here on Mac so I'll quickly enter it
- 00:40:29 here instead of localhost looks good
- 00:40:32 looks very good let's reload this one
- 00:40:34 more time let's now try offline mode
- 00:40:37 here by going offline it's looking days
- 00:40:39 decent now let's try it on the mobile
- 00:40:41 the
- 00:40:42 so there I'll visit the same URL of
- 00:40:44 course you should enter your URL and I
- 00:40:46 see my project here I'm also asked
- 00:40:48 whether I want to add it to your home
- 00:40:49 screen or not so I'll quickly do that
- 00:40:51 and once it has the same icon it's a
- 00:40:53 different app for my phone here because
- 00:40:56 it's not running on localhost and now if
- 00:40:58 I tap this icon now you see what I meant
- 00:41:01 it's running standalone like a real app
- 00:41:03 and if I open the task switcher here you
- 00:41:07 actually see this here is the app with
- 00:41:09 the theme color you can see the blue
- 00:41:11 toolbar and here is Chrome so it's
- 00:41:14 running as a separate process even
- 00:41:16 though technically it still runs powered
- 00:41:18 by Chrome it still uses Chrome it still
- 00:41:20 is a web app but it looks like a native
- 00:41:22 app it behaves like one so that's the
- 00:41:24 cool thing here we got this application
- 00:41:26 and finally if I check offline mode here
- 00:41:28 – by simply going into airplane mode
- 00:41:31 real quick if I now reload the app you
- 00:41:34 see it's still working it's still
- 00:41:36 working fine here and now if I reenable
- 00:41:39 Internet we're back to the online
- 00:41:41 experience so that's the cool thing this
- 00:41:44 is how it looks like if we run it on a
- 00:41:46 real server again any server you like as
- 00:41:48 long as it's over HTTPS since that is a
- 00:41:51 serviceworker requirement and i hope
- 00:41:53 this video gave you some insights into
- 00:41:55 how to create a basic progressive web
- 00:41:57 app which is installable and which pre
- 00:42:00 caches some files to give you a basic
- 00:42:03 offline functionality if you want to
- 00:42:05 dive much deeper check out my you deme
- 00:42:07 course and of course i'd be more than
- 00:42:09 happy to also welcome you in all the our
- 00:42:11 future videos on this channel bye