Corredor

ウェブ、プログラミングの勉強メモ。

Gulp-Description で Gulp タスクの説明書きを追加する

何やら Gulp v4 系では gulp.task().description(); という書き方ができるようになるらしいが、現行の v3.9.1 では対応しないようなので、Gulp-Description というツールを使うのが良さそうだ。

実際のコードはコチラ

今回紹介したパッケージとサンプルコードを利用し、AngularJS + Cordova なアプリで Appium を使った E2E テストを行うサンプルプロジェクトを作成した。以下を参考にしてほしい。

gulpfile.js はコチラ。

Gulp-Description の使い方

Gulp-Description は以下のようにインストールする。

# Gulp と Gulp-Load-Plugins のインストール

# Gulp-Description のインストール
$ npm i -D gulp-description

今回はデフォルトタスク、つまり $ gulp とだけ打って叩いた時に説明が出るようにしてみる。

gulp.task('default', () => {
  // Gulp-Load-Plugins 経由で gulp-description を使用
  $.description.help({
    main: ['appium', 'build', 'dev', 'e2e', 'emu'],
    description: {
      appium: 'Appium サーバを起動する (e2e タスクの前に実行しておくこと)',
      build : 'src ディレクトリのファイルをビルドし www ディレクトリに出力する',
      dev   : '開発用ライブリロードを開始する',
      e2e   : 'Protractor による E2E テストを実行する (事前に appium タスクを実行しておくこと)',
      emu   : 'ビルド後 iPhone7 シミュレータを起動する'
    }
  });
});

main 部分に表示させたいタスク名を列挙し、description 部分に連想配列の要領でタスク名と説明書きを記載する。gulpfile.js 内に存在しないタスクについての説明書きを書いても画面上には表示されない。

これで $ gulp と叩けばタスク説明が表示されるようになったが、Gulp をグローバルインストールしていない場合のことも考え、$ npm run info と打った時に表示されるようにしてみる。package.json にタスクを追加する。

"scripts": {
  "info": "gulp default",
  (以下略)

これで、以下のようにタスク説明が見られるようになった。

$ npm run info

> my-project@1.0.0 info /Users/Neo/MyProject
> gulp default

[15:16:14] Using gulpfile ~/MyProject/gulpfile.js
[15:16:14] Starting 'default'...
 === Main Task === 
appium                  Appium サーバを起動する (e2e タスクの前に実行しておくこと)
build                   src ディレクトリのファイルをビルドし www ディレクトリに出力する
dev                     開発用ライブリロードを開始する
e2e                     Protractor による E2E テストを実行する (事前に appium タスクを実行しておくこと)
emu                     ビルド後 iPhone7 シミュレータを起動する
[15:16:14] Finished 'default' after 4.17 ms

もちろん、デフォルトタスク以外で作っても問題ない。

上述のスクリプトでは gulp-description.help() ($.description.help()) というメソッドを使用したが、他にも all()dependency() といったメソッドもある。詳しくは公式の説明を参考にされたし。


本当は $ npm run とだけ打った時のタスク一覧に Description を追加したいんだけどな〜。そういう機能はなさそう (better-npm-run なら description が書けるけどちょっと違う気が)。

類似のツールに Gulp-Help というツールもあるので、コチラもドウゾ。

フロントエンドエンジニア養成読本 [HTML、CSS、JavaScriptの基本から現場で役立つ技術まで満載! ] (Software Design plus)

フロントエンドエンジニア養成読本 [HTML、CSS、JavaScriptの基本から現場で役立つ技術まで満載! ] (Software Design plus)

  • 作者: 斉藤祐也,石本光司,加藤賢一,水野隼登,谷拓樹,泉水翔吾,原一成,平木聡,佐藤歩,杉本吉章
  • 出版社/メーカー: 技術評論社
  • 発売日: 2014/07/02
  • メディア: 大型本
  • この商品を含むブログ (1件) を見る

cordova-plugin-browsersync で Live-Reload 開発を行う

Cordova アプリを作っていて、Live-Reload 開発を行いたいと思ったことはないだろうか。cordova-plugin-browsersync を使うと、Browser プラットフォーム限定なようだが、ライブリロード開発が可能になる。

プラグインのインストール

まずはプラグインをインストールする。

$ cordova plugin add cordova-plugin-browsersync

# Browser プラットフォームを入れていなければ追加する
$ cordova platform add browser

やることはコレだけ。後は cordova run の際にライブリロードを行うオプションを指定すれば良い。

$ cordova run browser --live-reload

これで任意のブラウザに cordova-plugin-browsersync の画面が開く。環境によっては何やらエラーっぽい見た目になっている場合もあるが、http://localhost:3000/ のトップに遷移すればちゃんとアプリが起動している。

./www/ ディレクトリ配下のファイルを操作すると Live-Reload が行われるので、./www/ ディレクトリ配下にソースファイルを置いている人はそのまま開発を進めていけば、保存する度に画面にも変更が反映される。

./www/ ディレクトリにはビルドしたファイルを格納するようにしている場合は、別途 Gulp スクリプトなどで ./src/ ディレクトリに対して Watch を仕掛け、./src/ ディレクトリ配下のファイルが変更されたらビルドを行い ./www/ ディレクトリに出力するようにしておく。こうすれば、./www/ の変化を cordova-plugin-browsersync が検知し、きちんとライブリロードされる。

HTML5でモバイルアプリ開発入門―モバイルアプリをプロデュース (SCC Books 359)

HTML5でモバイルアプリ開発入門―モバイルアプリをプロデュース (SCC Books 359)

Wiredep・Gulp-Inject・Gulp-Useref で HTML ファイルからの CSS・JS 読み込みを自動化

Webフロントエンド ハイパフォーマンス チューニング

Webフロントエンド ハイパフォーマンス チューニング

HTML ファイルから必要な Bower コンポーネントや自分で作ってビルドしたファイル群を読み込ませたり、そのファイル構成を変更したりするのが中々だるい。

そこで、HTML に書く style 要素・script 要素を整理してくれる Gulp 関連ツールとして、Wiredep・Gulp-Inject・Gulp-Useref の3つを紹介する。

実際のコードはコチラ

今回紹介したパッケージとサンプルコードを利用し、AngularJS + Cordova なアプリで Appium を使った E2E テストを行うサンプルプロジェクトを作成した。以下を参考にしてほしい。

gulpfile.js はコチラ。

まずは3つのツールをインストールしておく

説明の前に、3つのツールと、Gulp のインストールをしておく。

# Gulp-Load-Plugins は require() の手間を省くため導入
$ npm i -D gulp gulp-load-plugins
$ npm i -D wiredep gulp-inject gulp-useref

あとは package.jsonscripts に、"gulp": "gulp" というタスクを追加しておけば、$ npm run gulp でローカルインストールした Gulp が使えるようになる。

Wiredep とは

Wiredep は、Wiredep を使うプロジェクトの bower.jsondependencies に記載されている Bower Components から main ファイルを取得し、そのファイルを読み込むタグを HTML 中に書き込んでくれるツール。

HTML 側の設定

HTML 中の、Wiredep に link 要素を注入して欲しい場所には

<!-- bower:css -->
<!-- endbower -->

というコメントを入れておき、script 要素を注入して欲しい場所には

<!-- bower:js -->
<!-- endbower -->

と書くだけだ。Wiredep によって、このコメント部分に link 要素や script 要素が挿入される。

main ファイルの定義が足りない場合は

Bower Components によっては、その Bower コンポーネントの bower.json に記載の main ファイルだけでは必要なファイルが読み込めない場合がある。その場合は別途、自プロジェクトの bower.jsonoverrides として読み込むべきファイルを定義し直してやると良い。

例えば Angular UI Bootstrap の bower.json は以下のようになっているが、これでは CSS ファイルが足りない。

// ./bower_components/angular-bootstrap/bower.json
"main": ["./ui-bootstrap-tpls.js"],

そこで、自身の bower.json に以下のようにして CSS ファイルも読み込むよう、main を書き換える設定を入れてやる。

// ./bower.json
"overrides": {
  "angular-bootstrap": {
    "main": [
      "./ui-bootstrap-csp.css",
      "./ui-bootstrap-tpls.js"
    ]
  }
}

Gulp での処理方法とその結果

Gulp スクリプトにおいては、以下のようにしてやる。

const gulp = require('gulp');

gulp.task('html-inject', () => {
  // Wiredep のストリームを取得する
  const wiredep = require('wiredep').stream;
  return gulp
    .src('./src/index.html')    // 元とする ./src/index.html を得る
    .pipe(wiredep())            // Wiredep にコメント部分を処理させる
    .pipe(gulp.dest('./www'));  // ./www/ 配下に加工した index.html を出力する
});

コレだけ。

こうして Wiredep に処理された HTML (./www/index.html) は、以下のようになっている。

<!-- bower:css -->
<link rel="stylesheet" href="../bower_components/angular-bootstrap/ui-bootstrap-csp.css" />
<!-- endbower -->

<!-- bower:js -->
<script src="../bower_components/angular/angular.js"></script>
<script src="../bower_components/angular-bootstrap/ui-bootstrap-tpls.js"></script>
<script src="../bower_components/angular-route/angular-route.js"></script>
<!-- endbower -->

つまり、出力先ディレクトリから見た相対パスで bower_components ディレクトリ配下へのリンクを作っているだけだ。

これだけでは必要なファイルをビルド対象のディレクトリ (この場合 ./www/ 配下) に取り込めておらず、使い勝手が悪いので、あとで Gulp-Useref を使って調整する。

その前に Gulp-Inject の説明をする。

Gulp-Inject とは

Gulp-Inject というツールも、Wiredep とよく似ている。コチラは Bower Components に限らず、指定したファイルを読み込むための link 要素や script 要素を HTML 中に挿入してくれるというモノだ。

HTML 側の設定

HTML 側での書き方は Wiredep と同じくコメントで記載する。link 要素を出力したい場所には

<!-- inject:css -->
<!-- endinject -->

と記載し、script 要素を出力したい場所には

<!-- inject:js -->
<!-- endinject -->

と記載する。

Gulp での処理方法とその結果

今回はこのコメント部分に、別タスクで予めビルドしておいた CSS ファイルと JS ファイルを読み込むための設定をしてみる。

const gulp = require('gulp');
// Gulp-Load-Plugins を使って Gulp-Inject を $.inject() で使えるようにする
const $ = require('gulp-load-plugins')();

gulp.task('html-inject', () => {
  return gulp
    .src('./src/index.html')    // 元とする ./src/index.html を得る
    .pipe($.inject(             // Gulp-Inject を使用する
      gulp.src([
        './www/css/index.css',  // link 要素で出力したい CSS ファイルを指定
        './www/js/index.js'     // script 要素で出力したい JS ファイルを指定
      ]),
      { relative: true }        // 相対パス指定
    ))
    .pipe(gulp.dest('./www'));  // ./www/ 配下に加工した index.html を出力する
});

このように、挿入したい CSS・JS ファイルを配列で指定するだけ。

こうして生成された ./www/index.html 配下のようになっている。

<!-- inject:css -->
<link rel="stylesheet" href="../www/css/index.css">
<!-- endinject -->

<!-- inject:js -->
<script src="../www/js/index.js"></script>
<!-- endinject -->

確かに指定した ./www/css/index.css./www/js/index.js がリンクされている。しかし、なぜか相対パスの指定が ../www/ と冗長的な書き方になってしまっている。特段問題はないと思うが気持ち悪いので、これもこの後紹介する Gulp-Useref で修正する。

Wiredep と Gulp-Inject を同時に指定する

さて、今回は Wiredep と Gulp-Inject を使って、同じ ./src/index.html ファイルを編集したいので、1つのタスクにまとめてやる。難しいことはなく、IN と OUT (src()dest()) は同じなので、.pipe() を増やしてやるだけで良い。

const gulp = require('gulp');
const $ = require('gulp-load-plugins')();

gulp.task('html-inject', () => {
  const wiredep = require('wiredep').stream;
  return gulp
    .src('./src/index.html')    // IN
    .pipe(wiredep())            // Wiredep
    .pipe($.inject(             // Gulp-Inject
      gulp.src([
        './www/css/index.css',
        './www/js/index.js'
      ]),
      { relative: true }
    ))
    .pipe(gulp.dest('./www'));  // OUT
});

Gulp-Useref とは

Gulp-Useref は、HTML コメントで囲んだ範囲内の link 要素・script 要素のファイル群を1ファイルに結合して出力し、その1ファイルのみにリンクする link 要素・script 要素に HTML を書き換えてくれるものだ。

HTML 側の設定

実例で紹介しよう。まずは以下が ./src/index.html の加工前の状態だ (「▼」部分は説明書きで実際は記載していない)。入れ子の関係を分かりやすくするためインデントを付けているが、必須ではない。

<!-- build:css css/vendor.css -->
  ▼ Wiredep で Bower から CSS ファイルを注入する場所
  <!-- bower:css -->
  <!-- endbower -->
<!-- endbuild -->
    
<!-- build:css css/index.css -->
  ▼ Gulp-Inject で指定した CSS ファイルを注入する場所
  <!-- inject:css -->
  <!-- endinject -->
<!-- endbuild -->

<!-- build:js js/vendor.js -->
  ▼ Wiredep で Bower から JS ファイルを注入する場所
  <!-- bower:js -->
  <!-- endbower -->
<!-- endbuild -->

<!-- build:js js/index.js -->
  ▼ Gulp-Inject で指定した JS ファイルを注入する場所
  <!-- inject:js -->
  <!-- endinject -->
<!-- endbuild -->

ココに登場している、build:css とか build:js といったコメントが、Gulp-Useref が使うコメントだ。一番最初のコメントを例に取ると、

<!-- build:css css/vendor.css -->
<!-- endbuild -->

これで1セットだ。このコメントの範囲内にある CSS ファイル (link 要素) のみを抽出し、css/vendor.css という1つのファイルに結合する。ファイルを結合したら、css/vendor.css への link 要素のみをこのコメント部分に配置する、というワケだ。パスはその HTML ファイルから見ての相対パスになる。

Wiredep と Gulp-Inject を先に実行する

まずは先程紹介した、Wiredep + Gulp-Inject による注入タスクを実行し、./www/index.html を出力する。以下のようになっているはずだ。

<!-- build:css css/vendor.css -->
  <!-- Wiredep -->
  <!-- bower:css -->
  <link rel="stylesheet" href="../bower_components/angular-bootstrap/ui-bootstrap-csp.css" />
  <!-- endbower -->
<!-- endbuild -->

<!-- build:css css/index.css -->
  <!-- inject:css -->
  <link rel="stylesheet" href="../www/css/index.css">
  <!-- endinject -->
<!-- endbuild -->

<!-- build:js js/vendor.js -->
  <!-- bower:js -->
  <script src="../bower_components/angular/angular.js"></script>
  <script src="../bower_components/angular-bootstrap/ui-bootstrap-tpls.js"></script>
  <script src="../bower_components/angular-route/angular-route.js"></script>
  <!-- endbower -->
<!-- endbuild -->

<!-- build:js js/index.js -->
  <!-- inject:js -->
  <script src="../www/js/index.js"></script>
  <!-- endinject -->
<!-- endbuild -->

Wiredep と Gulp-Inject によって link 要素・script 要素が挿入されている。

Gulp-Useref による処理とその結果

次に、この ./www/index.html に対して Gulp-Useref を適用するタスクを作成する。

const gulp = require('gulp');
const $ = require('gulp-load-plugins')();

// ./www/index.html を生成する「html-inject」タスクを事前実行するタスクとして依存指定しておく
gulp.task('html-useref', ['html-inject'], () => {
  return gulp
    .src('./www/index.html')    // 前タスクで生成した ./www/index.html を取得する
    .pipe($.useref())           // Gulp-Useref を適用する
    .pipe(gulp.dest('./www'));  // ./www/ 配下に index.html を再度出力する
});

つまり、Wiredep と Gulp-Inject を行ったファイルを再度取得して Gulp-Useref を適用しているのだ。HTML ファイルの位置は ./www/ 配下になるので、ココからの相対パスだと <!-- build:css css/vendor.css --> という指定では ./www/css/vendor.css が生成される、という寸法になる。

これで ./www/index.html は以下のような記載になる。

<link rel="stylesheet" href="css/vendor.css">

<link rel="stylesheet" href="css/index.css">

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

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

Wiredep によって複数の link 要素・script 要素が列挙されていた部分は、./www/css/vendor.css./www/js/vendor.js という1つずつのファイルにまとめられた。

おまけに冗長的なパス指定になっていた index.cssindex.js があった link 要素・script 要素にも Gulp-Useref を噛ませることによって、パス指定を整形することができた。指定しているファイルが最初から1つずつしかないので、実質的にファイルの結合は発生していない。

コメントも消えて良い感じだ。

ファイルの結合と生成、そして HTML ファイル内の link 要素・script 要素の書き換えまでを一気にやってくれるのが Gulp-Useref なのだ。