目的
Docker上でPHP開発を行う際のブラウザ自動リロードをGulp+Browersyncで行う
前提
Ubuntu16.04
npm, nodeはインストール済み
この記事で追加するパッケージ
gulp-minify-css
: cssファイルのminify
gulp-coffee
: coffeeのcompile
gulp-sass
: sassのcompile
gulp-notify
: 通知
browser-sync
: ブラウザ自動リロード
gulp-connect-php
: phpのビルドインサーバーを起動
Task RunnerとしてGulpのビルドシステムをセットアップ
phpocean.com
1. install node
node -v
2. install npm
npm -v
3. テスト用のディレクトリ(プロジェクトディレクトリ)を作成しておく
- gulpをインストールする前にプロジェクトディレクトリを用意しておく
- よくプロジェクトという単語が出てくるが、ただのルートとなるディレクトリのこと(だと思う)
- まず、以下の構成でスタート
Build
└── index.html
- ちなみに、↑のために
tree
コマンドをインストール
vitux.com
4. install 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タスクを実行してみる
- まず、テスト用のcssファイル(
main.css
)を作成する。
- このcssファイルの内容がタスク実行後にminifyされることを確認する。
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を出すようにする
- 参考:
phpocean.com
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
gulpjs.com
- そして、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
❯ 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コマンドで指定して独立で実行できるタスク。
gulpjs.com
- さらに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.
gulpjs.com
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');
}
npm install --save-dev gulp-coffee
gulpfile.js
を編集。
- coffeeスクリプトをコンパイルする関数を追加
- タスクを
default
に変更
- watchに登録するタスクに
scripts
を追加。
- 並列でいいかと思ったので
parallel
に変更
- 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);
$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
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
or gulp build
を実行して、通知が出ればOK
Browsersyncを用いたLive Reloading [静的ファイル]
phpocean.com
www.browsersync.io
1. Browsersyncでブラウザ自動リロードしてみる
- プロジェクトディレクトリで
browser-sync
をインストール
npm install --save-dev browser-sync
gulpfile.js
を編集する
- この設定はBrowsersyncの公式ドキュメントを参考に書いてみた
- https://www.browsersync.io/docs/gulp
- Browsersyncはローカルサーバーを立ち上げる
- baseDir: たぶんローカルサーバーのドキュメントルート。プロジェクトのディレクトリにしておけばよさそう
- port: ローカルサーバーのポート。指定しない場合は3000
- open: task実行時にブラウザの自動起動のon/off
- notify: 通知するかどうか
- 今回は
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();
watch(['*.scss', '*.coffee', 'index.html'], series(mincss, scripts, html));
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を超えたことによるエラーだった。
参考:
github.com
3.対処
github.com
❯ 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を用意
- phpファイルをwatchして、ブラウザ自動リロードする
index.html
を 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();
watch(['*.scss', '*.coffee', paths.html], series(mincss, scripts, html));
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
を使ってみる
www.npmjs.com
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) {
browserSync.init({
proxy: 'http://localhost:8082'
});
}
function watcher(cb) {
browserSyncInit();
watch(['*.scss', '*.coffee', paths.html], series(mincss, scripts, html));
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