browserify + babelify + Gulp で IE11対応を試す

gulp-babel だけではIE対応が不十分なので、次の手として browserify + babelify + Gulp で挑みます。

具体的にはポリフィルの追加なのですが、 Babel が 7.4.0 から @babel/polyfill が非推奨となったため、 regenerator-runtimecore-js を直接読み込ませる形になります。

併せて import を使いたいので、 browserify + babelify の手法に則っていきたいと思います。

リポジトリは以下。

package.json

{
    "name": "tower_babel_test",
    "version": "2.0.0",
    "description": "browserify + babelify + Gulp で IE11 対応するテストプロジェクトです。",
    "main": "gulpfile.js",
    "scripts": {
        "start": "gulp",
        "gulp": "gulp"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "dependencies": {
        "regenerator-runtime": "^0.13.7",
        "core-js": "^3.6.5"
    },
    "devDependencies": {
        "@babel/core": "^7.11.6",
        "@babel/preset-env": "^7.11.5",
        "browserify": "^16.5.2",
        "babelify": "^10.0.0",
        "through2": "^4.0.2",
        "browser-sync": "^2.26.12",
        "gulp": "^4.0.2",
        "gulp-notify": "^3.2.0",
        "gulp-plumber": "^1.2.1",
        "gulp-rename": "^2.0.0",
        "gulp-uglify-es": "^2.0.0"
    }
}

babelify の他、 browserify とそれを Gulp から使用する上で必要な through2 を追加。

Gulp 周りで言うと、後述の容量圧縮のため gulp-renamegulp-uglify-es を追加しました。

逆に Babel を直接操作しないので @babel/cli を削除。

gulpfile.js

const gulp        = require('gulp');
const plumber     = require('gulp-plumber');
const notify      = require('gulp-notify');
const uglify      = require('gulp-uglify-es').default;
const rename      = require('gulp-rename');
const browserify  = require('browserify');
const through2    = require('through2');
const babelify    = require('babelify');
const browserSync = require('browser-sync').create();

const dir = {
    src: {
        js   : './src'
    },
    dist: {
        html : './dist',
        js   : './dist/js'
    }
};

const babelBuild = () => {
    const browserified = through2.obj((file, encode, callback) => {
        browserify(file.path)
            .transform(babelify)
            .bundle((error, response) => {
                if(error) {
                    return callback(error);
                }
                file.contents = response;
                callback(null, file);
            });
    });
    return gulp.src(`${dir.src.js}/**/*.js`)
        .pipe(browserified)
        .pipe(plumber({
            errorHandler: notify.onError({
                message: 'Error: <%= error.message %>',
                title: 'BabelBuild'
            })
        }))
        .pipe(uglify({
            output: {
                comments: 'all'
            }
        }))
        .pipe(rename((path) => {
            path.basename += '.min'
            path.extname = '.js'
        }))
        .pipe(gulp.dest(dir.dist.js));
};

const browsersync = () => {
    browserSync.init({
        server: {
            baseDir: dir.dist.html
        },
        open: 'external',
        https: true
    });

    const bReload = browserSync.reload;
    gulp.watch(
        dir.dist.html + '/**/*.html'
    )
        .on('add',    bReload)
        .on('change', bReload)
        .on('unlink', bReload);
    const sJs = gulp.series(babelBuild, browserSync.reload);
    gulp.watch(
        `${dir.src.js}/**/*.js`
    )
        .on('add',    sJs)
        .on('change', sJs)
        .on('unlink', sJs);
};

exports.server = browsersync;
exports.build = babelBuild;
exports.default = gulp.series(babelBuild, browsersync);

大きく変わったのは babelBuild タスクの部分。 gulp-babel から babelify + browserify に換装しました。

サンプル

続いてサンプル。

src/app.js

import 'core-js/stable';
import 'regenerator-runtime/runtime';

$(() => {
    const list = [
        'intro',
        'Rain Dog',
        'En',
        'sister',
        '最後の朝',
        'Island',
        'Tower',
        'SAKURA',
        'home'
    ];
    if (list.length > 0) {
        const $ol = $('<ol/>');
        for (const [key, val] of list.entries()) {
            const $li = $('<li/>');
            const num = key + 1;
            let numStr = String(num);
            if (num < 10) {
                numStr = `0${String(num)}`
            }
            $li.text(`${numStr}: ${val}`);
            $ol.append($li);
        }
        const bookshelf = 'bookshelf';
        $(`#${bookshelf}`).append($ol);
        $ol.css({
            listStyle: 'none outside',
            paddingInlineStart: 0
        });
    }
});

冒頭に import 'core-js/stable';, import 'regenerator-runtime/runtime'; が追加されました。

これで Gulpタスク を走らせると……

ブラウザでの表示確認 (IE)
ブラウザでの表示確認 (IE)

IEでも動作するようになりました。

備考

ファイル 分類 容量
src/app.js オリジナルのコード 837 バイト
dist/js/app.js browserify + babelify 465 キロバイト (476,244 バイト)
dist/js/app.min.js browserify + babelify + gulp-uglify-es 269 キロバイト (276,043 バイト)
ファイルサイズの比較

最初は uglify していなかったので、元のコードが837バイトしかなかったのに、 regenerator-runtimecore-js 入りトランスパイルポリフィルマシマシにしたら465キロバイトになってしまいました。

流石にこれは……と思ったので急遽 uglify を追加。これで269キロバイトには減りましたが、元コードから比べれば大幅増ではあります。

ついでにJSのトランスパイル処理も重い(十数秒かかる)ので、自動化していてももっさりした印象を受けます。

ヤッパIEタイオウスベキジャナカッタンデスカネー

備考2

前回に引き続き、サンプルプログラムには jizue の Bookshelf の曲名を拝借しました。 Babel → Tower の連想です。

参考

browserify

Browserify + Gulp

babelify

@babel/preset-env

ポリフィル

core-js

この記事を書いた人

アバター

アルム=バンド

フロントエンド・バックエンド・サーバエンジニア。LAMPやNodeからWP、Gulpを使ってejs,Scss,JSのコーディングまで一通り。たまにRasPiで遊んだり、趣味で開発したり。