Assetic は PHP の Asset 管理フレームワーク。css や javascript などのアセットを結合したり、minify して配信したりできるので、リクエスト数の削減が期待できる。特定のフレームワークに依存していないポータブルなライブラリなので、既存の環境に手軽に入れ込める。
Assetic をテンプレートエンジンから利用する方法として、本家では Twig を使う方法が紹介されているが、既存ソースの都合上、Smarty から使いたい。
調べてみたところ assetic-smarty なるプラグインを発見。が、使ってみたところ、config で期待されている設定方法がよくわからなかったので、以下のようにブロック関数プラグインを書きかえて使ってみることにした。
<?php
use Assetic\Asset\AssetCollection;
use Assetic\Asset\FileAsset;
use Assetic\AssetManager;
use Assetic\AssetWriter;
use Assetic\Filter\CssMinFilter;
use Assetic\Filter\JsMinFilter;
use Assetic\Filter\Yui;
function smarty_block_assetic($params, $content, &$smarty, &$repeat)
{
if ($repeat) {
$smarty->assign('asset_url', '/assets/' . $params['version'] . '/' . $params['bundle_name']);
$asset_absolute_path = DOCUMENT_ROOT_DIR . '/assets/' . $params['version'] . '/' . $params['bundle_name'];
if (!$params['debug'] && file_exists($asset_absolute_path)) {
// debugモードでない場合、既にリソース結合済みであれば再生成しない.
return;
}
$asset_files = preg_split('/[\s\n]+/', $params['assets']);
$assets = [];
foreach ($asset_files as $asset_file) {
$asset = new FileAsset(DOCUMENT_ROOT_DIR . '/' . $asset_file);
$assets[] = $asset;
}
$filters = [];
if ($params['bundle_type'] === 'css') {
$filters[] = new CssMinFilter();
$filters[] = new Yui\CssCompressorFilter('/path/to/yuicompressor.jar');
}
if ($params['bundle_type'] === 'js') {
$filters[] = new JsMinFilter();
$filters[] = new Yui\JsCompressorFilter('/path/to/yuicompressor.jar');
}
$asset_collection = new AssetCollection($assets, $filters);
$asset_collection->setTargetPath($params['bundle_name']);
$asset_manager = new AssetManager();
$asset_manager->set('sample', $asset_collection);
$output_dir = DOCUMENT_ROOT_DIR . '/assets/' . $params['version'];
$writer = new AssetWriter($output_dir);
$writer->writeManagerAssets($asset_manager);
} else {
echo $content;
}
}
これで、予め定義しておいた DOCUMENT_ROOT_DIR 直下から見た位置にあるファイル群を結合し、{DOCUMENT_ROOT_DIR}/assets/{version} 以下に出力される。
Smarty テンプレートからは、以下のようにすれば、作成済みの asset がない場合に限り Assetic でのファイル結合をおこなった上で、bundle_name に指定したファイル名で出力する。このブロック内で $asset_url が結合後のファイルへのパスに設定されるので、そのまま src 属性に指定してやれば良い。
{assetic
assets="js/aaa.js js/bbb.js js/ccc.js"
version="20140101"
bundle_name="all.js"
bundle_type="js"
}
<script type="text/javascript" src="{$asset_url|escape}"></script>
{/assetic}
version は設定ファイルなどから渡してやるのが良いと思う。
ひとまず、期待している動作は確認できた。