chlonolog

web, digital gadgets, and more.

現在のgulpfile.jsを公開します(2018年8月版)※8/23更新

※2018/08/23 更新しました。

最初のgulpfile.jsからだいぶ変更したので、改めてまとめてみました。

CoffeeScriptにしました

かっこが大量にあるコードだと、確認するのが面倒になりませんか? 私はみっつ以上重なっていると、ため息をつきながらエディタをそっ閉じしたくなります。
ということで、JavaScriptで書いていたコードをすべてCoffeeScriptに変更しました。需要とかオワコンとか関係ないです。どうせ自分用ですし。

以下の内容は、ほぼすべてCoffeeScriptで記述されています。
JavaScriptの構文で参照したい場合は、お手数ですがjs2coffeeで変換してください。


ディレクトリの構造

gulpfile.jsを、処理ごとに複数ファイルへ分割しました。

┬ web/ ┬ hexo-project/    - Hexoのプロジェクト
│      ├ hexo-project-2/  - Hexoのプロジェクト
│      └ hexo-project-3/  - Hexoのプロジェクト
│ node_modules/            - gulpで使用しているモジュール
├ _gulp/ ┬ fonts/         - フォントのサブセット化で使うデータを格納している場所
│        ├ tasks/         - 分割したgulpのタスク
│        ├ config.coffee  - gulpの設定ファイル
│        └ sass-lint.yml  - sass-lintの設定ファイル
├ _fonts/                  - サブセットを行うフォントを格納している場所
├ gulpfile.coffee
└ gulpfile.js              - gulpfile.coffeeを呼ぶだけのファイル

処理一覧

引数の書き方をよく忘れるので、gulp-helpを使ってヘルプテキストを書いてあります。

$ gulp help
Using gulpfile ~/hexo/gulpfile.js
Starting 'help'...

Usage
  gulp [TASK] [OPTIONS...]

Available tasks
  coffee                *.coffeeをjsに変換
  coffee:watch          coffeeの自動監視タスク
  concat-css            主要cssファイルの結合
  concat-js             主要jsファイルの結合
  concat-js:watch       concat-jsの自動監視タスク
  default               起動時処理 [sass:watch, coffee:watch, concat-js:watch, js:watch]
   --project            Hexoのプロジェクト名
   --theme              Hexoのテーマファイル名
  font                  pyftsubsetを使ってフォントのサブセットを作成し、woffとwoff2に変換する
   --type               フォントの出力タイプ (level1, level2, mini, text)
  font:fontmin          gulp-fontminを使ってフォントのサブセットを作成し、woffとwoff2に変換する Aliases: fontmin
   --type               フォントの出力タイプ (level1, level2, mini, text)
  font:make-text        Hexoのポストからサブセット用テキスト一覧を作成 Aliases: make-text
  help                  Display this help text.
  images                画像ファイルの圧縮 [images:thumbnail, images:eyecatch]
  images:eyecatch       画像ファイルを元にしたアイキャッチ画像作成 Aliases: eye, eyecatch
  images:thumbnail      画像ファイルを元にしたサムネイル作成 Aliases: thumb, thumbnail
  js                    *.jsをuglify・minify・gz圧縮
  js:watch              jsの自動監視タスク
  sass                  *.scssの構文チェック・cssに変換・minify・gz圧縮 [sass:lint]
  sass:lint             sass-lintを実行
  sass:watch            sassの自動監視タスク [sass]
  stylus                *.stylをcssに変換

gulpfile.js / gulpfile.coffee

CoffeeScriptで記述するために、gulpfile.jsでcoffeescriptを読み込んでいます。

require('coffeescript/register');
require('./gulpfile.coffee');

タスクをそれぞれ別ファイルに分割してあるので、gulpfile.coffeeもシンプルです。
gulpタスクのファイル分割は、こちらの記事を参考にしました。

分割したタスクの読み込みには、require-dirを使用しています。
defaultタスクの宣言部分についている'起動時処理'というテキストと、後ろについているoptions:は、gulp-helpで出力している説明文です。

gulp = require('gulp-help')(require('gulp'))

# 分割したgulpタスクを読み込む
dir = require 'require-dir'
dir './_gulp/tasks', recurse: true

#--------------------------------------------------

###
# 起動時処理
###
gulp.task 'default', '起動時処理', [
  'sass:watch'
  'coffee:watch'
  'concat-js:watch'
  'js:watch'
], -> ,
options:
  'project': 'Hexoのプロジェクト名'
  'theme':   'Hexoのテーマファイル名'

設定ファイル

タスク内で使用する設定は、すべてここにまとめています。
引数の値取得には、minimistを使用しています。
これによって、起動時に

$ gulp sass --project my-hexo-project --theme hexo-theme

とか

$ gulp font --type level2

といった指定ができるようになっています。

設定は処理ごとに必要な内容のみを読み込めるようになっており、個々のタスクからは

config = require('../config').XXXXX

という形で呼び出しています。

# gulpでパラメータを取得するにはminimist
# gulp --project font-sample --theme typography
# gulp font --type level2
minimist = require 'minimist'
env = 
  default:  # 引数の初期値
    project: 'hexo-theme'
    theme:   'mytheme'
    type:    'level2'
args = minimist process.argv.slice(2), env

hexo = {
  prefix: '/Users/myname/web/hexo/'
  suffix: '/themes/' + args.theme + '/source/'
}
path = {
  project: hexo.prefix + args.project   + hexo.suffix
  base:    hexo.prefix + 'hexo-project' + hexo.suffix
  css:     hexo.prefix + 'hexo-project' + hexo.suffix + 'css/'
  js:      hexo.prefix + 'hexo-project' + hexo.suffix + 'js/'
}

browsers = [ # Autoprefixer
  '> 1% in JP'
  'last 2 version'
  'ie >= 10'
  'iOS >= 9'
  'Android >= 4.4'
]

console.log 'watching Project: [ ' + path.project + ' ]'

#--------------------------------------------------

module.exports =
  # _gulp/concat_css.coffee
  concat_css:
    export: path.css
    browsers: browsers # autoprefixerで指定するベンダープレフィックスの設定
    default : [ # 結合するcssファイルの一覧
      path.css + '_slidebars.css'
      path.css + '_lity.min.css'
      path.css + '_styles.css'
    ]
  # _gulp/concat_js.coffee
  concat_js:
    path: path.js
    export: path.js
    file: [ # 監視するjsファイルの場所
      path.js + '_*.js'
      '!' + path.js + '*.min.js'
    ]
    default: [ # 結合するjsファイルの一覧 (default.js)
      path.js + '_jquery-3.3.1.min.js'
      path.js + '_bootstrap.min.js'
      path.js + '_fastclick.js'
      path.js + '_slidebars.js'
      path.js + '_lity.min.js'
      path.js + '_lazysizes/ls.unveilhooks.min.js'
      path.js + '_lazysizes/lazysizes.min.js'
    ]
    script: [  # 結合するjsファイルの一覧 (script-all.js)
      path.js + '_script.js'
      path.js + '_share.js'
      path.js + '_slider.js'
    ]
  # _gulp/js.coffee
  js:
    export: path.js
    file: [ # 監視するjsファイルの場所
      path.js + '*.js'
      '!' + path.js + '_*.js'
      '!' + path.js + '*.min.js'
    ]
  # _gulp/sass.coffee
  sass:
    path:     path.base + '_scss/'
    file:     path.base + '_scss/*.scss' # 監視するsassファイルの場所
    export:   path.css # cssファイルの出力先
    browsers: browsers # autoprefixerで指定するベンダープレフィックスの設定
    lint:
      config: '_gulp/sass-lint.yml' # sass-lintの設定ファイルの場所
      export: '_gulp/sass-lint.txt' # 結果出力先
      formatter: 'compact'          # 出力フォーマット
  # _gulp/stylus.coffee
  stylus:
    file    : path.css + '*.styl' # 変換するsassファイルの場所
    export  : path.css            # cssファイルの出力先
  # _gulp/coffee.coffee
  coffee:
    path: path.base + '_coffee/'
    file  : path.base + '_coffee/*.coffee' # 監視するcoffeeファイルの場所
    export: path.js # jsファイルの出力先
  # _gulp/font.coffee
  font:
    args: args
    font:
      path: '_fonts/src/'  # 大元のフォントの場所
      dest: '_fonts/dest/' # サブセット化したフォントの出力先
      text_posts: path.project + '_posts/'
  # _gulp/images.coffee
  images:
    folders: [
      {
        path: hexo.prefix + 'hexo-project' + path.suffix + 'images/'
        size: 400
      }
      {
        path: hexo.prefix + 'hexo-project-2' + path.suffix + 'images/'
        size: 150
      }
      {
        path: hexo.prefix + 'hexo-project-3' + path.suffix + 'images/'
        size: 300
      }
    ]
    image_type: '*.+(jpg|jpeg|png|gif|svg)' # 処理対象となるファイル
    mozjpeg_quarity: 80     # jpegの圧縮率
    imagemin_options:
      optimizationLevel: 7  # 最適化レベル
    compress:
      width:       1000
      height:      1000
      crop:        false    # cropする?
      upscale:     false    # 指定したサイズに画像を引き伸ばす?
      imageMagick: true     # imageMagick使う?
    thumbnail:
      imageMagick: true
    eyecatch:
      width:       830
      height:      580
      crop:        true
      gravity:     'Center' # cropする際の基準となる位置
      upscale:     true
      cover:       true     # 指定したwidthとheightに画像のサイズを合わせる?
      imageMagick: true

gulp-image-resizeのパラメータについて

image.compressimage.thumbnailimage.eyecatchの設定は、画像の圧縮・サムネイル作成・アイキャッチ画像作成gulp-image-resizeで使用しています。
upscaleとcoverの違いが微妙に分かりづらいのですが、違いは以下の通りです。

upscale

widthとheightが指定されている場合、画像の長辺をどちらかに合わせた形で引き伸ばします。

  • width: 500
  • height: 300
  • upscale: true

といった設定で 幅100px × 高さ50px の画像を処理した場合、

  1. 画像の長辺は幅の方
  2. widthに合わせて画像が引き伸ばされる(アスペクト比は変わらない)
  3. 幅500px × 高さ250px の画像が出力

となります。

cover

widthとheightのサイズに画像をきっちり合わせます。

  • width: 500
  • height: 300
  • cover: true

といった設定で 幅1000px × 高さ1000px の画像を処理した場合、

  1. widthとheightの値からはみ出た部分は、ばっさりカットされる
  2. 幅500px × 高さ300px の画像が出力

となります。

width・height・upscale・cover・cropをすべて指定することで、

  • 指定サイズより画像が大きければ縮小する(width・height)
  • 指定サイズより画像が小さければ引き伸ばす(upscale)
  • 引き伸ばした/縮小した画像を、widthとheightで指定したサイズに切り取る(cover・crop)

という処理が実行されます。アイキャッチ画像を写真から作る場合などに便利です。

主要cssファイルの結合

config.coffeeconcat_css.defaultに設定している複数のcssファイルをautoprefixerに通し、default.cssまとめています。

gulp         = require('gulp-help')(require('gulp'))
plumber      = require 'gulp-plumber'
notify       = require 'gulp-notify'
autoprefixer = require 'gulp-autoprefixer'
concat       = require 'gulp-concat'
config       = require('../config').concat_css

###
# 主要cssファイルの結合
# 結合結果は /css/default.css
###
gulp.task 'concat-css', '主要cssファイルの結合', ->
  gulp.src config.default
    .pipe plumber()
    .pipe autoprefixer
      browsers: config.browsers
    .pipe concat 'default.css'
    .pipe gulp.dest config.export
    .pipe notify
      title: '出力完了'
      message: "<%= file.relative %>"

主要jsファイルの結合

cssと同様config.coffeeconcat_js.defaultconcat_js.scriptに設定している複数のjsファイルを、default.jsscript-all.jsまとめています。

自動監視タスクconcat-js:watchは、gulpfile.coffeedefaultへ登録してあります。gulpを実行しておけば、ファイルに更新があるたびに処理を実行してくれます。

gulp         = require('gulp-help')(require('gulp'))
plumber      = require 'gulp-plumber'
notify       = require 'gulp-notify'
autoprefixer = require 'gulp-autoprefixer'
concat       = require 'gulp-concat'
config       = require('../config').concat_js

###
# 主要JSファイルの結合
###
gulp.task 'concat-js', '主要jsファイルの結合', ->
  gulp.src config.default
    .pipe plumber()
    .pipe concat 'default.js'
    .pipe gulp.dest config.export
    .pipe notify
      title: '出力完了'
      message: "<%= file.relative %>"

  gulp.src config.script
    .pipe plumber()
    .pipe concat 'script-all.js'
    .pipe gulp.dest config.export
    .pipe notify
      title: '出力完了'
      message: "<%= file.relative %>"

# 自動監視のタスク
gulp.task 'concat-js:watch', 'concat-jsの自動監視タスク', ->
  watcher = gulp.watch config.file, ['concat-js']
  watcher.on 'add', (event) ->
  watcher.on 'change', (event) ->

sassをcssに変換・minify・gz圧縮

scssファイルをcssに変換し、autoprefixerを通してからminifyし、最終的にgzipで圧縮しています。
ファイルとして出力されるのは、

  • *.min.css
  • *.min.css.gz

の2種類です。
gulp-sass単体では@importを遡ってコンパイルしてくれないため、こちらの記事を参考にgulp-cachedgulp-ifgulp-foreachsass-graphの組み合わせで解決しました。

ただ、参考にした記事のコードでは現状動きません。どうやらlodashの更新があったとかで、_の認識が変わってしまったのかな……? あまり詳しくないのでよく分かりませんが。
Underscore.jsをrequireし、

graph.visitAncestors childPath, (parent) ->
  files.push(parent) unless _.includes(files, parent)

となっている部分を

_ = require 'underscore'
(…)
graph.visitAncestors childPath, (parent) ->
  files.push(parent) unless _.contains(files, parent)

と修正することで動くようになりました。

gulp-sass-lintのみを動かすタスクsass:lintは、別途単体で作成してあります。sassの実行時、まずはsass:lintを実行してから本処理を行うようになっています。
単体で作成するメリットとしては、ファイルを変換せずsass-lintだけを動かすことができます。結果はファイル出力するようにしてありますので、ブラウザなりエディタなりで中身を確認しながら修正作業が行なえます。

自動監視タスクsass:watchは、gulpfile.coffeedefaultへ登録してあります。
ようやくKoalaから解放されました。やったね! お世話になりました!

gulp         = require('gulp-help')(require('gulp'))
plumber      = require 'gulp-plumber'
notify       = require 'gulp-notify'
fs           = require 'fs'
sass         = require 'gulp-sass'
lint         = require 'gulp-sass-lint'
mmq          = require 'gulp-merge-media-queries'
autoprefixer = require 'gulp-autoprefixer'
cleanCss     = require 'gulp-clean-css'
rename       = require 'gulp-rename'
gzip         = require 'gulp-gzip'
config       = require('../config').sass

# https://qiita.com/joe-re/items/542b3f6fdc577cf50509
cached       = require 'gulp-cached'
grapher      = require 'sass-graph'
forEach      = require 'gulp-foreach'
gulpIf       = require 'gulp-if'
_            = require 'underscore'
gulp.watching = false

###
# *.scssの構文チェック・cssに変換・minify・gz圧縮
###
gulp.task 'sass', '*.scssの構文チェック・cssに変換・minify・gz圧縮', ['sass:lint'], ->
  graph = grapher.parseDir config.path
  gulp.src config.file
    .pipe cached 'sass'
    .pipe plumber()
    .pipe gulpIf(@watching, forEach (currentStream, file) ->
      files = [ file.path ]
      addParent = (childPath) ->
        # @import元をたどる
        graph.visitAncestors childPath, (parent) ->
          files.push(parent) unless _.contains(files, parent)
          addParent parent
      addParent file.path
      gulp.src files, { base: config.path }
    )
    .pipe sass()
    .pipe mmq()
    .pipe autoprefixer
      browsers: config.browsers
    .pipe cleanCss()
    .pipe rename
      suffix: '.min'
      extname: '.css'
    .pipe gulp.dest config.export
    .pipe notify
      title: '出力完了'
      message: "<%= file.relative %>"
    .pipe gzip()
    .pipe gulp.dest config.export
    .pipe notify
      title: '出力完了'
      message: "<%= file.relative %>"

###
# sass:lintを実行
###
gulp.task 'sass:lint', '*.scssの構文チェック', ->
  file = fs.createWriteStream config.lint.export
  stream = gulp.src config.file
    .pipe plumber()
    .pipe lint
      configFile: config.lint.config
      options:
        formatter: config.lint.formatter
    .pipe lint.format file
  stream.on 'finish', ->
    file.end()
  stream
  console.log 'Check Lint: [ ' + config.lint.export + ' ]'

# 自動監視のタスク
gulp.task 'sass:watch', 'sassの自動監視タスク', ['sass'], ->
  @watching = true
  watcher = gulp.watch config.file, ['sass']

*.stylをcssに変換

滅多に使わないのですが、Hexoのプロジェクト内でstylusの使われているファイルがあるため、一応作成しました。
出力するファイルはcssファイルの結合対象なので、ここではstylus→cssの変換のみを行っています。

gulp    = require('gulp-help')(require('gulp'))
plumber = require 'gulp-plumber'
notify  = require 'gulp-notify'
stylus  = require 'gulp-stylus'
config  = require('../config').stylus

###
# *.stylをcssに変換
###
gulp.task 'stylus', '*.stylをcssに変換', ->
  msg = ''
  gulp.src config.file
    .pipe plumber()
    .pipe stylus
      'include css': true # @importを展開する
    .pipe gulp.dest config.export
    .pipe notify
      title: '出力完了'
      message: "<%= file.relative %>"

*.coffeeをjsに変換

出力するファイルはjsファイルの結合対象なので、ここではcoffee→jsの変換のみを行っています。
自動監視タスクcoffee:watchは、gulpfile.coffeedefaultへ登録してあります。

gulp    = require('gulp-help')(require('gulp'))
plumber = require 'gulp-plumber'
notify  = require 'gulp-notify'
coffee  = require 'gulp-coffee'
cached  = require 'gulp-cached'
config  = require('../config').coffee

###
# *.coffeeをjsに変換
# 圧縮とかはjsの方でするので、ここでは変換するだけ
###
gulp.task 'coffee', '*.coffeeをjsに変換', ->
  gulp.src config.file
    .pipe cached 'coffee'
    .pipe plumber()
    .pipe coffee()
    .pipe gulp.dest config.export
    .pipe notify
      title: '出力完了'
      message: "<%= file.relative %>"

# 自動監視のタスク
gulp.task 'coffee:watch', 'coffeeの自動監視タスク',  ->
  watcher = gulp.watch config.file, ['coffee']

*.jsをminify・gz圧縮

jsファイルをminify(uglify)し、最終的にgzipで圧縮しています。
ファイルとして出力されるのは、

  • *.min.js
  • *.min.js.gz

の2種類です。
自動監視タスクjs:watchは、gulpfile.coffeedefaultへ登録してあります。

JavaScript周りの処理が複数ありますが、順序としては

  1. coffeeで _xxxxxx.coffee を _xxxxxx.js に変換
  2. concat_jsで 複数の _xxxxxx.js を xxxxxx.js に結合
  3. jsで xxxxxx.js から xxxxxx.min.js と xxxxxx.min.js.gz を作成

となっています。
js_のついていないファイル & 末尾が.min.js(= minify済み)でないファイルが対象になるよう、config.coffeeで設定しています。この辺をちゃんとしておかないと処理がループしてしまうので、注意が必要です。

gulp    = require('gulp-help')(require('gulp'))
plumber = require 'gulp-plumber'
notify  = require 'gulp-notify'
uglify  = require 'gulp-uglify'
rename  = require 'gulp-rename'
gzip    = require 'gulp-gzip'
config  = require('../config').js

###
# *.jsをuglify・minify・gz圧縮
###
gulp.task 'js', '*.jsをuglify・minify・gz圧縮', ->
  gulp.src config.file
    .pipe plumber()
    .pipe uglify()
    .pipe rename
      suffix: '.min'
    .pipe gulp.dest config.export
    .pipe notify
      title: '出力完了'
      message: "<%= file.relative %>"
    .pipe gzip()
    .pipe gulp.dest config.export
    .pipe notify
      title: '出力完了'
      message: "<%= file.relative %>"

# 自動監視のタスク
gulp.task 'js:watch', 'jsの自動監視タスク', ->
  watcher = gulp.watch config.file, ['js']
  watcher.on 'add', (event) ->
  watcher.on 'change', (event) ->

画像の圧縮・サムネイル作成・アイキャッチ画像作成

圧縮処理と画像のリサイズ処理は、こちらの記事を参考にしました。

gulp        = require('gulp-help')(require('gulp'))
plumber     = require 'gulp-plumber'
notify      = require 'gulp-notify'
filelog     = require 'gulp-filelog'
newer       = require 'gulp-newer'
imageResize = require 'gulp-image-resize'
imagemin    = require 'gulp-imagemin'
mozjpeg     = require 'imagemin-mozjpeg'
pngquant    = require 'imagemin-pngquant'
config      = require('../config').images

###
# 画像ファイルの圧縮
# http://alice37.hatenablog.com/entry/2018/07/12/002204
# 本処理の前にサムネイル生成処理('thumbnail')を実行する
# ついでに画像サイズを
# config.compress.width / config.compress.height
# にリサイズしている
###
gulp.task 'images', '画像ファイルの圧縮', [
  'images:thumbnail'
  'images:eyecatch'
], ->
  config.folders.map (folder) ->
    source_path = folder.path.replace '/images/', '/_images/'

    gulp.src source_path + config.image_type
      .pipe plumber()
      .pipe newer folder.path
      .pipe imageResize config.compress
      .pipe imagemin [
        imagemin.gifsicle()
        mozjpeg quality: config.mozjpeg_quality
        pngquant()
        imagemin.svgo()
      ], verbose: true
      .pipe imagemin()
      .pipe gulp.dest folder.path
      .pipe filelog()
      .pipe notify
        title: '出力完了'
        message: "<%= file.relative %>"

###
# 画像のサムネイル作成
# https://whiskers.nukos.kitchen/2014/12/16/gulp-image-resize.html
###
gulp.task 'images:thumbnail', '画像ファイルを元にしたサムネイル作成', ->
  config.folders.map (folder) ->
    if folder.size > 0
      resize_options = 
        width: folder.size
        height: folder.size
        imageMagick: config.thumbnail.imageMagick
      source_path = folder.path.replace '/images/', '/_images/'

      gulp.src source_path + config.image_type
        .pipe plumber()
        .pipe newer folder.path + 'thumbnail/'
        .pipe imageResize resize_options
        .pipe imagemin config.imagemin_options
        .pipe gulp.dest folder.path + 'thumbnail/'
        .pipe filelog()
        .pipe notify
          title: '出力完了'
          message: "<%= file.relative %>"
, aliases: [ 'thumb', 'thumbnail' ]

###
# アイキャッチ画像の作成
###
gulp.task 'images:eyecatch', '画像ファイルを元にしたアイキャッチ画像作成', ->
  config.folders.map (folder) ->
    # 特定のサイトはアイキャッチ画像いらない
    if !/hexo-project-2/.test(folder.path) and folder.size > 0
      source_path = folder.path.replace '/images/', '/_images/'

      gulp.src source_path + config.image_type
        .pipe plumber()
        .pipe newer folder.path + 'eyecatch/'
        .pipe imageResize config.eyecatch
        .pipe imagemin config.imagemin_options
        .pipe gulp.dest folder.path + 'eyecatch/'
        .pipe filelog()
        .pipe notify
          title: '出力完了'
          message: "<%= file.relative %>"
, aliases: [ 'eye', 'eyecatch' ]

フォントのサブセット化・woff圧縮・woff2圧縮

gulp-fontminだとotfファイルを対象にできないので、fonttoolsのライブラリであるpyftsubsetをgulp-execで呼んでいます。詳細については過去の記事をどうぞ。

gulp-fontminを使った処理も、一応残してあります。
本家gulp-fontminだと個人的に不要なeot・svg・cssまで出力されてしまうため、私はforkしていらない部分を削ったものを使用しています。

テキスト内の日本語を抽出する手順・gulp-fontminを使ったwoffファイルの作成については、こちらの記事を参考にしました。

gulp      = require('gulp-help')(require('gulp'))
plumber   = require 'gulp-plumber'
notify    = require 'gulp-notify'
fs        = require 'fs'
rename    = require 'gulp-rename'
gzip      = require 'gulp-gzip'
gexec     = require 'gulp-exec'
exec      = require('child_process').exec
fontmin   = require 'gulp-fontmin'
ttf2woff2 = require 'gulp-ttf2woff2'
config    = require('../config').font

###
# pyftsubsetを使ってフォントのサブセットを作成し、woffとwoff2に変換する
# gulp font --type level2
#
# タイトルのみ・限界まで削ったバージョン  ./_fonts/subset-mini.txt
# Hexoのポストで使われている文字          ./_fonts/subset-text.txt
# 第一水準までの漢字                      ./_fonts/subset-level1.txt
# 第二水準までの漢字                      ./_fonts/subset-level2.txt
# 
# renameコマンドは brew install rename しないと入ってないよ
###

###
# 指定したファイルからサブセット対象文字データを取得し、
# 基本のテキストを追加した状態で返す
###
getSubsetText = (filename) ->
  ascii = "\\'\\!\\\"#$%&\\(\\)*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_\\`abcdefghijklmnopqrstuvwxyz\\{|\\}~"
  kana = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789ぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろわゐゑをんァアィイゥウェエォオヵカガキギクグヶケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロワヰヱヲンヴ、。、。,. ・:;?!゛゜´`¨^ ̄_ヽヾゝゞ〃仝々〆〇ー―‐/\~∥|…‥‘’“”〔〕〈〉《》「」『』【】+-±×÷=≠<>≦≧∞∴♂♀°′″℃¥$¢£%#&&*@@§☆★○●◎◇◆□■△▲▽▼※〒→←↑↓∀∃∠⊥⌒∂∇≡≒≪≫√∽∝∵∫∬ʼn♪†‡¶―—﹅"
  data = fs.readFileSync filename, encoding: 'utf-8'
  all = ascii + kana + data.toString().split('\n').join('')
  all # return

gulp.task 'font', 'pyftsubsetを使ってフォントのサブセットを作成し、woffとwoff2に変換する', ->
  options =
    continueOnError: false
    pipeStdout:      false
  reportOptions = 
    err:    false
    stderr: true
    stdout: true
  txt = getSubsetText './_gulp/fonts/subset-' + config.args.type + '.txt'
  cmd_woff = "pyftsubset <%= file.path %>" +
             " --text=\"" + txt +
             "\" --layout-features='*'" +
             " --flavor=woff"
  cmd_woff2 = "pyftsubset <%= file.path %>" +
              " --text=\"" + txt +
              "\" --layout-features='*'" +
              " --flavor=woff2"

  # textの場合は、実行前にmake-textでサブセット用文字データを作成する
  if config.args.type is 'text'
    gulp.run 'font:make-text'

  gulp.src config.font.path + '/*.*'
    .pipe plumber()
    .pipe gexec cmd_woff, options
    .pipe gexec cmd_woff2, options
    .pipe gexec 'rename s/.subset/-' + config.args.type + '/ ' + config.font.path + '/*.subset.*', options
    .pipe gexec 'mv ' + config.font.path + '/*.woff* ' + config.font.dest, options
    .pipe gexec.reporter reportOptions
    .pipe notify
      title: '出力完了'
      message: "<%= file.relative %>"
, options:
  'type': 'フォントの出力タイプ (level1, level2, mini, text)'

###
# Hexoのポストからサブセット用テキスト一覧を作成
# ./_fonts/subset-text.txt
# https://christina04.hatenablog.com/entry/2017/04/12/002333
###
gulp.task 'font:make-text', 'Hexoのポストからサブセット用テキスト一覧を作成', (cb) ->
  exec 'find ' + config.font.text_posts + ' -name *.md | xargs grep -dskip -o -h -e "[亜-熙ぁ-んァ-ヶ]" | sort | uniq > ./_gulp/fonts/subset-text.txt', (err, stdout, stderr) ->
    console.log stdout
    console.log stderr
    cb err
, aliases: [ 'make-text' ]

###*************************************************
# 以下、gulp-fontmin を使ったバージョン
# gulp fontmin --type level2
#
# gulp-fontminは
# npm install seeque/gulp-fontmin
# にforkしたものを使用
# 対象となるフォントファイルはttfのみなので注意
#
# https://github.com/ecomfe/fontmin
# https://github.com/ecomfe/gulp-fontmin
# https://christina04.hatenablog.com/entry/2017/04/12/002333
###
gulp.task 'font:fontmin', 'gulp-fontminを使ってフォントのサブセットを作成し、woffとwoff2に変換する', ->
  # textの場合は、実行前にmake-textでサブセット用文字データを作成する
  if config.args.type is 'text'
    gulp.run 'font:make-text'

  file = "<%= file.path %>"
  console.log file

  gulp.src config.font.path + '/*.ttf'
    .pipe plumber()
    .pipe fontmin
      text: getSubsetText './_gulp/fonts/subset-' + config.args.type + '.txt'
    .pipe rename
      suffix: '-' + config.args.type
    .pipe notify
      title: '出力完了'
      message: "<%= file.relative %>"
    .pipe gzip()
    .pipe gulp.dest config.font.dest
    .pipe notify
      title: '出力完了'
      message: "<%= file.relative %>"

  gulp.src config.font.path + '/*.ttf'
    .pipe plumber()
    .pipe fontmin
      text: getSubsetText './_gulp/fonts/subset-' + config.args.type + '.txt'
    .pipe rename
      suffix: '-' + config.args.type
    .pipe ttf2woff2()
    .pipe gulp.dest config.font.dest
    .pipe notify
      title: '出力完了'
      message: "<%= file.relative %>"
    .pipe gzip()
    .pipe gulp.dest config.font.dest
    .pipe notify
      title: '出力完了'
      message: "<%= file.relative %>"
, options:
  'type': 'フォントの出力タイプ (level1, level2, mini, text)'
, aliases: [ 'fontmin' ]

メンテナンスが非常に楽になりました

CoffeeScriptの採用と処理ごとにファイル分割したことで、かなり見通しが良くなりました。新しく処理を追加する場合も、ファイルを増やせばいいのでらくちん。
ヘルプテキストもきっちり設定しましたので、うっかり忘れても安心です。

コメント

© 2018 chlono