blog

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

    • Ryuichi Nonaka
    この記事は書かれてから1年以上経過しており、内容が古い場合があります。

    はじめに

    この記事はGulp.js(全俺) Advent Calendar 2014です。

    前回のこれからはじめる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が行えます。BrowserSyncの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を試してみたいと思います。

    シリーズ

    1. これからはじめるGulp(0):アドベントカレンダースケジュール
    2. これからはじめるGulp(1):bundler, rbenv, nodebrewでGulp環境を作ってみる
    3. これからはじめるGulp(2):gulp-sassを使ってSCSSをコンパイルするタスクを作ってみる
    4. これからはじめるGulp(3):gulp.watchでファイルの変更を監視しタスクを実行する
    5. これからはじめるGulp(4):gulp-connectモジュールを使ったローカルサーバの起動
    6. これからはじめるGulp(5):gulp-connectモジュールを使ったLiveReload
    7. これからはじめるGulp(6):gulp-plumberとgulp-notifyを使ったデスクトップ通知
    8. これからはじめるGulp(7):require-dirモジュールを使ったタスク単位のファイル分割
    9. これからはじめるGulp(8):delモジュールとvinyl-pathsモジュールを使ったファイルの削除
    10. これからはじめるGulp(9):Ruby版Sassが使えるgulp-ruby-sassへの乗り換え
    11. これからはじめるGulp(10):deprecatedになっていたgulp-connectからgulp-webserverへ乗り換える
    12. これからはじめるGulp(11):ブラウザ間でスクロールやクリック操作を同期できるBrowserSync
    13. これからはじめるGulp(12):gulp-imageminプラグインを使ったJPEG,PNG,GIF,SVGの最適化
    14. これからはじめるGulp(13):gulp-changedプラグインで変更されたファイルだけを処理させる
    15. これからはじめるGulp(14):gulp-cachedプラグインで変更されたSCSSファイルだけを処理させる
    16. これからはじめるGulp(15):gulp-responsiveプラグインを使ったレスポンシブイメージ作成の自動化
    17. これからはじめるGulp(16):gulp-image-resizeプラグインを使ってサムネイルやレスポンシブイメージを作る
    18. これからはじめるGulp(17):SketchTool(Sketch 3 command line tool)を使ったアートボード・スライスの書き出しとgulp-execプラグインを使ったSketchtoolの呼び出し
    19. これからはじめるGulp(18):SketchToolで何ができるのかコマンドと主要なオプションを使ってみる
    20. これからはじめるGulp(19):gulp-sketchとgulp-execを使ったSketch 3デザインデータの画像書き出し
    21. これからはじめるGulp(20):Node.jsのChild Processモジュールを使ってgulpからjekyllのbuildコマンドを実行する
    22. これからはじめるGulp(21):gulp-awspublishプラグインを使ったAmazon S3への静的Webサイトパブリッシュ
    23. これからはじめるGulp(22):gulp-iconfontとgulp-sketchを使ったアイコンフォント作成の自動化
    24. これからはじめるGulp(23):gulp-consolidateでgulp-iconfontで作ったアイコンフォントのシンボル一覧HTMLを作る
    25. これからはじめるGulp(24):gulp.spritesmithプラグインでSpriteイメージを作る
    26. これからはじめるGulp(25):Hologramとgulp-hologramでスタイルガイドを作る
    27. これからはじめるGulp(26):Sketch3のサブディレクトリ書き出しに対応したgulp-sketchを試す

    コメント・フィードバック