masato's blog

Framework7でHTML5モバイルアプリをつくる - Part2: GulpとBowerでパッケージを1つにまとめる

前回はFramework7のパッケージはBowerからインストールした後、HTMLファイルから直接bower_componentsディレクトリからJavaScriptとCSSをロードしていました。Gulpから事前にBowerを使ってインストールしたパッケージを公開用ディレクトリにパブリッシュすることが今回の目的です。今のところFramework7だけしか使っていませんが、bower_components配下にインストールされたパッケージのJavaScriptやCSSを1つのファイルにまとめて、本番用にファイルスサイズを圧縮させます。

プロジェクト

Gulpタスクから公開用ディレクトリにBowerパッケージをコピーした後のディレクトリ構造は以下のようになります。リポジトリはこちらです。

$ cd ~/node_apps/docker-framework7
$ tree
.
├── Dockerfile
├── README.md
├── app.js
├── bower.json
├── bower_components -> /dist/bower_components
├── docker-compose.yml
├── gulpfile.js
├── node_modules -> /dist/node_modules
├── package.json
└── public
├── about.html
├── css
├── dist
│   ├── css
│   │   ├── vendor.css
│   │   └── vendor.min.css
│   └── js
│   ├── vendor.js
│   └── vendor.min.js
├── index.html
└── js
└── index.js

package.json

GulpからBowerパッケージをまとめる方法はいくつかありますが、今回は以下のプラグインを使います。package.jsonのdevDependenciesフィールドに必要なプラグインを定義します。

package.json
{
"name": "framework7-docker",
"description": "framework7 docker",
"version": "0.0.1",
"private": true,
"dependencies": {
"express": "~4.13.3"
},
"devDependencies": {
"bower": "~1.5.2",
"gulp": "~3.9.0",
"gulp-util": "~3.0.6",
"gulp-concat": "~2.6.0",
"gulp-filter": "~3.0.1",
"gulp-uglify": "~1.4.0",
"gulp-minify-css": "~1.2.1",
"gulp-rename": "~1.2.2",
"main-bower-files": "~2.9.0"
},
"scripts": {
"start": "node app.js",
"postinstall": "bower install",
"bower": "gulp bower"
}
}

main-bower-files

dependencies

main-bower-filesはプロジェクトのbower.jsonのdependenciesに定義されたパッケージを参照します。今回の例ではFramework7だけです。

bower.json
{
"name": "framework7-docker",
"version": "0.0.1",
"private": true,
"dependencies": {
"framework7": "~1.2.0"
},
"overrides": {
"framework7": {
"main": [
"dist/js/framework7.js",
"dist/css/framework7.ios.css",
"dist/css/framework7.ios.colors.css"
]
}
}
}

main-bower-filesをrequireしてコールすると、Bowerパッケージのbower.jsonのmainセクションに定義されたエントリポイントファイル名を配列で返してくれます。

var bower = require('main-bower-files');
console.log(bower());

実行結果

[ '/app/bower_components/framework7/dist/js/framework7.js',
'/app/bower_components/framework7/dist/css/framework7.ios.css',
'/app/bower_components/framework7/dist/css/framework7.ios.colors.css' ]

Gulpタスクでは取得したエントリポイントのファイル名からストリームで中身を結合して圧縮していく処理をつないでいきます。

overrides

ただし、Framework7のbower.jsonmainセクションは以下のようにディレクトリになっているためmain-bower-filesはファイル名が取得できません。

bower.json
...
"main": "dist/",
...

プロジェクトのbower.jsonにoverridesセクションを定義して、パッケージ毎のmainセクションを上書きすることができます。下の例ではJavaScriptとCSSファイルをエントリポイントに追加します。

bower.json
...
"overrides": {
"framework7": {
"main": [
"dist/js/framework7.js",
"dist/css/framework7.ios.css",
"dist/css/framework7.ios.colors.css"
]
}
}
...

gulpfie.js

gulpfile.jsを作成します。bowerJSとbowerCSSタスクはJavaScriptとCSSの違いはありますが処理内容は同じです。

  1. main-bower-filesからパッケージのエントリポイントのファイル名を配列で取得する
  2. JavaScriptかCSSのどちらかにフィルタする
  3. ファイルの中身を1つにまとめて、公開用ディレクトリに出力する
  4. 1つにまとめたファイルの中身を圧縮して、公開用ディレクトリに出力する
gulpfie.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');
var publishDir = 'public/dist',
dist = {
js: publishDir + '/js/',
css: publishDir + '/css/'
};
gulp.task('bowerJS', function() {
var jsFilter = gulpFilter('**/*.js');
return gulp.src(bower())
.pipe(jsFilter)
.pipe(concat('vendor.js'))
.pipe(gulp.dest(dist.js))
.pipe(uglify())
.pipe(rename({
extname: '.min.js'
}))
.pipe(gulp.dest(dist.js));
});
gulp.task('bowerCSS', function() {
var cssFilter = gulpFilter('**/*.css');
return gulp.src(bower())
.pipe(cssFilter)
.pipe(concat('vendor.css'))
.pipe(gulp.dest(dist.css))
.pipe(minifyCss())
.pipe(rename({
extname: '.min.css'
}))
.pipe(gulp.dest(dist.css))
});
gulp.task('bower', ['bowerJS', 'bowerCSS']);
gulp.task('default', ['bower']);

package.jsonのscriptsセクションに"bower": "gulp bower"を定義していて、npn run scriptsとして実行して、bowerJSとbowerCSSタスクをまとめて実行します。

$ npm run bower

Docker Composeを使って実行します。

$ docker-compose run --rm f7 npm run bower
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 prebower framework7-docker@0.0.1
npm info bower framework7-docker@0.0.1
> framework7-docker@0.0.1 bower /app
> gulp bower
[17:25:57] Using gulpfile /app/gulpfile.js
[17:25:57] Starting 'bowerJS'...
[17:25:57] Starting 'bowerCSS'...
[17:26:11] Finished 'bowerJS' after 14 s
[17:26:11] Finished 'bowerCSS' after 14 s
[17:26:11] Starting 'bower'...
[17:26:11] Finished 'bower' after 18 μs
npm info postbower framework7-docker@0.0.1
npm info ok

index.html

最後にbower_componentsを参照していたindex.htmlファイルを編集します。JavaScriptとCSSファイルを公開用のdistディレクトリからロードするように変更します。

index.html
...
<head>
...
<link rel="stylesheet" href="/dist/css/vendor.css">
</head>
...
<body>
...
<script type="text/javascript" src="/dist/js/vendor.js"></script>
...
</body>