公開用のサイトに限らず、実験用や勉強用に静的なサイトを作成する事がちょくちょくあります。その度に自分のスニペットやネタ帳から色々ひっぱり出し、時にはGoogleで検索したりして(まあそれが知識のアップデートになっている事も多々あるけど)作成していました。

けど、決まりきっている作業やコピペをするのは時間が勿体無いし、今のデフォルトテンプレートはこんな感じかな?というのを可視化するために、自分用の静的サイトのテンプレート的な物を作ってみる事にしました。

middlemanのv4がリリースされてSprocketsが非標準になったのでsassとjsのタスクもgulpで行うようにし、middleman+gulpな環境を作ってみます。

ちなみに今回作ったリポジトリはt4traw/static_site_bootstrapです。

記事を書いている時の環境は、Mac OS X 10.10 El Capitan/Ruby 2.3.0/Node 5.9.1です。

目次

  1. 最初の準備
  2. middleman+gulpの設定
  3. sass関連の設定と設計
  4. javascript関連の設定
  5. build時のtaskと仕上げ
  6. githubに上げておけば簡単にmiddlemanのテンプレートに!

最初の準備

Rubyはインストール済みとします。Nodeは最新の物をインストールしました。はじめての人はPATHを設定しましょう。 ※gulpのPATHの通し方についてはこのページが非常に参考になります。参考: コマンドパスを自動で通し npm install -g しない

$ brew uninstall node.js && brew update && brew install node.js
$ echo 'export PATH=$PATH:./node_modules/.bin' >> ~/.zshrc
$ source ~/.zshrc

テンプレートを作っていきます。僕はrbenv-gemsetを使っているので、gemset用のファイルを作成し、Gemfileを作成します。

$ mkdir static_site_bootstrap
$ cd static_site_bootstrap
$ rbenv gemset init static_site_bootstrap
$ bundle init

Gemfileの中にmiddlemanを書きbundle install、さらにmiddleman initします。

$ bundle
$ middleman init

middleman initする時に色々聞かれますが、Livereload以外は全て「n」で。compassは最近あまり使わないし、gulpを使うならまあいいかなと思って、今回から使わない事に。config.ruが欲しい人などは必要に応じて「Y」にしてください。

次にgulpの初期設定をします。

$ npm init
$ npm install gulp --save-dev

package.jsonが生成され、

{
  "name": "static_site_bootstrap",
  "version": "1.0.0",
  "description": "",
  "main": "gulpfile.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "gulp": "^3.9.1",
  }
}

といった具合に書かれていると思います。あとは処理を書くためのgulpfile.jsを作成すれば必要なファイルがひとまず揃います。

$ touch gulpfile.js

middleman+gulpの設定

middleman+gulpの設定をしていきます。

とりあえずmiddlemanのconfigを設定。僕はてっきりmiddlemanのcssとかjsをgulpとか外部ツールに渡して生成を完全に分離できるのかと思ってたんだけど、Sprocketが非標準になってもstylesheetsなどをbuild時にコンパイルしてしまう(all.cssを何故かallという拡張子無しのファイルで出力してくれる)。これは困る。

なので、ignoreと書いてmiddleman buildの時に無視するようにします。

ただ、stylesheetsのパスなどは設定されてないとまずいので、set :css_dirなどはちゃんと書かないとダメです。そして、external_pipeline(外部パイプライン)を設定します。

ignore 'REAMDME.md'

set :css_dir, 'stylesheets'
set :js_dir, 'javascripts'
set :images_dir, 'images'
set :layouts_dir, '_layouts'

activate :external_pipeline,
  name: :gulp,
  command: build? ? './node_modules/gulp/bin/gulp.js' : './node_modules/gulp/bin/gulp.js watch',
  source: "source"

configure :build do
  ignore 'stylesheets/*'
  ignore 'javascripts/*'
end

これでbundle exec middlemanでmiddlemanを起動したらgulp watchしているのと同じ状態になりました。

次にgulpfile.jsにgulpのタスクで最低限必要な事を書きます。

var gulp = require('gulp');

gulp.task('default', function(){
  //
});

gulp.task('watch', function(){
  //
});

defaultタスクが無いとgulpが使えないって怒られるので注意。とりあえずここでテスト。

$ bundle exec middleman

ターミナルでgulpのwatchが走っている事が確認できました。

sass関連の設定と設計

sassに関する設定をしていきます。middleman serveのプレビューではsource/stylesheetsにcssが無いとダメなので、ひとまずsource/stylesheetsにcssを生成する事にします。

今までall.cssにsassの@importで結合していましたがgulpで全部まとめて出力するようにしました。

僕の場合cssは

  • initialize/ (ex: normalize.sass, variables.sass)
  • foundation/ (ex: base.sass, layout.sass)
  • user/ (ex: header.sass, footer.sass)

と3つのフォルダに分けて書くようにしています。

initializeフォルダには最初に読まれてないといけないcssリセットや変数などをまとめておくvariables.sass。foudationフォルダにはレイアウトや基本設定。userには、より細部の必要なスタイルを書いていきます。

これらをまとめて出力するためにgulp-concatを使用します。あと当然必要なgulp-sassと、prefixを自動でつけてくれるgulp-autoprefixerをインストールします。最終的な名前をall.cssにする為にgulp-renameも入れます。

$ npm install --save-dev gulp-concat gulp-sass gulp-autoprefixer gulp-rename
var concat       = require('gulp-concat');
var sass         = require('gulp-sass');
var autoprefixer = require("gulp-autoprefixer");
var rename       = require('gulp-rename');

gulp.task('css.sass', function(){
  return gulp.src([
    'source/stylesheets/initialize/**/!(_)*.sass',
    'source/stylesheets/foundation/**/!(_)*.sass',
    'source/stylesheets/user/**/!(_)*.sass'
  ])
    .pipe(concat('all.sass'))
    .pipe(sass.sync().on('error', sass.logError))
    .pipe(autoprefixer())
    .pipe(rename('all.css'))
    .pipe(gulp.dest('source/stylesheets'));
});

アンダースコアのついたファイルは除外するために、!(_)*.sassといった指定方法にしました。userフォルダの中で@importで読み込む用のsassが欲しい場合にも対応できます。

これでsource/stylesheetsの中にall.cssが生成されるようになりました。これを更新があったら自動的に回せるように、watchタスクの中に入れておきます。

gulp.task('watch', function(){
  gulp.watch(['source/stylesheets/**/*.sass'], ['css.sass']);
});

all.cssはバージョン管理する必要が無いので.gitignoreに追加しておきます。

javascript関連の設定

javascriptも同じくsourceの中にall.jsが無いとダメなので、jsファイルで更新があったら生成されるようにします。

バリバリフロントエンドな方はもっと凝った内容になると思うのですが、僕は簡単なjavascriptやjqueryを使うぐらいなので結合するだけのシンプルな内容です。

  • library/ (ライブラリ本体)
  • module/ (プラグインなど)
  • user/ (実際のjavascript)

こんな具合のフォルダ構成で、あとはそれをall.jsに結合します。

gulp.task('js.concat', function(){
  return gulp.src([
    'source/javascripts/library/**/!(_)*.js',
    'source/javascripts/module/**/!(_)*.js',
    'source/javascripts/user/**/!(_)*.js',
   ])
    .pipe(concat('all.js'))
    .pipe(gulp.dest('source/javascripts'))
});

watchにもjsの更新と処理を追加します。

gulp.task('watch', function(){
  gulp.watch(['source/stylesheets/**/*.sass'], ['css.sass']);
  gulp.watch(['source/javascripts/**/*.js'], ['js.concat']);
});

all.jsもバージョン管理する必要が無いので.gitignoreに追加しておきます。

build時のtaskと仕上げ

最後にbuildする時のminifyやuglifyを追加。

$ npm install --save-dev gulp-cssmin gulp-uglify

minifyやuglifyしたファイルはそのままbuildフォルダに保存。

var cssmin       = require('gulp-cssmin');
var uglify       = require('gulp-uglify');

gulp.task('css.cssmin', function(){
  return gulp.src('source/stylesheets/*.css')
    .pipe(cssmin())
    .pipe(gulp.dest('build/stylesheets'));
});

gulp.task('js.uglify', function(){
  return gulp.src('source/javascripts/*.js')
    .pipe(uglify())
    .pipe(gulp.dest('build/javascripts'))
});

で、実際のbuildタスクを作成するのだけど、

gulp.task('build', [
  ['css.sass', 'js.concat', 'css.cssmin', 'js.uglify']
);

こんな感じで書くとうまくいかない。配列の順番通りにやってくれるかと思ったら、gulpは並列処理なので、全部同時にやってしまう。順序を設定する為にはrun-sequenceが必要みたい。

$ npm install --save-dev run-sequence

で、こんな感じに書くと思い通りの動作になった。

var runSequence  = require('run-sequence');

gulp.task('build', function(callback){
  return runSequence(
    ['css.sass', 'js.concat'],
    ['css.cssmin', 'js.uglify'],
    callback
  );
});

仕上げに、gulpでエラーが出た時に処理が止まらないようにし、さらにそれを通知するようにgulp-plumberとgulp-notifyを追加。

$ npm install --save-dev gulp-plumber gulp-notify

各タスクに処理を追加する。

gulp.task('css.cssmin', function(){
  return gulp.src('source/stylesheets/*.css')
    .pipe(plumber({errorHandler: notify.onError('<%= error.message %>')}))
    .pipe(cssmin())
    .pipe(gulp.dest('build/stylesheets'));
});

あとはこれをmiddleman buildした時に自動的に走るようにする。

configure :build do
  ignore 'stylesheets/*'
  ignore 'javascripts/*'
  after_build do
    system('gulp build')
  end
end

buildのテストをしてみる。

$ bundle exec middleman build

buildディレクトリにstylesheetsの中には結合とminifyされたall.css、javascriptsの中には結合とuglifyされたall.jsが生成されてたらOKです。やったー!

githubに上げておけば簡単にmiddlemanのテンプレートに!

作ったリポジトリをgithubにpushしておけば、例えば今回のリポジトリをテンプレートをテンプレートにして制作したい場合、適当なtestディレクトリを作って

$ middleman init -T t4traw/static_site_bootstrap

と打てば自動的に作成したテンプレートとbundle installをしてくれる。ただ.gitignoreが作られないので、そこは自分で作るか何かしら方法を作っておいた方が良さそう。

というわけで、middleman+gulpで簡単な静的サイトテンプレートの作り方でした。