Middleman + SinatraでALOHA FISHMANSのサイトをリニューアルしました

  • 2014年3月 9日 03:31
  • ruby

去年の秋頃、友人経由で、Fishmansファンのためのイベント「お彼岸ナイト」を開催しているALOHA FISHMANSの人たちを紹介してもらったのですが、何か僕で手伝えることがあれば、、というわけでサイトのフルリニューアルを手伝わせていただきました。

今回利用した技術としては

フロントエンド

バックエンド

インフラ

コード管理

  • github(のプライベートレポジトリ)

な、感じ。

今回、このリニューアルでいろいろハマったところや工夫できたことがあったので、もろもろまとめたいと思います。

CSSフレームワーク

以前のサイトは、PCでの閲覧のみ意識していたような作りになっていたので、スマホ(というかタッチデバイス)への対応が一番の要件でした。

さて、じゃぁレスポンシブ対応のCSSフレームワークを選ぶか、、と思って選定に入りました。検討したのはこんな感じ。

CSSフレームワークは似たものが乱立していてさてどうするか。。と思ったのですが、こんな基準で選びました。

  1. サイズが小さい
  2. スマートフォンに最適化されたUIが標準で用意
  3. フレームワークに依存したマークアップを強要されない

Bootstrapは1.が引っかかってやめました。あと、デフォルトの見た目が「いかにも」な感じになるのでもうちょっとシンプルで単純なスタイルが欲しかったこともあって利用はヤメ。

Foundationは全体的にバランスがいいのですが、メニューまわりのマークアップがちょっと複雑なので保留に。最終的には利用することにしたのですが、正直いまだにメニューまわりにクセがある印象なので、そんなに強くオススメできません。。

Skeltonはシンプルでいいんだけども2の観点で見ると、自分でスタイルいじるのは最低限に抑えたかったので、全然スマホサイトっぽい感じがしなかったのでヤメ。

HTML KickStartはすごく単純なマークアップで一番最初は利用していたのですが、メニューまわりのデフォルトの見た目がまったくスマホサイトっぽくない感じだったので途中でヤメました。

Pureはフォント周りのスタイルは一番好きなのですが、マークアップにpure-*とフレームワーク依存のclassやdata属性を強要されるのがどうにもシックリこなかったのでヤメ。

ベストなものは無い

これだけ乱立してるCSSフレームワークだから、さすがにグッとくるものがあるだろう。。と思い込んでたのですが、正直いまだにグッとくるものは見つかってません。。 Foundationを消去法的に利用しましたが、デフォルトのリストUIの見た目はあまりグっとこなかったので、結局いろいろベースとなるスタイルは自分で用意しました。

たとえばクックパッドで利用しているSaraフレームワークは、このへん見た目的にもマークアップ的にも、相当使いやすくなっていると実感できたので、SaraがOSSで公開されてれば。。(チラッチラッ)と何度も思った次第です。

そう考えると、これだけCSSフレームワークが乱立するのもやはり一周回って理解できるわけで、みんな痒いところに手を届かせるために「俺の考えた最強CSSフレームワーク」を作ろうとするんでしょうね。。

middleman

フロントエンドの基盤はmiddlemanにするのは最初から決めていました。

オリジナルのサイトはベースはPHPで実装されていて、チケット管理ページなど動的ページが一部あるものの、ユーザに見える部分はほぼ全てのページが静的な情報なため、PHPのメリットはレイアウトをDRYに書ける、というところに留まっていそうでした。

middlemanは最終的に静的なページを出力しつつ、

  • haml/slimなどのテンプレート言語
  • assetパイプライン
  • LiveReload

などのツールがすぐ使えるので、最近のRailsで開発するような感覚で開発を進めることができるのが大きなメリットです。

実際今回触った感想としてmiddlemanは大正解でした。今後も数ページだけのサイトだったらmiddlemanを利用しない理由は無いんじゃないかな、と言えそうです。1点を除いては。。

Sinatra

1点を除いては、と言ったのは動的なページが出てきたときの対応です。

middlemanはそもそも静的サイトジェネレータなので、動的なページなんて入れようとするほうが悪いのですが、いかんせん必要なものは必要です。今回もイベントのチケット予約に1ページだけ必要でした。

ロジックはシンプルなのでSinatraで完結できれば。。と安易に思っていたのですが、いかんせん事例がほとんどありません。milddeman公式サイトにももちろん載っていません。

で、おそらく唯一であろうヒントはmiddleman作者のThomasさんのコードの断片。要するにconfig.rbに特定のパスだけSinatra::Baseにリクエストを処理させる方法です。

「開発時はいいけどリリース時はproduction環境にどうやって載せるんや。。。」と悩んでたのですがnginxで特定のパスへのリクエストだけUnicorn(で動かしたSinatra)へリクエストを流すようにすればなんとかなりそうかも?と思ってトライ。このへんのインフラ全然触ったことなかったのでハマりましたが、なんとかかんとかできました。

ディレクトリ構造

開発時はこんな感じにしてます。

  • build (ビルドしてできる静的HTMLファイル)
  • app (Sinatraなんかの動的な処理をまとめ)
    • config.ru (production用、開発時は使わない)
  • source (静的ページの開発)
  • config.rb (Sinatraの設定)

middleman buildするとminifyやgzip化されたHTMLファイルがbuildディレクトリにできるので、リリース時はこの中身をまるっとrsync。nginxも基本このファイルを直接返します。

appはSinatraの実態。たとえばこんなかんじ。

app/ticket_reservation.rb

require 'sinatra'
require 'active_record'
require 'mysql2'
require_relative 'models/ticket'

config = YAML.load_file('./database.yml')
ActiveRecord::Base.establish_connection(config["db"]["development"])

class TicketReservation < Sinatra::Base
  post '/reserve' do
    ...
    redirect '/events/reserved'
  end
end

こいつをconfig.rbから呼び出しておく。

config.rb

require_relative 'app/ticket_reservation'

...

map '/tickets' do
  run TicketReservation
end

これで、middleman serverで手元でサーバを起動すると/ticketsのリクエストだけSinatraでハンドリングすることができます。

app/config.ru

開発時は利用しないのですが、productionではUnicornで利用するために必要です。プロセスの再起動はいい感じのタイミングにお願いしたいので、unicorn-worker-killerに任せてます。(設定はデフォルトのまま...)

require_relative 'ticket_reservation'

# Unicorn self-process killer
require 'unicorn/worker_killer'

# Max requests per worker
use Unicorn::WorkerKiller::MaxRequests, 3072, 4096

# Max memory size (RSS) per worker
use Unicorn::WorkerKiller::Oom, (192*(1024**2)), (256*(1024**2))

# Run main app
run TicketReservation

production環境

こんなかんじのディレクトリツリーにしてます。

  • alohafishmans.com
    • app
    • public

リリース時は

  • build ⇛ public
  • app ⇛ app

へrsyncして、appのコードを変更したときのみUnicornを再起動させています。

nginx

config.rbでの設定と同じような感じで設定します。/ticketsへのリクエストだけをUnicornを利用するようにします。こんなかんじ。

alohafishmans.com.conf

upstream unicorn_alohafishmans {
  server unix:/path/to/alohafishmans.com/app/tmp/sockets/unicorn.sock
  fail_timeout=0;
}

server {
  server_name alohafishmans.com;

  location ^~ /tickets/ {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://unicorn_alohafishmans/;
  }

  location / {
    root /path/to/alohafishmans.com/public;
  }
}

その他の問題

基本的な構成は以上なのですが、その他にも細かいとこにもいろいろハマりました。。一応メモがてら残しておきます。

濁点問題

今回ブログのコンテンツのURLを、SEOを意識してタイトルをパス名に入れたURLにしました。例えばこんな感じ。

これも実際は「3/22「お彼岸ナイトvol.8 2014春」まであと1ヶ月!!」ディレクトリと、その直下にindex.htmlを作っているだけですが、buildしてrsyncするとアクセスできず404が。 どうもディレクトリ名がバグっておかしなものになっている模様。。

日本語が悪い??と思いきや、アクセスできるページもある。1文字づつ削って、問題の切り分けをするとどうやら「まであと1ヶ月」の「で」が悪い模様(!)

なんだこりゃ。。。。と思いきやUTF8-Macのエンコーディングに起因する話な模様。解決策としてはrsyncを3系にバージョンアップして(brew install rsyncでOK)iconvオプションをつければ良い。

rsync --iconv=UTF-8-MAC,UTF-8 -avz build/ foo@bar:/path/to/alohafishmans.com/public

FacebookのLikeをすると「You like 404 Not Found」問題

Likeボタンはそれなりに何度も設置しているつもりなのですが、今回はogpの設定をして、DeveloperページのDebuggerで見て情報が正確に設定されているにもかかわらず。Likeするとダイアログに「You like 404 Not Found」が出る、という謎現象に悩まされました。

類似の話としてSEM pdxの記事で全く同じものがあったのですが、向こうでは「IPv6を無効にしたらどうにかなったよ」と言ってる一方、僕の方では無効にしても全く変化なし。

で、やっとこさ気づいたのですが元々のボタンを

.fb-like{ data: { layout: 'button_count', width: '130', href: CGI.escape(page_url) }}

にしていたのですがdata-hrefの指定がどうも間違っていいた模様。正解は

.fb-like{ data: { layout: 'button_count', width: '130', href: page_url }}

コレ。

日本語がパスに含まれてるのを気にしてURLエンコードしていたのですが、まさかそれが足を引っ張っていたとは。。。 (ドキュメント見てもURLエンコードについて特に何も書いて無さそうなのですが。。)

まとめ

久々にゼロの状態からインフラ、DB、アプリケーションの実装まで全部実装したのですが、いい勉強になりました。特にインフラ面は現職ではセットアップ周りを自分ですることはここ数年ほとんどなかったので、仕組みを理解するいい機会になったと実感しています。

また、middlemanは相当使いやすく便利な一方、少しでも凝ったことをしようとするとハマるポイントも割りとあるので、改めて別途エントリをまとめるなり、プラグイン系へ修正PR投げるなりして貢献したいと思います。

最後に、Fishmans好きな人はお彼岸ナイトもぜひぜひ遊びにきてください :)

関連広告

Trackbacks:0

TrackBack URL for this entry
http://blog.katsuma.tv/mt-tb.cgi/269
Listed below are links to weblogs that reference
Middleman + SinatraでALOHA FISHMANSのサイトをリニューアルしました from blog.katsuma.tv

Home > ruby > Middleman + SinatraでALOHA FISHMANSのサイトをリニューアルしました

Search
Feeds

Return to page top