- 読みやすいブログのために textlint したい
- それなら markdown で記事を書いて git で管理したい
- livereload でプレビューしつつ書き進められたら便利
今回のソース : getto-systems/blog : GitHub
CONTENTS
APPENDIX
html を livereload でプレビューする
まずコンテンツが表示されるとやる気が出るので、 web サーバーのセットアップから行う。
$ npm install --save-dev \ gulp \ gulp-server-livereload
public/ をドキュメントルートとしてポート 8000 で web サーバーを立てて、 livereload するように設定する。
var gulp = require("gulp"); var path = { root: "public/" }; gulp.task("livereload", function(){ gulp.src(path["root"]) .pipe( require("gulp-server-livereload")({ host: "0.0.0.0", livereload: true, open: true }) ); });
public/index.html に適当なファイルを置いて livereload するか確認する。
livereload 用のスクリプトは html か body タグを目印にして埋め込まれるので、 html か body タグを含める必要がある。
<!doctype html> <html lang="ja"> <body> <h1>Hello</h1> <p>world!!</p> </body> </html>
web サーバーを立ち上げてコンテンツを確認する。
$ gulp livereload
http://localhost:8000 にアクセスして、 public/index.html を編集した時にリロードされれば OK。
markdown を html に変換する
html の表示を確認したので、次は markdown を html に変換する。
$ npm install --save-dev \ gulp-plumber \ gulp-markdown
src/ 以下の .md ファイルを public/ 以下に html として変換するように設定する。
- gulp-plumber : 変換エラーとかの場合でも、 watch が停止しないようにする
var path = { root: "public/", md: "src/**/*.md" }; gulp.task("build", function(){ gulp.src(path["md"]) .pipe( require("gulp-plumber")() ) .pipe( require("gulp-markdown")() ) .pipe( gulp.dest(path["root"]) ); }); gulp.task("livereload", function(){ gulp.src(path["root"]) .pipe( require("gulp-server-livereload")({ host: "0.0.0.0", livereload: true, open: true }) ); gulp.watch(path["md"],["build"]); });
src/index.md に適当なファイルを作成する。
# Hello world!!
サーバーを再起動して http://localhost:8000 にアクセスして確認する。
$ gulp livereload
src/index.md を編集してみて、 html ができていれば OK。
この時点では、作成された html に body や html タグがないため、 livereload が効いていない。
layout をつけてブログの体裁を整える
markdown を html に変換するための構成は整えたが、レイアウトがないため、 livereload もできない。
レイアウトを整えて、さらにブログの CSS も適用したい。
$ npm install --save-dev \ gulp-front-matter \ gulp-layout \ jade
front-matter で markdown ファイルに追加した追加情報を取り出して layout に流すように設定。
gulp.task("build", function(){ gulp.src(path["md"]) .pipe( require("gulp-plumber")() ) .pipe( require("gulp-front-matter")({remove: true}) ) .pipe( require("gulp-markdown")() ) .pipe( require("gulp-layout")(function(file){ return file.frontMatter }) ) .pipe( gulp.dest(path["root"]) ); });
markdown に front-matter 用の情報を追加する。
- ファイルの先頭に追加
---で囲んで記述- yaml 形式
- layout : 必須。テンプレートファイルのパスを指定
- その他 : テンプレートファイルで使用するパラメータを記述
--- layout: template/hatena.jade title: Hello --- # Hello world!!
テンプレートを作成する。(今回作成したテンプレート全体は APPENDIX に掲載)
doctype html
html(lang="ja")
head
meta(charset="utf-8")
title= title
block meta
meta(name="viewport", content="width=device-width")
body
!= contents
http://localhost:8000 にアクセスして確認する。
$ gulp livereload
src/index.md を編集した時にテンプレートの通りに変換されれば OK。
textlint で校正する
$ npm install --save-dev \ textlint \ textlint-rule-preset-ja-technical-writing \ gulp-textlint
front-matter の追加情報を削除した後のコンテンツを校正するように設定する。
gulp.task("build", function(){ gulp.src(path["md"]) .pipe( require("gulp-plumber")() ) .pipe( require("gulp-front-matter")({remove: true}) ) .pipe( require("gulp-textlint")({formatterName: "pretty-error"}) ) .pipe( require("gulp-markdown")() ) .pipe( require("gulp-layout")(function(file){ return file.frontMatter }) ) .pipe( gulp.dest(path["root"]) ); });
textlint は .textlintrc から設定を読み込むようになっているので、 .textlintrc を作成する。
{ "rules": { "preset-ja-technical-writing": true } }
今回は textlint-rule-preset-ja-technical-writing を使うことにした。
ルールやフィルタなど、色々あるようなのでその辺りは後日調整していくことにする。
$ gulp livereload
http://localhost:8000 にアクセスして src/index.md を編集した時に textlint のログが出れば OK。
まとめ
これでとりあえず livereload でプレビューしながら markdown で記事を書いて textlint することができるようになった。
あとはブログを書きながら textlint の設定周りを見直して行こう。
参考資料
- これからはじめるGulp(10):deprecatedになっていたgulp-connectからgulp-webserverへ乗り換える : whiskers
- Markdownをgulpを使いutf-8でhtml出力する(styleも適用) : Qiita
- gulp で markdown から html と pdf を生成してみる : Qiita
- textlintで日本語の文章をチェックする : Web Scratch
- textlint-ja/textlint-rule-preset-ja-technical-writing : GitHub
npm install
$ npm init $ npm install --save-dev \ gulp \ gulp-front-matter \ gulp-layout \ gulp-markdown \ gulp-plumber \ gulp-server-livereload \ gulp-textlint \ jade \ textlint \ textlint-rule-preset-ja-technical-writing
.gitignore
/node_modules /public /tmp
- 生成された html は git の管理下には置かない
gulpfile
var gulp = require("gulp"); var path = { root: "public/", md: "src/**/*.md" }; gulp.task("build", function(){ gulp.src(path["md"]) .pipe( require("gulp-plumber")() ) .pipe( require("gulp-front-matter")({remove: true}) ) .pipe( require("gulp-textlint")({formatterName: "pretty-error"}) ) .pipe( require("gulp-markdown")() ) .pipe( require("gulp-layout")(function(file){ var params = file.frontMatter; var now = new Date; params["year"] = now.getFullYear(); params["month"] = now.getMonth() + 1; params["day"] = now.getDate(); return params; }) ) .pipe( gulp.dest(path["root"]) ); }); gulp.task("livereload", function(){ gulp.src(path["root"]) .pipe( require("gulp-server-livereload")({ host: "0.0.0.0", livereload: true, open: true }) ); gulp.watch(path["md"],["build"]); });
hatena.jade
doctype html
html(lang="ja")
head
meta(charset="utf-8")
block meta
meta(name="viewport", content="width=device-width")
link(rel="shortcut icon", href="https://cdn.image.st-hatena.com/image/favicon/7d002255cb0e4d23cfb606cb7389b8ae0a0b7b28/version=1/https%3A%2F%2Fcdn.mogile.archive.st-hatena.com%2Fv1%2Fimage%2Fshun-fix9%2F302460045853663223.jpg")
link(rel="icon", sizes="192x192", href="https://cdn.image.st-hatena.com/image/square/d9eb56e83fa4523b913ab7befea4071b11f6da72/backend=imagemagick;height=192;version=1;width=192/https%3A%2F%2Fcdn.mogile.archive.st-hatena.com%2Fv1%2Fimage%2Fshun-fix9%2F302460045853663223.jpg")
link(rel="stylesheet", type="text/css", href="https://cdn.blog.st-hatena.com/css/blog.css?version=f0b292df77a2318c6378b0b109796c5516eaa0af&env=production")
link(rel="stylesheet", type="text/css", href="https://blog.hatena.ne.jp/-/blog_style/10328537792368208553/c23573905a14dfd09e2cf281442a1fc65f9ca1a5")
body(class="page-index header-image-enable enable-top-editarea globalheader-off")
div(id="container")
div(id="container-inner")
header(id="blog-title", data-brand="hatenablog")
div(id="blog-title-inner", style="background-image: url('https://cdn-ak.f.st-hatena.com/images/fotolife/s/shun-fix9/20170811/20170811115417.png'); background-position: center -343px;")
div(id="blog-title-content")
h1(id="title")
a(href="/")
!= "げっとシステムログ"
h2(id="blog-description")
!= "WEB開発関連メモ"
div(id="content", class="hfeed")
div(id="content-inner")
div(id="wrapper")
div(id="main")
div(id="main-inner")
article(class="entry hentry js-entry-article date-first autopagerize_page_element chars-2800 words-200 mode-markdown entry-odd", id="entry-10328749687185662488")
div(class="entry-inner")
header(class="entry-header")
div(class="entry-date date first")
a(href="#", rel="nofollow")
time(pubdate)
span(class="date-year")
!= year
span(class="hyphen")
!= "-"
span(class="date-month")
!= month
span(class="hyphen")
!= "-"
span(class="date-day")
!= day
h1(class="entry-title")
a(href="#", class="entry-title-link bookmark")
!= title
div(class="entry-content")
!= contents
aside(id="box2")
div(id="box2-inner")
div(class="hatena-module hatena-module-search-box")
div(class="hatena-module-title")
!= "検索"
div(class="hatena-module-body")
form(class="search-form" action="#" method="get")
input(type="text", class="search-module-input", placeholder="記事を検索")
input(type="submit", value="検索", class="search-module-button")