クモのようにコツコツと

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

【gulp】browser-syncによる自動リロード(watch()の分離、defaultでSassと同時に実行)

gulpの続きです。前回watch()メソッドで自動コンパイルを体験しました。今回はもう一歩進んでブラウザも毎回リロードするのではなくファイルの修正→保存のたびにブラウザも自動リロードをしたく。「browser-sync」を使います。Sass(SCSS)コンパイルも同時に実行するため、 watch()やdefaultタスクを分離して書く必要がありました。それではいきましょう!

【目次】

※参考:【Gulp】watch()メソッドでSass(SCSS)を自動コンパイル - クモのようにコツコツと

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

browser-syncのインストール

ブラウザの自動リロードについて調べると「browser-sync」が一番使われているようだ。

※参考:Browsersync - Time-saving synchronised browser testing

これをインストールする。

ターミナルのcdコマンドで、前回作業したSass(SCSS)環境のフォルダ「gulp_sass」に移動する。

cd /(フォルダ)/gulp_sass

「browser-sync」をインストール。

npm i -D browser-sync

インストール成功するとpackage.jsonに「browser-sync」が追記される。

  "devDependencies": {
    "browser-sync": "^2.26.7",
    "gulp": "^4.0.2",
    "gulp-sass": "^4.0.2"
  }

今回やりたいこと

  • html、css、jsのファイルを修正、保存したらブラウザが自動リロード
  • Sass(SCSS)もコンパイルしたらブラウザを自動リロード

browser-syncのタスクさえ書けばこれが実現できるのかな、と思っていたが、実際に書いてみると最初の1回しか実行されなかった。。

それだけでなく、下記の処理も書く必要があった。

  • watch()メソッドでbrowser-syncもSass(SCSS)も監視する
  • そのため前回Sass(SCSS)のタスクの中に書いたwatch()メソッドを外に分離して、その中でbrowser-syncとSass(SCSS)を監視
  • タスク名が複数になるので、それら全てをgulpのみで実行できるようにdefault(タスク名が不要になる)の中で複数のタスクの実行を設定する

このやりたいことに一番近い内容を下記の記事が実現していて、とても参考になりました!

※参考:gulp4とbrowser-syncを使用したブラウザ自動更新機能作成 | Darablog

対象ファイルの変更

JSファイルを追加

今回、JSの修正による自動リロードもやってみたかったので、JSファイルを追加した。

JSコード

window.onload = () => {
    console.log("成功!");
}

ウィンドウがリロードされたらコンソールに「成功!」という文字を表示する。

上記のJSファイル(common.js)をHTMLにリンクして紐付ける

HTMLコード

<script src="js/common.js"></script>

別ページを追加

複数のHTMLファイルで自動リロードできるか検証したいのでページを追加した。

別ページ(other.html)を追加 HTMLコード

<!doctype html>
<html>
<head>
   <meta charset="UTF-8">
   <title>別ページ</title>
   <link rel="stylesheet" href="css/common.css">
   <link rel="stylesheet" href="css/other.css">
   <script src="js/common.js"></script>
</head>

<body>
    <section id="scss">
        <h1>別ページ</h1>
        <p class="lede"><a href="/">Topへ</a></p>
        </section>
    </section>
</body>
</html>

Topページ(index.html)にも別ページへのリンクを追加する。

 <p><a href="other.html">別ページへ</a></p>

browserSyncの設定

ここからはgulpの設定ファイルである「gulpfile.js」の修正になる。先程の記事を参考に進める。

※参考:gulp4とbrowser-syncを使用したブラウザ自動更新機能作成 | Darablog

browser-sync読み込み

最初にbrowser-syncを読み込む。

const browserSync = require('browser-sync'); 

変数browserSyncrequire()browser-syncを読み込む

browserSync.init()でリロードするhtmlファイルを設定

次にbrowserSync.init()でリロードするhtmlファイルを設定する。

// リロードするhtml
gulp.task('browser-sync', (done) => {
    browserSync.init({
        server : {
            baseDir : './',
            index : 'index.html',
        },
    });
    done();
});
  • gulp.task()の第一引数はタスク名でbrowser-sync
  • 第二引数は無名関数で、無名関数の引数はdone
    無名関数の一つ目の処理はbrowserSync.init()メソッドで引数は連想配列
    連想配列のキーはserverでその値も連想配列
    連想配列の一つ目のキーはbaseDirで値は./(フォルダのパス)
    二つ目のキーはindexで値はindex.html(Topページのファイル名) 二つ目の処理はdone()

ふむふむ。リロードを実現するためのサーバ設定だなこれは。フォルダのパスとトップページのファイル名を指定している。

コールバック関数done()

コールバック関数done()の実行は前回までのreturnとは別の書き方になる。

browser-syncではreturnを使っていないので、done()というコールバック関数を実行するようにしました(公式ではcb()となっています)。

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

これでbrowser-syncというタスクでリロードのためのサーバが起動する。

(ちなみに、gulp 4ではgulp.task()自体も非推奨のようだが。。今回はひとまずgulp.task()で書く)

「コールバック関数」とは引数として渡される関数のこと。

※参考:https://wa3.i-3-i.info/word12295.html

indexキーはTopページのファイル名に

ちなみにindexキーのファイル名をワイルドカード*.htmlにしてみたところ、ページの表示が「Cannot GET」というエラーになる。

f:id:idr_zz:20200408080343j:plain

indexキーはトップページの指定らしく固有のファイル名(index.html)がいいようだ。

(index.html以外のhtmlファイルが自動リロードされるか気になったので、先程のother.htmlを追加した)

browserSync.reload()でリロード設定

上記だけだとリロードは実現できず、もう一つbrowserSync.reload()というメソッドでリロード設定を書く

// リロード設定
gulp.task('browser-reload', (done) => {
    browserSync.reload();
    done();
});
  • gulp.task()の第一引数はタスク名でbrowser-reload
  • 第二引数は無名関数で、無名関数の引数はdone
    無名関数の最初の処理はbrowserSync.reload() 次の処理はdone()

これでbrowser-reloadというタスクでリロードが実行される。

watch()の分離

上記の設定だけだとファイルの修正のたびに自動リロードはされなかった。watch()メソッドで修正の対象ファイルを監視する必要があった。

Sass(SCSS)コンパイルのwatch()メソッドを分離

前回、Sass(SCSS)コンパイルのタスクの中にwatch()メソッドを組み入れたが、今回はSass(SCSS)コンパイルと自動リロード、二つのタスクに対してwatch()メソッドで監視したい。そのため、watch()メソッドをSass(SCSS)コンパイルや自動リロードの外側に書く必要があった。

前回のコード

gulp.task('sass',  () => {
    return gulp.watch("css/*.scss", () => {
        return gulp
        .src('css/*.scss')
        .pipe(sass({
                    outputStyle: 'expanded'
                })
            )
        .on("error", sass.logError)
        .pipe(gulp.dest('css'));
    });
});

詳細は前回の記事を参照
※参考:【Gulp】watch()メソッドでSass(SCSS)を自動コンパイル - クモのようにコツコツと

ここからwatch()メソッド部分を除外する。

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

また、returnではなくコールバック関数done()の書き方にしてみた。

除外したのはwatch()メソッドは下記の部分

return gulp.watch("css/*.scss", () => {
    // タスク処理
    });

watch()メソッドを設定

watch()メソッドは外部に別途まとめて書いた。

// 監視ファイル
gulp.task('watch-files', (done) =>  {
    gulp.watch("./*.html", gulp.task('browser-reload'));
    gulp.watch("./css/*.css", gulp.task('browser-reload'));
    gulp.watch("./css/*.scss", gulp.task('sass'));
    gulp.watch("./js/*.js", gulp.task('browser-reload'));
    done();
});
  • gulp.task()の第一引数はタスク名でwatch-files
  • 第二引数は無名関数で引数はdone、この中にwatch()の設定を書く
  • 1つ目のgulp.watch()、第一引数でhtmlファイル、第二引数はgulp.task()で引数はbrowser-reload
  • 2つ目のgulp.watch()、第一引数でcssファイル、第二引数はgulp.task()で引数はbrowser-reload
  • 3つ目のgulp.watch()、第一引数でscssファイル、第二引数はgulp.task()で引数はsass
  • 4つ目のgulp.watch()、第一引数でjsファイル、第二引数はgulp.task()で引数はbrowser-reload
  • 最後にコールバック関数done()を実行

scssファイルはsassタスクを実行するが、それ以外はbrowser-reloadタスクを実行する。ファイル名はワイルドカード*で汎用的にしている。

defaultタスクを設定

今回、watch-filesbrowser-syncsassと複数のタスクを設定した。

これまではnpx gulp sassなどのタスク名で実行していたが、defaultタスクを設定するとタスク名が不要でnpx gulpだけでgulpが動く。

この中に複数のタスクを紐付けて実行されるようにする。

複数タスク実行の書き方(Gulp3とGulp4の違い)

ここ、今回重要だったんだけど、複数のタスクの実行をしたいときこのようなエラーが起きた。

AssertionError [ERR_ASSERTION]: Task function must be specified

gulp 3までとgulp 4で書き方が変わっていいる部分があり、gulp 3までの書き方だとエラーになった!

※参考:Gulp環境構築にて「AssertionError [ERR_ASSERTION]: Task function must be specified」の原因はgulp v4にバージョンアップした事による仕様変更 - Qiita

glup 3とgulp 4の変更点。

※参考:gulp v4.0.0がプレリリース! 移行方法と変更点まとめ | satoyan419.com

この中で今回一番関係したのは、引数の指定方法(複数のタスクを引数に入れるため)

gulp 3までの書き方

gulp.task('default', ['タスク名', 'タスク名'], () => {
    // タスクの処理
});
  • gulp.task()の第一引数はdefault(タスク名が不要になる)
  • 第二引数は配列でこの中に実行したいタスク名を入れる
  • 第三引数は無名関数でその中にタスクの処理を書く

gulp 4からの書き方

gulp.task('default', gulp.series( gulp.parallel('タスク名'', 'タスク名''), () =>{
    // タスクの処理
}));
  • gulp.task()の第一引数はdefault(タスク名が不要になる)
  • 第二引数はgulp.series()メソッドでその引数にさらにgulp.parallel()メソッド。この引数の中に実行したいタスク名を入れる
  • 第三引数は無名関数でその中にタスクの処理を書く

配列ではなくgulp.series()とさらにその中に入れ子になったgulp.parallel()メソッドを書く。

gulp.series()gulp.parallel()の違いは

  • gulp.series:タスクを直列処理する
  • gulp.parallel:タスクを並列処理する

※参考:gulp v4.0.0がプレリリース! 移行方法と変更点まとめ | satoyan419.com

defaultタスクで複数のタスクを実行

上記のgulp4の書き方でdefaultタスクに複数のタスクを設定する。

// タスク実行
gulp.task('default', gulp.series( gulp.parallel('watch-files', 'browser-sync', 'sass'), (done) => {
    done();
}));
  • gulp.task()の第一引数はdefault(タスク名不要)
  • 第二引数はgulp.series()で、gulp.series()の第一引数はgulp.parallel()
    gulp.parallel()の引数にwatch-filesbrowser-syncsassを書く
    gulp.series()の第二引数は無名関数で、無名関数の引数はdone
    無名関数の中でdone()を実行

これでnpx gulpを実行するとリロードとSass(SCSS)コンパイルが常に実行される。

挙動確認

gulpを実行(ブラウザが開く)

上記のコードでやりたい挙動が実現できた!

まずターミナルでgulpを実行!

npx gulp

ブラウザでTOPページ(index.html)が立ち上がる! f:id:idr_zz:20200408071447j:plain

URLはローカルホストのポート番号3000

http://localhost:3000/

デベロッパーツール のコンソールを開くと「成功しました!」のテキストが。 f:id:idr_zz:20200408072705j:plain JSも動いている!

別ページに移動

一番したの「別ページへ」から別ページ(other.html)に移動

http://localhost:3000/other.html

よし!別ページも問題なく表示されている f:id:idr_zz:20200408071613j:plain

HTMLの修正(Topページ)

Topページ(index.html)に戻って f:id:idr_zz:20200408071703j:plain

h1タグを打ち替えてみる

<h1>SCSS事始め(with 自動リロード)</h1>

おお!h1のテキストが自動的に変わった! f:id:idr_zz:20200408071850j:plain

HTMLの修正(別ページ)

別ページ(other.html)も打ち替えてみよう。 f:id:idr_zz:20200408071613j:plain

pタグを追加

<p>別ページもリロードされるかテストですと。</p>

おお、pタグが追加された! f:id:idr_zz:20200408072137j:plain

Sass(SCSS)のコンパイル

sassファイルを修正してコンパイルが自動リロードで適用されるかテスト。

common.scssのh2の文字色orange

#oya {
  /*中略*/
  h2 {
    color: orange;
    font-size: 1.5em;
    line-height: 1.2;
    }

f:id:idr_zz:20200408071850j:plain

blueにしてみると…

#oya {
  /*中略*/
  h2 {
    color: blue;
    font-size: 1.5em;
    line-height: 1.2;
    }

おお!h2タグの見出しが青くなった! f:id:idr_zz:20200408072603j:plain

JSファイルの修正

最後にJSファイルの修正を試みる。

デベロッパーツール のコンソールは「成功しました!」だが… f:id:idr_zz:20200408072705j:plain

コンソールのテキストを「成功したでござる!」に変えてみると…

window.onload = () => {
    console.log("成功したでござる!");
}

おお!コンソールの文字が変わった! f:id:idr_zz:20200408073008j:plain

gulpfile.js全体

最後にgulpfile.js全体のコード

const gulp = require('gulp');
const sass = require('gulp-sass');
const browserSync = require('browser-sync'); 

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

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

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

// 監視ファイル
gulp.task('watch-files', (done) =>  {
    gulp.watch("./*.html", gulp.task('browser-reload'));
    gulp.watch("./css/*.css", gulp.task('browser-reload'));
    gulp.watch("./css/*.scss", gulp.task('sass'));
    gulp.watch("./js/*.js", gulp.task('browser-reload'));
    done();
});

// タスク実行
gulp.task('default', gulp.series( gulp.parallel('watch-files', 'browser-sync', 'sass'), (done) => {
    done();
}));
  • 変数browserSyncbrowser-syncを読み込む
  • sassタスクからwatch()の記述を除外
  • browser-syncタスクでリロードするhtmlファイルを設定
  • browser-reloadタスクでリロード設定
  • watch-filesタスクで監視対象のファイルと実行するタスクを設定
  • defaultタスクでgulpコマンドで実行するタスクを設定

最後に

ということで、自動リロードを体験できましたー。成功までは結構苦戦しました。gulp3とgulp4の書き方の違いなども知ることができました。

また、今回は自動リロードだけではなく、Sass(SCSS)コンパイルも同時に実行するためにwatch()メソッドを外側で設定する方法やdefaultタスクで複数のタスクを同時に実行する方法も知ることができました。

これまで単体で試してきたメタ言語(HTMLテンプレート、AltCSS、AltJS)を融合して、自動でコンパイル→リロード、をするための出発点になりそうです♪

それではまた!


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