gulpでSVGをWebフォント化する

YuG1224/gulp-task-svg-webify

Web フォント化するためにIcoMoonに SVG をアップロードするのが面倒なので、SVG 画像を minify して、Web フォント化する gulp タスクを作りました。

参考にしたのはここ。

[Gulp][Sketch 3][SketchTool]これからはじめるGulp(23):gulp-consolidateでgulp-iconfontで作ったアイコンフォントのシンボル一覧HTMLを作る

UI/UX Design、フロントエンド系について学習した内容をメモしています。

構造

全体の構造は以下。

src/svg/以下に SVG 画像を置けば、dist以下に生成される仕組みになっています。

.
├── README.md
├── dist
│   ├── css
│   ├── fonts
│   ├── index.html
│   └── svg
├── doc
├── gulpfile.coffee
├── node_modules
├── package.json
└── src
    ├── svg
    ├── template.css
    └── template.html

gulp minify

svg の minify にはgulp-svgminを使います。

./src/svg/以下に置いた SVG を圧縮して、./dist/svg/以下に出力します。

gulp = require "gulp"
foreach = require "gulp-foreach"
svgmin = require "gulp-svgmin"
concat = require "gulp-concat"

# minify
gulp.task "minify", () ->
  return gulp.src ["src/svg/*.svg"]
    .pipe foreach (stream, file) ->
      filename = file.path.replace file.base, ""
      stream.pipe svgmin()
        .pipe concat filename
    .pipe gulp.dest "dist/svg"

gulp webify

minify した SVG を元にgulp-iconfontgulp-consolidateで webfont 化します。

template 用の css と html はcognitom/symbols-for-sketchにある template を自分が好きな Handlebars 形式に改変して使わせて頂きました。

Web フォント化した時にデフォルトでは Unicode の私用領域の最初 E001 から埋めていくのですが、SoftBank の絵文字と衝突してしまい環境によっては正しく表示されなくなります。

携帯電話の絵文字 - Wikipedia

文字コードは、多くの事業者で Shift_JISもしくは Unicodeの空き領域に2バイトのコードを割り当てて使用している(従って 外字の一種)。ただし SoftBank(Yahoo!ケータイ)ではShift_JISの場合に特殊な エスケープシーケンスを用いて文字を表記する方式であり、 au (EZWeb) では HTMLの タグを独自に拡張した表記法もある。このほか、HTMLの数値文字参照の形で文字コードを十進数もしくは十六進数で記述する方法もあるが、機種によって絵文字が表示できない場合もある。当初はISベースのコードのみでの対応であったが、その後 Unicode の外字にマッピングした絵文字も利用されるようになった。

スマホ利用もあると考えて、options.startCodepoint0xF001にしてみました。

gulp = require "gulp"
foreach = require "gulp-foreach"
iconfont = require "gulp-iconfont"
consolidate = require "gulp-consolidate"
concat = require "gulp-concat"
rs = require("run-sequence").use(gulp)

options =
  fontName: "webfont"
  className: "wf"
  startCodepoint: 0xF001

# webify
gulp.task "webify", () ->
  return gulp.src ["dist/svg/*.svg"]
    .pipe iconfont options
    .on "codepoints", (codepoints, options) ->
      for val in codepoints
        val.codepoint = val.codepoint.toString(16).toUpperCase()
      engine = "handlebars"
      consolidateOptions =
        glyphs: codepoints,
        fontName: options.fontName
        fontPath: "../fonts/"
        className: options.className

      gulp.src "src/template.css"
        .pipe consolidate engine, consolidateOptions
        .pipe concat "#{options.fontName}.css"
        .pipe gulp.dest "dist/css/"

      gulp.src "src/template.html"
        .pipe consolidate engine, consolidateOptions
        .pipe concat "index.html"
        .pipe gulp.dest "dist/"

    .pipe gulp.dest "dist/fonts/"

gulp webserver

SVG を編集しながら、生成された Web フォントをブラウザで確認するために、webserver のタスクも作りました。

src/svg/*.svgの変更を監視して minify,webify が実行され、distの変更を監視して livereload 機能が動きます。

debug画面

gulp = require "gulp"
del = require "del"
rs = require("run-sequence").use(gulp)
webserver = require "gulp-webserver"

# watch
gulp.task "watch", () ->
  gulp.watch ["src/svg/*.svg"], () ->
    rs "clean", "minify", "webify"

# webserver
gulp.task "webserver", ["compile", "watch"], () ->
  gulp.src "dist"
    .pipe webserver
      livereload: true

# clean
gulp.task "clean", (done) ->
  del ["dist/*/*"], done

# initialize
gulp.task "initialize", (done) ->
  del ["dist"], done

# compile
gulp.task "compile", (done) ->
  rs "initialize", "minify", "webify", done

まとめ

$ gulp compile    // minify, webify を1回のみ実行
$ gulp webserver  // 変更を監視して、minify, webify を実行し、ブラウザ画面を自動更新

途中、gulp-iconfontが最低 500x500 以上の SVG が対象ということに気づかず、Web フォントが崩れてしまう現象にハマった。

素材が 500x500 以上というのが気になるけれど、ひとまずこれで IcoMoon にアップしなくてもローカル環境で Web フォント化することが出来るようになった。