ふりぶろぐ
Web Engineer's Blog
gulp

【gulp, webpack】フロントエンド開発環境を最新化する

pug, sass, js の開発環境のテンプレートがあったのですが、バージョンが非常に古かったのですべて最新化しました。

  • node v7.6.0 -> v13.1.0
  • yarn 1.17.0 -> 1.19.1
  • gulp 3.9.1 -> 4.0.2
  • webpack 1.14.0 -> 4.41.2

gulpとwebpackのアップデートにかなり苦労しました。

gulp 4系、webpack 4系って今までと全然違いますね。

ちなみにベースとなるテンプレート環境は私が作ったものではないので、gulpもwebpackもほとんど初心者です。

nodeアップデート

まずはnodeのアップデートを行いました。

まずは普通にnodebrewからバージョンを最新版にしてみる。

$ nodebrew install-binary latest

こちらのコマンドで最新版をインストール。(2019年11月現在 最新版v13.1.0)

その後、いつもどおり起動してみるとエラーが。

delがないと言われているので入れてみる。

$ yarn add -D del

とりあえずこれで動くようにはなりました。

yarnアップデート

yarnはアップデートするつもりなかったけど、作業をしていたらアップデートを促されたので指定されたとおりにやってみた。

$ curl --compressed -o- -L https://yarnpkg.com/install.sh | bash

このコマンドを実行してターミナルを再起動しただけで最新版のyarnをインストールできました。(2019年11月現在 最新版v1.19.1)

アップデートしても動作には特に影響はなさそう。

package.jsonアップデート

package.jsonを最新化した影響でgulpとwebpackも一緒にアップデートされました。

package.jsonの最新化にはnpm-check-updatesを使用しました。

インストールして実行するだけで最新化してくれます。

$ npm install -g npm-check-updates
$ npm-check-updates -u

gulpアップデート

ここが一番苦労しました。

ざっくりと解説しますが、実際はもっとハマってる箇所ありました。

基本的には、gulp 3系からgulp 4系への書き換え。

defaultタスク

まずはdefaultのタスクから修正していきました。

import gulp from 'gulp';	
import runSequence from 'run-sequence';	

const config = require('../config').default;

gulp.task('default', () => {
  runSequence(...config.runTasks);
});

configファイルから実行するタスクの情報を取得し、runSequence()で処理する設定になっていました。

しかし、gulp 4系ではrunSequence()を使用できなくなったみたいです。

runSequence()の代わりにgulp.series()とgulp.parallel()を使用します。

const gulp = require('gulp');

gulp.task('default', gulp.series(
  'sprite',
  gulp.parallel('pug', 'sass', 'script'),
  gulp.parallel('watch', 'httpd')
));

修正した結果、こんなコードに。

confから読み込んでいるせいで可読性が悪かったので直接指定するようにしました。

spriteを実行した後にpug, sass, scriptを並列で処理して、最後にwatch, httpdを並列で処理するといった流れです。

地味な部分ですが、最初のインポート処理にimportを使用するとエラーになったので、すべてrequireに書き換えています。

gulpfile.js

sprite, pug, sass等のタスクは別ファイルで定義してgulpfile.jsで先に読み込んでいます。

require('./gulp/tasks/watch');
require('./gulp/tasks/httpd');

require('./gulp/tasks/sprite');
require('./gulp/tasks/file');
require('./gulp/tasks/music');
require('./gulp/tasks/iconfont');

require('./gulp/tasks/pug');
require('./gulp/tasks/sass');
require('./gulp/tasks/script');
require('./gulp/tasks/image');

require('./gulp/tasks/build');
require('./gulp/tasks/default');

今までは以下のようにrequire-dirを使用して読み込んでいたのですが、読み込み順を考慮しなくてはならなくなったので1つずつ読み込むようにしました。

import requireDir from 'require-dir';	

// 各タスクを読み込む	
requireDir('gulp/tasks', { recurse: true });

余談ですが、gulpfile.jsはgulpfile.xxxx.jsというファイル名でも読み込んでくれるみたいです。

もともとはgulpfile.babel.jsという名前になっていました。

監視タスク

少し省略はしますが、gulp 3系では以下のように監視タスクを読み込んでいました。

import gulp from 'gulp';	
import gulpLoadPlugins from 'gulp-load-plugins';	

// 各種設定を読み込む	
const $       = gulpLoadPlugins();	
const config  = require('../config');

gulp.task('watch', () => {

  // pug
  $.watch(config.pug.watch, () => {
    gulp.start(['pug']);
  });

});

watchの書き方も少し変わったようで、書き換える必要がありました。

gulp 4系のほうがシンプルで読みやすいですね。

const gulp = require('gulp');
const config = require('../config');

// watch 実行タスク
gulp.task('watch', () => {
  // pug
  gulp.watch(config.pug.watch, gulp.task('pug'));
});

watchを読み込んでgulp.startを使用していましたが、gulp 4系ではgulp.watchとgulp.taskを使用します。

watchの第一引数はconfから読み込んでいますが、特に修正はしていません。

同じ値を渡しても問題ないと思います。

その他のビルドファイル

その他のビルドファイル(pug.js, sass.js, script.js)はimportをrequireに書き換えただけ。

処理の部分は特に修正は必要ありませんでした。

基本的にはgulp 3系のコードで動作すると思います。

webpackアップデート

JSファイルをコンパイルするときにwebpackを使用していました。

confファイルの定義の仕様がいろいろと変わっていたのでエラーが出ました。

書き換えた部分をざっくりとまとめておきます。

mode

modeを指定しないと警告が出てしまっていました。

entryと同じ階層にmodeを追加しました。

‘production’, ‘development’, ‘none’ のどれかを指定してください。

  mode: isProduction ? 'production' : 'development',
  entry: {
    vendor: ['jquery'],
  },
  output: {
    filename: '[name]'
  },

extensions

  resolve: {
    extensions: ['', '.js'],
    modulesDirectories: [
      'node_modules',
      'src'
    ]
  }

このようにextensionsで空文字を指定していましたが、指定できなくなっていました。

というわけで空文字指定は削除。

  resolve: {
    extensions: ['.js'],
    modulesDirectories: [
      'node_modules',
      'src'
    ]
  }

devtool

devtool: isProduction ? null : 'source-map',

devtoolの値としてnullを使用していましたが、falseに変える必要がありました。

devtool: isProduction ? false : 'source-map',

module

module: {
    preLoaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'eslint',
      },
    ],
    loaders: [
      {
        test: /\.js$/,
        loader: 'babel',
        exclude: /node_modules/,
        query: {
          cacheDirectory: !isProduction,
        },
      },
    ]
  },

preLoaders, loadersはrulesに変わりました。

また、loaderで指定するloaderはxxxx-loaderと指定する必要がありました。

module: {
    rules: [
      {
        enforce: 'pre',
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'eslint-loader',
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        exclude: /node_modules/,
        query: {
          cacheDirectory: !isProduction,
        },
      },
    ]
  },

しれっと追加している enforce: ‘pre’ が結構重要で、これを入れることでビルド前にコードの検証を行ってくれます。

これを入れなかったらとんでもない数のエラーが出ました。

plugins

  plugins: [
    new webpack.optimize.CommonsChunkPlugin({	
      name: 'vendor',	
      filename: 'vendor.bundle.js',	
      minChunks: Infinity,	
    }),	

    // プラグインの並べ替え
    new webpack.optimize.OccurenceOrderPlugin()
  ]

プラグインとしてCommonsChunkPluginとOccurenceOrderPluginを使用していましたが、どちらもなくなってしまったみたい。

CommonsChunkPluginはプラグインの外で指定するようになり、OccurenceOrderPluginは名前が若干変わりました。

  optimization: {
    splitChunks: {
      name: 'vendor.bundle.js',
      chunks: 'initial',
    }
  },
  plugins: [
    // プラグインの並べ替え
    new webpack.optimize.OccurrenceOrderPlugin()
  ]

まとめ

最新化するに当たって修正した箇所についてまとめてみました。

エラー内容を記録していなかったため、こちらでまとめられないのが少々心残りではありますが、少しでも役に立てばと思います。

結構時間がかかってしまいましたが、いろいろと勉強になりました。

gulp, webpackにも少し慣れたし、テンプレート環境もアップデートできたし良かったです。

ABOUT ME
りーふ
たまにブログを書いてるWebエンジニア。 サーバーサイドメインでインフラとフロントエンドもたまにやります。 Javaが得意。 Play Frameworkが好き。 本業は迷惑をかけない程度に手を抜くスタイル。 意識高い系は苦手。