クモのようにコツコツと

フロントエンドエンジニア イイダリョウの技術ブログ。略称「クモコツ」

【gulpfile.js】gulp.task()を関数化(←gulp4推奨)他、リファクタリング

メタ言語の続きです。前回はimageminを使ってメタ言語コンパイル環境で画像圧縮も実行しました。今回はgulpfile.jsの中のgulp.task()をgulp4で推奨されている関数の形に変更します。その他にもいくつかリファクタリングしました。それではいきましょう!

【目次】

※参考:前回記事
【gulp-imagemin】メタ言語コンパイル環境で画像圧縮も実行する - クモのようにコツコツと

※参考:【メタ言語】HTMLテンプレートエンジン、AltCSS、AltJSのまとめ
qiita.com

前回のおさらい

「src/img」フォルダに画像を保存すると https://cdn-ak.f.st-hatena.com/images/fotolife/i/idr_zz/20201122/20201122162233.jpg

「dest/img」フォルダに圧縮された画像が書き出される。 https://cdn-ak.f.st-hatena.com/images/fotolife/i/idr_zz/20201122/20201122162337.jpg

imageminというパッケージを使っている。詳細は前回の記事を参照

※参考:【gulp-imagemin】メタ言語コンパイル環境で画像圧縮も実行する - クモのようにコツコツと

メタ言語環境でこれまで実現したことはこちらのまとめを参照

※参考:qiita.com

今回は機能の追加は行わないがgulpの設定ファイルである「gulpfile.js」を中心にコードのリファクタリングを行う。

package.jsonのnpm scriptに追記

これまで、gulpを起動するときに下記のnpxコマンドを打っていた。

$ npx gulp

こちらの記事を参考に、起動コマンドの種類を増やしてみる。

※参考:npm run で任意のコマンドを実行する (npm run/start) | まくまくNode.jsノート

※参考:gulpの起動を簡単にする方法 - Qiita

package.json

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack",
    "gulp": "gulp", // 追加
    "start": "gulp" // 追加
  },
  • gulpキーを追加(値はgulp
  • startキーを追加(値はgulp

gulpキーを追加することによって下記のコマンドでも起動できるようになった!

$ npm run gulp

startキーを追加することによって下記のコマンドでも起動できるようになった!

$ npm start

TypeScriptのJSONファイルのインポート部分を修正

前回TypeScriptからJSONファイルを読み込めるようにしたが、よく見たら警告(Warning)が出てた。

Should not import the named export 'unsei' (imported as 'Unsei') from default-exporting module (only default export is available soon)

名前付きエクスポート 'unsei'( 'Unsei'としてインポート)をdefault-exportingモジュールからインポートしないでください(デフォルトのエクスポートのみがまもなく利用可能になります)

はて、名前付きエクスポート?デフォルトエクスポート?今回インポートしているのはJSONファイルなのだが。

「kekka.ts」修正前

import * as Unsei from "../../../json/unsei.json";

「kekka.ts」修正後

import Unsei from "../../../json/unsei.json";

ひとまず* asをなくしたら警告は出なくなった。


なお、tsのモジュールをインポートする際には名前付きでエクスポートした方がいいようだ(デフォルトだとインポート時に名前をどうにでも変えられちゃうため)

※参考:なぜ default export を使うべきではないのか? - LINE ENGINEERING

※参考:ES modulesのexport defaultは使わないほうがよい - Islands in the byte stream

※参考:Avoid Export Default - TypeScript Deep Dive 日本語版

※参考:export - JavaScript | MDN

ファイルのパスを変数化

gulpの各タスクの中にいろいろなファイルのパスがあるが、見通しが悪いのと重複があるため、取り出して変数化した。

こちらはコンパイル前の「src」フォルダのパス

// ファイルパス:コンパイル前
const srcJsonFiles = './src/json/**/*.json';
const srcDataJson = './src/json/data.json';
const srcEjsFiles = './src/ejs/**/*.ejs';
const srcEjsPartial = '!./src/ejs/**/_*.ejs';
const srcScssFiles = './src/scss/**/*.scss';
const srcTsFiles = './src/ts/**/*.ts';
const srcImgFiles = './src/img/**/*'
const srcImgFileType = '{jpg,jpeg,png,gif,svg}';

こちらはコンパイル後の「dest」フォルダのパス

// ファイルパス:コンパイル後
const destDir = './dest/';
const destHtmlFiles = './dest/*.html';
const destIndexHtml = 'index.html';
const destCssDir = './dest/css';
const destCssFiles = './dest/css/*.css';
const destJsDir = './dest/js';
const destJSFiles = './dest/js/*.js';
const destImtDir = './dest/img';
const destImgFiles = './dest/img/*';

各タスクの中パスは変数に置き換えている。

これで今後、ファイル名やフォルダ名などが修正になる場合もメンテがしやすくなる。

gulp.task()を関数化

gulp.task()はgulp4では非推奨

以前、こちらにも書いたが、gulp.task()はgulp4から非推奨になっている。

※参考:【HTML】MarkdownをGulpでHTMLにコンパイルしてみる - クモのようにコツコツと

今のところまだ使えるが将来に備えてgulp4で推奨されている関数の形に変えたい。

gulpのドキュメント

※参考:Async Completion | gulp.js

その他参考にした記事

※参考:絶対つまずかないGulp 4入門(2019年版) - インストールとSassを使うまでの手順 - ICS MEDIA

※参考:Gulp4の変更点と新しい書き方 - Qiita

※参考:gulp4再入門 gulpfileの分割とnodeモジュールの利用 - Qiita

※参考:【自分備忘録】gulp4まとめ(ざっくり) - Qiita

※参考:【gulp4】もう迷わないgulpfile.jsの書き方|Kohei|note

EJSコンパイル

修正前

// EJSコンパイル
gulp.task('ejs',  (done) => {
    const data = JSON.parse(fs.readFileSync('./src/json/data.json'));
    gulp.src(["./src/ejs/**/*.ejs", "!./src/ejs/**/_*.ejs"])
      .pipe(plumber())
      .pipe(ejs(data))
      .pipe(ejs({}, {}, { ext: ".html" }))
      .pipe(rename({ extname: ".html" }))
      .pipe(replace(/^[ \t]*\n/gmi, ""))
      .pipe(gulp.dest("./dest/"));
    done();
});

修正後

// EJSコンパイル
const compileEjs = (done) => {
    const data = JSON.parse(fs.readFileSync(srcDataJson));
    gulp.src([srcEjsFiles, srcEjsPartial])
      .pipe(plumber())
      .pipe(ejs(data))
      .pipe(ejs({}, {}, { ext: '.html' }))
      .pipe(rename({ extname: '.html' }))
      .pipe(replace(/^[ \t]*\n/gmi, ''))
      .pipe(gulp.dest(destDir));
    done();
};
  • gulp.task()を変数compileEjsに変更(中身はアロー関数)
  • パスの部分を先ほどの変数に置き換え

基本的にはこの形式で修正している。関数名は冒頭に設定しているインポート系の変数名とかぶらないよう変えている。

関数化はもう一つgulp.src()の前にreturnを入れる方法もある。こちらはコールバックのdone()は不要。

const 関数名 = () => {
    return gulp.src(パス)
      .pipe(処理);
      .pipe(処理);
      .pipe(処理…);
};

しかしこの形では動かない処理もあったため、今回はより汎用的なdone()を使う形で統一した。

Sass(SCSS)コンパイル

Sass(SCSS)ファイルをコンパイルしてCSSファイルにする部分。

修正前

// sassコンパイル
gulp.task('sass', (done) => {
    gulp.src('./src/scss/**/*.scss')
        .pipe(sass({
                    outputStyle: 'expanded'
                })
            )
        .on("error", sass.logError)
        .pipe(gulp.dest('./dest/css'));
    done();
});

修正後

// sassコンパイル
const compileSass = (done) => {
    gulp.src(srcScssFiles)
        .pipe(sass({
                    outputStyle: 'expanded'
                })
            )
        .on('error', sass.logError)
        .pipe(gulp.dest(destCssDir));
    done();
};

webpackのバンドル

TypeScriptのファイルをWebpackでバンドルしJSファイルにする部分。

修正前

// webpackのバンドル実行
gulp.task("webpack", (done) => {
    webpackStream(webpackConfig, webpack)
      .pipe(gulp.dest("./dest/js"));
    done();
});

修正後

// webpackのバンドル実行
const bundleWebpack = (done) => {
    webpackStream(webpackConfig, webpack)
      .pipe(gulp.dest(destJsDir));
    done();
};

リロードするhtml

browserSyncでリロードするHTMLファイル(index.html)を指定

修正前

// リロードするhtml
gulp.task('browser-sync', (done) => {
    browserSync.init({
        server : {
            baseDir : './dest/',
            index : 'index.html',
        },
    });
    done();
});

修正後

// リロードするhtml
const reloadFile = (done) => {
    browserSync.init({
        server : {
            baseDir : destDir,
            index : destIndexHtml,
        },
    });
    done();
};

リロード設定

browserSyncでリロードを行う設定

修正前

// リロード設定
gulp.task('browser-reload', (done) => {
    browserSync.reload();
    done();
});

修正後

// リロード設定
const reloadBrowser = (done) => {
    browserSync.reload();
    done();
};

画像圧縮

前回追加した画像を圧縮する設定

修正前

// 画像圧縮
gulp.task('imagemin', (done) => {
    gulp.src('./src/img/**/*.{jpg,jpeg,png,gif,svg}')
    .pipe(imagemin(
      [
        pngquant({ quality: '65-80', speed: 1 }),
        mozjpeg({ quality: 80 }),
        imagemin.svgo(),
        imagemin.gifsicle()
      ]
    ))
    .pipe(gulp.dest('./dest/img'));
    done();
});

修正後

// 画像圧縮
const minifyImage = (done) => {
    gulp.src(srcImgFiles + srcImgFileType)
    .pipe(imagemin(
      [
        pngquant({ quality: '65-80', speed: 1 }),
        mozjpeg({ quality: 80 }),
        imagemin.svgo(),
        imagemin.gifsicle()
      ]
    ))
    .pipe(gulp.dest(destImtDir));
    done();
};

関数をタスク化

こちらは今回初めて書く処理。これまでの関数をタスク化する設定。

// タスク化
exports.compileEjs = compileEjs;
exports.compileSass = compileSass;
exports.bundleWebpack = bundleWebpack;
exports.reloadFile = reloadFile;
exports.reloadBrowser = reloadBrowser;
exports.minifyImage = minifyImage;
  • exports.タスク名 = 関数名という形式で関数をタスク化する

監視ファイル

gulp.watch()で監視するファイルを指定する部分

修正前

// 監視ファイル
gulp.task('watch-files', (done) =>  {
    gulp.watch(["./src/ejs/**/*.ejs", "./src/json/**/*.json"], gulp.task('ejs'));
    gulp.watch("./dest/*.html", gulp.task('browser-reload'));
    gulp.watch("./src/scss/**/*.scss", gulp.task('sass'));
    gulp.watch("./dest/css/*.css", gulp.task('browser-reload'));
    gulp.watch(["./src/ts/**/*.ts", "./src/json/**/*.json"], gulp.task('webpack'));
    gulp.watch("./dest/js/*.js", gulp.task('browser-reload'));
    gulp.watch("./src/img/**/*", gulp.task('imagemin'));
    gulp.watch("./dest/img/*", gulp.task('browser-reload'));
    done();
});

修正後

// 監視ファイル
const watchFiles = (done) => {
    gulp.watch([srcEjsFiles, srcJsonFiles], compileEjs);
    gulp.watch(destHtmlFiles, reloadBrowser);
    gulp.watch(srcScssFiles, compileSass);
    gulp.watch(destCssFiles, reloadBrowser);
    gulp.watch([srcTsFiles, srcJsonFiles], bundleWebpack);
    gulp.watch(destJSFiles, reloadBrowser);
    gulp.watch(srcImgFiles, minifyImage);
    gulp.watch(destImgFiles, reloadBrowser);
    done();
};
  • gulp.task()を関数化する部分はこれまでと同じ
  • gulp.watch()の第二引数がタスク名(関数名)だけでよくなる

タスク実行

最後のタスク実行はこれまでの関数化と形がちょっと違う。

修正前

// タスク実行
gulp.task('default', 
    gulp.series(gulp.parallel(
        'watch-files', 'browser-sync', 'ejs', 'sass', 'webpack', 'imagemin'
    ), (done) => {
    done();
}));

修正後

// タスク実行
exports.default = gulp.series(
    watchFiles, reloadFile, compileEjs, compileSass, bundleWebpack, minifyImage
);
  • exports.defaultを定義する
  • gulp.series()の中身はタスク名(関数名)だけでいい

なお、gulp.series()の中身は関数名だけにしたが、並列処理にしたい場合はgulp.parallel()に入れてもいい。

※参考:Gulp - v4 の series と parallel を使って直列・並列処理を制御する - 22時に寝ようと思って2時に寝る。

動作確認

gulpを起動してみる。

$ npm start

localhostの3000でブラウザが起動する! https://cdn-ak.f.st-hatena.com/images/fotolife/i/idr_zz/20201122/20201122161636.jpg メタ言語や画像に変更を加えるとコンパイルを実行し、修正が反映される。

修正内容(GitHub)

※参考:gulp.task()を関数化、他 · ryo-i/frontendMetaLanguage@f20f5f8 · GitHub

プレビュー画面(GitHab Pages)

※参考:メタ言語同時コンパイル(EJS、Sass(SCSS)、TypeScript)

最後に

ということで、gulp.task()の関数化をはじめ、いろいろリファクリングしました。細かいところですが、クオーテーションもシングル' 'とダブル" "が混在していたので、シングルクオーテーションで統一しました。だいぶコードの処理内容が見やすくなったと思います!

次は、この内容をベースに新しいリポジトリにクローンして、メタ言語のフロントエンド開発環境のスタートキットみたいのを作りたく思います。(ここ最近ずっとやりたかったこと、ようやく!w)

それではまた!


※参考:【メタ言語】HTMLテンプレートエンジン、AltCSS、AltJSのまとめ
qiita.com