Your Angular app as Progressive Web App

The Angular-CLI build will create this for you when you build your app.

Structure of the PWAManifest.

jsonFor a PWA to run, we need several extra files.

First, we need a manifest.

json, which is the web app manifest: a simple JSON file that tells the browser about your web application and how it should behave when “installed” on the user’s mobile device or desktop.

Notable attributes in this manifest are name, short_name, description, theme_color, and background_color.

Make sure these are properly entered.

The short_name is used as name of your application when added to a home screen, so make sure to add it.


jsonThe above steps also generated a ngsw-config.

json file, which contains the configuration on how the Angular build process will create your service worker.

We will discuss the most important settings in-depth later.

IconsThe icons are more important than you think, so make sure you create them in the proposed sizes.

If you’re practical, you can use one of the many online fav-icon generators available.

Make sure icons of 192 x 192 pixels and 512 x 512 pixels exist, since these are used by Android to display the “Add to Home Screen” install prompt and used by the Microsoft Store to automatically index and package your app.

If you look in the manifest.

json, you’ll see a node icons.

Take note of the sizes there that are automatically generated.

My advice is that you make sure you have suitable icons for all these sizes.

"icons": [ (.

) { "src": "assets/icons/icon-192×192.

png", "sizes": "192×192", "type": "image/png" }, { "src": "assets/icons/icon-512×512.

png", "sizes": "512×512", "type": "image/png" }]Unfortunately, Apple’s iOS is still somewhat lagging behind on PWA support.

To make sure your app also has an icon on iOS devices, add these lines to your index.

html’s head-tag.

Make sure the referenced files exist in their respective sizes.

<link rel="apple-touch-icon" href="/assets/icons/apple-touch-icon-iphone.

png"/><link rel="apple-touch-icon" sizes="152×152" href="/assets/icons/apple-touch-icon-iphone.

png"/><link rel="apple-touch-icon" sizes="167×167" href="/assets/icons/apple-touch-icon-ipad-retina.

png"/><link rel="apple-touch-icon" sizes="180×180" href="/assets/icons/apple-touch-icon-iphone-retina.


jsonAs stated earlier, the ngsw-config.

json contains the settings on how the Angular-CLI build process will create your service worker.

The default config will basically consist of an index attribute, usually pointing to your index.

html, and the assetGroups.

With this last attribute you can specify which files will utilise a certain install or update strategy.

{ "index": "/index.

html", "assetGroups": [ { "name": "app", "installMode": "prefetch", "resources": { "files": [ "/favicon.

ico", "/index.

html", "/*.

css", "/*.

js" ] } }, { "name": "assets", "installMode": "lazy", "updateMode": "prefetch", "resources": { "files": [ "/assets/**", "/*.

(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)" ] } } ]}Install StrategyThis strategy is to tell the application how it should install the app on the user’s device.

By default, the ngsw-worker.

js has set the install strategy (installMode) to prefetch, meaning all files specified will be fetched while it’s caching the current version of the app.

This is bandwidth-intensive but ensures resources are available whenever they’re requested, even if the browser is currently offline.

{ "name": "app", "installMode": "prefetch", "resources": { "files": [ "/favicon.

ico", "/index.

html", "manifest.

json", "/*.

css", "/*.

js" ] }}The alternative strategy is lazy, which means that resources will only be installed on demand.

Usually this strategy will only be used for caching the assets as described next!Caching AssetsYour assets are configured by default as assetsGroup assets.

Again we have the prefetch and lazy strategies available.

{ "name": "assets", "installMode": "lazy", "updateMode": "prefetch", "resources": { "files": [ "/assets/**", "/*.

(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)" ] }}Notice that the installMode is set to lazy while the updateMode is set to prefetch, meaning that assets will be loaded on demand, but if an assets has already been cached it will be pro-actively updated.

If you want to add assets from external servers or CDNs (like Google fonts), amend the resources like this:"resources": { "files": [ "/assets/**", "/*.

(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)" ], "urls": [ "https://fonts.


com/**" ]}Data GroupsData Groups are different than assets in the sense that they are not packaged with the version of your app.

They could, for example, come from an API.

They can be cached with two different strategies: freshness and performance.

The freshness strategy is useful for resources that change frequently and you don’t want to show outdated data for.

This strategy will always try to get a new version of the resource before falling back to the cache.

"dataGroups": [{ "name": "api-freshness", "urls": [ "https://my.


com/user" ], "cacheConfig": { "strategy": "freshness", "maxSize": 5, "maxAge": "1h", "timeout": "3s" }}]This snippet will get data from the /user endpoint and will be cached for at most 1 hour, a maximum of 5 responses and a timeout of 3 seconds.

After this it will fallback to the cache.

The performance strategy, the default strategy, is more useful for resources that don’t change a lot.

It will always show the cached version of a resource if available, but this can obviously lead to staleness of the response.

Test drive!Now when you would launch your application with ng serve, and you check your Application tab in DevTools, you may notice that no service worker has been registered.

The Angular-CLI serve function does not support service workers, which is why the service worker does not show up.

We’re going to do an, in my opinion, annoying workaround by doing a production build and serving that independently.

npm i -g http-serverng build –prodhttp-server -p4200 -c-1 dist/<name-of-app>I personally like to set the port of this server to 4200, because when I type an “l” in my url bar, “http://localhost:4200” is the first suggestion that shows up and keeps it in line with ng serve.

Now when we visit localhost:4200, and check our Application tab in DevTools.

If you see this, then the service worker has successfully registered.

When you look at your Network tab and refresh (not a hard refresh) you can see the difference in requests.

Left you see that the size column indicates how large the downloaded bundle was, and right you see it was loaded from the service worker instead.

However, if you view this on mobile, you will not see an “Add to home screen” prompt from Android.

Those will only be brought up over HTTPS connection, so keep that in mind when you’re testing your application in the wild.

You can find a very simple implementation at https://github.


There’s a separate commit turning the application into a PWA, so you have a clear overview what’s changed.

More functionalityWe have our service worker running, files are being prefetched and services are being cached.

People can install our app through the “Add to Home screen” prompt and can interact with the application like a native app.

While this already sounds like a huge step forward, we have so many more possibilities.

In this article I will not discuss or show how we can extend these functionalities, but rather inform you on what’s possible and available.

Later articles will go further in depth.

SwUpdate: Notify your users on updatesYou can leverage the @angular/service-worker SwUpdate to trigger update checks and force updates.

For example, when your users are using the app or website and you just deployed a new version, you can trigger a modal or toaster informing the users about this update and ask them to reload to always have the newest experience.

SwPush: Notifications to interactWith the @angular/service-worker SwPush we can subscribe and listen to push notifications from the Service Worker.

For this we also need a server to actually send these notifications obviously.

SummaryIn this article we have discussed the steps we need to take to upgrade our current application to a PWA.

We have seen that with a few simple steps, we can leverage Angular and the Angular-CLI to generate a powerful service worker to give your users a more smooth experience of your website, while still enjoying the benefits of a native app.

Looking for a job in Amsterdam?I work for Sytac as a Senior Front-end developer and we are looking for medior/senior developers that specialise in Angular, React, Java or Scala.

Sytac is a very ambitious consultancy company in the Netherlands that works for a lot of renowned companies in banking, airline, government and retail sectors.

You can think of companies like ING, KLM, Deloitte, Ahold Delhaize, ABN AMRO, Flora holland and many more.

From a personal opinion Sytac really sets itself apart with their client portfolio, but also with how they take care of their employees.

They do really care about the wellbeing of their employees.

Apart from a good salary (50K-75k), you will notice this in regular meetings with the consultant managers but also by the amount of events they organise and all the other perks they offer to keep all employees happy.

If you think you have what it takes to work with the best, send me an email on arjen.


io and I’ll be happy to tell you more.


. More details

Leave a Reply