Symfony Component Advent Calendar 2023の10日目の記事です。
画像やJSをロード、"AssetMapper"
AssetMapperはアセットのマッピングと、公開領域へのファイルの生成を行うコンポーネントです。
Symfony 6.3から導入された新しいコンポーネントですが、実はSymfonyでのフロントエンドの扱いが大きく変わるコンポーネントとなっており、Symfony公式ドキュメントではWebpack Encoreではなく、AssetMapperを推奨しています。
インストール
composer require symfony/asset-mapper
assetsディレクトリへのアクセスは別途Asset
コンポーネントが必要です。また、当然ながらTwig
も必要です。
composer require symfony/asset symfony/twig-pack
インストールすると、以下のファイルが作成されます。
assets/app.js
assets/styles/app.css
config/packages/asset_mapper.yaml
importmap.php
また、templates/base.html.twig
が更新されます。
{% block javascripts %}
+ {{ importmap('app') }}
{% endblock %}
使い方
AssetMapperは主にふたつの機能があります。一つがassets
ディレクトリに置いたファイルへアクセス・公開する機能、もう一つが、importMapを使ったJavaScriptのインポートです。
Assetへのアクセス
assetsディレクトリ内の画像などのURLは asset('{assetsディレクトリからの相対パス}')
を使うことで自動的に生成されます。
<img src="{{ asset('images/sample.png') }}">
<!-- /assets/images/sample-{バージョン文字列}.png -->
バージョンの文字列はファイルが更新されるたびに新しい文字列になります。
開発環境では特になにもせずにこの記述でアクセスできますが、本番環境ではassetsディレクトリのファイルを公開領域であるpublic
に移動される必要があります。移動させる場合は以下のコマンドを実行します。
bin/console asset-map:compile
実行すると、public
にバージョン文字列を付与した状態でファイルがコピーされます。
ImportMap
開発環境では、JavaScriptは templates/base.html.twig
に追記された{{ importmap('app') }}
によって自動で読み込まれます。本番環境では先ほどのbin/cosole asset-map:compile
を実行すればおなじくpublic
領域に移動できます。
例:
import Person from "./person.js";
export default class {
hello() {
const person = new Person()
return person.hello('PHPer')
}
}
export default class {
hello = name => 'Hello ' + name;
}
import Sample from "./sample.js"
console.log(Sample.prototype.hello())
ブラウザのコンソール
Hello PHPer
サードパーティ製のパッケージの読み込み
サードパーティ製はimport
時にCDNでアクセスすれば読み込めます。
import { Alert } from 'https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/+esm';
ですが、めんどくさいです。AssetMapperはnpmパッケージ上のサードパーティ製パッケージの情報をimportmap.php
に追記することで、HTML出力時に自動的にパッケージをimportします。追記する場合は、以下のコマンドを使うと簡単に追記できます。
bin/console importmap:require bootstrap
return [
'app' => [
'path' => './assets/app.js',
'entrypoint' => true,
],
'bootstrap' => [
'version' => '5.3.0',
],
];
このようにすれば、import
時の記述はこのようにできます。
import { Alert } from 'bootstrap';
さて、上記のコマンドを実行してなぜサードパーティのパッケージにアクセスできるかというと、{{ importmap('app') }}
の出力が以下のようになっているからです。
<script type="importmap">
{
"imports": {
"app": "/assets/app-f389ccbe276b2074b6a0fa768c244921.js",
"/assets/sample.js": "/assets/sample-248cf7faeba93e0400a862a6d448a0da.js",
"/assets/person.js": "/assets/person-b64cf9aac50c2f6da0b6a2ba027b68e6.js",
"bootstrap": "https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/+esm",
}
}
</script>
これにより、import
時に該当のモジュールを解決することができます。
同様にサードパーティのCSSもapp.jsにimport
すれば利用できます。
上記のようにimportmapが作成され、CDN経由で該当のスクリプトをロードします。ここまでのコマンドを実行していただくとわかるのですが、packages.json
は作られません。つまり、このコンポーネントでサードパーティ製のパッケージを利用するのであれば、npmは不要です。
なぜかSymfony7になるとapp.jsで読み込んだjsの中のimport(上記例だとperson.js)が読み込まれない模様。修正が入ると思います。
まとめ
今回はAssetMapper
について紹介しました。以前紹介したSymfony UXもWebpack EncoreとAssetMapperのどちらでも動作するようになっており、今後の動向が非常に気になるコンポーネントです。