Template::Toolkitでファイルのタイムスタンプを付加
Railsだとimage_tagを使えば画像ファイルの更新日時をくっつけて
<img src="foo.jpg?1234567890" />
みたいにしてくれて、画像が更新されればブラウザは画像をキャッシュしていても新しくリクエストしてくれたりする。で、Catalyst/Template::Toolkitだとどうやるんだろう?ってことで書いてみた。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package MyApp::View::Plugin::Ts; | |
=head1 MyApp::View::Plugin::Ts | |
imgタグのsrc属性値やlinkタグのhref属性値に対象のファイルの更新時刻を付加することで | |
ファイルの更新が行われた際にブラウザがキャッシュを捨てて再度リクエストすることを促すためのTTプラグイン | |
=cut | |
use strict; | |
use warnings; | |
use base qw/Template::Plugin/; | |
use Encode; | |
my %cached_timestamps = (); | |
=head1 imgタグ | |
=head2 Usage | |
[% USE Ts %] | |
[% Ts.img_tag('/static/images/logo.jpg') %] | |
=> <img src="/static/images/logo.jpg?12345678" /> | |
=cut | |
sub img_tag { | |
my ($self, $src, $alt) = @_; | |
return qq{<img src="@{[$self->ts($src)]}" alt="@{[$alt]}" />}; | |
} | |
=head1 CSS用linkタグ | |
=head2 Usage | |
[% USE Ts %] | |
[% Ts.css_link_tag('/static/css/style.css') %] | |
=> <link rel="stylesheet" type="text/css" href="/static/css/style.css?1234890" /> | |
=cut | |
sub css_link_tag { | |
my ($self, $href) = @_; | |
return qq{<link rel="stylesheet" type="text/css" href="@{[$self->ts($href)]}" />}; | |
} | |
=head1 タイムスタンプ付きURLパスを返す | |
=head2 Usage | |
[% USE Ts %] | |
[% Ts.ts('/static/images/logo.jpg') %] | |
=>'/static/images/logo.jpg?12345678' | |
[% Ts.image('/static/images/foo/bar.jpg') %] | |
=> '/static/images/foo/bar.jpg?12345678' | |
=cut | |
sub ts { | |
my ($self, $source) = @_; | |
my $timestamp = $self->_get_timestamp($source); | |
return $source . '?' . $timestamp; | |
} | |
sub _get_timestamp { | |
my ($self, $source) = @_; | |
my $timestamp; | |
if (defined $cached_timestamps{$source}) { | |
$timestamp = $cached_timestamps{$source}; | |
} else { | |
my $path = MyApp->config->{home} . '/root' . $source; | |
$timestamp = 86400 * (-M $path) + $^T; | |
$cached_timestamps{$source} = $timestamp; | |
} | |
return $timestamp; | |
} | |
1; |
これをlib/MyApp/Views/Pluginに置いて、MyApp::View::TTとかに書かれている__PACKAGE__->configに
PLUGIN_BASE => 'TclandSp::View::Plugin',
を追加して各テンプレートで
[% USE Ts %]
すれば、例えば
[% Ts.ts('/static/images/logo.jpg') %]
が
/static/images/logo.jpg?1234567890
になる。これをimgタグと組み合わせて
<img src="[% Ts.ts('/static/images/logo.jpg') %]" />
とかするといい。
以下メモ:
- -M演算子はperlのインタプリタが起動してからの相対日数を返すので、606024=86400をかけて、さらにインタプリタの起動した時刻$^Tを足し合わせることで絶対時間が得られる
- MyAppが入っちゃうのが残念。うまく回避したい。
- imgタグやlinkタグもまとめて出力してくれるメソッドも定義したけど、altやwidth、heightなんかも指定したくなったときに不便だなと思ってもっぱらTs.tsだけ使ってる。
- 複数テンプレートで共通で使うプラグインはPRE_PROCESSで呼んでるテンプレート中でまとめてUSEすると便利。
やっぱりフルスタックのRailsはデカいけど便利だ。