Skip to content
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
836 lines (616 sloc) 33.8 KB

The Web is on 🔥 FIRE 🔥

🚧 WIP 🚧

Since I rarely have the time to proofread these notes, their quality isn't as high as I would like, especially with regards to phrasing and syntax.

Yet, I intend to use them as a foundation for some better content (blog posts especially) I'll write in the near future.

👋You can easily help me work faster, if you're are impatient to read them. Open an issue telling me what you think is missing in this document. Or, even better, send me a PR, even if it only fixes a typo 😉

Table des matières

Introduction: PWA vs FIRE

Since the first list of what Progressive Web Apps (aka PWA) are Alex Russel introduced in his now famous blog post, Progressive Web Apps: Escaping Tabs Without Losing Our Soul, was to complicated to remember (see below), those where quickly reduced to just 4, and then 3 principles and technologies.

On Google Developers, when the PWA home page was created in December 2015, it included this long list of "what PWAs are" from Alex Russel's blog post:

  • Progressive - Work for every user, regardless of browser choice because they’re built with progressive enhancement as a core tenet.
  • Responsive - Fit any form factor: desktop, mobile, tablet, or whatever is next.
  • Connectivity independent - Enhanced with service workers to work offline or on low quality networks.
  • App-like - Feel like an app to the user with app-style interactions and navigation because it's built on the app shell model.
  • Fresh - Always up-to-date thanks to the service worker update process.
  • Safe - Served via HTTPS to prevent snooping and ensure content hasn’t been tampered with.
  • Discoverable - Are identifiable as “applications” thanks to W3C manifests and service worker registration scope allowing search engines to find them.
  • Re-engageable - Make re-engagement easy through features like push notifications. Installable - Allow users to “keep” apps they find most useful on their home screen without the hassle of an app store.
  • Linkable - Easily share via URL and not require complex installation.

These 4 topics were (and still are):

  • the App Shell approach, for better First Miningful Paint score
  • Web App Manifests, for a2hs & discoverability
  • Service Workers, for network reliability
  • Push Notifications, for re-engagement

In order to help people remember those four topics, Google used for some times the acronym "FIRE" as a mnemonic of the 4 pillars of PWAs and Web Apps quality (check out, for example, the PWA Roadshow playlist on Youtube).

FIRE stand for:

  1. Fast
  2. Integrated
  3. Reliable
  4. Engaging

This helped advocate for a wider range of technologies and methods.

Today, most people from the Chrome Team still use "PWA" as a synonym of "Quality/Good Web App". But due to the simplification I talked about previously, this isn't what most people think when they hear "PWA".

PWAs tends to be confused with "Installable Web Apps", reducing it to a2hs only.

Now, there is two ways to look at PWAs:

  1. from a "Business" perspective, they are a good alternative to native apps
  2. from a developer perspective, making a Web App "Progressive" means raising the quality level for users, using the latests innovations of the Web Platform

For all these reasons, I now prefer to make a clear distinction between those two perspectives, using respectively "PWA" and "FIRE app" to talk about them.


FIRE basis

Fast: App Shell

Integrated: Manifest & a2hs

Web App Manifest and a2hs are well supported by Firefox Mobile, and by Edge Beta 78 (aka Edgium, apparently soon to be released as stable) and Chrome on all there supported OS.

Firefox Desktop

A2HS isn't yet supported by Firefox Desktop, but mozillians are working on it. The related Meta Issue priority has been recently (october 10, 19) set to P3, meaning it was added to the backlog.

The --app option, permitting to run web applications in "app mode" and therefor blocking the Meta issue, isn't prioritized, even if it was created two years ago.

Yet, Dave Townsend (aka Mossop), the lead architect for Firefox front-end, commented in september:

"We're in the process of planning out a feature similar to this. We likely wouldn't accept a patch here until we're done with the current investigations (mostly at the research stage right now)."


Well, with Apple, it's a different kettle of fish.


Pretty much everything about PWA in Safari is about finding the right workaround. There even are some kind of weird libraries for that, like a2hs.js for example.

It's now the only browser builder who rejects the usage of the term (they prefer "HTML5 apps" apparently 🤷‍♂).

Safari was even the latest major browser to support service worker (the freaking March 29, 2018, more than 3 years after Chrome, Firefox and Opera, with Safari 11.1 & iOS 11.3)!

Apple is constantly making the a2hs related UX a nightmare (see the capture below) while rejecting "HTML 5 apps" from the AppStore. And most related features are undocumented.

Apple a2hs

All of this makes some people suspicious about this strategy being driven by fear of loosing money, against all Safari (or even iOS) user interest.

Currently, the best resources to dive into this issues are written by Maximiliano Flirtman. Go check its last blog post about this, in which he goes in details into PWA & web dev limitations in iOS 13 & iPadOS.


Reliable: Service Worker

Engaging: Push Notifications

How the Web evolves

Standardization process, involving standardization authorities and integrators (i.e. Web Browsers builders).

Standardization authorities


World Wide Web Consortium -

How it works


Web Hypertext Application Technology Working Group -

Why it was created
How it works

Since May 2019, the war is over between the W3C and WHATWG!


:octocat: On Github:



Web Incubator Community Group -

July 2015: Launch announcement



Ecma International, Technical Committee 39 - ECMAScript -

How it works

:octocat: On Github




Remaining controversies



Youtube & Netflix quickly adopted EME, while moving away from, respectively, Flash and Silverlight.

Regarding Youtube, we can simply notice that the "Embed a playlist" documentation still gives today the following example:

<iframe width="560" height="315" src="" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>

Where encrypted-media is explicitly allowed in this iframe feature policy.

On that topic, read Why YouTube & Netflix use MPEG-DASH in HTML5 and HTML5 video at Netflix.


From the very beginning, EME faced strong criticism from representatives from Mozilla. Here are some example messages:

It even caused some protests, led by Richard Stallman and the FSF.

After its standardization, the EFF Announced its resignation from W3C.

An integrated Web

PWA Install UX

in Chrome



« The mini-infobar is an interim experience that becomes annoying (the number of PWAs is growing). Starting in Chrome 76, it's possible to prevent the mini-infobar from appearing by calling preventDefault() on the beforeinstallprompt event (see 2019/05 mini-infobar-update), but according to our observations very few developers do it. »

Issue 988301, comment 1

omnibox install icon

omnibox install icon

in Firefox Mobile


Firefox info banner

Only shows once!

Firefox info banner

Closing the App Gap

Chrome: Unlocking new capabilities for the web

Web Share Target API

🚀 Launched Capability

⚠️ Should not be confused with the Web Share API, which permits to share data from a web page, as follow:

navigator.share({title: 'Example Page', url: ''});
  "name": "Web Share Target Test App",
  "share_target": {
    "action": "sharetarget.html",
    "params": {
      "title": "title",
      "text": "text",
      "url": "url"
handling the incoming content

Data is passed using get param.


window.addEventListener('DOMContentLoaded', () => {
  const parsedUrl = new URL(window.location);
  // searchParams.get() will properly handle decoding the values.
  console.log('Title shared: ' + parsedUrl.searchParams.get('title'));
  console.log('Text shared: ' + parsedUrl.searchParams.get('text'));
  console.log('URL shared: ' + parsedUrl.searchParams.get('url'));
Level 2

Permits to share/receive images.


The Web Share API itself is only supported by Chrome Android and ... Safari 🎉 (see caniuse).

Firefox 72 should support the Web Share API too (see 🐞 1402369 & 1312422). Yet, Firefox Nightly doesn't for now (tested on 72.0a1 (2019-10-30), see Fenix #328, android-components #3486, 780).

Level 1 is only supported by Chrome 71+.

Mozilla expressed its support (#176 & PR#183) and prioritized the related issues (Fenix #4637, #5783 & 🐞 1476515).

Level 2 is supported by Chrome for Android 76 (see status), while the Web Share API level 2 is supported by Chrome for Android 75+ (see status).


Async Clipboard API (images)

🚀 Launched Capability (Chrome 76)

/** Write contents of the textarea to the clipboard when clicking "Copy" */
copy.onclick = async () => {
  await navigator.clipboard.writeText(out.value)

/** Read from clipboard when clicking the Paste button */
paste.onclick = async () => {
  const text = await navigator.clipboard.readText()
  return text;


/** Write the Chrome logo to the clipboard when clicking "Copy" */
copy.onclick = async () => {
try {
  const imgURL = '/images/generic/file.png';
  const data = await fetch(imgURL);
  const blob = await data.blob();
  await navigator.clipboard.write([
    new ClipboardItem(Object.defineProperty({}, blob.type, {
      value: blob,
      enumerable: true
  console.log('Image copied.');
} catch(e) {
  console.error(e, e.message);

/** Read from clipboard when clicking the Paste button */
paste.onclick = async () => {
  try {
    const clipboardItems = await;
    const blobOutput = await clipboardItems[0].getType('image/png');
    document.getElementById('image-field').src =
  } catch(e) {
    log('Failed to read clipboard');

/** Watch for pastes */
navigator.clipboard.addEventListener('clipboardchange', async e => {
  const text = await navigator.clipboard.getText();
  log('Updated clipboard contents: '+text)

The clipboard API is (partially) supported by Chome 66+, Firefox63+ and Opera 53+.


  • the async part is supported by
    • Chrome 66+
    • Firefox 63+ behind the flag, but there is still some issues (see the Mozilla Standards Positions about this in 89 & 206)
  • this is because there is still some ongoing discussions about this in W3C TAG
  • the support for images (what we're talking about here) was added by Chrome 76.

Badging API

⚠️ Only available in Chrome, behind #enable-experimental-web-platform-features, on Windows and macOS.

No GNU/Linux nor ChromeOS support here. This is why I need to use a Windows VM for that 🤷‍♂.

A new shape for this API was decided in september, and added to Chrome in Oct '19, but not released in Canary yet (see comment) and the specs are behing updated.

navigator.setClientBadge(42, { client });





Shape Detection API

face detection
const faceDetector = new FaceDetector({
  // (Optional) Hint to try and limit the amount of detected faces
  // on the scene to this maximum number.
  maxDetectedFaces: 5,
  // (Optional) Hint to try and prioritize speed over accuracy
  // by, e.g., operating on a reduced scale or looking for large features.
  fastMode: false
try {
  const faces = await faceDetector.detect(image);
  faces.forEach(face => drawMustache(face));
} catch (e) {
  console.error('Face detection failed:', e);
barecode detection
const barcodeDetector = new BarcodeDetector({
  // (Optional) A series of barcode formats to search for.
  // Not all formats may be supported on all platforms
  formats: [
try {
  const barcodes = await barcodeDetector.detect(image);
  barcodes.forEach(barcode => searchProductDatabase(barcode));
} catch (e) {
  console.error('Barcode detection failed:', e);
text detection
const textDetector = new TextDetector();
try {
  const texts = await textDetector.detect(image);
  texts.forEach(text => textToSpeech(text));
} catch (e) {
  console.error('Text detection failed:', e);

This API highly depends on hardware acceleration, and most devices doesn't support it for now. Using it on some devices could give you some better performances. Yet, you should absolutely add a fallback (see "Best Practices" below). Due to a combination of hardware (old computers, notebooks & Samsung Galaxy S8) and software (ArchLinux being the only host OS I have on my Dell XPS) limitations, I myself wasn't able to use this API yet.

Chrome Status

Support for this API is dependant on hardware acceleration features that vary by operating system.

  • BarcodeDetector: Android*, macOS (improved accuracy in 10.13+)
  • FaceDetector: Android, macOS (improved accuracy in 10.13+), Windows 10
  • TextDetector: Android*, macOS 10.11+, Windows 10

* Requires a device with the Play support libraries installed.

Best Practices

Caution: This API is an optimization and not something guaranteed to be available from the platform for every user. Developers are expected to combine this with their own image recognition code and take advantage of the native optimization when it is available.

Here, the given example is opencv.js, but you could use any other vision & ML library, like face-api.js for face detection for example.


Contacts Picker API

⚠️ Unofficial Proposal Draft

getContactsButton.addEventListener('click', async () => {
  const contacts = await
      ['name', 'email'],
      {multiple: true});
  if (!contacts.length) {
    // No contacts were selected, or picker couldn't be opened.

only on Chrome 77+ on Android M or later


And more...

  • Get Installed Related Apps
  • Native File System
  • Wake Lock API

A modular Web

Import Maps & built-in modules

Import Maps:

Built-in modules:

KV Storage:

HTML Elements provided as build-in modules

see also:

experiments in progress

An adaptive Web

Media Queries Level 5

Dark/Light Mode

Read Hello darkness my old friend by Thomas Steiner on

Emulation / DevTools

Issue 977243: DevTool helper for prefers-color-scheme: dark


feat: emulate prefers-color-scheme #4906


from stackoverflow:

  1. open about:config
  2. add a ui.systemUsesDarkTheme integer entry set to 1
  3. restart firefox

Reduced Motion

Move Ya! Or maybe, don't, if the user prefers-reduced-motion!



A more efficient Web


You can’t perform that action at this time.