- 目的
- 前提
- この記事で追加するパッケージ
- Task RunnerとしてGulpのビルドシステムをセットアップ
- fileのwatchとタスク完了のnotifyタスクを追加する
- Browsersyncを用いたLive Reloading [静的ファイル]
- エラー ENOSPC: System limit for number of file watchers reached
- Browsersyncをを用いたLive Reloading [動的ファイル]
目的
Docker上でPHP開発を行う際のブラウザ自動リロードをGulp+Browersyncで行う
前提
Ubuntu16.04
npm, nodeはインストール済み
この記事で追加するパッケージ
gulp-minify-css
: cssファイルのminifygulp-coffee
: coffeeのcompilegulp-sass
: sassのcompilegulp-notify
: 通知browser-sync
: ブラウザ自動リロードgulp-connect-php
: phpのビルドインサーバーを起動
Task RunnerとしてGulpのビルドシステムをセットアップ
Gulpをインストールし、minify cssタスクを実行してみる
参考:
1. install node
省略
確認
node -v
2. install npm
省略
確認
npm -v
3. テスト用のディレクトリ(プロジェクトディレクトリ)を作成しておく
Build └── index.html
- ちなみに、↑のために
tree
コマンドをインストール
4. install gulp
- Gulpはグローバルインストール
sudo npm install --global gulp
5. package.jsonを用意する
- プロジェクトディレクトリ(Build)直下に
package.json
を作成する - 今回は手動で作る(仕組みを理解するために
npm init
は使わない) - 以下の様に最初は空っぽでよい
{ }
- この時点での構成
Build ├── index.html └── package.json
6. プロジェクトディレクトリ(Build)でGulpをセットアップする
cd Build sudo npm install --save-dev gulp
- ちなみに
--save-dev is used to save the package for development purpose. Example: unit tests, minification..
--save is used to save the package required for the application to run.
- 空っぽだった
package.json
に依存関係が追記されている
{ "devDependencies": { "gulp": "^4.0.2" } }
- この時点での構成
❯ tree -L 1 Build Build ├── index.html ├── node_modules ├── package-lock.json └── package.json
7. Gulp Taskを作成する
- ここからがGulpのメイン
- 本題とは関係ないけど、
minify css
タスクを設定、実行してみる - まずは、プロジェクトディレクトリ(Build)直下に、
gulpfile.js
を作る。
In order to tell Gulp what tasks it should run, we need to create a special file that will contain/list those tasks -the file is named gulpfile.js.
- この時点での構成
❯ tree -L 1 Build Build ├── gulpfile.js ├── index.html ├── node_modules ├── package-lock.json └── package.json
gulp-minify-css
をインストールする。
sudo npm install --save-dev gulp-minify-css
- インストール後、
gulpfile.js
に以下のコードを追記。(今回は参考サイトのコードをそのまま流用)
var gulp = require('gulp'); var minifyCss = require('gulp-minify-css'); gulp.task('mincss', function(){ var fb = gulp.src('main.css'); fb.pipe(minifyCss()); fb.pipe(gulp.dest('main')); return fb; });
8. minify cssタスクを実行してみる
body{ margin:0; padding:0; background-color:teal; }
- この時点での構成
❯ tree -L 1 Build Build ├── gulpfile.js ├── index.html ├── main.css ├── node_modules ├── package-lock.json └── package.json
- 準備が整ったところで、プロジェクトディレクトリ(Build)をカレントにしてタスクを実行しみてる。
❯ gulp mincss zsh: correct 'gulp' to 'ul' [nyae]? n [19:53:56] Using gulpfile ~/Build/gulpfile.js [19:53:56] Starting 'mincss'... [19:53:56] Finished 'mincss' after 40 ms
❯ tree -L 1 Build Build ├── gulpfile.js ├── index.html ├── main ├── main.css ├── node_modules ├── package-lock.json └── package.json
- 確かに、minifyされたcssファイルが生成されている。これでひとまずGulpタスクを1つ設定、実行することができた。
❯ cat main.css body{margin:0;padding:0;background-color:teal}
fileのwatchとタスク完了のnotifyタスクを追加する
- fileをwatchするタスクを追加する
- 今回はcssファイルを修正し、保存した時に↑のminify cssタスクが自動実行されるようにする
- また、sass fileのcompileが完了した際にnotifyを出すようにする
- 参考:
1. 必要なパッケージをインストール
- プロジェクトディレクトリ(Build)で以下パッケージをインストール
- permissionの原因でgulp-sassはsudoなしで実行。。
sudo npm install --save-dev gulp-notify npm install --save-dev gulp-sass
2. Watchタスクを追加、、する前に
- ここで、Gulpの公式ページでgulpコマンドラインが新しくなっていることを知ったので、インストールしたgulpを一度アンインストールして再度インストール。(参考にしている記事が古いため、gulpfile.jsのjsの書き方も古そう。。。)
sudo npm rm --global gulp sudo npm install --global gulp-cli
- そして、gulpfile.jsもさすがに書き直した。
const { src, dest } = require('gulp'); const minifyCss = require('gulp-minify-css'); exports.default = function() { return src('main.css') .pipe(minifyCss()) .pipe(dest('main')) }
- タスク名を設定していないのでこの場合のタスクの実行は引数なし
gulp
- プロジェクトのtaskを確認できる
❯ gulp --tasks [22:52:17] Tasks for ~/Build/gulpfile.js [22:52:17] └── default
- せっかくなので、task名を設定しておく。あと関数に切り出しておく
const { src, dest } = require('gulp'); const minifyCss = require('gulp-minify-css'); function mincss(cb) { return src('main.css') .pipe(minifyCss()) .pipe(dest('main')) } exports.mincss = mincss;
❯ gulp --tasks [22:59:31] Tasks for ~/Build/gulpfile.js [22:59:31] └── mincss
❯ gulp mincss
- Taskには
Public tasks
とPirvate tasks
がある。publicはgulpコマンドで指定して独立で実行できるタスク。
- さらにGulpでは複数あるタスクを直列or並列に結合(compose)し巨大なタスク群を構成できる。
series()
To have your tasks execute in order, use the series() method.
parallel()
For tasks to run at maximum concurrency, combine them with the parallel() method.
3. watchタスクを追加
watch
もsrc
やdest
と同じくgulpのobject。- なので、watchに関しては今までインストールしてきたパッケージは関係ない
- 参考記事の書き方が古いので同じことを公式のページを参考にES6以降のJS風に書き換える(これが今時なのかよくわからん。。。)
- 一番シンプルな使い方は
wathc(${監視対象ファイル}, ${TASK})
- listenするeventはdefaultは全て。対象eventを明示的に指定もできる。
The watch function takes two arguments: the file(s) to watch and a call to action. The second argument can be a closure (anonymous function) or a javascript object.
const { src, dest, series, watch } = require('gulp'); const minifyCss = require('gulp-minify-css'); function mincss(cb) { return src('main.css') .pipe(minifyCss()) .pipe(dest('main')) } exports.mincss = function() { watch('main.css', series(mincss)); console.log('seen'); }
gulp mincss
を実行すると、seen
が表示される。(バックグラウンド実行ではない)。この状態がfileをwatchしている状態複数種類のファイルをwatchしてみる
- 今回はcoffeeスクリプトのwatchを追加してみる
- まず、
gulp-coffee
をインストール
npm install --save-dev gulp-coffee
gulpfile.js
を編集。- defaultにしたので実行コマンドは以下でOK
gulp
- 変更後
const { src, dest, parallel, watch } = require('gulp'); const minifyCss = require('gulp-minify-css'); const coffee = require('gulp-coffee'); function mincss(cb) { return src('*.css') .pipe(minifyCss()) .pipe(dest('main')) } function scripts(cb) { return src('*.coffee') .pipe(coffee()) .pipe(dest('js')); } exports.default = function() { watch(['*.css', '*.coffee'], parallel(scripts, mincss)); console.log('seen'); }
- 追加したわりに試さないんかーいとなった
4. さらにSassファイルもcompileしてみる
- さらに本題が外れるがSassのcompileもしてみる
- まずは、
gulp-sass
をインストールする
npm install --save-dev gulp-sass
main.css
をmain.scss
にリネーム- sassをcompileするタスクを追加する。
- それ以外にも、watchを切り出したのとseries,parallelをネストして整理してみた
- parallelとseriseのネストは公式ドキュメントの通りにした。(色々やるとエラーが出た。非同期怖い)
const { src, dest, series, parallel, watch } = require('gulp'); const minifyCss = require('gulp-minify-css'); const coffee = require('gulp-coffee'); const sass = require('gulp-sass'); function mincss(cb) { return src('main.scss') .pipe(sass().on('error', sass.logError)) .pipe(minifyCss()) .pipe(dest('main')) } function scripts(cb) { return src('script.coffee') .pipe(coffee()) .pipe(dest('js')); } function watcher(cb) { watch(['*.scss', '*.coffee'], series(mincss, scripts)); console.log('seen'); } exports.build = series(mincss, scripts); exports.default = parallel(series(mincss, scripts), watcher);
main.scss
の中身を編集する
$color-title: #333; h1{ color:$color-title; }
gulp
を実行してみる(gulp build
でもいい)main
ディレクトリに以下の内容でmain.css
が生成されていれば成功
h1{color:#333}
5. Nofificationが出るようにする
- まだまだ本題から外れる
- まずは、
gulp-sass
をインストールする
npm install --save-dev gulp-notify
gulpfile.js
を編集する
const { src, dest, series, parallel, watch } = require('gulp'); const minifyCss = require('gulp-minify-css'); const coffee = require('gulp-coffee'); const sass = require('gulp-sass'); const notify = require('gulp-notify'); function mincss(cb) { return src('main.scss') .pipe(sass().on('error', sass.logError)) .pipe(minifyCss()) .pipe(dest('main')) .pipe(notify('Done!')); } function scripts(cb) { return src('script.coffee') .pipe(coffee()) .pipe(dest('js')); } function watcher(cb) { watch(['*.scss', '*.coffee'], series(mincss, scripts)); console.log('seen'); } exports.build = series(mincss, scripts); exports.default = parallel(series(mincss, scripts), watcher);
gulp
orgulp build
を実行して、通知が出ればOK
Browsersyncを用いたLive Reloading [静的ファイル]
- 少し本題に近づく
- 参考:
1. Browsersyncでブラウザ自動リロードしてみる
- プロジェクトディレクトリで
browser-sync
をインストール
npm install --save-dev browser-sync
gulpfile.js
を編集する- この設定はBrowsersyncの公式ドキュメントを参考に書いてみた
- https://www.browsersync.io/docs/gulp
- Browsersyncはローカルサーバーを立ち上げる
- 今回は
index.html
だけwatchして、変更があった際に自動リロードするようにした
const { src, dest, series, parallel, watch } = require('gulp'); const minifyCss = require('gulp-minify-css'); const coffee = require('gulp-coffee'); const sass = require('gulp-sass'); const notify = require('gulp-notify'); const browserSync = require('browser-sync').create(); function mincss(cb) { return src('main.scss') .pipe(sass().on('error', sass.logError)) .pipe(minifyCss()) .pipe(dest('main')) .pipe(notify('Done!')); } function scripts(cb) { return src('script.coffee') .pipe(coffee()) .pipe(dest('js')); } function html(cb) { src('index.html'); } function browserSyncInit(cb) { browserSync.init({ server : { baseDir: './' }, port: 8081, open: true, notify: true }); } function watcher(cb) { browserSyncInit(); // compile tasks watch(['*.scss', '*.coffee', 'index.html'], series(mincss, scripts, html)); // live reload task watch('index.html').on('change', browserSync.reload); console.log('under watching...'); } exports.build = series(mincss, scripts); exports.default = parallel(series(mincss, scripts), watcher);
- gulp実行を実行すると自動でブラウザ(or tab)も起動し、index.htmlの内容が表示される
gulp
- 試しに、index.htmlの内容を変更するとブラウザが自動でリロードされることが確認できればOK
エラー ENOSPC: System limit for number of file watchers reached
1.発生したエラー
- 次の作業をするために試行錯誤しているうちにこのエラーが発生するようになった。
❯ gulp [22:46:02] Using gulpfile ~/Build/gulpfile.js [22:46:02] Starting 'default'... [22:46:02] Starting 'watcher'... [22:46:02] Starting 'mincss'... [22:46:02] 'watcher' errored after 56 ms [22:46:02] Error: ENOSPC: System limit for number of file watchers reached, watch 'index.html' at FSWatcher.start (internal/fs/watchers.js:165:26) at Object.watch (fs.js:1275:11) at createFsWatchInstance (/home/shouhei/Build/node_modules/chokidar/lib/nodefs-handler.js:38:15) at setFsWatchListener (/home/shouhei/Build/node_modules/chokidar/lib/nodefs-handler.js:81:15) at FSWatcher.NodeFsHandler._watchWithNodeFs (/home/shouhei/Build/node_modules/chokidar/lib/nodefs-handler.js:233:14) at FSWatcher.NodeFsHandler._handleFile (/home/shouhei/Build/node_modules/chokidar/lib/nodefs-handler.js:262:21) at FSWatcher.<anonymous> (/home/shouhei/Build/node_modules/chokidar/lib/nodefs-handler.js:495:21) at FSReqCallback.oncomplete (fs.js:160:5) [22:46:02] 'default' errored after 61 ms [22:46:02] The following tasks did not complete: <series>, mincss [22:46:02] Did you forget to signal async completion?
2.原因
- 原因はgulpではなくOS(Ubuntu)のinotifyの監視ファイル数のlimitを超えたことによるエラーだった。
参考:
3.対処
- 参考:
- まず、現在のinotifyの上限を確認
❯ cat /proc/sys/fs/inotify/max_user_watches 8192
- 今回は一時的に上限を変更
❯ sudo sysctl fs.inotify.max_user_watches=524288 fs.inotify.max_user_watches = 524288 ~/Build ❯ cat /proc/sys/fs/inotify/max_user_watches 524288
- sysctl関連のファイルのリロード(ipv6の設定ファイルがないらしいが今回の件とは関係ないので放置)
❯ sudo sysctl -p sysctl: cannot stat /proc/sys/net/ipv6/conf/all/disable_ipv6: そのようなファイルやディレクトリはありません sysctl: cannot stat /proc/sys/net/ipv6/conf/default/disable_ipv6: そのようなファイルやディレクトリはありません
- 上限を変更後、gulpを実行するとエラーは発生しなくなった
Browsersyncをを用いたLive Reloading [動的ファイル]
1. index.phpを用意
2. gulpfile.jsも修正
- gulpfile.jsも
index.php
に変更する
const { src, dest, series, parallel, watch } = require('gulp'); const minifyCss = require('gulp-minify-css'); const coffee = require('gulp-coffee'); const sass = require('gulp-sass'); const notify = require('gulp-notify'); const browserSync = require('browser-sync').create(); const paths = { html: 'index.php', css: 'main.scss', script: 'script.coffee' } function mincss(cb) { return src(paths.css) .pipe(sass().on('error', sass.logError)) .pipe(minifyCss()) .pipe(dest('main')) .pipe(notify('Done!')); } function scripts(cb) { return src(paths.script) .pipe(coffee()) .pipe(dest('js')); } function html(cb) { src(paths.html); } function browserSyncInit(cb) { browserSync.init({ server : { baseDir: './' }, port: 8081, open: true, notify: true }); } function watcher(cb) { browserSyncInit(); // compile tasks watch(['*.scss', '*.coffee', paths.html], series(mincss, scripts, html)); // live reload task watch(paths.html).on('change', browserSync.reload); console.log('under watching...'); } exports.build = series(mincss, scripts); exports.default = parallel(series(mincss, scripts), watcher);
3. gulp実行するが、Errorとなる
- gulpを実行。しかし、ローカルサーバーが起動し、ブラウザも自動起動するが
Cannot GET /
が表示されるだけ。(タブにはErrorと表示されている。) - 原因は、gulpのローカルサーバーではphpまでは実行してくれない。何かしらphpサーバーを用意する必要がある
4. gulp-connect-php
- 今回は、phpのビルドインサーバーを起動するパッケージ
gulp-connect-php
を使ってみる
5. 必要なパッケージをインストール
npm install --save-dev gulp-connect-php
6. gulpfile.jsを修正
- 前回のstatic file serverの場合: Browsersyncがローカルサーバーとなっていた
- 今回はgulp-connect-phpでビルドインのサーバーを立ち上げ、BrowsersyncはそのサーバーのProxyとなる
const { src, dest, series, parallel, watch } = require('gulp'); const minifyCss = require('gulp-minify-css'); const coffee = require('gulp-coffee'); const sass = require('gulp-sass'); const notify = require('gulp-notify'); const browserSync = require('browser-sync').create(); const connectPHP = require('gulp-connect-php') const paths = { html: 'index.php', css: 'main.scss', script: 'script.coffee' } function mincss(cb) { return src(paths.css) .pipe(sass().on('error', sass.logError)) .pipe(minifyCss()) .pipe(dest('main')) .pipe(notify('Done!')); } function scripts(cb) { return src(paths.script) .pipe(coffee()) .pipe(dest('js')); } function html(cb) { src(paths.html); } function browserSyncInit(cb) { //------------------------------------- // Start a Browsersync static file server //------------------------------------- // browserSync.init({ // server : { // baseDir: './' // }, // port: 8081, // open: true, // notify: true // }); //------------------------------------- // Start a Browsersync proxy //------------------------------------- browserSync.init({ proxy: 'http://localhost:8082' }); } function watcher(cb) { browserSyncInit(); // compile tasks watch(['*.scss', '*.coffee', paths.html], series(mincss, scripts, html)); // live reload task watch(paths.html).on('change', browserSync.reload); console.log('under watching...'); } function php(cb) { connectPHP.server({ base: '.', hostname: 'localhost', port:8082 }) } exports.build = series(php, mincss, scripts); exports.default = parallel(series(php, mincss, scripts), watcher);
7. gulpを実行
- ブラウザが自動起動するが今回はBrowsersyncのプロキシを介すので、
localhost:3000
にアクセスすることになる
❯ gulp [01:58:06] Using gulpfile ~/Build/gulpfile.js [01:58:06] Starting 'default'... [01:58:06] Starting 'watcher'... [01:58:06] Starting 'mincss'... under watching... PHP 7.0.33-0ubuntu0.16.04.4 Development Server started at Sun Jun 9 01:58:07 2019 Listening on http://localhost:8082 Document root is /home/shouhei/Build Press Ctrl-C to quit. [Browsersync] Proxying: http://localhost:8082 [Browsersync] Access URLs: ------------------------------------- Local: http://localhost:3000 External: http://192.168.1.23:3000 ------------------------------------- UI: http://localhost:3001 UI External: http://localhost:3001 ------------------------------------- [Sun Jun 9 01:58:07 2019] 127.0.0.1:56466 [200]: / [01:58:07] gulp-notify: [Gulp notification] Done! [01:58:07] Finished 'mincss' after 250 ms [01:58:07] Starting 'scripts'... [01:58:07] Finished 'scripts' after 102 ms [Sun Jun 9 01:58:07 2019] 127.0.0.1:56474 [200]: / [01:58:17] Starting 'mincss'... [01:58:17] gulp-notify: [Gulp notification] Done! [01:58:17] Finished 'mincss' after 28 ms [01:58:17] Starting 'scripts'... [01:58:17] Finished 'scripts' after 12 ms [01:58:17] Starting 'html'... [Browsersync] Reloading Browsers... (buffered 2 events) [Sun Jun 9 01:58:17 2019] 127.0.0.1:56532 [200]: /
8. 最後にブラウザ自動リロードが実行されるかを確認する
- index.phpを編集し、ブラウザ自動リロードが実行されればOK