2010年6月アーカイブ

6/19 Hack-A-Thon。

| コメント(0) | トラックバック(0)

各paramをmt:varに突っ込んでテンプレートを動的にbuildするcgi。

plugins/Viewer/tmpl/example.tmpl の場合、

mt-viewer.cgi?blog_id=1&template=example

mt-viewer.cgi?blog_id=1&template=example&id=1

とすることでid=1のページ(エントリ)アーカイブ的なものを作ったり。

テンプレートの中身を

<$mt:include module="$template" blog_id="$blog_id"$>

とかすることで各ブログ/ウェブサイトのモジュールをテンプレートとして使えるようになります。

詳細はまたいずれ。お疲れさまでしたー(今頃ビール飲んでるんやろな...)。

MTIncludeは遅いのか?

| コメント(0) | トラックバック(0)

結論を先に書きます。遅くない。遅い場合についてもMTIncludeタグ自身の影響は些少。

MTのスタティック・パブリッシングにおける再構築とはつまりこういうことかと思います。

  1. テンプレートをロードしてコンテクストをセットする。
  2. 各タグ内で必要に応じてデータを取得したりコンテクストをセットし、
  3. ブロック(テンプレート)をコンパイルしてビルドしていく。
  4. この時インクルードされているテンプレート(モジュールやウィジェット)があればロードして展開する。

詳しくはlib/MT/Template/WeblogPublisher.pm (lib/MT/Template/Builder.pm とか、あと各テンプレートタグについては lib/MT/Template/ContextHandlers.pmなんか)を見れば理解できると思います。

さて、上記の4番目のロードとは、SQLを発行してデータベースからテンプレートを読み込むことを指します。SELECT * FROM `mt_template` WHERE template_blog_id=2 AND template_name='サイドバー' AND template_type='custom' みたいなやつです。

ですので、当然ながらフラット化されたテンプレートと比較すると遅くなる、重くなると思われがちで、一見この指摘は正しいように思えます。それがMTIncludeが重いといわれる原因でしょうか?

実際にやってみました。

  • 新規にMTをインストール。標準以外のプラグインはなし。
  • クラッシックウェブサイト以下にクラシックブログを作成。
  • このブログをエクスポートしたデータをインポート(エントリー数は588)。
  • ブログ記事の再構築を行う(5回計測。平均3分46.0秒)

3分43秒 / 3分44秒 / 3分48秒 / 3分49秒 / 3分46秒

さて、ブログ記事テンプレートの「サイドバー」モジュールをブログ記事テンプレートの該当箇所にそのまま貼付けて再構築を行いました。MTIncludeを使わないパターンです。結果...

3分55秒 / 3分53秒 / 3分49秒 / 3分47秒 / 3分51秒

変わんなかった(5回計測。平均3分49.2秒)。むしろ遅い?変わらないのはともかく遅くなった原因はわかんないです。が、まぁ誤差の範囲でしょう。

但し、以下の事実は知られていないかもしれないので書いておきます。

インクルードしているテンプレートモジュール(ウィジェット)のロードは1リクエストにつき1回だけ

具体的にはlib/MT/Template/ContextHandlers.pm の3598行目。MT::Requestにキャッシュされていない時だけロードされます。

ちなみに1リクエストというのは、mt.cgiへのリクエストです。MTのブログ記事の再構築は1度のリクエストで環境変数 EntriesPerRebuild の設定値(初期値は40)ずつ実行されます。40ファイル再構築後はリダイレクトして再び40ファイルの再構築を(これをエントリ数を40で割った回数分)繰り返すわけです。 588ファイルの再構築であれば、リクエストは15回です。EntriesPerRebuildの値を100にすればリクエストはわずか6回。つまり、テンプレートをロードするためのSQLのリクエストは100ファイルの再構築時にわずか(インクルードしているモジュールが1つあたり) 1   6 回です。

つまり、インクルードしていることの影響は些少といえます。

さて次。コンパイルです。ビルドする前にコンパイルします。MTIgnore云々の話はこのコンパイル時の話になります。計測のため(というか本当に速くなるんだったらいいなと思って)MTCompileCacheBlockというタグを作ってテストします。

sub _hdlr_compile_cache {
    my ( $ctx, $args, $cond ) = @_;
    require MT::Request;
    my $key = $args->{ key };
    my $id = "compile_cache_$key";
    my $r = MT::Request->instance;
    my $cache = $r->cache( $id );
    my $builder = $ctx->stash( 'builder' );
    my $tokens;
    if ( $cache ) {
        $tokens = $cache;
    } else {
        my $tmpl = $ctx->stash( 'uncompiled' ) || '';
        $tokens = $builder->compile( $ctx, $tmpl );
        $r->cache( $id, $tokens );
    }
    my $res = $builder->build( $ctx, $tokens );
    return $res;
}

テンプレートは以下のようにモジュールを囲む形で書きます。

<MTCompileCacheBlock key="sidebar">
    <$mt:Include module="サイドバー"$>
</MTCompileCacheBlock>

3分51秒 / 3分51秒 / 3分46秒 / 3分46秒 / 3分47秒

3分48.2秒。これも...誤差の範囲じゃないですか?

高速化云々の話をする時には「どこがツボ」かを考えないと無駄な努力に終わる可能性が高い。

ツボは何? そう、ツボは「ビルド」です。テンプレートキャッシュが有効なのはキャッシュした部分のテンプレートをビルドする処理を2回目以降スキップできるから劇的な効果が見込めるわけです。

では何故MTIncludeが重い(遅い)と(しばしば)指摘されるのか?

本当のところはわかりません。推測ですがおそらく「最近のブログ記事」とか「最近のコメント」等の相応に負荷のかかるブロックタグを利用したブロックがモジュール化されているからじゃないかという気がしますが。確かにそういった場合にキャッシュしていない場合に全体的に重くなることは事実で、でもそれはMTIncludeのせいではなくて各ページで共通の結果を出力する部分をキャッシュせずに処理していることが問題なわけです。MT3の頃だったか、モジュールをインデックス・テンプレートにして吐き出しておいてファイルとしてインクルードするようなTipsがあったかと思いますが、確かに劇的に効果的にはたらくケースもあります。

MT4(.xだったか記憶曖昧ですが)から実装されたテンプレートモジュールのキャッシュを使えば一定時間はビルドされずキャッシュが使われますからこれは効果があります。但し、再構築中に間違いに気づいてブログ記事を削除したりしたときに「最新のブログ記事」リストに削除したものが残ってしまうといった問題がないわけではないので、リクエスト毎にキャッシュを生成するようなプラグインなどはお手軽で、データベースでなくメモリへのキャッシュですので(最初の1回しか)クエリも発行されないといったメリットがあり劇的に軽量化できます。

ということで、フロントエンジニアの人はMTIgnoreもMTIncludeも積極的に使って可読性が高くメンテナビリティに優れたテンプレートを書くことに集中すれば良いと思うのです。思うのでした。

追記

モジュールをフラット化した状態でCompile結果をキャッシュして実測。

4分1秒 / 3 分52秒 / 以下省略

あとMTIgnoreタグで囲めば処理しないという幻想がまことしやかにささやかれていた時期がありましたが、
あいつ一旦タグの内容なめてからコメントアウトしてますから、処理時間はその分もかかりますよ。
不要な記述はMTIgnoreするのではなく、テンプレート上から削除しましょう。

おっと、知らなかった。確認。

lib/MT/Template/Tags/Blog.pm の 166行目にちょっと追記。


    MT->log($name);

インデックス・テンプレートを作成


<MTBlogName>

プレビューまたは再構築してログ確認すると、ブログ名がログに残る。

テンプレートを下記のように修正。


<MTIgnore><MTBlogName></MTIgnore>

プレビューまたは再構築してログ確認すると、ブログ名がログに......残りませんね(そりゃそうだろ)。

一応念のため確認。

lib/MT/Template/ContextHandlers.pm の23行目


            Ignore         => sub { '' },

はぁ...

モジュール使わないとか直書きするとかコメント削除とか考えてないで可視性が良くメンテナンスしやすいテンプレートにすることだけ考えてたら良いと思うよ。あとはバックエンドの実装の人とか偉い人とか(ハードにお金出してくれる人とか)が考えたらいい。

MTQダッシュボードウィジェット Dakiny さんの呼びかけがトリガーなのかMTQにMTへの要望が色々上がってくるようになりましたね。日本発、日本語でこういうのが投げられてそれが反映されるってのが英語が得意な僕としても楽ちんだし、いずれにしてもダイレクトに製品担当者とコミュニティがやり取り出来るのがいいんじゃないでしょうか。

で、コメントフィードはないの? と呟いたら

Twitter / シックス・アパート株式会社: 追加しました! http://bit.ly/9WU0 ...

追加しました! http://bit.ly/9WU0t8 RT @junnama: MTQってコメントフィードはないんですかね?

とのことなので、MTQダッシュボードプラグインをタブ切り替えでコメントも表示できるようにしました。

*MTFeed関係のファンクションタグが貧弱で投稿者の名前とかとれないんですよね。これ、要望あげましょうか。

こういうのはMovable Typeコンテストに「ダッシュボードの部」ってのを設けたらいいんじゃないかなー

ユーザーダッシュボードの充実を希望 - MTQ | Movable Type 5 ユーザーコミュニティ

WordPress を引き合いに出すのは気分悪くする人もいるかもしれないのでしたくないのですが、しかし、あまりにも違うので議論にお付き合い下さい。

(中略)

Movable Type のユーザーダッシュボードの場合は、今後開発されるのでしょう!というような感じで、ほとんど有用な情報が表示されません。あるいは、あえてシンプルにして初心者に優しくしているのかもしれません。だとしたら、ブログのダッシュボードの方は、充実してもらいたいものです。


ということで、ユーザーダッシュボードを楽しく(そしてちょっとだけ便利に)してくれるプラグイン6種。 既にこれまでに公開済みのものも含みますが新規に2つほど追加して公開済みのものも若干手直しを入れてまとめて公開します(変更のないものもあります)。

ユーザーダッシュボードのキャプチャ

MT_Tags

MTタグを定期的にTweetしてくれるTwitterアカウント「MT_Tags」が紹介するタグをランダムにユーザーダッシュボードのタイトル(こんにちは、Junnamaさん)の代わりに表示します。気が散る方にはお勧めしません。

MTQ

MTQのフィードから新着10件を表示するウィジェットです。

QuickEntry

ダッシュボードからブログ記事を投稿出来るウィジェット(MT5.02でjQueryの扱い方が変更になっている点に対応、右カラム/メインカラムどちらに表示させることも可能にしました(出来てなかったので差し替え済み))。

UserDashboard

ユーザーダッシュボードに左メニューを表示させ、This is Youウィジェットを右カラムへ移動して着脱可能にします(不具合指摘いただいていたのですが5.02で動作確認済みです)。

ViewSite

ユーザーダッシュボード/システムメニューにViewSiteリンク(サイトを別ウィンドウで表示するリンク)を追加します(既に公開しているものと変更はなし)。

LoveRebuild

ユーザーダッシュボード/システムメニューにも再構築リンクを表示するウィジェットです(見栄えの修正 - * ふざけた画像は取り敢えず外したw)。

ちなみにこのエントリはQuickEntryダッシュボードからの投稿です。

Dakiny さんの呼びかけに壱さんが反応する形で何だかスレッドまで立ってますね。以下、引用は主に壱さんのエントリから。

今後のMTへの要望(その1・再構築編)

1.「再構築の重さ」で多くのユーザーを失った

まぁ、これが直接の原因かどうかは僕にはわかんないんですけどね。静的パブリッシングだから採用されるっていうケースも多いのは事実です。個人ブログとしてではなく、そこそこの規模のCMSが前提ですが。

2.MT標準のダイナミックパブリッシングは不十分

多くのプラグインはダイナミックパブリッシングには対応していません。
また、テンプレート内にPHPを記述することもよくありますが、そのテンプレートをダイナミックパブリッシング化する際には、PHPの部分をSmartyの記法に書き換える必要があります。
これらのことから、既存のブログをダイナミックパブリッシングに変えるのは困難です。
実質的に、ダイナミックパブリッシングは使えないと言って良いでしょう。

不十分なのは単にプラグインの書き手の手抜きではあるわけですよね。Power CMS for MTは基本ダイナミック全対応が前提です。確かに2つの言語で書くことの負担はあるわけですが。SAKKさんに落ち度があるとしたら、ドキュメントとかサンプルの少なさですね。ことダイナミックに関しては。

まぁ、前置きはいいです。黙ってコードを書けよってことだよ。

RebildAt1stViewを書き直した

  • MTディレクトリの直下のtools以下に「rebuild-from-fi」を設置して実行可能なパーミッション(755とか)を与える
  • plugins/以下にRebuildAt1stViewディレクトリをコピー(DBのアップグレードあり)
  • mtmlディレクトリのmtview_php.mtmlを出力ファイル名mtview.php、_htaccess.mtmlを出力ファイル名.htaccessとしてテンプレートに登録、再構築
  • 適用したいインデックス/アーカイブテンプレート編集画面で「このテンプレートの再構築を最初のリクエスト時に行う」にチェックを入れます
  • 再構築(チェックを入れてたら一瞬で終わる筈>再構築は単なるファイル削除だから)
  • 最初にリクエストがあった時点でファイルがなければ再構築されファイルが出力されます(で、ビルドされたファイルの内容がブラウザに返されます)

処理はPHPで行います。PHPがPerlスクリプトを介してビルドするから、Perlプラグインがそのまま使えます。吐き出されたファイルがPHPだったら、それもちゃんと処理されます。

何かうまく説明出来ないけどね、Perl版ダイナミックだけどPHPで動いててPHPが使えるソリューション、ってことだね。

話題ですよね。iPad。で、いち早くiPad対応サイトを作るべく、ね。(忙しくて話題について行けないと思われるのが癪なので)

Perl/PHP両方あるので管理画面や検索結果などにも適用できますが、やっぱりダイナミックパブリッシングかDynamicMTMLで同一URLでスタイル分岐させる等で動かすのが正攻法かと思います。実際はCSSとかJavaScriptだけでも出来てしまうんでしょうが。

<mt:IfiPad>
iPad向け
<mt:else>
そうじゃない向け
</mt:else>
</mt:IfiPad>

テストはしていません(一応UA情報変えて確認はしたけど...ってか、動くと思いますよ普通に)。ってまだ買ってないんだもの。

Facebook

Twitter

このアーカイブについて

このページには、2010年6月に書かれたブログ記事が新しい順に公開されています。

前のアーカイブは2010年5月です。

次のアーカイブは2010年7月です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

Powered by Movable Type 6.2.6