LoginSignup
14
14

More than 3 years have passed since last update.

【ビルド不要】HTML単体でES6+をトランスパイルしIE11へ対応

Last updated at Posted at 2018-12-25

(2020/07/03 ... 記事を全面リニューアルしました)

令和の時代、わが国の企業は大部分が未だIEの呪縛に囚われている・・・

MicrosoftがいくらIEを非推奨としてEdge(Chromium)を推奨しても、御社の情シスはそれを許しません。

そんな闘う社内エンジニアの方々に朗報です。

HTMLサンプル

index.html
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="height=device-height, width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
        <meta http-equiv="x-ua-compatible" content="ie=edge">

        <script src="https://cdn.jsdelivr.net/npm/@babel/polyfill@latest/dist/polyfill.min.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/@babel/standalone@latest/babel.min.js"></script>

        <title>Babel</title>
    </head>

    <body>
        Babel Test
    </body>

    <style>
        html{
            color: #d8d8d8;
            background-color: #242424;
        }
    </style>

    <script type="text/babel" data-presets="env,stage-3">
        class FileReaderEx extends FileReader{
            constructor(){
                super();
            }

            #readAs(blob, ctx){
                return new Promise((res, rej)=>{
                    super.addEventListener("load", ({target}) => res(target.result));
                    super.addEventListener("error", ({target}) => rej(target.error));
                    super[ctx](blob);
                });
            }

            readAsArrayBuffer(blob){
                return this.#readAs(blob, "readAsArrayBuffer");
            }

            readAsDataURL(blob){
                return this.#readAs(blob, "readAsDataURL");
            }

            readAsText(blob){
                return this.#readAs(blob, "readAsText");
            }
        }

        (async()=>{
            const blob = new Blob([new Uint8Array(1024)]);
            const buffer = await new FileReaderEx().readAsArrayBuffer(blob);
            console.log(buffer);
        })();
    </script>
</html>

バリバリなES6+ですが、このHTMLはそっくりそのままIE11で動きます。

解説

@babel/standaloneというBabelのスタンドアロン版を使用します。
通常版はWebpackやParcelといったビルドツール経由で受動的に使用されることを前提としているのに対し、スタンドアロン版はそれ単体で能動的に動作します。

@babel/polyfillはBabelがトランスパイル時に使用する機能も含まれているので@babel/standaloneより先にロードする必要があります。

具体的な動作としては、HTML内の<script type="text/babel">タグを検出し、その中のソースコードをトランスパイルした後にHTML内へ挿入します。

通常であればbabelrcに記載するコンフィグはdata-xxx属性へ記載します。

babelrc
{
    "presets": [
        "@babel/preset-env",
        "@babel/preset-stage-3"
    ]
}
<script type="text/babel" data-presets="env,stage-3">

また、Babelはwindow.Babelとしてグローバルスコープへ展開されているので、ソースコードを任意のタイミングでトランスパイルすることも可能です。

const src = "(async() => await new Promise(res => res(1)))();";

const transpiled = Babel.transform(src, {
    presets: ["env", "stage-3"]
}).code;

なお、通常版は7.4.0から@babel/polyfillの使用が非推奨となり、代わりにポリフィル内部で使用されていたcore-jsregeneratorを直接ロードする方法が推奨となりました。
しかし、この2つは現時点ではバンドル済のコードが存在しないため、スタンドアロン版ではバンドル済の@babel/polyfillを使用する必要があります。

おわりに

御社が1日も早くIEの呪縛から解放されますように...

SpecialThanks

14
14
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
14