Nwht0xn1

RailsでnpmのFontAwesomeのWebフォントをS3経由で配信するCreated on 2016-05-19 by r7kamura

npm packageのFontAwesomeに含まれるSCSSとフォントファイルをRailsで利用しながら、S3とCloudFront経由で配信されるように設定する方法について。今回WikiHubでこのような利用方法を試したので、その技術情報をまとめておく。

$fa-font-pathを指定する

現状のSprocketsでは、assets:precompileするとWebフォントに対してもdigestの付いたパスが生成されるが、font-url("...")asset-url("...") をフォントファイルに対して利用しても、digestの付かないパスを生成してしまう。しかも、npm packageのFontAwesome用のSCSSファイルをimportして利用したいという都合上、どのみちURL部分に font-url を使うように直接編集したりはできない。

URLの前半部分はSCSSの $fa-font-path 変数を通して変更できるようになっているので、この仕組みを利用することにする。WikiHubのコードでは、以下のようにして、ERBを利用してCloudFrontのdistributionのURLをCSS中に埋め込んでいる。Railsでは、application.scss.erb のように後ろに拡張子 .erb を付けると、ERBとして評価したあとで、SCSSとしてコンパイルしてくれるようになる。

$fa-font-path: "<%= Rails.configuration.action_controller.asset_host %>/assets" !default;
@import "font-awesome/scss/font-awesome";

シンボリックリンクを配置する

FontAwesomeでは以下の5種類のフォントファイルを使用する。

ln -s ../../node_modules/font-awesome/fonts/fontawesome-webfont.eot public/assets/fontawesome-webfont.eot
ln -s ../../node_modules/font-awesome/fonts/fontawesome-webfont.svg public/assets/fontawesome-webfont.svg
ln -s ../../node_modules/font-awesome/fonts/fontawesome-webfont.ttf public/assets/fontawesome-webfont.ttf
ln -s ../../node_modules/font-awesome/fonts/fontawesome-webfont.woff public/assets/fontawesome-webfont.woff
ln -s ../../node_modules/font-awesome/fonts/fontawesome-webfont.woff2 public/assets/fontawesome-webfont.woff2

Railsでデプロイ時にS3にassetsを配置してCloudFront経由で配信する - Programming という記事で説明したように、WikiHubでは asset_sync を利用して、assets:precompileを実行した後に public/assets 以下のファイルをS3の特定のbucketにアップロードするようにしている。したがって、public/assets 以下にシンボリックリンクを配置しておくと、適当なタイミングでフォントファイルをS3にアップロードしてくれるようになる。

なお、asset_syncの設定に config.manifest = true という項目が残っていると、フォントファイルがmanifestに登録されていないがためにアップロード対象にならなくなってしまうので、この設定を外しておくことには注意したい。

CORSの設定をする

別ドメインのWebフォントをブラウザから読み込んで利用するには、そのWebフォントを配信するエンドポイントが、特定の条件でCORSに対応していなければならない。S3ではデフォルト設定でCORS用のレスポンスヘッダを含んでくれているが、Webフォントを読み込めるようにするには、少し設定を追加しなければならない。S3のbucketのCORS設定は、デフォルトでは以下のような設定になっている。

<CORSConfiguration>
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>Authorization</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

これに、次のように <AllowedHeader>Content-*</AllowedHeader> の項目を追加する必要がある。

<CORSConfiguration>
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>Authorization</AllowedHeader>
        <AllowedHeader>Content-*</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

なお、誤ったヘッダ情報もCloudFrontにキャッシュされてしまうので、先に設定を反映しておかないと、CORSの制約で正しくWebフォントが反映されないという事態を招いてしまうことに注意したい。