middleman-blogで記事毎に画像を管理する方法

middleman

Middlemanで記事内で使う画像をサイト全体の画像のディレクトリに入れて管理すると、どの記事に関連した画像かわかりにくくなってしまいます。記事毎に画像を管理できたら便利です。

directory_indexesを有効にできない?

dierctory_indexesを有効にしない場合の管理方法

dierctory_indexesを有効にしない場合は、以下のサイトの説明通りにやればうまくいきそうです。

初めてのMiddleman:Middleman-Blogで記事毎に画像を管理する方法

dierctory_indexesを有効にすると起こる問題

有効にした場合、上記のサイトの方法だと適切な画像なパスが出力されません。公式ドキュメントのこの部分には以下のように書いてあります。

記事のサブディレクトリ

ブログ記事に紐付いた拡張子なしのサブディレクトリは, ビルド時に 正しい場所へ複製されたファイルが入っています。 例えば, 次のディレクトリ構造です:

1
2
3
source/2011-10-18-middleman.html.markdown
source/2011-10-18-middleman/photo.jpg
source/2011-10-18-middleman/source_code.rb

この出力 (directory_indexes が有効化された場合) は次のようになります:

1
2
3
build/2011/10/18/middleman/index.html
build/2011/10/18/middleman/photo.jpg
build/2011/10/18/middleman/source_code.rb

単一のブログ記事に属しているファイル (例えば画像) は source 内で一緒に保管し出力することができます。ブログ構造に依存し,記事の中で相対リンクの使用を可能にしますが, 記事の内容がサイトの他の部分, 例えばカレンダーやタグページ, で使われる場合には注意が必要です。

ブログ記事から記事のサブディレクトリにあるものにリンクしたい場合,ディレクトリ名を含むことに注意してください:

1
2
Wrong: [私の写真][photo.jpg]
Right: [私の写真][2011-10-18-middleman/photo.jpg]

この方法で動作するはずですが, :asset_hash のようなその他の Middleman の機能では動作しません。 詳細についてはこのissueを確認してください。

directory_indexexを有効にした場合は、:asset_hasが動かない上に、サブディレクトリ名を指定しなければならないということです。

なので、公式マニュアルはこの部分で、以下のような対処法を提示しています。

アセットパスに関する注意事項

ディレクトリインデックスを有効化する場合, 画像ファイル名だけで アセットファイルの呼び出し (例: 画像ファイル) を行うと失敗します。次のように完全な抽象パスを使って呼び出す必要があります:

1
![すごい画像](/posts/2013-09-23-some-interesting-post/amazing-image.png)

わずかにこのプロセスを自動化するには, Markdown をまずは ERB で作成します。 例えば /posts/2013-09-23-some-interesting-post.html.markdown.erb ファイルがあるとします:

1
![すごい画像](<%= current_page.url %>some-image.png)

つまり、この対処法はerbを使わなければならない上に、:asset_hashが動かない問題は解決していません。

Markdown内にerbの余計なコードを書かなければいけないし、.html.markdown.erbという風に拡張子が長くなり見づらくなります。

また、:asset_hashが使えないと、画像を差し替えたにもかかわらず、ユーザ側が再訪問しても古い画像をブラウザのキャッシュから表示してしまう危険性があります。

directory_indexesを有効にしつつ記事毎に画像を管理する方法

ディレクトリ構成

試行錯誤した結果、source内の記事と画像ファイルをあるディレクトリ構成にすると可能になることがわかりました。以下はこのサイトのディレクトリ構成です。

1
2
3
4
5
6
7
8
9
10
11
source
    └─ articles
            └─ 2015-11
                     └─ 14-sample-article
                                           ├── images
                                           │         ├── sample01.jpg
                                           │         ├── sample02.jpg
                                           │         ├── sample03.jpg
                                           │         ├── sample04.jpg
                                           │         └── sample05.png
                                           └── index.html.md

動作させるためのポイント

これと全く同じ構成しなければならないわけではなく、抑えるべきポイントは2つです。

  • 記事タイトルが入ったディレクトリ内にindex.html.mdを入れます。(私の場合は{日付}-{タイトル}というディレクトリにしています。)
  • 画像も同じディレクトリにいれます。(お好みで画像専用のディレクトリ作ってもOKです。)

ディレクトリがすっきり見やすいという副次効果も

前述した公式ドキュメントの対処法のディレクトリ構成だと、同じ階層に記事ファイルと同じ名前のディレクトリが必要になり、項目が多くなりみずらくなります。こちらの構成だと、1つのディレクトリに記事ファイルも画像もまとめることができ、項目が少なくなりすっきり見やすくなります。

Markdown内での書き方

このようにindex.html.mdからの相対パスを書くだけで、よしなにパスを生成してくれます。もちろん:asset_hashのハッシュ値がついたファイル名になって生成されます。

1
![サンプルの画像](sample01.jpg)

build時の画像の配置先が変わる

特に作業が変わるわけではないので意識する必要はないのですが、1つ変化することがあるので、記載しておきます。

前述した公式マニュアルでの対処法だと、middleman buildを実行したらbuild/{記事のURL}/配下に画像ファイルが配置されます。

ですが、この記事で紹介している方法だと、source内のディレクトリ構成でそのまま画像がbuild配下にコピーされます。なので、上記の例だとbuild/articles/2015-11/14-sample-article/に画像が配置されます。

上記のMarkdownの書き方できちんとこのパスを生成してくれます。

config.rbの設定

微細な差異でこの方法が動作しなくなる可能性もあるので、このサイトのconfig.rbをシェアします。(コメントは削除しています)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
activate :blog do |blog|
  blog.permalink = "{title}"
  blog.sources = "articles/{year}-{month}/{day}-{title}/index.html"
  blog.layout = "article"
  blog.default_extension = ".md"

  blog.tag_template = "tag.html"
  blog.calendar_template = "calendar.html"

  blog.paginate = true
  blog.per_page = 10
  blog.page_link = "page/{num}"
  blog.custom_collections = {
    category: {
      link: '/categories/{category}/index.html',
      template: 'category.html'
    }
  }
  blog.new_article_template = "article.erb"
end
activate :directory_indexes

page "/feed.xml", layout: false

activate :livereload

set :css_dir, 'stylesheets'
set :js_dir, 'javascripts'
set :images_dir, 'images'
set :partials_dir, 'partials'
set :trailing_slash, true
set :markdown_engine, :kramdown
set :markdown, input: "GFM"
activate :i18n, mount_at_root: :ja

activate :dotenv
activate :syntax, line_numbers: true
activate :asset_hash

configure :build do
  activate :minify_html
  activate :minify_css
  activate :minify_javascript
end

activate :deploy do |deploy|
  deploy.method   = :ftp
  deploy.host     = ENV['HOST']
  deploy.path     = '/webfood'
  deploy.user     = ENV['USERNAME']
  deploy.password = ENV['PASSWORD']
end
  • middlemanのバージョン : 3.4.0
  • middleman-blogのバージョン : 3.6.0.beta.2

まとめ

Middlemanは細かな挙動はドキュメントだけだとわからないので、一つ一つ実験していかなければならないのがつらいところです。

とはいえ、これで記事ごとに画像を管理することができ、directory_indexes:asset_hashを使え、より管理しやすい構成になります。参考にして頂ければと思います。

参考

羊毛や小麦