仕事が忙しいほどブログを書きたくなる。

◆何の話か

SPAのサイト作ってて、古いブラウザ使ってる人にメッセージ出したいと思いました。任意の画面を表示させたい。

Babel使えば動くんだけど、「動くように」はしたくない。だって古いブラウザだもの。新しいやつ使いやがれ。

◆以下に紹介されるやり方が正しいか

知らん。考えてたらひらめいたというだけ。もっといい方法あるかもね。

◆結論

一例だけど。

  <script>
    function r() {
      document.body.innerHTML = "<main>そのブラウザは古いです。申しわけありませんが動かねぇよバカが。</main>";
    };
  
    window.addEventListener('DOMContentLoaded', function(event) {
      (function (){
        "use strict";
        try {
          window.Function("var foo = (x) => x"); // ES6のアロー関数
          window.Function("let { ...x } = { y: 1 };"); // ES2016+のobject-rest-spread
        } catch (e) { r(); }
      })();
    });
  </script>

これをHTMLのhead要素にぶち込んだれや。なるべく上のほうにね。

◆作戦

  • あるブラウザで任意の記法が利用できるかどうかを確認したい。
  • でも、その記法が書いてあったら画面がぶっ壊れる。
  • どうしよ…
  • 天啓「実行時に構文解析して例外をキャッチすればいいんじゃね?」
  • あー…え?それできるの?
  • できるわ。

文字列をコードとして変換するのはeval…じゃのうて、Window.Functionのコンストラクタを使いましょう。

文字を変換できなかった場合(古いブラウザだった場合)は、bodyのHTMLを上書きしてしまえ。IE死ね!

変換のタイミングはDOMがロードされた後。DOMContentLoadedにしてみる。変えてもいいと思うけど。

▼body書き換え

function r() {
  document.body.innerHTML = "<main>そのブラウザは古いです。申しわけありませんが動かねぇよバカが。</main>";
};

単にbodyを書き換える関数「r」。

このrを「古いブラウザって判定された時」に動かす。

▼判定

function (){
  "use strict";
  try {
    window.Function("var hoge = (x) => x"); // ES6のアロー関数
    window.Function("var { ...hoge } = { fuga: 1 };"); // ES2016+のobject-rest-spread
  } catch (e) { r(); }
}

たとえば

  • アロー関数が使えない
  • オブジェクトのスプレッドが使えない

を判定したいときはこうなる。window.Functionってので文字列を関数に変換できる。変換に失敗したブラウザはcatchに入る。

この判定スクリプトをDOMロード時に即時実行すればよい。

おまえ「EcmaScriptのバージョンでは判定してなくね?」

せやね。機能Xが実装されてるかどうかで判別するほかない。この記事はタイトル詐欺だ。

◆どういうスクリプトを動かせばいいんや

ES6に対応してないなら「var hoge = (x) => x」の変換でエラーがでるんだったな。ES5では?

調べよう。

ECMAScrip compatibility tableってサイトがある。

上の「5」「6」「2016+」とかクリックして調整したり「Show obsolete platforms」のチェックボックスをONにしてみたりで。

例えば「Array.isArray」はES5から使えるようになった機能らしいんで、「Array.isArray(0)」の変換を試みればいいじゃない。目当てのブラウザとそのバージョンにおける実装状況を眺めつつな。

◆結

なんとなく動く。はず。headのなるべく上に書くことを忘れずに。あと、もっといい方法あったら教えろ。