§パブリックアセットの操作
Playでパブリックリソースを提供することは、他のHTTPリクエストを提供することと同じです。コントローラー/アクションパスを使用してCSS、JavaScript、または画像ファイルをクライアントに配信するのと同じルーティングを使用します。
§public/ フォルダー
慣例により、パブリックアセットはアプリケーションの `public` フォルダーに保存されます。このフォルダーは、好きなように整理できます。次の構成をお勧めします。
public
└ javascripts
└ stylesheets
└ images
この構造に従うと、簡単に始めることができますが、仕組みを理解すれば、変更することを妨げるものはありません。
§WebJars
WebJarsは、sbtの一部である便利で慣例的なパッケージングメカニズムを提供します。たとえば、ビルドファイルに次の依存関係を追加するだけで、一般的な Bootstrapライブラリ を使用することを宣言できます。
libraryDependencies += "org.webjars" % "bootstrap" % "3.3.6"
WebJarsは、便宜上、パブリックアセットを基準とした `lib` フォルダーに自動的に抽出されます。たとえば、RequireJs への依存関係を宣言した場合、次のような行を使用してビューから参照できます。
<script data-main="@routes.Assets.at("javascripts/main.js")" type="text/javascript" src="@routes.Assets.at("lib/requirejs/require.js")"></script>
`lib/requirejs/require.js` パスに注意してください。 `lib` フォルダーは抽出されたWebJarアセットを示し、 `requirejs` フォルダーはWebJar artifactIdに対応し、 `require.js` はWebJarのルートにある必要なアセットを参照します。明確にするために、 `requirejs` webjarの依存関係は、ビルドファイルで次のように宣言されます。
libraryDependencies += "org.webjars" % "requirejs" % "2.2.0"
§パブリックアセットはどのようにパッケージ化されますか?
ビルドプロセス中に、 `public` フォルダーの内容が処理され、アプリケーションクラスパスに追加されます。
アプリケーションをパッケージ化すると、すべてのサブプロジェクトを含むアプリケーションのすべてのアセットが `target/my-first-app-1.0.0-assets.jar` の単一のjarに集約されます。このjarは、Playアプリケーションがそれらを提供できるように、配布に含まれています。このjarは、アセットをCDNまたはリバースプロキシにデプロイするためにも使用できます。
§Assetsコントローラー
Playには、パブリックアセットを提供するための組み込みコントローラーが付属しています。デフォルトでは、このコントローラーはキャッシング、ETag、gzip、および圧縮のサポートを提供します。 Assetsコントローラーがサポートするスタイルは2つあります。1つ目はPlayの設定を使用する方法、2つ目はアセットパスをコントローラーに直接渡す方法です。
§Assetsコンポーネントのバインド
ランタイム依存性注入を使用している場合、Playはデフォルトでロードされる `AssetsModule` にバインディングを提供しています。(アセットを使用していない場合は、 `play.modules.disabled += controllers.AssetsModule` 設定を追加することで、このモジュールを無効にできます。)そこでのバインディングにより、 `Assets` クラスを注入できます。
コンポーネントトレイトを使用してコンパイル時依存性注入を行う場合は、 `controllers.AssetsComponents` を混在させる必要があります。すると、コントローラーは `assets: Assets` として使用できるようになります。コントローラーを自分で構築する必要はありません。
§設定を使用したアセットの使用
アセットが中央に配置されている場所が1つしかない最も一般的なケースでは、設定を使用して場所を指定できます。
play.assets {
path = "/public"
urlPrefix = "/assets"
}
そして、パラメーターを1つ指定して `Assets.at` メソッドを使用します。
Assets.at(file: String)
次に、routesで
GET /assets/*file controllers.Assets.at(file)
§アセットパスを直接渡す
`Assets` コントローラーは、2つのパラメーターを持つ `at` アクションも定義します。
Assets.at(path: String, file: String)
`path` パラメーターは固定でなければならず、アクションによって管理されるディレクトリを定義します。 `file` パラメーターは通常、リクエストパスから動的に抽出されます。
`conf/routes` ファイルにある `Assets` コントローラーの一般的なマッピングを以下に示します。
GET /assets/*file controllers.Assets.at(path="/public", file)
`.*` 正規表現に一致する `*file` 動的部分を定義していることに注意してください。たとえば、このリクエストをサーバーに送信すると
GET /assets/javascripts/jquery.js
ルーターは次のパラメーターで `Assets.at` アクションを呼び出します。
controllers.Assets.at("/public", "javascripts/jquery.js")
単一の静的ファイルにルーティングするには、パスとファイルの両方を指定する必要があります。
GET /favicon.ico controllers.Assets.at(path="/public", file="favicon.ico")
§パブリックアセットのリバースルーティング
routesファイルにマッピングされているコントローラーと同様に、リバースコントローラーは `controllers.routes.Assets` に作成されます。これを使用して、パブリックリソースを取得するために必要なURLを反転します。たとえば、テンプレートから
<script src="@routes.Assets.at("javascripts/jquery.js")"></script>
`DEV` モードでは、デフォルトで次の結果が生成されます。
<script src="/assets/javascripts/jquery.js"></script>
アプリが `DEV` モードで実行されておらず、**かつ** `jquery.min.js` または `jquery-min.js` ファイルが存在する場合、デフォルトでは縮小ファイルが代わりに使用されます。
<script src="/assets/javascripts/jquery.min.js"></script>
これにより、開発中のJavaScriptファイルのデバッグが容易になります。もちろん、これはJavaScriptファイルだけでなく、あらゆるファイル拡張子に対して機能します。
アプリケーションの実行モードに関係なく、Playが ` .min。*` または `-min。*` ファイルを自動的に解決しないようにするには、 `application.conf` で `play.assets.checkForMinified = false` を設定できます(または、 `DEV` モードでも常に縮小ファイルを解決するには `true` に設定します)。
ルートを反転するときに、最初の `folder` パラメーターを指定しないことに注意してください。これは、routesファイルが `Assets.at` アクションの単一のマッピングを定義しており、 `folder` パラメーターが固定されているためです。したがって、指定する必要はありません。
ただし、次のように `Assets.at` アクションの2つのマッピングを定義する場合
GET /javascripts/*file controllers.Assets.at(path="/public/javascripts", file)
GET /images/*file controllers.Assets.at(path="/public/images", file)
リバースルーターを使用するときは、両方のパラメーターを指定する必要があります。
<script src="@routes.Assets.at("/public/javascripts", "jquery.js")"></script>
<img src="@routes.Assets.at("/public/images", "logo.png")" />
§パブリックアセットのリバースルーティングとフィンガープリント
sbt-web は、高度に設定可能なアセットパイプラインの概念をPlayにもたらします。たとえば、ビルドファイルで
pipelineStages := Seq(rjs, digest, gzip)
上記は、RequireJsオプティマイザー(sbt-rjs)、ダイジェスター(sbt-digest)、次に圧縮(sbt-gzip)の順序で実行します。多くのsbtタスクとは異なり、これらのタスクは宣言された順序で次々に実行されます。
本質的に、アセットフィンガープリントを使用すると、静的アセットを積極的なキャッシュ命令とともにブラウザーに提供できます。これにより、サイトへのその後の訪問でダウンロードが必要なアセットが少なくなるため、ユーザーのエクスペリエンスが向上します。 Railsはまた、アセットフィンガープリントの利点についても説明しています。
上記の `pipelineStages` の宣言と、必要なプラグインの `plugins.sbt` に必要な `addSbtPlugin` 宣言は、開始点です。次に、Playにどのアセットをバージョン管理するかを宣言する必要があります。
フィンガープリントされたアセットの実際のパスを取得するには、2つの方法があります。最初の方法は静的状態を使用し、通常のリバースルーティングと同じスタイルをサポートします。実行中のPlayアプリケーションによって設定されたアセットメタデータを参照することでこれを行います。 2つ目の方法は、設定を使用してAssetsFinderを挿入してアセットを見つけることです。
§リバースルーティングと静的状態の使用
静的状態のリバースルーターを使用する予定がある場合、次のルートファイルエントリはすべてのアセットがバージョン管理されることを宣言します。
GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset)
**注:** `file: Asset` と書くことで、 `file` がアセットであることを示していることを確認してください。
その後、例えば scala.html
ビュー内で、リバースルーターを使用します。
<link rel="stylesheet" href="@routes.Assets.versioned("assets/css/app.css")">
このアプローチの欠点は、渡したパスからダイジェストを含む最終的な縮小パスにAsset
を変換する特別なロジックが必要になることです。また、パスを定義するためにモックできるコンポーネントがないため、ユニットテストがより困難になります。
§設定とAssetsFinderの使用
設定でパスを定義し、コントローラーにAssetsFinder
をインジェクトして最終パスを取得することもできます。設定では、アセットのpath
(アセットを含むディレクトリ)とurlPrefix
(アプリケーション内のURLのプレフィックス)を設定します。
play.assets {
path = "/public"
urlPrefix = "/assets"
}
ルートファイルでは、次のようにルートを定義できます。
GET /assets/*file controllers.Assets.versioned(file)
(ここでは: Asset
型注釈を使用しないでください)
その後、AssetsFinder
をテンプレートに渡して、最終パスを取得するために使用できます。
@(assetsFinder: AssetsFinder)
<link rel="stylesheet" href="@assetsFinder.path("assets/css/app.css")">
このアプローチの利点は、静的な状態を設定する必要がないことです。つまり、AssetsFinder
のインスタンスを渡すだけで、実行中のアプリケーションなしでコントローラーとテンプレートのユニットテストを実行できます。これにより、String
を返す抽象メソッドを実装するだけで、ユニットテストのモックが簡単になります。
また、AssetsFinder
アプローチを使用すると、静的な状態を使用しないため、同じクラスローダーで複数の自己完結型アプリケーションを同時に実行することが容易になります。これはテストにも役立ちます。
AssetsFinder
インターフェースは、フィンガープリントが使用されていない場合でも機能します。フィンガープリント付きまたは縮小されたアセットが見つからない場合は、元のアセットを返します。
§ETagサポート
Assets
コントローラーは、ETag HTTPヘッダーを自動的に管理します。ETag値は、ダイジェスト(アセットパイプラインでsbt-digest
が使用されている場合)またはリソース名とファイルの最終変更日時から生成されます。リソースファイルがファイルに埋め込まれている場合は、JARファイルの最終変更日時が使用されます。
WebブラウザがこのEtagを指定してリクエストを行うと、サーバーは304 NotModifiedで応答できます。
§Gzipサポート
同じ名前で.gz
サフィックスを使用するリソースが見つかった場合、Assets
コントローラーは後者を配信し、次のHTTPヘッダーを追加します。
Content-Encoding: gzip
ビルドにsbt-gzip
プラグインを含め、pipelineStages
での位置を宣言するだけで、gzipファイルを生成できます。
§追加のCache-Control
ディレクティブ
通常、キャッシュの目的にはEtagを使用すれば十分です。ただし、特定のリソースにカスタムCache-Control
ヘッダーを指定する場合は、application.conf
ファイルで指定できます。例えば
# Assets configuration
# ~~~~~
play.assets.cache."/public/stylesheets/bootstrap.min.css"="max-age=3600"
部分的なパスを使用して、そのパス以下のすべてのアセットのカスタムCache-Control
を指定することもできます。例えば
# Assets configuration
# ~~~~~
play.assets.cache."/public/stylesheets/"="max-age=100"
play.assets.cache."/public/javascripts/"="max-age=200"
Playは、/public/javascripts
以下のすべてのアセット(/public/javascripts/main.js
など)にmax-age=200
を使用し、/public/stylesheets
以下のすべてのアセット(/public/stylesheets/main.css
など)にmax-age=100
を使用します。
§追加ディレクティブの適用方法
Playは、Cache-Control
ディレクティブを辞書順に、次に具体的なものから具体的なものへとソートします。例えば、次の設定が与えられた場合
# Assets configuration
# ~~~~~
play.assets.cache."/public/stylesheets/"="max-age=101"
play.assets.cache."/public/stylesheets/layout/"="max-age=102"
play.assets.cache."/public/stylesheets/app/"="max-age=103"
play.assets.cache."/public/stylesheets/layout/main.css"="max-age=103"
play.assets.cache."/public/javascripts/"="max-age=201"
play.assets.cache."/public/javascripts/app/"="max-age=202"
play.assets.cache."/public/javascripts/app/main.js"="max-age=203"
ディレクティブは次の順序でソートおよび適用されます。
play.assets.cache."/public/javascripts/app/main.js"="max-age=203"
play.assets.cache."/public/javascripts/app/"="max-age=202"
play.assets.cache."/public/javascripts/"="max-age=201"
play.assets.cache."/public/stylesheets/app/"="max-age=103"
play.assets.cache."/public/stylesheets/layout/main.css"="max-age=103"
play.assets.cache."/public/stylesheets/layout/"="max-age=102"
play.assets.cache."/public/stylesheets/"="max-age=101"
注:
play.assets.cache."/public/stylesheets"="max-age=101"
のような設定は、public/stylesheets.css
とpublic/stylesheets/main.css
の両方に一致するため、ディレクトリをより明確に区別するために末尾に/
を追加することをお勧めします。例えば、play.assets.cache."/public/stylesheets/"="max-age=101"
のようにします。
§管理対象アセット
Play 2.3以降、管理対象アセットはsbt-webベースのプラグインによって処理されます。2.3より前は、PlayはCoffeeScript、LESS、JavaScriptリンティング(ClosureCompiler)、RequireJS最適化の形式で管理対象アセット処理をバンドルしていました。以下のセクションでは、sbt-webと、同等の2.2機能を実現する方法について説明します。ただし、Playはこのアセット処理テクノロジーに限定されず、多くのプラグインがsbt-webで利用可能になるはずです。利用可能なプラグインの詳細については、sbt-webプロジェクトをご確認ください。
多くのプラグインは、sbt-webのjs-engineプラグインを使用します。js-engineは、優れたTriremeプロジェクトを介してJVM内で、または優れたパフォーマンスのためにNode.jsで直接、Node APIに記述されたプラグインを実行できます。これらのツールは開発サイクル中にのみ使用され、Playアプリケーションの実行時には関与しません。Node.jsがインストールされている場合は、次の環境変数を宣言することをお勧めします。Unixの場合、SBT_OPTS
が他の場所で定義されている場合は、次のようにすることができます。
export SBT_OPTS="$SBT_OPTS -Dsbt.jse.engineType=Node"
上記の宣言により、sbt-webプラグインを実行する際にNode.jsが使用されるようになります。
§Rangeリクエストのサポート
Assets
コントローラーは、レンジリクエストと部分レスポンスの仕組みを定義するRFC 7233の一部を自動的にサポートします。Assets
コントローラーは、リクエストに満たせるRange
ヘッダーが存在する場合、206 Partial Content
を配信します。また、すべてのアセット配信に対してAccept-Ranges: bytes
を返します。
**注:**複数の範囲をより適切に処理するためにいくつかの解析が行われますが、`multipart/byteranges` はまだ完全にはサポートされていません。
Assets
コントローラーを使用せずにファイルを配信する際に、206 Partial Content
を返すこともできます。
§Scalaバージョン
def video(videoId: Long): Action[AnyContent] = Action { implicit request =>
val videoFile = getVideoFile(videoId)
RangeResult.ofFile(videoFile, request.headers.get(RANGE), Some("video/mp4"))
}
§Javaバージョン
public Result video(Http.Request request, Long videoId) {
File videoFile = getVideoFile(videoId);
return RangeResults.ofFile(request, videoFile);
}
どちらの例も、リクエストされた範囲に従って、ビデオファイルの一部のみを配信します。
このドキュメントに誤りを見つけましたか?このページのソースコードはこちらにあります。ドキュメントガイドラインを読んだ後、プルリクエストを送信してください。質問やアドバイスがあれば、コミュニティフォーラムにアクセスして、コミュニティとの会話を始めてください。