Nette Assets

Webアプリケーションで静的ファイルの管理を手動で行うことにうんざりしていませんか?パスのハードコーディング、キャッシュの無効化、ファイルバージョニングの心配はもう必要ありません。Nette Assetsは、画像、スタイルシート、スクリプト、その他の静的リソースの作業方法を変革します。

  • スマートバージョニングにより、ブラウザは常に最新のファイルをロードします
  • ファイルの種類と寸法の自動検出
  • 直感的なタグによるシームレスなLatte連携
  • ファイルシステム、CDN、Viteをサポートする柔軟なアーキテクチャ
  • 最適なパフォーマンスのための遅延ロード

Nette Assetsを使用する理由

静的ファイルの操作は、多くの場合、反復的でエラーが発生しやすいコードを意味します。URLを手動で構築し、キャッシュバストのためにバージョンパラメータを追加し、異なるファイルタイプを異なる方法で処理します。これにより、次のようなコードになります。

<img src="/images/logo.png?v=1699123456" width="200" height="100" alt="Logo">
<link rel="stylesheet" href="/css/style.css?v=2">

Nette Assetsを使用すると、このすべての複雑さが解消されます。

{* URL、バージョニング、寸法がすべて自動化されます *}
<img n:asset="images/logo.png">
<link n:asset="css/style.css">

{* または単に *}
{asset 'css/style.css'}

それだけです!ライブラリは自動的に次のことを行います。

  • ファイル変更時間に基づいてバージョンパラメータを追加します
  • 画像の寸法を検出し、HTMLに含めます
  • 各ファイルタイプに適切なHTML要素を生成します
  • 開発環境と本番環境の両方を処理します

インストール

Nette AssetsをComposerを使用してインストールします。

composer require nette/assets

PHP 8.1以降が必要で、Nette Frameworkと完全に連携しますが、スタンドアロンでも使用できます。

最初のステップ

Nette Assetsは設定なしでそのまま動作します。静的ファイルをwww/assets/ディレクトリに配置し、使用を開始します。

{* 自動寸法で画像を表示 *}
{asset 'logo.png'}

{* バージョニング付きのスタイルシートを含める *}
{asset 'style.css'}

{* JavaScriptモジュールをロード *}
{asset 'app.js'}

生成されるHTMLをより細かく制御するには、n:asset属性またはasset()関数を使用します。

動作原理

Nette Assetsは、強力でありながら使いやすい3つのコアコンセプトに基づいて構築されています。

アセット – スマートになったファイル

アセットは、アプリケーション内の静的ファイルを表します。各ファイルは、便利な読み取り専用プロパティを持つオブジェクトになります。

$image = $assets->getAsset('photo.jpg');
echo $image->url;      // '/assets/photo.jpg?v=1699123456'
echo $image->width;    // 1920
echo $image->height;   // 1080
echo $image->mimeType; // 'image/jpeg'

異なるファイルタイプは異なるプロパティを提供します。

  • 画像: 幅、高さ、代替テキスト、遅延ロード
  • スクリプト: モジュールタイプ、整合性ハッシュ、クロスオリジン
  • スタイルシート: メディアクエリ、整合性
  • オーディオ/ビデオ: 期間、寸法
  • フォント: CORSを使用した適切なプリロード

ライブラリは自動的にファイルタイプを検出し、適切なアセットクラスを作成します。

マッパー – ファイルの取得元

マッパーは、ファイルの検索方法とそれらのURLの作成方法を知っています。ローカルファイル、CDN、クラウドストレージ、またはビルドツールなど、さまざまな目的のために複数のマッパーを持つことができます(それぞれに名前があります)。組み込みのFilesystemMapperはローカルファイルを処理し、ViteMapperは最新のビルドツールと連携します。

マッパーは設定で定義されます。

レジストリ – メインインターフェース

レジストリはすべてのマッパーを管理し、メインAPIを提供します。

// サービスにレジストリを注入
public function __construct(
	private Nette\Assets\Registry $assets
) {}

// 異なるマッパーからアセットを取得
$logo = $this->assets->getAsset('images:logo.png'); // 'image' マッパー
$app = $this->assets->getAsset('app:main.js'); // 'app' マッパー
$style = $this->assets->getAsset('style.css'); // デフォルトマッパーを使用

レジストリは自動的に正しいマッパーを選択し、パフォーマンスのために結果をキャッシュします。

PHPでアセットを操作する

レジストリは、アセットを取得するための2つのメソッドを提供します。

// ファイルが存在しない場合、Nette\Assets\AssetNotFoundException をスローします
$logo = $assets->getAsset('logo.png');

// ファイルが存在しない場合、null を返します
$banner = $assets->tryGetAsset('banner.jpg');
if ($banner) {
	echo $banner->url;
}

マッパーの指定

使用するマッパーを明示的に選択できます。

// デフォルトマッパーを使用
$file = $assets->getAsset('document.pdf');

// プレフィックス付きの特定のマッパーを使用
$image = $assets->getAsset('images:photo.jpg');

// 配列構文で特定のマッパーを使用
$script = $assets->getAsset(['scripts', 'app.js']);

アセットのプロパティとタイプ

各アセットタイプは関連する読み取り専用プロパティを提供します。

// 画像のプロパティ
$image = $assets->getAsset('photo.jpg');
echo $image->width;     // 1920
echo $image->height;    // 1080
echo $image->mimeType;  // 'image/jpeg'

// スクリプトのプロパティ
$script = $assets->getAsset('app.js');
echo $script->type;     // 'module' または null

// オーディオのプロパティ
$audio = $assets->getAsset('song.mp3');
echo $audio->duration;  // 秒単位の期間

// すべてのアセットは文字列にキャスト可能 (URLを返します)
$url = (string) $assets->getAsset('document.pdf');

寸法や期間などのプロパティは、アクセスされたときにのみ遅延ロードされるため、ライブラリは高速に動作します。

Latteテンプレートでアセットを使用する

Nette Assetsは、タグと関数による直感的なLatte連携を提供します。

{asset}

{asset}タグは完全なHTML要素をレンダリングします。

{* レンダリング: <img src="/assets/hero.jpg?v=123" width="1920" height="1080"> *}
{asset 'hero.jpg'}

{* レンダリング: <script src="/assets/app.js?v=456" type="module"></script> *}
{asset 'app.js'}

{* レンダリング: <link rel="stylesheet" href="/assets/style.css?v=789"> *}
{asset 'style.css'}

このタグは自動的に次のことを行います。

  • アセットタイプを検出し、適切なHTMLを生成します
  • キャッシュバストのためにバージョニングを含めます
  • 画像の寸法を追加します
  • 正しい属性(type、mediaなど)を設定します

HTML属性内で使用すると、URLのみを出力します。

<div style="background-image: url({asset 'bg.jpg'})">
<img srcset="{asset 'logo@2x.png'} 2x">

n:asset

HTML属性を完全に制御する場合:

{* n:asset 属性は src、寸法などを埋めます *}
<img n:asset="product.jpg" alt="Product" class="rounded">

{* 関連する任意の要素で動作します *}
<script n:asset="analytics.js" defer></script>
<link n:asset="print.css" media="print">
<audio n:asset="podcast.mp3" controls></audio>

変数とマッパーを使用します。

{* 変数は自然に動作します *}
<img n:asset="$product->image">

{* 波括弧でマッパーを指定します *}
<img n:asset="images:{$product->image}">

{* 配列表記でマッパーを指定します *}
<img n:asset="[images, $product->image]">

asset()

最大限の柔軟性を得るには、asset()関数を使用します。

{var $logo = asset('logo.png')}
<img src={$logo} width={$logo->width} height={$logo->height}>

{* または直接 *}
<img src={asset('logo.png')} alt="Logo">

オプションのアセット

{asset?}n:asset?tryAsset()を使用して、不足しているアセットを適切に処理します。

{* オプションのタグ - アセットがない場合は何もレンダリングしません *}
{asset? 'optional-banner.jpg'}

{* オプションの属性 - アセットがない場合はスキップします *}
<img n:asset?="user-avatar.jpg" alt="Avatar" class="avatar">

{* フォールバック付き *}
{var $avatar = tryAsset('user-avatar.jpg') ?? asset('default-avatar.jpg')}
<img n:asset=$avatar alt="Avatar">

{preload}

ページ読み込みパフォーマンスを向上させます。

{* <head> セクション内 *}
{preload 'critical.css'}
{preload 'important-font.woff2'}
{preload 'hero-image.jpg'}

適切なプリロードリンクを生成します。

<link rel="preload" href="/assets/critical.css?v=123" as="style">
<link rel="preload" href="/assets/important-font.woff2" as="font" crossorigin>
<link rel="preload" href="/assets/hero-image.jpg" as="image">

高度な機能

拡張子の自動検出

複数のフォーマットを自動的に処理します。

assets:
	mapping:
		images:
			path: img
			extension: [webp, jpg, png]  # この順序で試行

これで、拡張子なしでリクエストできます。

{* logo.webp、logo.jpg、または logo.png を自動的に検索します *}
{asset 'images:logo'}

最新のフォーマットによるプログレッシブエンハンスメントに最適です。

スマートバージョニング

ファイルは変更時間に基づいて自動的にバージョニングされます。

{asset 'style.css'}
{* 出力: <link rel="stylesheet" href="/assets/style.css?v=1699123456"> *}

ファイルを更新すると、タイムスタンプが変更され、ブラウザのキャッシュが強制的に更新されます。

アセットごとにバージョニングを制御します。

// 特定のアセットのバージョニングを無効にする
$asset = $assets->getAsset('style.css', ['version' => false]);

// Latteで
{asset 'style.css', version: false}

フォントアセット

フォントは適切なCORSで特別に扱われます。

{* crossorigin 付きの適切なプリロード *}
{preload 'fonts:OpenSans-Regular.woff2'}

{* CSSでの使用 *}
<style>
@font-face {
	font-family: 'Open Sans';
	src: url('{asset 'fonts:OpenSans-Regular.woff2'}') format('woff2');
	font-display: swap;
}
</style>

カスタムマッパー

クラウドストレージや動的生成などの特別なニーズに合わせてカスタムマッパーを作成します。

use Nette\Assets\Mapper;
use Nette\Assets\Asset;
use Nette\Assets\Helpers;

class CloudStorageMapper implements Mapper
{
	public function __construct(
		private CloudClient $client,
		private string $bucket,
	) {}

	public function getAsset(string $reference, array $options = []): Asset
	{
		if (!$this->client->exists($this->bucket, $reference)) {
			throw new Nette\Assets\AssetNotFoundException("アセット '$reference' が見つかりません");
		}

		$url = $this->client->getPublicUrl($this->bucket, $reference);
		return Helpers::createAssetFromUrl($url);
	}
}

設定に登録します。

assets:
	mapping:
		cloud: CloudStorageMapper(@cloudClient, 'my-bucket')

他のマッパーと同様に使用します。

{asset 'cloud:user-uploads/photo.jpg'}

Helpers::createAssetFromUrl()メソッドは、ファイル拡張子に基づいて正しいアセットタイプを自動的に作成します。

参考文献.toc-further-reading

バージョン: 1.0