Framework7でHTML5モバイルアプリをつくる - Part3: gulp-webserverとgulp-watchでLiveReloadする

Gulpプラグインを使い開発用サーバ-の起動とライブリロードの設定をします。開発用サーバーはExpressサーバーとは独立して起動するのでフロントサイドのSPAの開発が行うことができます。リポジトリはこちらです。

パッケージの追加

package.jsonのdevDependenciesに今回の作業で追加するパッケージを定義します。

package.json
...
"devDependencies": {
...
"gulp-watch": "~4.3.5",
"gulp-webserver": "~0.9.1",
"del": "~2.0.2",
"run-sequence": "~1.1.2"
},
"scripts": {
"start": "node src/server/app.js",
"postinstall": "bower install",
"clean": "gulp clean",
"bower": "gulp bower",
"build": "gulp build",
"dev-server": "gulp"
}
}

インストール

Dockerイメージのビルド課程でRUN npm installが実行されます。

Dockerfile
...
COPY package.json /app/
COPY bower.json /app/
RUN npm install

package.jsonのscriptsセクションに定義してあるpost install`セクションからBowerパッケージもDockerイメージにインストールされます。

$ docker-compose run --rm f7 npm run build

config.js

Gulpのビルドタスクでディレクトリ名やファイル名はまとめてconfig.jsに定義しておきます。相対パスの辺りの記述は現在ではふつうに連結して使えました。

config.js
'use strict';
var path = require('path');
var filter = {
html: '**/*.html',
js: '**/*.js',
css: '**/*.css',
},
srcDir = './src',
/*relativeSrcPath = path.relative('.', srcDir),*/
relativeSrcPath = srcDir,
src = {
server: relativeSrcPath + '/server/',
client: relativeSrcPath + '/client/',
scripts: relativeSrcPath + '/client/js/' + filter.js,
views: './views/' + filter.html
},
distDir = './dist',
dist = {
base: distDir,
js: distDir + '/js/',
css: distDir + '/css/'
},
output = {
buildJs: 'bundle.js',
buildCss: 'bundle.css',
bowerJs: 'vendor.js',
bowerCss: 'vendor.css',
minJs: '.min.js',
minCss: '.min.css'
};
module.exports = {
src: src,
dist: dist,
filter: filter,
output: output
}

Gulpビルドタスク (del, run-sequence)

以下のサイトを参考にビルドタスクを書いていきます。

gulpfile.js

最初に作成したgulpfile.jsの全文です。

gulpfile.js
'use strict';
var gulp = require('gulp'),
gutil = require('gulp-util'),
concat = require('gulp-concat'),
rename = require('gulp-rename'),
uglify = require('gulp-uglify'),
minifyCss = require('gulp-minify-css'),
gulpFilter = require('gulp-filter'),
bower = require('main-bower-files'),
webserver = require('gulp-webserver'),
watch = require('gulp-watch'),
del = require('del'),
runSequence = require('run-sequence'),
config = require('./config');
gulp.task('clean', function(cb) {
return del(config.dist.base, cb);
});
gulp.task('copy', function() {
return gulp.src(config.src.views)
.pipe(gulp.dest(config.dist.base));
});
gulp.task('scripts', function() {
return gulp.src(config.src.scripts)
.pipe(concat(config.output.buildJs))
.pipe(gulp.dest(config.dist.js))
.pipe(uglify())
.pipe(rename({
extname: config.output.minJs
}))
.pipe(gulp.dest(config.dist.js));
});
gulp.task('bowerJs', function() {
var jsFilter = gulpFilter(config.filter.js);
return gulp.src(bower())
.pipe(jsFilter)
.pipe(concat(config.output.bowerJs))
.pipe(gulp.dest(config.dist.js))
.pipe(uglify())
.pipe(rename({
extname: config.output.minJs
}))
.pipe(gulp.dest(config.dist.js));
});
gulp.task('bowerCss', function() {
var cssFilter = gulpFilter(config.filter.css);
return gulp.src(bower())
.pipe(cssFilter)
.pipe(concat(config.output.bowerCss))
.pipe(gulp.dest(config.dist.css))
.pipe(minifyCss())
.pipe(rename({
extname: config.output.minCss
}))
.pipe(gulp.dest(config.dist.css));
});
gulp.task('watch', function () {
watch(config.src.scripts, function () {
gulp.start(['scripts']);
});
watch(config.src.views, function () {
gulp.start(['copy']);
});
});
gulp.task('webserver', function() {
console.log(config.dist.base);
return gulp.src(config.dist.base)
.pipe(webserver({
host: process.env.DEV_HOST || 'localhost',
port: process.env.DEV_PORT || 8080,
livereload: true
}));
});
gulp.task('bower', ['bowerJs', 'bowerCss']);
gulp.task('build', function(cb) {
runSequence('clean', ['bower', 'scripts', 'copy'], cb);
});
gulp.task('default', ['webserver','watch']);

buildタスク

buildタスクではrun-sequenceパッケージを使いタスクの直列処理と並列処理を制御します。cleanタスクが終了後に配列で定義したタスクを並列で実行します。

gulpfile.js
gulp.task('build', function(cb) {
runSequence('clean', ['bower', 'scripts', 'copy'], cb);
});

開発用サーバーとライブリロード (gulp-watch, gulp-webserver)

以下のサイトを参考に開発サーバーのタスクを書いていきます。

watchタスク

gulp-watchを使ったwatchタスクを用意して開発しているJavaScriptとHTMLファイルのディレクトリの更新を監視します。JavaScriptとHTMLファイルに編集があった場合にそれぞれscriptsタスクとcopyタスクが実行されます。公開用のdistディレクトリに変換されたファイルがコピーされます。

gulpfile.js
gulp.task('watch', function () {
watch(config.src.scripts, function () {
gulp.start(['scripts']);
});
watch(config.src.views, function () {
gulp.start(['copy']);
});
});

webserverタスク

gulp-webserverを使い開発用のWebサーバーを起動するタスクです。

gulpfile.js
gulp.task('webserver', function() {
console.log(config.dist.base);
return gulp.src(config.dist.base)
.pipe(webserver({
host: process.env.DEV_HOST || 'localhost',
port: process.env.DEV_PORT || 8080,
livereload: true
}));
});

開発をクラウド上で行っているので、 docker-compose.ymlにバインドするホスト名をenvironmentセクションの環境変数として0.0.0.0にバインドします。またportsセクションにDockerホストにマップして公開するポートを定義します。

docker-compose.yml
environment:
- DEV_HOST=0.0.0.0
- DEV_PORT=8080
ports:
- 3030:3000
- 8090:8080
- 35729:35729

buildタスク

run-sequenceプラグインを使いタスク処理の順番を直列と並列に制御します。

gulpfile.js
gulp.task('build', function(cb) {
runSequence('clean', ['bower', 'scripts', 'copy'], cb);
});
gulp.task('default', ['webserver','watch']);

cleanタスク

delパッケージは、プロジェクトをビルドする前のcleanタスクで公開用ディレクトリをクリアする目的で使います。returnしないとタスクが途中で止まってしまうので注意が必要です。

gulpfile.js
gulp.task('clean', function(cb) {
return del(config.dist.base, cb);
});

ビルドと実行

同様にbuildコマンドと、

Run arbitrary package scriptsにrun-scriptの使い方が書いてあります。package.jsonのscriptsセクションに定義したdev-serverコマンドをnpm run dev-serverから実行します。

$ docker-compose run --rm f7 npm run build
$ docker-compose run --rm --service-ports f7 npm run dev-server
npm info it worked if it ends with ok
npm info using npm@2.13.3
npm info using node@v3.2.0
npm info predev-server framework7-docker@0.0.1
npm info dev-server framework7-docker@0.0.1
> framework7-docker@0.0.1 dev-server /app
> gulp
[21:02:03] Using gulpfile /app/gulpfile.js
[21:02:03] Starting 'webserver'...
./dist
[21:02:03] Webserver started at http://0.0.0.0:8080
[21:02:03] Starting 'watch'...
[21:02:03] Finished 'watch' after 12 ms
[21:02:03] Finished 'webserver' after 62 ms
[21:02:03] Starting 'default'...
[21:02:03] Finished 'default' after 11 μs

開発用サーバーはsrc/client/js/viewsディレクトリを監視します。ファイルに変更があると、公開用のdistディレクトリにファイルの結合と圧縮を行いコピーします。