Transcript
This transcript was autogenerated. To make changes, submit a PR.
You.
Hello everybody. Would you like to be able to
create an application that is always offline or at
least it looks like make? It would be always alight for our users
even though there is no Internet connectivity, this today is
possible thanks to progressive web apps and other modern technologies.
In this session we will see how it's possible to build such an application
and also we will see the different benefits
that progressive web apps can bring into our project.
When I talk about the progressive web apps, I'm always
a bit sad to see that very few people are aware of the
potentiality of this technology and even less people
are using actively in their own project. Progressive web apps.
That's a bit indeed, because progressive web application can
really bring a lot of functionality and feature to our projects,
no matter of complexity of the project or how big it
is. And let's start seeing
first of all, the differences between a progressive web app and
a native application, either Android or iOS.
This doesn't want to be at all a competition nor a fight,
but just list out some concrete differences.
First of all, we don't have to fulfill
the requirements or the rules of a play store
or App Store. We can just deploy our progressive web app
that it is simply a web application enriched
with some other functionalities and once live on
the server it's available to everybody. So immediately online
then we don't have to save and
provide different versions of it, we just have one versions.
Of course, if some functionalities will not be available in
some of the browser, then these will be progressive,
hidden or not provided to these users
that cannot have the latest browser or a compatible
browser. But still, the experience has to be very
smooth and there should be no showstoppers
on the other side. Typically building a progressive web
app is much cheaper than a native app. This because
we can reuse the know how we have internally in our team.
For example, we can reuse our web team to
create also a progressive web app. The know how is exactly the same
as to create a normal web application.
And lastly, it has a much smaller memory footprint
because we don't have to download many packages and
indeed we will see later on. Indeed,
the used memory on the device is much smaller compared
to a native app. Before going
on, just a couple of words about me. My name is Francesco Leardini
and I work as a software engineer, a consultant
for Trivadis, a consultancy company in Switzerland.
But I'm originally from Italy, from the north on the
Algria coast. It's a very nice place, especially in summer. The photo indeed
is taken from my location. That said,
let's start our progressive web apps journey.
Let's imagine a very common scenario. We are traveling or
just commuting to the office and we are passing through
an area that is not very well covered. So we
can have an intermittent connectivity and in some
pages even we could be completely offline. So if
we are reading, for example, our favorite news website or a
blog post, when we pass from one page to the next, this is
what can happen. So simply a default offline
page. Indeed, for our users this would be not a real good
experience. But with progressive web apps we can provide
a much better user experience. As a minimum, we can
provide some corporate colors or
icons with some static data so that even though the
user is offline still it can recognize the logo
or some colors of our company and eventually still benefit
from this content. If we can provide some meaningful
static data like some
items on sale if you are an e commerce shop,
or some telephone numbers on
the other side, and this is the case of Trivago on the right side,
we can provide even a further and richer
experience. In this case, Trivago, when we access the website
for a second time and we are offline, provides us a labyrinth
game. This is a very clever move from them because we
can keep the user attention locked on the
website using this game so that as soon as the
Internet connectivity is then restored, the user will be automatically
redirected to the requested page.
So that with this let's call it trick or good
way of keeping interest of the user, we can
save a potential customer that otherwise would have been most
probably lost. So this is possible thanks to progressive web apps.
Let's see also another difference.
A little test trying to recognize which one is the native
app of the Android this is
a screenshot of my Android device and which one is a progressive
web app. Of course we can see immediately the shape is different,
but other than that there are not big difference. If we open it,
we can see that the layout itself is quite similar.
There are not really big differences and indeed it's very difficult
to recognize which one is the progressive app and on the other side which
one is the native app. Indeed it's very
difficult. As I said, I give you a little
so called hint and this probably should really help
you to understand which one is the native app and which one is a progressive
web app. Most probably yes, you got it.
From the size the native app we can see
it takes much more space or memory space
on a user device, while a progressive web apps is almost
minimal or really minimal. If we look again at the
layout once again we can see that the differences are
really, really small and is almost impossible to understand
and to see which one is the native app and which one is the
progressive web app. And this indeed is one of the core goals
of a progressive app being able to provide
an experience that is as close as possible as a
native app, not only in the functionalities provided,
but also in the layout. So we want to enrich
the experience for a user assessing our web application
and make it as close as possible to what could have been
if the user would have used a native app.
Before going further, just some small
words about what are the core components that are
present in a progressive web app. First of all, we have to talk
about service workers. Service workers are
just a JavaScript component very similar to a web worker.
They operate on a separate thread from the one
used by the main application, so that even though
the service worker crashes, so stop running or it's very
very lengthy or executing a very heavy task,
this will not affect at all our main application and this is
exactly what we want. Let's see how
a service worker operates on our client side.
So when we request our progressive web app, we get
the response and we also download the
service worker. That is, as we said, is just a JavaScript file.
Then according to how we implement caching strategies for
this service worker, we could eventually already save in the
local cache some assets and some other files.
This makes it possible that from next time the user
assess our progressive web apps, even though there is
no Internet connectivity still we are able through
the service worker to provide this requested data from the
local cache. So there is no need to go at all over the network
and the user not only receives this response
extremely quickly, but also when he or
she is offline. So no need of being connected
to the network at all. Web manifest
is a JSON file that contains
all the instruction to tell the user agent
how our progressive web apps should be
rendered. Once open, it's also a very important
file that we have to create in
a proper way. So to fill in a proper way in order to be able
to be installed on a client's device,
our progressive web app let's see, the first two
proper name and short name will be used as a label or
as a text string under the icon. Once this
will be installed on a user device
display mode tells how the browser
should render our progressive app. We can use a browser value.
In that case it's just a default way of or
view that we get once we assess with the mobile device
our progressive web app. But it's more interesting standalone
where we can see that some UI elements of the browser, for example
the address bar are removed. So gives a much more
feeling of a progressive of a native app.
And on the other side full screen that as the name side
says we can use the whole device screen and this is
more suited for device for application that
are media rich or for games. For example we
can define a starting URL for our PWA
because we want to provide, as again we said native
feeling so that when the users open our progressive
web apps, we want to provide always the same home page or
always the same starting page and not the last visited URL.
Lastly, we can define some icons that can be used not only
on the user device home screen but also as a
splash screen. If the browser supports that.
Typically we can provide a different resolution
or different sizes so that we can have a pixel perfect
experience for our users. As a
minimum we should provide two sizes,
192 for 992 or
512 per 512.
We can even provide a purpose. Purpose that says
how this icon will be displayed on a user device.
In this case we can see we define the maskable and
as a fallback any that is the default value. We will see
just in a second what are maskable icons.
So these are the minimum properties that we can define
in a manifest file in order to be able to make it installable
on a user device. Let's see what are
maskable icons. Let's start
saying before that some manufacturers like for example
Samsung at the beginning decided to have all icons on
a device with the same shape. And after
this also other producers decided to have the
same idea but giving a different size. So because
of this Android from the version
Oreo of Android OS decided
to introduce the concept of adaptive icons. So being able
to provide images with an extra space
around that can be cut, it cropped in order to
be able to provide different shapes according to
our or the user wish. This is okay,
this is nice, but it's a problem if we define some
or we already created some progressive web apps and we provided
our icons that are not maskable. If we do that,
we will see that our icons will be either
cropped so some parts will be cut away or they will have
a white background instead of using the whole background
as wished or as desired. To do that we
can create maskable icons. So we define a
circular area where radio is 40% of
the image size and this is called the safe
area. So we can place within this safe area
all the part that we want to be sure that won't be cropped
in any kind of shape and everything that is outside might
be cropped according to the final shape
that will be used. So if we target
Android devices for our progressive web apps,
we have to keep in mind these
aspects. So we have to create icons that are maskable.
That said, let's see how can we make our web
application extremely fast and also how can be possible to
provide data even while offline? This is possible
thanks to caching strategies because by default a service
worker doesn't know anything about which assets to
cache and when to provide from the cache.
These assets we have to define thanks to caching
strategies. Yes,
we can see that the mobile traffic in
the past years really took over the desktop traffic over
Internet and this is something we have really to keep in mind,
being able to optimising our web application even for
mobile devices. So not only for desktop application,
but mobile devices nowadays have a really strong weight
on the market. So we have to keep this in mind.
The first cache structuring we will going to see
is the cache first. As the name suggests,
we make a request and this request gets
intercepted by the service worker and then the
service worker. If there is a match with some cached
assets that we define, then these will be immediately
provided from the cache. So no need to go over the network and
respond extremely fast. On the other side,
if the assets are not available on the cache, there will be a normal
network request. As a fallback, this caching
strategy is to be chosen if we want to implement
an offline first approach. On the
other side, we can implement a network first caching strategy.
As the name suggests, we go first over the network
because we want to provide the very latest response
with the most up to date data or values. This is
the case for example when we want to provide values
from a caching stock exchange API and
so we don't want to provide the cache the data unless there is
no network connectivity. So as a fallback we can go over
the cache if possible. We want to provide the
latest up to date data from the network.
And aside these there are also kind of hybrid services
or strategies. One of these is called stale
while revalidate strategy. What this does is that when
the service worker intercepts a request, it goes
immediately over the cache and tries to provide from
there the requested assets so that the response is
extremely fast. But in the background it also goes over
the network and tries to fetch any new updated
asset and updates the relative version in the cache.
So that any following request will get a newer version
straight from the cache to implement.
This strategy is not very complex, but there are some lines of
code we have to provide.
We don't go over the code because it's quite simple, but just to say that
there is some work that we have to implement, especially if we
wanted to create some more complex strategies
of logic for our application. However, thanks for
us, there are some tools that we can use. One of
these is workbox. Workbox is a set of libraries
and node modules that makes very easy to cache
assets and to create or implement
caching strategies. We can see in this case with just
three lines of code we can say, or we
can implement the stalewall revalidate
strategy, the one we saw just before. And thanks to that
we can say that we want to cache all JavaScript and the CSS
file. For example, we define routes where
we can provide a string or in this case regisc in
order to match some specific path or some
specific files that we want to cache.
So workbox, it's a really powerful tool
or set of libraries that nowadays is kind of considered a
state of art in order to implement advanced scenarios for
progressive web apps. It's also important to say that
workbox is a framework agnostic, so we can work with
Forbox in our react project Vue JS angular
no matter, or even vanilla Javascript, it will just
work on the other side if we are working with
some framework like for example angular, it's also possible
to start with the progressive web apps and it's very
easy. Thanks to the NGraD schematics,
we can inject progressive web apps capabilities into
an existing file. We will
see shortly a demo that shows how easy is to
go and to create a progressive
app starting from an angular project. There is the
code on GitHub. You can see and
download the code there so you don't need to pay attention to all the
details. And the goal of this demo is to see and
to demonstrate how easy is to create a progressive web
app application starting from an angular project.
So we can see here I have my
visual code with the simple basic
new angular project and I
already ran the NgAd angular PWA command.
What this command does is that it downloads the service
worker module and register for us. Plus it creates some
other files that we will describe very soon. We can see
that we register the file ng serviceworkerworker
Js file. This is the real service worker that so
is stored in the node modules.
We cannot manually change this service worker file
otherwise every time our
solution is built, all the changes that we
did will be wiped out and we
enabled this registration. So this service worker we wanted
to register only when we have a production build
this because we want to go over only for
our production releases. One of
the files that is created is the manifest file. As we saw before,
there are some properties that are already prefilled with some
default values for us. Of course we can customize as we want and
we can see that there are also many more sizes
that are created for us per default.
But much more interesting is the NGSW so
angular service worker configuration file.
This is a JSON file that is created for us. And here is the
real magic here. Actually we can define the assets,
static assets or APIs that we want to cache by
default. Angular creates only an asset groups array
where it's possible to define static
assets. So JavaScript files or ATML files
that will be cached according to different installed
mode strategies. Let's calculate this.
The first object has an installed mode prefetch and here
we can put all the files that we want to be cached
already when the service worker is
loaded and installed. These are for example all the core files
that we want to provide immediately when the user access
our website and is offline.
So with this install mode prefetch value
we can tell to the service worker grab all these files
and install already or download and save in the
cache already while you are installing.
It's important to note that if one of these files fails
to be downloaded, the service worker installation fails,
will be aborted and so it will be obtained
again. Next time the users assess the
pages or we refresh the page itself so we don't have to
put their big files or too many files, just a bare
minimum. On the other side we have another
array with name property assets in this
case and installed mode lazy. We wanted to
target here all assets files or font files for
example that are not so crucial for our application.
By defining install mode lazy, we tells the service worker that
we wanted to download and store in the cache those files only
after they have been requested a first time and then
we can see we have an update mode property with value prefetch.
This means tells to the service
worker to upload the stored value the
assets in the cache as soon as a new value is available
on the server. We could have users here a value instead
of prefetch a value of lazy. In that case we would have updated
our stored assets only after they
have been requested a second time. So these values are
created by default for us with the ngrad angular PWA
command, but it's possible also to
go further and to cache
also APIs. For that we have to create a data groups
array and create different cache
names. In this case, for example, I wanted to target an
API where URL providing
dead jokes and we want to define strategy performance.
Strategy performance in angular means a cache first.
So we go immediately over the network,
sorry, over the cache, and we
can have a retain policy of five entries and
a max age of 15 minutes. After that time the
cache will be renewed. So this
strategy is to provide extremely
faster responses. And even though there is no network connectivity
on the other side, we create another
group and we want to cache an
API that provides cat's image. We are really
fans of cats, so we want the very latest images.
Because of this we use a strategy freshness and strategy
freshness means network first.
As we saw before, we can provide again a maxi and max
age values as in the previous cache
configuration group. But here we can also define a timeout
can be 5 seconds one day or a different
timeout. One day actually would be way too
long. So means that if we trigger a
request and the timeout occurs, then we instruct
the service worker that the user
could be eventually offline, or in the case the
network is too slow. So there will be
a fallback and the service worker will try to provide the response
from the cache. So this is everything we
have to create, nothing else. And we are already able to create
and to provide an angular application with just these
a few commands. But let's see now,
how does it look like this is
our application that we just saw? Where on the left side
we have the joke that is coming from the dead joke API,
and on the right side the freshness strategy
with the cats images.
If we open the devtools, in this case I'm using
chrome and we go on the application tab, we can see
that over the service workers menu
we can have an overview about the service worker that
is installed. If we click on a manifest, we can see
just a nice representation of all the values that
are coming or properties that are coming from the web manifest.
In the cache storage we have all the assets that
have been cached. Now if we switch on the network
tab and we refresh the page first time
and now refresh it again, we can see that the joke
doesn't change. And if we check the
network tab, we can see that API providing the joke comes
from the service worker. There is no network
response or payload going back and forth while
the search API for the cat image just comes
back. Now if I go offline and I refresh the
page, we can see that the images and that joke
are provided. And if we check the network tab, we can
see that both endpoints now are provided from
the cache. So there is no network connectivity and
we can provide that thanks to these caching strategies and the service
worker. We can provide the data even though we are offline
from the cache. Very nice and it's in a very simple
way. So now I'm going online again, I refresh and again
we can get a very new fresh image.
And this is to show how easy is to
create a progressive web app with angular
very few steps. Let's continue with
our application, with our presentation, sorry.
And let's see one limit of progressive
web apps. We can see that we could cache
some get calls when we try to fetch
some data. But would it be possible to provide a better experience?
Because what is the case if we want
to provide also the possibility
of to store somehow or persist somehow,
even put and post changes while
the user is offline? How this is possible? This is not
possible by default with the cache API interface,
but we can create some custom solution.
For example, we can implement indexdb
that stores while the user is offline all the put or post
requests that are attempt. And then as soon as the
user restore its connectivity, then we
can implement our logic that we go in order one
by one to these appending requests and we trigger them
one by one. Indeed, not very complex,
but we have to implement quite some
logic. There are so other
tools we can use. For example, Farbas platform provides
a set of functionalities and services for mobile
devices implementation and web implementation.
But we are in this case much more interested in cloud
Firestore in the umbrella of services and products offered.
Cloud Firestore is a NoSQL database
that provides also offline storage. And this is great
for us because with just one command we can
create this indexdb and store all
the changes for us in a very transparent
way for the user. Once we imported
the library, we have to enable the
offline persistence if we are implementing a web application,
while for a mobile application it's already enabled by default.
So we invoke the enable persistence method and
that's all what we have to do. From that moment, all requests
that we ship will be cached by cloud
firestore and will be saved locally.
There is a 40 megabyte megabyte cache
threshold, but we can define a bigger or a smaller
value according we want. As soon as then we reach
this limit, all the oldest values
or records will be wiped away, wiped out from the cache,
and then these value that are stored locally will be
available even when the user is offline.
So that not only it's possible to access this data
while offline, but also to interact. So make
changes over this data while offline, and cloud Firestore
will keep track of all these pending changes. And then as soon as
the network is restored so the
connectivity to the server is restored again,
cloud Firestore will go over these appending changes and ship
them one by one, synchronizing them to the server.
All this is done out of the box for us. We don't have to do
absolutely anything.
So let's see now a slightly more complex
solution that indeed tries to
justify the title of this session, so that offline web
application nowadays don't exist anymore.
We will see. The demo is
also an angular application,
sorry, using angular material for the layout, we can see
the cards and using cloud Firestore
as a NoSQL database. With offline storage
aside, I will try to mirror
my phone.
Just a second. Yes,
connected please.
I will see how it is the progressive
web applications on
my Android device and on
the server. Let's say like this,
sorry, like this, side by side.
So this application I implemented,
it's a progressive application, as we said, I implemented in order to keep track
of all restaurants or nice bars that I visited while
traveling with my wife. So it's a nice way to keep track of
good bars and suggest to my friends, or even not suggest if
they were being so bad. One good things
of it of the progressive apps is that they are responsive.
So for example, in the web view we can
see that if I narrow the window, the layout adapts
automatically. On the other side, if I open my progressive
web app on the device, we can see that we have one line of cards
only and there is no label aside of
the icons. Another nice things is that
we can see that my progressive
web app is displayed as it would be a
separate application, as it would be
a native apps, and not as a party of Chrome browser.
So indeed another aspect to show much
more close to a native app. So if
I now change one
entry, so I just write edit and I save
it automatically. This change is propagated thanks
to sockets and thanks to cloud Firestore is propagated
to all the other clients that are listening to it. So that's
why on the right side I can see that this entry has
been also updated on my phone.
But now let's see a much more interesting scenario. So I
switch off connectivity. So I go in airplane mode
on my phone and I refresh the page. So not
only I can see all the content because I
store these documents locally and this is a progressive web
apps. So all the assets are here, icons and so on are here available.
But I can also open a completely new entry
in restaurant and for example let's
write it offline, save it for a title
and then let's see that this change affects only
my phone. So my progressive
app on the phone because of course there is no connectivity, I'm cut
off, I'm offline and there is no offline
server synchronization. And now
the interesting thing is that as soon as I will go online
again, let's just make, for the sake of demo,
just change the other one. Also the title
and let's save it.
So we have the first two entries that have been
changed, the other are still here visible, but of course we don't change
them. So now I switch my airplane
mode off and I will go online again. What I would
expect is that here on the left side, so on the web
view this client will get these
two values. So the Sagami Milano and the bar North
island entry will be updated with the entries
that I edited on my phone. So I go
online again and according to my connection, if faster,
yeah, it's quite fast. So we can see that the changes that I did
on my phone, so on the progressive web, apps stored on my phone
have been propagated on the server and then to all
the other clients listening to that. And this indeed it's
quite cool because for the user now let me switch
off again the connectivity, so let me go again offline
for the user. Actually there is absolutely no difference whether
being online or offline. We just provide
a great experience because everything is working exactly
in the same way, either offline and online.
So this is a very nice combination of technologies
with this progressive web app and also other
cool technologies like cloud, Firestore and its functionality
of offline storage, offline persistence.
So should we now replace all
our native apps with progressive web apps or should we just go
with the progressive web apps? Well, I would
say it depends on the cases. Of course, there is no silver bullet.
As always, there are some limitations
still in progressive web apps. Some of them are, for example,
that many functionalities are still not fully
supported by Apple. So if we wanted to target
also Apple devices or iOS,
we won't be able to use the full spectrum of functionality
of progressive web apps, for example web notification or some
web manifest properties. This is quite unfortunate, but it's
still the case on the other side. Progressive web apps
can do only what web applications can do.
One thing is that it's not possible to assess the device
contacts, even though Google is bringing on the contact Picker API,
but it's still something experimental and not really
widely used. And lastly,
native apps have in general much better performances.
So if we have to provide an application that is extremely
media rich or is a game, then it's better we go with
native apps because native
apps can be tied to the underlying operating
system while PWAs are provided
through the browser.
Before concluding, I would like to give you some links that might
stimulate further your interest for progressive web
apps and give you even more information about them.
The first two websites,
PWA Rocks and Upscope is a kind of media
or application gallery where you can find a lot
of samples of progressive apps. So to
get an idea of what is possible to create with
the progressive web apps, it's really cool. They are really cool websites.
Progressivewebapstats.com shows
all successful stories and in which measure progressive
web app benefit or improved the
Roy and other metrics for different
websites and domains and the
last two websites.
So PWA is a stack overflow collection of
the the biggest requested or most viewed
requested about progressive web apps and service worker
and what PWA can do today collects a
set of functionalities and features that they are possible to
implement in progressive web apps.
So these are very interesting links and
websites that I really strongly suggested to visit if you are interested
to dig deeper in progressive web apps.
That said, thank you very much for your attention.
You can reach me on Twitter handle or
from time to time I write articles on the dev IO portal
and that's it. Thank you very much. I hope you enjoyed my talk
and if you have questions please contact
me in Twitter or just follow me if you are interested to get updates.
Thank you very much.