TL;DR
PWA-ize lets you add any web page to your mobile home screen, that opens in a dedicated browser window (not a browser tab!). This makes them feel more like regular apps, without any installation from the store.
Need an example? Here is how dev.to behaves when added directly, and the same dev.to added through PWA-ize (Android 11):
In case you don't want to have too many shortcuts on your home screen, the shortcuts page can be used as a launcher instead. It is a simple PWA page that displays a clickable list of your favorite sites.
PWA... Kezaco ?
PWA, short for Progressive Web App, has been around for some time now. Paraphrasing Mozilla's doc:
PWAs are websites that can be installed on a device’s home screen without an app store. Unlike regular web apps with simple home screen links or bookmarks, PWAs can be downloaded in advance and can work offline, as well as use regular Web APIs.
So in other words, when you add a PWA-enabled web page to your home screen, it will open in a separate (and dedicated) browser window, and feel more like a regular app. For non-PWAs, though, clicking on the shortcut will launch the default browser app and open the page on a new tab.
There is way more to it (offline mode, etc), but this separation is to me the single most useful feature.
Since many websites are not PWAs (and prefer to force us into using a native app, ikes), I created PWA-ize, that makes ANY page open in a dedicated window, PWA or not. The cherry on the cake: you can decide to open a specific page directly, instead of the index of the site (URL parameters, etc. also work).
Testimony
Ok, I am the only one currently using it. But I love it !
I have at least a half-screen of PWA-ized shortcuts for all my day-to-day activities. For example:
- MeteoSuisse,
- The page displaying the menus at work,
- The page for booking my fitness classes (with some filters setup thanks to URL parameters, so it opens exactly what I need),
- dev.to (obviously),
- bookfortoday, science-fiction category,
- ... (at least 6 more ...)
Let me know what you think, at please leave a ⭐ !
(For the interested devs out there)
Conditions for a dedicated window
For a shortcut added to home screen to open on a dedicated window, two conditions must be met:
- the website should declare a Web Manifest, and
- the manifest should set the
display
property to something other thanbrowser
(the default).
Given the two conditions listed above, my idea was thus to create a manifest on the fly for a given URL.
Changing manifests using Javascript
Manifests are referenced in a meta
tag in the header and are only used at install time (after you click Add to Home Screen). It can thus be instrumented via Javascript:
<link rel="manifest" id="manifest-placeholder" />
const metaTag = document.getElementById("manifest-placeholder")
// generate the manifest
const jsonManifest = JSON.stringify({
name: "...",
display: "fullscreen",
// ...
});
// attach it as base64 to the meta tag
const blob = new Blob([jsonManifest], {type: "application/json"})
metaTag.setAttribute("href", URL.createObjectURL(blob))
Manifest's start URL
A manifest is tightly coupled to the page that references it: when installed, it will open the page it was downloaded from. We can tweak the URL a bit, but it must be in the same domain. It is thus not possible to simply ask the user-agent to open an unrelated URL (e.g. https://dev.to
). Here is my workaround.
From the manifest specification:
The manifest's
start_url
member is a string that represents the start URL, which is the URL the developer would prefer the user agent to load when the user launches the web application (e.g., when the user clicks on the icon of the web application from a device's application menu or home screen).
This seems promising, but has a limitation: the start_url
is ignored if not the same origin as the document URL (aka page defining the manifest).
Thus, it is not possible to set the start_url
to https://dev.to
, but it is possible to set it to some random page (in the same domain) that will redirect to https://dev.to
.
This is the role of the redirect.html
page:
<html>
<head><title>PWA-ize redirect</title></head>
<body>
<div id="message"></div>
<script type="text/javascript">
// simply redirect to the given URL
const params = new URLSearchParams(window.location.search)
try {
window.location.href = new URL(params.get("url")).href
} catch (error) {
document.addEventListener("DOMContentLoaded", function () {
document.getElementById("message").innerHTML =
`An error occurred ${error}. The url option is empty or invalid ${window.location.href}`
})
}
</script>
</body>
</html>
With this, we can use in the manifest:
{
"start_url": "https://derlin.github.io/pwa-ize/redirect.html?url=https://dev.to/"
}
The only downside of this redirect is that since we leave the manifest's domain, the browser top bar will show again. A small price to pay I guess.
Manifest icons
A manifest can (must) provide icons, that may be used in the home screen and on the splash screen.
There are multiple services available to grab favicons, such as Google S2, duckdcuckgo icons API, and Icon Horse. I explained the first in this article (and others in the comments) if you are interested.
![derlin](https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F678845%2F70a4210c-2961-42c0-bca6-682f88e4b579.png)
Get favicons from any domain using a hidden google API
Lucy Linder ・ Oct 28 '21
.
The only problem is that the manifest should contain not only the link to icons but also their type and size. The type can be taken from the response's Content-Type
header, but the size is another matter.
One possibility to get the actual size of an image is to use the Img
like this:
const img = new Image()
img.onload = function () {
// here we can get the actual size !
// not the type though ...
console.log(`${this.src} => ${this.height}x${this.width}`)
}
img.src = `<URL of the image>`
I currently use Google S2 because it always returns PNG, so I don't need yet another request to get the content type (as the image trick above doesn't let you access the response headers).
Google S2 returns a 16x16 icon by default, so I use the sz
query parameter (a size hint) to loop through common image sizes, (16
, 128
, 256
, 512
) and add the ones I find in the manifest.
If you are interested in the actual code, have a look at src/utils/google-s2.js
.
PWA-ize webapp
For this small project, I decided to go with Vue3 and materialize-css, with some tweaks on the colour scheme.
I bootstrapped the project using vue create
, and only had to add the .prettierc
to get better formatting.
I needed multiple HTML pages since my shortcuts page needs a specific and fixed manifest. This was easy to achieve: I just used the pages
configuration of vue.config.js
.
To deploy to GitHub Pages, I have a simple Github Actions workflow, and
The shortcuts page is using localStorage
to persist the list of links.
Written with ❤️ by derlin
Top comments (0)