Gulp 4 + Webpack 5 を試す ( 未完 / terser-webpack-plugin で TypeError: Cannot read property ‘javascript’ of undefined エラーになる)

以前、browserify + babelify + Gulp で IE11対応を試すの記事で browserify + babelify を試しましたが、今回は Webpack に挑んでみます。

ただし、プレーンな Gulp 環境ではなく、 Ususama で。

コード

package.json

// 略
    "devDependencies": {
// 略
        "glob": "7.1.6",
        "webpack": "^5.1.3",
        "webpack-stream": "^6.1.0",
        "terser-webpack-plugin": "^5.0.0",
// 略
    }
// 略

gulp-uglify-esgulp-concat を除き、代わりに webpack 本体と Gulp で Webpack を使用するために必要な webpack-stream 、そして minifier の terser の Webpack 用プラグインである terser-webpack-plugin を追加。

gulp/tasks/js.js

const gulp          = require('gulp');
const plumber       = require('gulp-plumber');
const notify        = require('gulp-notify');
const webpack       = require('webpack');
const webpackStream = require('webpack-stream');
const rename        = require('gulp-rename');
const dir           = {
    dist: {
        js: './dist/js'
    }
};

const webpackConfig = require('../../weppack.config');

const jsBuild = () => {
    return webpackStream(webpackConfig)
        .pipe(plumber({
            errorHandler: notify.onError({
                message: 'Error: <%= error.message %>',
                title: 'jsLibBuild'
            })
        }))
        .pipe(rename((path) => {
            path.basename += '.min'
            path.extname = '.js'
        }))
        .pipe(gulp.dest(dir.dist.js));
};

module.exports = jsBuild;

webpack.config.js

const webpack       = require('webpack');
const webpackTerser = require('terser-webpack-plugin');
const path          = require('path');
const glob          = require('glob');
const dotenv        = require('dotenv').config();
const dir           = {
    src: {
        js: './src/js'
    }
};

const mode = () => {
    return process.env.DEV_MODE === 'dev' ? 'development' : 'production';
};
const modeFlag = () => {
    return process.env.DEV_MODE === 'dev' ? false : true;
};
const entry = () => {
    const entries = glob
        .sync(
            '**/*.js',
            {
                ignore: [
                    '_plugins/**'
                ],
                cwd: dir.src.js
            }
        )
        .map(function (key) {
            return [key, path.resolve(dir.src.js, key)];
        });
    return Object.fromEntries(entries)
};
module.exports = {
    mode: mode(),
    entry: entry(),
    output: {
        filename: '[name]'
    },
    optimization: {
            minimizer: [
            new webpackTerser({
                extractComments: 'some',
                terserOptions: {
                    compress: {
                        drop_console: modeFlag(),
                    },
                },
            }),
        ],
    }
};

いくつかの記事を参考にしながらタスクを組みます。

自分でカスタマイズした部分は以下。

  • .envdev, demo, prod のモードを切り替えているので、その部分を process.env.DEV_MODE で振り分け
    • Webpack の設定の modeterser-webpack-plugindrop_console のフラグが関係しています
  • 複数の .js ファイルをエントリポイントにしたかったのでその部分はwebpackのentryファイルを複数指定、globパッケージの使い方 – Qiitaを参考に
  • 最終的なファイル名は XXX.min.js の形にしたかったので gulp-rename を通しました

jQuery の扱い

タスク自体は上記のやり方で走ることが確認できました( DEV_MODE=dev )。

次は現時点ではまだ jQuery を使用しているので、 jQuery をどう読み込ませるかが課題ですが、以下のようにして動作することを確認しました。

app.js

import $ from 'jquery';
import 'jquery.easing/jquery.easing';

$(() => {
    /* 処理 */
});

sitesearch.js

import $ from 'jquery';
import List from 'list.js';

//サイト内検索
export default () => {
    const options = {
        valueNames: ['searchTitle', 'searchText'],
    };
    const searchList = new List('listSearch', options);
    //hits
    searchList.on('searchComplete', function (a) {
        $('#hits').text(a.matchingItems.length);
    });
};

サイト内検索で List.js を使用しているのですが、これについてはHow am I suppose to import list.js with es6 and webpack ? · Issue #559 · javve/list.jsの Issues の方法で解決しました。

ここまでは比較的順調でした。

しかし、間も無く壁に突き当たることになります……。

TypeError: Cannot read property ‘javascript’ of undefined エラー

DEV_MODE=dev で動作することは確認できたので、 DEV_MODE=prod に切り替えました。

すると、以下のエラーが出てしまいました。

TypeError: Cannot read property 'javascript' of undefined
    at PATH\TO\PROJECT\node_modules\terser-webpack-plugin\dist\index.js:366:38

DEV_MODE=dev に戻すと先ほどと同じように問題なく動作。上記でこのフラグが関係するのは modeterser-webpack-plugindrop_console の2箇所なので、そのどちらかだろうとアタリを付けます。

試しに drop_console を常に false としましたが、 DEV_MODE=prod でエラーは再現しました。

となると、 mode の方ということになります。

ここでエラー文で検索すると、以下の Issues を発見。 terser-webpack-plugin 本家のリポジトリです。

発生個所も含めてエラー文が同じです。

別の方のコメントを見ると、原因は以下の模様。

  • terser-webpack-plugin 5 は Webpack 4 とは互換性がない
  • webpack-stream の内部で使用している Webpack がバージョン 4 系

yep, we are working on it, release with fix will be today/tomorrow

TypeError: Cannot read property ‘javascript’ of undefined ・ Issue #335 ・ webpack-contrib/terser-webpack-plugin (2020/10/16日 22:04 JST)

わりとタイムリーなものを踏んでしまったようなので、 fixed されるのを待つ感じですかね……。

参考

Gulp + Webpack

webpack-stream

Webpack, 複数エントリポイントとoutput

List.js import

terser-webpack-plugin

この記事を書いた人

アルム=バンド

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