♰Dark Mode♰ を作れるようになった Google Chrome 76 リリースノート要約

だいたい毎月リリースされている Google Chrome 、バージョン 76 の安定板がリリースされましたので要約します。

- [Chrome Releases: Stable Channel Update for Desktop](https://chromereleases.googleblog.com/2019/07/stable-channel-update-for-desktop_30.html)
- [New in Chrome 76  |  Web  |  Google Developers](https://developers.google.com/web/updates/2019/07/nic76)

総計 43 個のセキュリティ fix が入っています。

## PWA インストールボタン

デスクトップ版でも Progressive Web App, Web アプリケーションをネイティブアプリっぽく利用出来るシステムを簡単に利用してもらえるように、アドレスバー(Omnibox と呼ばれることも)のお気に入りボタンの隣に **「PWA インストールボタン」** が追加されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332028/9c92f0b6-14e9-5697-3168-9cc8b0f3d115.png)

PWA として正しい設定(manifest.json 等)がされていれば表示されるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332028/bac875fc-23ed-5faf-aa94-290014424d09.png)

弊プロダクトの [ザ・シードオンライン](https://seed.online) も PWA に対応しているので、プラスボタンが出ているのが分かると思います。 PWA の民主化が進んでいてとても嬉しい！

もちろんこの PWA は元々 mobile 向けに開発されたものなので、 mobile でもインストールを促すプロンプトが出ますよ(これは以前から)。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332028/ed8884ed-ae03-9930-31d6-aa22014c5092.png)

検索から辿ってきて一度きりしかみないようなページでこれが出てくると「うるさっ」となりますが、週に1度以上使うようなページでは、ホーム画面にリンクがあった方が嬉しいこともあると思います。良く使うページは是非 PWA インストールしてみましょう！

この mobile PWA インストールバーをより柔軟に処理できるような仕組みも追加されました。具体的には、任意のタイミングでプロンプトを表示出来るようになります。

```js
let deferredPrompt = null;

// PWA インストールバーを表示出来るタイミングでこのイベントが発火されます
window.addEventListener('beforeinstallprompt', (evt) => {
  // Chrome 76 で、デフォルトのインストールバーを出さないようにすることが出来るようになりました。
  evt.preventDefault();

  // 後からプロンプトを表示出来るようにする
  deferredPrompt = evt;
});

// 自作のボタンをクリックした時
pwaInstallBtm.addEventListener('click', async () => {
  if (deferredPrompt) {
    // PWA インストールをするかどうかのプロンプトをここで後から表示
    deferredPrompt.prompt();
    const choiceResult = await deferredPrompt.userChoice;
    if (choiceResult.outcome === 'accepted') {
      console.log(`インストールしました！`);
    } else {
      console.log(`インストールしませんでした。`);
    }
    deferredPrompt = null;
  }
});
```

- [Add to Home Screen  |  Web Fundamentals  |  Google Developers](https://developers.google.com/web/fundamentals/app-install-banners/)
- [In Chrome 76 you can hide the Add to Home screen mini-infobar  |  Web  |  Google Developers](https://developers.google.com/web/updates/2019/05/mini-infobar-update)
- [Patterns for Promoting PWA Installation (mobile)  |  Web Fundamentals  |  Google Developers](https://developers.google.com/web/fundamentals/app-install-banners/promoting-install-mobile)

## WebAPK の更新頻度向上

Android に PWA をインストールすると、バックグラウンドで自動的に `WebAPK` と呼ばれるものが生成されます。これは、例えば App Launcher に PWA アプリを表示出来るようにしたり、 manifest に登録されたページ以外にアクセスしたらブラウザに移動するように誘導したり、パーミッションやストレージをうまく(ネイティブアプリっぽく)扱うための仕組みです。

この manifest の更新チェックが、大体 3 日置きくらいだったのが 1 日置きくらいになりました。なので、 manifest の更新をより早くユーザに届けることが可能です。

## ♰Dark Mode♰

最近流行ですよね、ダークモード。 [macOS](https://support.apple.com/ja-jp/HT208976) や [Windows 10](https://docs.microsoft.com/ja-jp/windows-insider/at-home/whats-new-wip-at-home-19h1#windows-%E3%83%A9%E3%82%A4%E3%83%88%E3%83%86%E3%83%BC%E3%83%9E)、 [Android Q](https://www.gizmodo.jp/2019/05/android-q-dark-thema-handson.html) など、 OS レベルでのサポートが盛んにおこなわれています。

Google Chrome 76 からは、 OS がどのようなカラースキームを利用しているかどうかを判別するために `prefers-color-scheme` という CSS メディアクエリが追加されました。

```css
body {
  /* 通常は白背景 */
  background-color: #EEE;
  color: #111;
}
@media (prefers-color-scheme: dark) {
  /* dark カラースキーマを使っているなら黒背景 */
  body {
    background-color: #111;
    color: #EEE;
  }
}
```

このようなスタイルでダークテーマを実装することが可能になっています。

かなり詳細なダークモードに関しての紹介は web.dev のブログで行われています。

[Hello darkness, my old friend  |  web.dev](https://web.dev/prefers-color-scheme/)

## puppeteer for Firefox

[puppeteer/experimental/puppeteer-firefox at master · GoogleChrome/puppeteer](https://github.com/GoogleChrome/puppeteer/tree/master/experimental/puppeteer-firefox)

Headless Chromium(Chrome) を node.js から自動操作出来る puppeteer の Firefox 版が開発中です。凄い。恐らく New Edge も Chromium ベースになるので、きっと操作出来るようになるでしょう。 puppeteer 万歳。

## その他細かな改善

### `Promise.allSettled()`

今まで複数の Promise の完了を待つには `Promise.all()` を用いる必要がありました。

`Promise.allSettled()` を使えば、「ただ待つだけ」が出来るようになります。

```js
const promises = [
  fetch('/a'),
  fetch('/b'),
  fetch('/c'),
];

// これまで
const results = await Promise.all(promises);

// 待つだけ
await Promise.allSettled(promises);
```

### blob 読み込みが楽になった

```js
const text = await blob.text();
const arrBuff = await blob.arrayBuffer();
const stream = await blob.stream();

// 今までは `FileReader` を利用して頑張って読み込む必要がありました...
const oldText = await (new Promise((resolve) => {
  const reader = new FileReader();
  reader.addEventListener('loadend', (e) => {
    const text = e.srcElement.result;
    resolve(text);
  });
  reader.readAsText(file);
}));
```