これからはじめるGulp #11:ブラウザ間でスクロールやクリック操作を同期できるBrowserSync

2014.12.11

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

前回のこれからはじめるGulp(10):deprecatedになっていたgulp-connectからgulp-webserverへ乗り換えるでgulp-webserverへの乗り換えを試しました。今回はブラウザ間のスクロールやクリックも同期できるBrowserSyncを試してみます。

Browser-Syncについて

BrowserSyncはレシポンシブなWebサイトを開発する際、表示や動作に関するテストを効率化できるツールです。複数のデバイス・ブラウザ間でリロード、スクロール、クリックなどを同期することができます。BrowserSyncはGrunt/Gulpまたはコマンドラインから使うことができます。

BrowserSyncのインストール

最早説明するまでもないですがBrowserSyncをインストールします。なにやらエラー> (node-gyp rebuild 2> builderror.log) || (exit 0)のようなものが出ていますがとりあえず無視。

$ npm install browser-sync --save-dev

> ws@0.5.0 install /Users/nukos/Projects/gulp.whiskers.nukos.kitchen/node_modules/browser-sync/node_modules/socket.io/node_modules/engine.io/node_modules/ws
> (node-gyp rebuild 2> builderror.log) || (exit 0)

  CXX(target) Release/obj.target/bufferutil/src/bufferutil.o
  SOLINK_MODULE(target) Release/bufferutil.node
  SOLINK_MODULE(target) Release/bufferutil.node: Finished
  CXX(target) Release/obj.target/validation/src/validation.o
  SOLINK_MODULE(target) Release/validation.node
  SOLINK_MODULE(target) Release/validation.node: Finished

> ws@0.4.31 install /Users/nukos/Projects/gulp.whiskers.nukos.kitchen/node_modules/browser-sync/node_modules/socket.io/node_modules/socket.io-client/node_modules/engine.io-client/node_modules/ws
> (node-gyp rebuild 2> builderror.log) || (exit 0)

  CXX(target) Release/obj.target/bufferutil/src/bufferutil.o
  SOLINK_MODULE(target) Release/bufferutil.node
  SOLINK_MODULE(target) Release/bufferutil.node: Finished
  CXX(target) Release/obj.target/validation/src/validation.o
  SOLINK_MODULE(target) Release/validation.node
  SOLINK_MODULE(target) Release/validation.node: Finished
browser-sync@1.7.2 node_modules/browser-sync
├── emitter-steward@0.0.1
├── opt-merger@1.1.0
├── easy-extender@2.1.0
├── opn@1.0.0
├── commander@2.5.0
├── object-path@0.8.1
├── eazy-logger@2.0.0 (opt-merger@0.2.1)
├── minimist@1.1.0
├── ua-parser-js@0.7.3
├── browser-sync-client@0.5.2
├── foxy@6.0.0 (http-proxy@1.7.3)
├── resp-modifier@1.0.0 (minimatch@1.0.0)
├── connect@3.3.3 (utils-merge@1.0.0, parseurl@1.3.0, debug@2.1.0, finalhandler@0.3.2)
├── tfunk@3.0.0 (object-path@0.6.0, chalk@0.5.1)
├── portscanner-plus@0.1.0 (q@1.0.1, portscanner@0.2.3)
├── serve-static@1.7.1 (utils-merge@1.0.0, escape-html@1.0.1, parseurl@1.3.0, send@0.10.1)
├── serve-index@1.5.2 (parseurl@1.3.0, batch@0.5.1, http-errors@1.2.7, debug@2.1.0, accepts@1.1.3, mime-types@2.0.3)
├── lodash@2.4.1
├── dev-ip@0.1.7 (lodash@2.2.1)
├── glob-watcher@0.0.7 (gaze@0.5.1)
├── localtunnel@1.5.0 (debug@0.7.4, optimist@0.3.4, request@2.11.4)
└── socket.io@1.2.1 (debug@0.7.4, has-binary-data@0.1.3, socket.io-adapter@0.3.1, socket.io-parser@2.2.2, engine.io@1.4.3, socket.io-client@1.2.1)

browserSyncタスクの作成

公式のドキュメントを参考にServerタスクを作ります。

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

BrowserSyncタスクを作ります。

var paths = {
  srcDir : 'src',
  prvDir : 'prv',
  dstDir : 'prd'
}

gulp.task('browser-sync', function() {
  browserSync({
    server: {
      baseDir: paths.prvDir
    }
  });
});

あとはデフォルトタスクで実行されるようにします。

gulp.task('default', ['watch', 'browser-sync']);

参考としてこんな感じのgulpfile.jsファイルになります。

var gulp      = require('gulp');
var path      = require('path');

var requireDir = require('require-dir');
var dir        = requireDir('./_tasks', {recurse: true});

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

var paths = {
  srcDir : 'src',
  prvDir : 'prv',
  dstDir : 'prd'
}

gulp.task('browser-sync', function() {
  browserSync({
    server: {
      baseDir: paths.prvDir
    }
  });
});

gulp.task('watch', ['sass:prv', 'html:prv'], function(){
  var scssWatchGlob = paths.srcDir + '/assets/_scss/*.scss';
  var htmlWatchGlob = paths.srcDir + '/*.html';

  var watcher = gulp.watch( scssWatchGlob, ['sass:prv']);
  watcher.on('change', function(event) {
    console.log('File ' + event.path + ' was ' + event.type + ', running tasks...');
  });

  gulp.watch( htmlWatchGlob, ['html:prv']);
});

gulp.task('default', ['watch', 'browser-sync']);

BrowserSyncを試す

とりあえず$ gulpを実行してみます。
勝手にブラウザが立ち上がりhttp://localhost:3000/を開くはずです。タブか別ブラウザでもう一つhttp://localhost:3000/を開きます。この状態でスクロールしてみるとどちらの画面も同じようにスクロールすればSync成功です。

BrowserSyncでLiveReload

BrowserSyncのLiveReloadはブラウザ側に拡張機能がなくても動作します。LiveReloadはディレクトリ配下を監視するわけではないので、gulp-connectと同じ手法でパイプラインの最後でリロード用のメソッド.pipe(browserSync.reload({stream:true}));を呼びます。SassタスクでLiveReloadを有効にした場合このようになります。

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

…

gulp.task('sass:prv', function(){
  var srcGlob = paths.srcDir + '/assets/_scss/**/*.scss';
  var dstGlob = paths.prvDir + '/assets/css';
  var errorMessage = "Error: <%= error.message %>";
  var sassOptions = {
    bundleExec : true,
    style      : 'nested',
    require    : ['bourbon', 'neat'],
    loadPath   : ['vendor/bundle/ruby/2.1.0/gems/bitters-0.10.1/app/assets/stylesheets']
  }

  gulp.src( srcGlob )
    .pipe(plumber({
      errorHandler: notify.onError( errorMessage )
    }))
    .pipe(sass( sassOptions ))
    .pipe(gulp.dest( dstGlob ))
    .pipe(browserSync.reload({stream:true})); //<-
});

locationを同期する

location(開いているページ)の同期は初期設定では無効となっているためBrowserSyncのオプションを有効にします。有効にすることでリンクをクリックした時にページ遷移も同期できるようになります。

gulp.task('browser-sync', function() {
  browserSync({
    server: {
      baseDir: paths.prvDir
    },
    ghostMode: {
      location: true
    }
  });
});

これでWebサーバー、LiveReload、ブラウザ間の同期まで実現できました。レスポンシブなWebサイトを開発する際に便利そうです。明日以降は画像の軽量化やレスポンシブ用の画像生成についてするためにgulp-imagemin等を試してみたいと思います。

この記事はこれからはじめるGulp(11):ブラウザ間でスクロールやクリック操作を同期できるBrowserSyncの転載記事です。