「ウェブアプリ開発」と「ウェブ制作」って別のジャンルなのかなあ。主に受託のコーポレートウェブ制作を生業にしていると流行りのウェブアプリケーションフレームワーク的なものにあまり馴染めない。まるで別世界の出来事のようだ。これって何となくURLディスパッチに対する発想の違いな気がしたので、Mojoliciousのディスパッチャを豪快に差し替えて、ウェブ制作を「デプロイ」できるようにした。apache風のディスパッチャをMojoliciousに登録する「MojoX::Tusu」。
- リクエストパスはサーバーのディレクトリ階層を意味する。
- テンプレートもstaticファイルもpublic_htmlに突っ込む。
- server-parsedの対象は拡張子で決める。
- apacheのDirectoryIndexに相当する機能。
- apacheのErrorDocumentに相当する機能。
- otherのread権限のないファイルへのアクセスは403エラー。
- apacheを真似てディレクトリfooへのアクセスはfoo/にリダイレクトしてみた。
Mojoliciousルートにpublic_htmlを作り、手元にあったいくつかの静的サイトデータを突っ込んだところ、ビルトインサーバー, CGI, hypnotoad上で今までどおり動作しました。そして、PHPで言えば「AddType application/x-httpd-php .html
」としたのと似た状態になり、htmlファイル内の好きなところに動的コンテンツを挿入できるという訳です。ただし、念のため先に書いておくと、Mojoliciousの標準のテンプレート命名規則(index.html.epとか)がMojoX::Tusuの差し替えたディスパッチャの方針と合致しないため、今のところepやeplは使えません。epRendererあたりをそっくり差し替えれば行けそうですが、とりあえず僕のお気に入りのテンプレートエンジン「Text::PSTemplate」でお楽しみください。
MojoX::Tusuを用いたMojoliciousアプリは下記のようになります。とりあえずrouteは必要ありません。
use MojoX::Tusu;
use strict;
use warnings;
use base 'Mojolicious';
sub startup {
my $self = shift;
my $tusu = MojoX::Tusu->new($self);
}
URLディスパッチに関しては内部的に下記のようなことをやってます。リクエストパスがテンプレートの在り処を意味するという訳です。ちなみにname('')としているのはテンプレート名が空(/へのアクセス)のとき、自動生成されたroute名がテンプレート名になってしまうからなのです。
$app->routes
->route('/:template', template => qr{.*})
->name('')
->to(cb => sub {$_[0]->render(handler => 'tusu')});
URLディスパッチルールが昔ながらのルールに乗っ取っているので、mojolicious rootが必要な場合意外はテンプレート内にurl_forと書く必要はありません。デザイナーさんが使うオーサリングソフトとの親和性も高いです。リンクパスの表記を巡っては、ここ1年くらいhtmlのbaseタグを活用して乗り切ってきたのですが、いろいろ面倒を抱え込むことにもなってやめたという経緯もあります。なお、このデフォルトのrouteは初回のon_processフックで登録してるので、startup内でルートが登録されればそちらが優先されます。
ドキュメントルート。内部的にはこうです。
$app->static->root('public_html');
$app->renderer->root('public_html');
Mojoliciousのデフォルトディスパッチャはstaticファイルを先に存在確認するようになってます。テンプレートとstaticを同じディレクトリに詰め込むと、全てstaticとして扱われてしまうので、フロントディスパッチャを組み直しています。デフォルトでは.htmlと.htmと.xmlだけテンプレートとして処理し、それ以外はstatic。ただし、DirectoryIndexの適用やパーミッションのチェックなどをして、エラーを返したりもします。なお、スクリプトファイルがあるとソースが見えちゃうので、リバースプロキシなりhtaccessなりで排除しないといけません。
お問い合わせフォームを作りたくなったら、もちろんrouteを追加することもできます。
sub startup {
my $self = shift;
my $tusu = MojoX::Tusu->new($self);
my $r = $self->routes;
$r->route('/inquiry/')->via('post')->to(cb => sub {
})
}
ただし、MojoX::Tusu方式では、routeはあくまでディレクトリであって、inqueryコントローラーを意味しないってのは譲れないルールなのです。実際、/inquiry/へのアクセスの際には先ず/inquiry/index.htmlの存在確認がなされます。
public_html直下にindex.cgiを置いてCGIモードでも動かせます。その場合は
RewriteCond %{REQUEST_FILENAME} ((.(html|htm|xml))|/)$
RewriteRule ^(.*)$ index.cgi/$1 [QSA,L]
としておけば動くと思います。また、この場合、public_html内に既設のcgiやphpがあるとそのまま動くので、放っておきたい過去の遺物がある場合に便利です。
また、稼働中のサイトの一部のディレクトリにMojoX::Tusuを導入したい場合は、仮想的なドキュメントルートを作ってmojoliciousルートを跨ぎます。
RewriteEngine On
RewriteBase /path/to/root/
RewriteCond %{REQUEST_URI} ((.(html|htm|xml))|/)$
RewriteCond %{REQUEST_FILENAME} !index.cgi
RewriteRule ^(.*)$ public_html/index.cgi/$1 [QSA,L]
RewriteCond %{REQUEST_FILENAME} !index.cgi
RewriteCond %{REQUEST_FILENAME} !public_html
RewriteRule ^(.*)$ public_html/$1 [QSA,L]
とすれば、外からは/path/to/root/a/b.htmlと見える物が/path/to/root/public_html/index.cgi/a/b.htmlを指すようになる、はず。mod_rewriteはちょっと自身なし。
MojoX::TusuはhtmlファイルをText::PSTemplateを使ってレンダリングするので、こんな感じでHTMLを拡張できます。
<html>
<div>
<% include('copyright.html') %>
</div>
MojoX::Tusu(というかMojolicious)はテンプレートエラーをプリティに表示してくれるので、デザイナーさんでも作業しやすい。

あと、MojoX::Tusuは独自にプラグインとコンポーネントという仕組みも提供していて、いろいろ拡張できます。
つづく