4 フォロワー

アセット

Yii におけるアセットとは、Web ページで参照できるファイルのことです。CSS ファイル、JavaScript ファイル、画像ファイル、動画ファイルなどがあります。アセットは Web からアクセス可能なディレクトリに配置され、Web サーバーによって直接提供されます。

アセットをプログラム的に管理することが望ましい場合がよくあります。たとえば、ページで yii\jui\DatePicker ウィジェットを使用する場合、必要な CSS ファイルと JavaScript ファイルを手動で探してインクルードする代わりに、自動的にインクルードされます。また、ウィジェットを新しいバージョンにアップグレードすると、アセットファイルの新しいバージョンが自動的に使用されます。このチュートリアルでは、Yii で提供される強力なアセット管理機能について説明します。

アセットバンドル

Yii はアセットをアセットバンドルの単位で管理します。アセットバンドルとは、単にディレクトリにあるアセットのコレクションです。アセットバンドルを ビューに登録すると、バンドル内の CSS ファイルと JavaScript ファイルがレンダリングされた Web ページにインクルードされます。

アセットバンドルの定義

アセットバンドルは、yii\web\AssetBundle を継承した PHP クラスとして指定されます。バンドルの名前は、対応する完全修飾 PHP クラス名 (先頭のバックスラッシュなし) です。アセットバンドルクラスは オートロード可能である必要があります。通常、アセットがどこにあるか、バンドルに含まれる CSS ファイルと JavaScript ファイル、およびバンドルが他のバンドルにどのように依存するかを指定します。

次のコードは、基本プロジェクトテンプレートで使用されるメインアセットバンドルを定義しています。

<?php

namespace app\assets;

use yii\web\AssetBundle;

class AppAsset extends AssetBundle
{
    public $basePath = '@webroot';
    public $baseUrl = '@web';
    public $css = [
        'css/site.css',
        ['css/print.css', 'media' => 'print'],
    ];
    public $js = [
    ];
    public $depends = [
        'yii\web\YiiAsset',
        'yii\bootstrap\BootstrapAsset',
    ];
}

上記の AppAsset クラスは、アセットファイルが URL @web に対応する @webroot ディレクトリの下にあること、バンドルには単一の CSS ファイル css/site.css が含まれ、JavaScript ファイルが含まれていないこと、バンドルが他の 2 つのバンドルである yii\web\YiiAssetyii\bootstrap\BootstrapAsset に依存していることを指定しています。 yii\web\AssetBundle のプロパティに関する詳細は、以下を参照してください。

  • sourcePath: このバンドルに含まれるアセットファイルのルートディレクトリを指定します。ルートディレクトリがWebアクセス可能でない場合は、このプロパティを設定する必要があります。そうでない場合は、代わりにbasePathプロパティとbaseUrlプロパティを設定する必要があります。パスエイリアスをここで使用できます。
  • basePath: このバンドルに含まれるアセットファイルが格納されている、Webアクセス可能なディレクトリを指定します。sourcePathプロパティを指定すると、アセットマネージャはこのバンドルのアセットをWebアクセス可能なディレクトリに公開し、このプロパティを適切に上書きします。アセットファイルがすでにWebアクセス可能なディレクトリに存在し、アセットの公開が不要な場合は、このプロパティを設定する必要があります。パスエイリアスをここで使用できます。
  • baseUrl: basePathディレクトリに対応するURLを指定します。basePathと同様に、sourcePathプロパティを指定すると、アセットマネージャはアセットを公開し、このプロパティを適切に上書きします。パスエイリアスをここで使用できます。
  • css: このバンドルに含まれるCSSファイルをリストする配列。ディレクトリセパレータとしてフォワードスラッシュ "/" のみを使用する必要があることに注意してください。各ファイルは、文字列として単独で指定することも、属性タグとその値とともに配列で指定することもできます。
  • js: このバンドルに含まれるJavaScriptファイルをリストする配列。この配列の形式はcssと同じです。各JavaScriptファイルは、次の2つの形式のいずれかで指定できます。
    • ローカルJavaScriptファイルを表す相対パス(例:js/main.js)。ファイルの実際のパスは、yii\web\AssetManager::$basePathを相対パスの先頭に追加することで決定でき、ファイルの実際のURLは、yii\web\AssetManager::$baseUrlを相対パスの先頭に追加することで決定できます。
    • 外部JavaScriptファイルを表す絶対URL。たとえば、https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.jsまたは//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.jsなど。
  • depends: このバンドルが依存するアセットバンドルの名前をリストする配列(後述します)。
  • jsOptions: このバンドル内のすべてのJavaScriptファイルを登録するために呼び出されるyii\web\View::registerJsFile()メソッドに渡されるオプションを指定します。
  • cssOptions: このバンドル内のすべてのCSSファイルを登録するために呼び出されるyii\web\View::registerCssFile()メソッドに渡されるオプションを指定します。
  • publishOptions: ソースアセットファイルをWebディレクトリに公開するために呼び出されるyii\web\AssetManager::publish()メソッドに渡されるオプションを指定します。これは、sourcePathプロパティを指定した場合にのみ使用されます。

アセットの場所

アセットは、その場所に基づいて、次のように分類できます。

  • ソースアセット:アセットファイルはPHPソースコードと一緒に配置されており、Web経由で直接アクセスすることはできません。ページでソースアセットを使用するには、Webディレクトリにコピーし、公開済みアセットと呼ばれる状態にする必要があります。このプロセスはアセット公開と呼ばれ、後で詳しく説明します。
  • 公開済みアセット:アセットファイルはWebディレクトリに配置されており、Web経由で直接アクセスできます。
  • 外部アセット:アセットファイルは、WebアプリケーションをホストしているWebサーバーとは異なるWebサーバーに配置されています。

アセットバンドルクラスを定義するときに、sourcePathプロパティを指定すると、相対パスを使用してリストされたアセットはすべてソースアセットと見なされます。このプロパティを指定しない場合、それらのアセットは公開済みアセットであることを意味します(したがって、それらがどこにあるかをYiiに知らせるためにbasePathbaseUrlを指定する必要があります)。

不要なアセット公開プロセスを避けるために、アプリケーションに属するアセットをWebディレクトリに配置することをお勧めします。これが、前の例のAppAssetsourcePathの代わりにbasePathを指定する理由です。

拡張機能の場合、それらのアセットはWebアクセスできないディレクトリ内のソースコードと一緒に配置されているため、それらのアセットバンドルクラスを定義するときにsourcePathプロパティを指定する必要があります。

注: source pathとして@webroot/assetsを使用しないでください。このディレクトリは、アセットマネージャがソース場所から公開されたアセットファイルを保存するためにデフォルトで使用されます。このディレクトリ内のコンテンツは一時的なものと見なされ、削除される可能性があります。

アセットの依存関係

Webページに複数のCSSまたはJavaScriptファイルを含める場合、オーバーライドの問題を回避するために特定の順序に従う必要があります。たとえば、WebページでjQuery UIウィジェットを使用している場合は、jQuery JavaScriptファイルがjQuery UI JavaScriptファイルの前に含まれていることを確認する必要があります。このような順序をアセット間の依存関係と呼びます。

アセットの依存関係は、主にyii\web\AssetBundle::$dependsプロパティを通じて指定されます。AppAssetの例では、アセットバンドルは他の2つのアセットバンドル、yii\web\YiiAssetおよびyii\bootstrap\BootstrapAssetに依存しています。つまり、AppAssetのCSSファイルとJavaScriptファイルは、依存する2つのバンドルのファイルの後に含まれます。

アセットの依存関係は推移的です。つまり、バンドルAがBに依存し、BがCに依存する場合、AもCに依存します。

アセットのオプション

cssOptionsjsOptionsプロパティを指定して、CSSファイルとJavaScriptファイルがページに含まれる方法をカスタマイズできます。これらのプロパティの値は、yii\web\View::registerCssFile()およびyii\web\View::registerJsFile()メソッドにそれぞれ渡されます。これらのメソッドは、ビューがCSSファイルとJavaScriptファイルを含めるために呼び出すときに使用されます。

注:バンドルクラスで設定したオプションは、バンドル内のすべてのCSS/JavaScriptファイルに適用されます。異なるファイルに異なるオプションを使用する場合は、上記で述べた形式を使用するか、別のアセットバンドルを作成し、各バンドルで1組のオプションを使用する必要があります。

たとえば、IE9以下のブラウザに対してCSSファイルを条件付きで含めるには、次のオプションを使用できます。

public $cssOptions = ['condition' => 'lte IE9'];

これにより、バンドル内のCSSファイルが次のHTMLタグを使用して含められるようになります。

<!--[if lte IE9]>
<link rel="stylesheet" href="path/to/foo.css">
<![endif]-->

生成されたCSSリンクタグを<noscript>でラップするには、次のようにcssOptionsを構成できます。

public $cssOptions = ['noscript' => true];

ページのheadセクションにJavaScriptファイルを含めるには(デフォルトでは、JavaScriptファイルはbodyセクションの最後に含められます)、次のオプションを使用します。

public $jsOptions = ['position' => \yii\web\View::POS_HEAD];

デフォルトでは、アセットバンドルが公開されるとき、yii\web\AssetBundle::$sourcePathで指定されたディレクトリ内のすべてのコンテンツが公開されます。publishOptionsプロパティを構成することにより、この動作をカスタマイズできます。たとえば、yii\web\AssetBundle::$sourcePathの1つまたはいくつかのサブディレクトリのみを公開するには、アセットバンドルクラスで次のようにすることができます。

<?php
namespace app\assets;

use yii\web\AssetBundle;

class FontAwesomeAsset extends AssetBundle 
{
    public $sourcePath = '@bower/font-awesome'; 
    public $css = [ 
        'css/font-awesome.min.css', 
    ];
    public $publishOptions = [
        'only' => [
            'fonts/*',
            'css/*',
        ]
    ];
}  

上記の例では、「fontawesome」パッケージのアセットバンドルを定義しています。only公開オプションを指定することにより、fontsおよびcssサブディレクトリのみが公開されます。

BowerとNPMアセットのインストール

ほとんどのJavaScript/CSSパッケージは、Bowerおよび/またはNPMパッケージマネージャによって管理されています。PHPの世界では、PHPの依存関係を管理するComposerがありますが、PHPパッケージと同様に、composer.jsonを使用してBowerパッケージとNPMパッケージの両方をロードできます。

これを実現するには、composerを少し構成する必要があります。これを行うには、2つのオプションがあります。


asset-packagistリポジトリの使用

この方法は、NPMまたはBowerパッケージを必要とするほとんどのプロジェクトの要件を満たします。

注: 2.0.13以降、BasicおよびAdvancedアプリケーションテンプレートの両方がデフォルトでasset-packagistを使用するように事前に構成されているため、このセクションをスキップできます。

プロジェクトのcomposer.jsonで、次の行を追加します。

"repositories": [
    {
        "type": "composer",
        "url": "https://asset-packagist.org"
    }
]

アプリケーション構成@npmおよび@bower エイリアスを調整します。

$config = [
    ...
    'aliases' => [
        '@bower' => '@vendor/bower-asset',
        '@npm'   => '@vendor/npm-asset',
    ],
    ...
];

その仕組みを知るには、asset-packagist.orgにアクセスしてください。

fxp/composer-asset-pluginの使用

asset-packagistと比較して、composer-asset-pluginはアプリケーション構成を変更する必要はありません。代わりに、次のコマンドを実行して特別なComposerプラグインをグローバルにインストールする必要があります。

composer global require "fxp/composer-asset-plugin:^1.4.1"

このコマンドは、Composerを介してBowerおよびNPMパッケージの依存関係を管理できるようにするcomposerアセットプラグインをグローバルにインストールします。プラグインをインストールすると、コンピューター上のすべてのプロジェクトがcomposer.jsonを介してBowerおよびNPMパッケージをサポートするようになります。

インストールされたパッケージをYiiを使用して公開する場合は、プロジェクトのcomposer.jsonに次の行を追加して、インストールされたパッケージが配置されるディレクトリを調整します。

"config": {
    "fxp-asset": {
        "installer-paths": {
            "npm-asset-library": "vendor/npm",
            "bower-asset-library": "vendor/bower"
        }
    }
}

注:fxp/composer-asset-pluginは、asset-packagistと比較して、composer updateコマンドを大幅に遅くします。


ComposerでBowerとNPMをサポートするように構成した後

  1. アプリケーションまたは拡張機能のcomposer.jsonファイルを変更し、requireエントリにパッケージをリストします。ライブラリを参照するには、bower-asset/PackageName(Bowerパッケージの場合)またはnpm-asset/PackageName(NPMパッケージの場合)を使用する必要があります。
  2. composer updateを実行します。
  3. アセットバンドルクラスを作成し、アプリケーションまたは拡張機能で使用する予定のJavaScript/CSSファイルをリストします。sourcePathプロパティを@bower/PackageNameまたは@npm/PackageNameとして指定する必要があります。これは、Composerがこのエイリアスに対応するディレクトリにBowerまたはNPMパッケージをインストールするためです。

注: 一部のパッケージでは、すべての配布ファイルをサブディレクトリに配置する場合があります。この場合、sourcePathの値としてサブディレクトリを指定する必要があります。たとえば、yii\web\JqueryAssetは、@bower/jqueryではなく@bower/jquery/distを使用します。

アセットバンドルの使用

アセットバンドルを使用するには、yii\web\AssetBundle::register()メソッドを呼び出して、ビューに登録します。たとえば、ビューテンプレートでは、次のようにアセットバンドルを登録できます。

use app\assets\AppAsset;
AppAsset::register($this);  // $this represents the view object

情報: yii\web\AssetBundle::register() メソッドは、basePathbaseUrl など、公開されたアセットに関する情報を含むアセットバンドルオブジェクトを返します。

他の場所でアセットバンドルを登録する場合、必要なビューオブジェクトを提供する必要があります。例えば、ウィジェットクラスでアセットバンドルを登録するには、$this->view でビューオブジェクトを取得できます。

アセットバンドルがビューに登録されると、Yii は内部的にその依存アセットバンドルをすべて登録します。また、アセットバンドルが Web からアクセスできないディレクトリにある場合、Web ディレクトリに公開されます。その後、ビューがページをレンダリングする際、登録されたバンドルにリストされている CSS および JavaScript ファイルに対して <link> および <script> タグが生成されます。これらのタグの順序は、登録されたバンドル間の依存関係と、yii\web\AssetBundle::$css および yii\web\AssetBundle::$js プロパティにリストされているアセットの順序によって決まります。

動的アセットバンドル

通常の PHP クラスであるアセットバンドルは、それに関連する追加のロジックを保持し、内部パラメータを動的に調整できます。例えば、高度な JavaScript ライブラリを使用する場合、各サポート言語ごとに分割されたソースファイルに国際化機能がパックされている場合があります。そのため、ライブラリの翻訳を機能させるために、特定の '.js' ファイルをページに追加する必要があります。これは、yii\web\AssetBundle::init() メソッドをオーバーライドすることで実現できます。

namespace app\assets;

use yii\web\AssetBundle;
use Yii;

class SophisticatedAssetBundle extends AssetBundle
{
    public $sourcePath = '/path/to/sophisticated/src';
    public $js = [
        'sophisticated.js' // file, which is always used
    ];

    public function init()
    {
        parent::init();
        $this->js[] = 'i18n/' . Yii::$app->language . '.js'; // dynamic file added
    }
}

特定のアセットバンドルは、yii\web\AssetBundle::register() によって返されるインスタンスを介して調整することもできます。例えば

use app\assets\SophisticatedAssetBundle;
use Yii;

$bundle = SophisticatedAssetBundle::register(Yii::$app->view);
$bundle->js[] = 'i18n/' . Yii::$app->language . '.js'; // dynamic file added

注: アセットバンドルの動的な調整はサポートされていますが、予期しない副作用につながる可能性があり、可能な限り避けるべき悪い習慣です。

アセットバンドルのカスタマイズ

Yii は、yii\web\AssetManager によって実装される assetManager という名前のアプリケーションコンポーネントを通じてアセットバンドルを管理します。yii\web\AssetManager::$bundles プロパティを設定することで、アセットバンドルの動作をカスタマイズできます。例えば、デフォルトの yii\web\JqueryAsset アセットバンドルは、インストールされた jquery Bower パッケージの jquery.js ファイルを使用します。可用性とパフォーマンスを向上させるために、Google がホストするバージョンを使用することができます。これは、アプリケーション構成で次のように assetManager を構成することで実現できます。

return [
    // ...
    'components' => [
        'assetManager' => [
            'bundles' => [
                'yii\web\JqueryAsset' => [
                    'sourcePath' => null,   // do not publish the bundle
                    'js' => [
                        '//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js',
                    ]
                ],
            ],
        ],
    ],
];

yii\web\AssetManager::$bundles を介して、同様に複数のアセットバンドルを設定できます。配列のキーは、アセットバンドルのクラス名(先頭のバックスラッシュなし)である必要があり、配列の値は対応する構成配列である必要があります。

ヒント: アセットバンドルで使用するアセットを条件付きで選択できます。次の例は、開発環境では jquery.js を使用し、それ以外の場合は jquery.min.js を使用する方法を示しています。

'yii\web\JqueryAsset' => [
    'js' => [
        YII_ENV_DEV ? 'jquery.js' : 'jquery.min.js'
    ]
],

無効にしたいアセットバンドルの名前を false に関連付けることで、1つまたは複数のアセットバンドルを無効にできます。無効化されたアセットバンドルをビューに登録すると、その依存バンドルは登録されず、ビューもページにバンドル内のアセットを含めません。例えば、yii\web\JqueryAsset を無効にするには、次の構成を使用できます。

return [
    // ...
    'components' => [
        'assetManager' => [
            'bundles' => [
                'yii\web\JqueryAsset' => false,
            ],
        ],
    ],
];

yii\web\AssetManager::$bundlesfalse に設定することで、すべてのアセットバンドルを無効にすることもできます。

yii\web\AssetManager::$bundles を介して行われたカスタマイズは、アセットバンドルの作成時、つまりオブジェクトコンストラクタの段階で適用されることに注意してください。したがって、その後バンドルオブジェクトに対して行われた調整は、yii\web\AssetManager::$bundles レベルで設定されたマッピングを上書きします。特に、yii\web\AssetBundle::init() メソッド内で行われた調整、または登録されたバンドルオブジェクトに対する調整は、AssetManager の構成よりも優先されます。以下は、yii\web\AssetManager::$bundles を介して設定されたマッピングが効果を発揮しない例です。

// Program source code:

namespace app\assets;

use yii\web\AssetBundle;
use Yii;

class LanguageAssetBundle extends AssetBundle
{
    // ...

    public function init()
    {
        parent::init();
        $this->baseUrl = '@web/i18n/' . Yii::$app->language; // can NOT be handled by `AssetManager`!
    }
}
// ...

$bundle = \app\assets\LargeFileAssetBundle::register(Yii::$app->view);
$bundle->baseUrl = YII_DEBUG ? '@web/large-files': '@web/large-files/minified'; // can NOT be handled by `AssetManager`!


// Application config :

return [
    // ...
    'components' => [
        'assetManager' => [
            'bundles' => [
                'app\assets\LanguageAssetBundle' => [
                    'baseUrl' => 'https://some.cdn.com/files/i18n/en' // makes NO effect!
                ],
                'app\assets\LargeFileAssetBundle' => [
                    'baseUrl' => 'https://some.cdn.com/files/large-files' // makes NO effect!
                ],
            ],
        ],
    ],
];

アセットマッピング

複数のアセットバンドルで使用されている、誤った/互換性のないアセットファイルパスを「修正」したい場合があります。例えば、バンドル A が jquery.min.js バージョン 1.11.1 を使用し、バンドル B が jquery.js バージョン 2.1.1 を使用するとします。各バンドルをカスタマイズすることで問題を解決できますが、より簡単な方法は、アセットマップ機能を使用して、誤ったアセットを目的のアセットにマッピングすることです。そのためには、次のように yii\web\AssetManager::$assetMap プロパティを構成します。

return [
    // ...
    'components' => [
        'assetManager' => [
            'assetMap' => [
                'jquery.js' => '//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js',
            ],
        ],
    ],
];

assetMap のキーは、修正したいアセットの名前であり、値は目的のアセットパスです。アセットバンドルをビューに登録すると、css および js 配列内の相対アセットファイルは、このマップに対して検査されます。キーのいずれかがアセットファイルの最後の部分(yii\web\AssetBundle::$sourcePath が利用可能な場合は接頭辞が付いている)であることが判明した場合、対応する値がアセットを置き換え、ビューに登録されます。例えば、アセットファイル my/path/to/jquery.js はキー jquery.js に一致します。

注: 相対パスを使用して指定されたアセットのみがアセットマッピングの対象となります。ターゲットのアセットパスは、絶対 URL または yii\web\AssetManager::$basePath に相対的なパスのいずれかである必要があります。

アセットの公開

前述のように、アセットバンドルが Web からアクセスできないディレクトリにある場合、バンドルがビューに登録されると、そのアセットは Web ディレクトリにコピーされます。このプロセスは、アセットの公開と呼ばれ、アセットマネージャーによって自動的に行われます。

デフォルトでは、アセットは URL @web/assets に対応するディレクトリ @webroot/assets に公開されます。この場所は、basePath および baseUrl プロパティを設定することでカスタマイズできます。

ファイルコピーによるアセットの公開の代わりに、OS と Web サーバーが許可している場合は、シンボリックリンクの使用を検討できます。この機能は、linkAssetstrue に設定することで有効にできます。

return [
    // ...
    'components' => [
        'assetManager' => [
            'linkAssets' => true,
        ],
    ],
];

上記の構成では、アセットマネージャーは、アセットバンドルが公開されるときに、アセットバンドルのソースパスへのシンボリックリンクを作成します。これはファイルコピーよりも高速であり、公開されたアセットが常に最新の状態であることを保証することもできます。

キャッシュバスター

プロダクションモードで実行されている Web アプリケーションの場合、アセットやその他の静的リソースに対して HTTP キャッシュを有効にするのが一般的な慣習です。この慣習の欠点は、アセットを変更してプロダクションにデプロイするたびに、HTTP キャッシュのためにユーザーのクライアントが古いバージョンを使用し続ける可能性があることです。この欠点を克服するために、バージョン 2.0.3 で導入されたキャッシュバスター機能を使用できます。これは、yii\web\AssetManager を次のように構成することで実現できます。

return [
    // ...
    'components' => [
        'assetManager' => [
            'appendTimestamp' => true,
        ],
    ],
];

これにより、公開されたすべてのアセットの URL に、最終変更タイムスタンプが付加されます。例えば、yii.js の URL は /assets/5515a87c/yii.js?v=1423448645" のようになります。ここで、パラメータ vyii.js ファイルの最終変更タイムスタンプを表します。アセットを変更すると、その URL も変更されるため、クライアントはアセットの最新バージョンを取得します。

一般的に使用されるアセットバンドル

コア Yii コードは、多くのアセットバンドルを定義しています。その中で、次のバンドルは一般的に使用されており、アプリケーションまたは拡張コードで参照される場合があります。

  • yii\web\YiiAsset: これは主に、JavaScript コードをモジュールで整理するメカニズムを実装する yii.js ファイルを含みます。また、data-method および data-confirm 属性やその他の便利な機能に対する特別なサポートを提供します。yii.js の詳細については、クライアントスクリプトセクションを参照してください。
  • yii\web\JqueryAsset: jQuery Bower パッケージの jquery.js ファイルを含みます。
  • yii\bootstrap\BootstrapAsset: Twitter Bootstrap フレームワークの CSS ファイルを含みます。
  • yii\bootstrap\BootstrapPluginAsset: Bootstrap JavaScript プラグインをサポートするための Twitter Bootstrap フレームワークの JavaScript ファイルを含みます。
  • yii\jui\JuiAsset: jQuery UI ライブラリの CSS および JavaScript ファイルを含みます。

コードが jQuery、jQuery UI、または Bootstrap に依存している場合は、独自にバージョンを作成するのではなく、これらの事前定義されたアセットバンドルを使用する必要があります。これらのバンドルのデフォルト設定がニーズを満たさない場合は、アセットバンドルのカスタマイズのサブセクションで説明されているようにカスタマイズできます。

アセット変換

開発者は、CSS や JavaScript コードを直接記述する代わりに、拡張構文で記述し、特別なツールを使用して CSS/JavaScript に変換することがよくあります。例えば、CSS コードの場合、LESS または SCSS を使用し、JavaScript の場合は、TypeScript を使用できます。

アセットバンドルの css および js プロパティに、拡張構文で記述されたアセットファイルをリストできます。例えば、

class AppAsset extends AssetBundle
{
    public $basePath = '@webroot';
    public $baseUrl = '@web';
    public $css = [
        'css/site.less',
    ];
    public $js = [
        'js/site.ts',
    ];
    public $depends = [
        'yii\web\YiiAsset',
        'yii\bootstrap\BootstrapAsset',
    ];
}

このようなアセットバンドルをビューに登録すると、アセットマネージャーは自動的にプリプロセッサツールを実行して、認識された拡張構文のアセットを CSS/JavaScript に変換します。ビューが最終的にページをレンダリングするとき、拡張構文の元のアセットの代わりに、ページに CSS/JavaScript ファイルが含まれます。

Yii は、ファイル名拡張子を使用して、アセットがどの拡張構文であるかを識別します。デフォルトでは、次の構文とファイル名拡張子を認識します。

Yiiは、アセットを変換するためにインストール済みのプリプロセッサツールに依存します。例えば、LESSを使用するには、lesscプリプロセッサコマンドをインストールする必要があります。

プリプロセッサコマンドとサポートされる拡張構文は、次のようにyii\web\AssetManager::$converterを設定することでカスタマイズできます。

return [
    'components' => [
        'assetManager' => [
            'converter' => [
                'class' => 'yii\web\AssetConverter',
                'commands' => [
                    'less' => ['css', 'lessc {from} {to} --no-color'],
                    'ts' => ['js', 'tsc --out {to} {from}'],
                ],
            ],
        ],
    ],
];

上記では、yii\web\AssetConverter::$commandsプロパティを介して、サポートされる拡張構文を指定しています。配列のキーはファイル拡張子名(先頭のドットなし)で、配列の値は、結果のアセットファイル拡張子名と、アセット変換を実行するためのコマンドです。コマンド内のトークン{from}{to}は、それぞれソースアセットファイルのパスとターゲットアセットファイルのパスに置き換えられます。

情報: 上記で説明した方法以外にも、拡張構文でアセットを扱う方法はあります。例えば、gruntのようなビルドツールを使用して、拡張構文のアセットを監視し、自動的に変換することができます。この場合、元のファイルではなく、結果のCSS/JavaScriptファイルをアセットバンドルにリストする必要があります。

アセットの結合と圧縮

Webページには、多数のCSSファイルやJavaScriptファイルが含まれる場合があります。HTTPリクエストの回数と、これらのファイルのダウンロードサイズを削減するために、複数のCSS/JavaScriptファイルを1つまたはごく少数のファイルに結合して圧縮し、Webページに元のファイルではなく、これらの圧縮されたファイルを含めるのが一般的な手法です。

情報: アセットの結合と圧縮は、通常、アプリケーションが本番モードのときに必要になります。開発モードでは、デバッグの目的上、元のCSS/JavaScriptファイルを使用する方が便利な場合が多くあります。

以下では、既存のアプリケーションコードを変更せずにアセットファイルを結合および圧縮する方法を紹介します。

  1. アプリケーション内で、結合および圧縮する予定のアセットバンドルをすべて見つけます。
  2. これらのバンドルを1つまたは複数のグループに分割します。各バンドルは、単一のグループにのみ属することができることに注意してください。
  3. 各グループのCSSファイルを単一のファイルに結合/圧縮します。JavaScriptファイルについても同様に行います。
  4. 各グループに対して新しいアセットバンドルを定義します。
    • cssプロパティとjsプロパティを、それぞれ結合されたCSSファイルとJavaScriptファイルに設定します。
    • 各グループのアセットバンドルをカスタマイズするには、cssプロパティとjsプロパティを空にし、dependsプロパティを、そのグループ用に作成した新しいアセットバンドルに設定します。

この方法を使用すると、ビューでアセットバンドルを登録するときに、元のバンドルが属するグループの新しいアセットバンドルが自動的に登録されます。その結果、元のファイルではなく、結合/圧縮されたアセットファイルがページに含まれます。

上記のアプローチをさらに説明するために、例を使用してみましょう。

アプリケーションには、XとYの2つのページがあるとします。ページXはアセットバンドルA、B、Cを使用し、ページYはアセットバンドルB、C、Dを使用します。

これらのアセットバンドルを分割するには、2つの方法があります。1つは、すべてのアセットバンドルを含む単一のグループを使用する方法で、もう1つは、AをグループX、DをグループY、(B, C) をグループSに入れる方法です。どちらが良いでしょうか?それは状況によります。最初の方法には、両方のページが同じ結合されたCSSファイルとJavaScriptファイルを共有するため、HTTPキャッシュがより効果的になるという利点があります。一方、単一のグループにはすべてのバンドルが含まれるため、結合されたCSSファイルとJavaScriptファイルのサイズが大きくなり、最初のファイル転送時間が長くなります。この例では簡単にするために、最初の方​​法、つまりすべて​​のバンドルを含む単一のグループを使用します。

情報: アセットバンドルをグループに分割することは簡単な作業ではありません。通常、さまざまなページでのさまざまなアセットの実際のトラフィックデータに関する分析が必要です。最初は、簡単にするために単一のグループから始めることができます。

既存のツール(例えば、Closure CompilerYUI Compressor)を使用して、すべてのバンドルのCSSファイルとJavaScriptファイルを結合および圧縮します。ファイルは、バンドル間の依存関係を満たす順序で結合する必要があることに注意してください。例えば、バンドルAがBに依存し、BがCとDの両方に依存している場合、アセットファイルはCとDから始めて、次にB、最後にAという順序でリストする必要があります。

結合と圧縮の後、1つのCSSファイルと1つのJavaScriptファイルを取得します。それらは、all-xyz.cssall-xyz.jsという名前であると仮定します。ここで、xyzは、HTTPキャッシュの問題を回避するためにファイル名を一意にするために使用されるタイムスタンプまたはハッシュを表します。

これで最後のステップです。アプリケーション設定で、アセットマネージャを次のように設定します。

return [
    'components' => [
        'assetManager' => [
            'bundles' => [
                'all' => [
                    'class' => 'yii\web\AssetBundle',
                    'basePath' => '@webroot/assets',
                    'baseUrl' => '@web/assets',
                    'css' => ['all-xyz.css'],
                    'js' => ['all-xyz.js'],
                ],
                'A' => ['css' => [], 'js' => [], 'depends' => ['all']],
                'B' => ['css' => [], 'js' => [], 'depends' => ['all']],
                'C' => ['css' => [], 'js' => [], 'depends' => ['all']],
                'D' => ['css' => [], 'js' => [], 'depends' => ['all']],
            ],
        ],
    ],
];

アセットバンドルのカスタマイズのサブセクションで説明したように、上記の設定により、各バンドルのデフォルトの動作が変更されます。特に、バンドルA、B、C、Dは、アセットファイルを持たなくなります。それらはすべて、結合されたall-xyz.cssファイルとall-xyz.jsファイルを含むallバンドルに依存するようになりました。その結果、ページXでは、バンドルA、B、Cの元のソースファイルを含める代わりに、これら2つの結合ファイルのみが含まれます。ページYでも同じことが起こります。

上記の方法をよりスムーズに機能させるための最後の秘訣が1つあります。アプリケーション設定ファイルを直接変更する代わりに、バンドルのカスタマイズ配列を別のファイルに配置し、条件付きでこのファイルをアプリケーション設定に含めることができます。例:

return [
    'components' => [
        'assetManager' => [
            'bundles' => require __DIR__ . '/' . (YII_ENV_PROD ? 'assets-prod.php' : 'assets-dev.php'),  
        ],
    ],
];

つまり、アセットバンドルの構成配列は、本番モードの場合はassets-prod.phpに、非本番モードの場合はassets-dev.phpに保存されます。

注: このアセット結合メカニズムは、登録済みのアセットバンドルのプロパティを上書きするyii\web\AssetManager::$bundlesの機能に基づいています。ただし、上記ですでに述べたように、この機能は、yii\web\AssetBundle::init()メソッドまたはバンドル登録後に実行されるアセットバンドルの調整には対応していません。アセットを結合する際には、このような動的なバンドルの使用は避けるべきです。

assetコマンドの使用

Yiiは、上記で説明したアプローチを自動化するassetという名前のコンソールコマンドを提供します。

このコマンドを使用するには、まず、結合するアセットバンドルとそのグループ化方法を記述する構成ファイルを作成する必要があります。最初にasset/templateサブコマンドを使用してテンプレートを生成し、ニーズに合わせて変更することができます。

yii asset/template assets.php

このコマンドは、現在のディレクトリにassets.phpという名前のファイルを生成します。このファイルの内容は次のようになります。

<?php
/**
 * Configuration file for the "yii asset" console command.
 * Note that in the console environment, some path aliases like '@webroot' and '@web' may not exist.
 * Please define these missing path aliases.
 */
return [
    // Adjust command/callback for JavaScript files compressing:
    'jsCompressor' => 'java -jar compiler.jar --js {from} --js_output_file {to}',
    // Adjust command/callback for CSS files compressing:
    'cssCompressor' => 'java -jar yuicompressor.jar --type css {from} -o {to}',
    // Whether to delete asset source after compression:
    'deleteSource' => false,
    // The list of asset bundles to compress:
    'bundles' => [
        // 'yii\web\YiiAsset',
        // 'yii\web\JqueryAsset',
    ],
    // Asset bundle for compression output:
    'targets' => [
        'all' => [
            'class' => 'yii\web\AssetBundle',
            'basePath' => '@webroot/assets',
            'baseUrl' => '@web/assets',
            'js' => 'js/all-{hash}.js',
            'css' => 'css/all-{hash}.css',
        ],
    ],
    // Asset manager configuration:
    'assetManager' => [
    ],
];

このファイルを変更して、bundlesオプションで結合する予定のバンドルを指定する必要があります。targetsオプションでは、バンドルをグループに分割する方法を指定する必要があります。上記のように、1つまたは複数のグループを指定できます。

注: エイリアス@webroot@webはコンソールアプリケーションでは使用できないため、設定で明示的に定義する必要があります。

JavaScriptファイルは結合、圧縮され、js/all-{hash}.jsに書き込まれます。ここで、{hash}は結果ファイルのハッシュに置き換えられます。

jsCompressorオプションとcssCompressorオプションは、JavaScriptとCSSの結合/圧縮を実行するためのコンソールコマンドまたはPHPコールバックを指定します。デフォルトでは、YiiはJavaScriptファイルの結合にClosure Compilerを、CSSファイルの結合にYUI Compressorを使用します。これらのツールを手動でインストールするか、お好みのツールを使用するようにこれらのオプションを調整する必要があります。

構成ファイルを使用して、assetコマンドを実行してアセットファイルを結合および圧縮し、新しいアセットバンドル構成ファイルassets-prod.phpを生成できます。

yii asset assets.php config/assets-prod.php

生成された構成ファイルは、前のサブセクションで説明したように、アプリケーション構成に含めることができます。

注: yii\web\AssetManager::$bundlesまたはyii\web\AssetManager::$assetMapを使用してアプリケーションのアセットバンドルをカスタマイズしており、このカスタマイズを圧縮ソースファイルに適用したい場合は、アセットコマンド構成ファイルのassetManagerセクションにこれらのオプションを含める必要があります。

注: 圧縮ソースを指定する際には、パラメータが動的に調整される(例えば、init()メソッドまたは登録後)アセットバンドルの使用は避けるべきです。圧縮後に正しく機能しない可能性があります。

情報: assetコマンドを使用することは、アセットの結合と圧縮プロセスを自動化する唯一の方法ではありません。優れたタスクランナーツールであるgruntを使用して、同じ目標を達成できます。

アセットバンドルのグループ化

前のサブセクションでは、アプリケーションで参照されるアセットファイルのHTTPリクエストを最小限に抑えるために、すべてのアセットバンドルを単一のバンドルに結合する方法について説明しました。これは実際には必ずしも望ましいとは限りません。例えば、アプリケーションに「フロントエンド」と「バックエンド」があり、それぞれ異なるJavaScriptファイルとCSSファイルを使用しているとします。この場合、「フロントエンド」と「バックエンド」の両方のアセットバンドルを単一のバンドルに結合することは意味がありません。「フロントエンド」のアセットバンドルは「バックエンド」では使用されないため、「フロントエンド」のページがリクエストされたときに「バックエンド」のアセットを送信するのはネットワーク帯域幅の無駄になります。

上記の問題を解決するには、アセットバンドルをグループに分割し、各グループのアセットバンドルを結合することができます。次の構成は、アセットバンドルをグループ化する方法を示しています。

return [
    ...
    // Specify output bundles with groups:
    'targets' => [
        'allShared' => [
            'js' => 'js/all-shared-{hash}.js',
            'css' => 'css/all-shared-{hash}.css',
            'depends' => [
                // Include all assets shared between 'backend' and 'frontend'
                'yii\web\YiiAsset',
                'app\assets\SharedAsset',
            ],
        ],
        'allBackEnd' => [
            'js' => 'js/all-{hash}.js',
            'css' => 'css/all-{hash}.css',
            'depends' => [
                // Include only 'backend' assets:
                'app\assets\AdminAsset'
            ],
        ],
        'allFrontEnd' => [
            'js' => 'js/all-{hash}.js',
            'css' => 'css/all-{hash}.css',
            'depends' => [], // Include all remaining assets
        ],
    ],
    ...
];

ご覧のとおり、アセットバンドルは、allSharedallBackEndallFrontEndの3つのグループに分割されています。それぞれが適切なアセットバンドルのセットに依存します。例えば、allBackEndapp\assets\AdminAssetに依存します。この構成でassetコマンドを実行すると、上記仕様に従ってアセットバンドルが結合されます。

情報: ターゲットバンドルの1つに対してdepends構成を空のままにすることができます。そうすることで、その特定のアセットバンドルは、他のターゲットバンドルが依存しない残りのすべてのアセットバンドルに依存することになります。

タイプミスを見つけましたか、またはこのページを改善する必要があると思いますか?
githubで編集 !