Elixir
Phoenix

PhoenixでS3 + CloudFrontでアセットを配信する

More than 1 year has passed since last update.

やりたいこと

priv/static以下の静的ファイルをmixのタスクからS3にアップロードし、CloudFrontからアセットを配信したい

やったこと

PHPでLaravel向けにvinelab/cdnというアセットライブラリがあるのだけどElixirに似たようなライブラリがなかったのでポートしたのを作ってS3 + CloudFrontで配信出来るようにした

cdn | Hex (GitHub)

Installation

  • mix.exsに依存を追加
{:cdn, "~> 0.0.4"}
  • 依存更新
mix deps.get
  • configを追加

config/config.exs

config :cdn,  include: [
                directories: ["priv/static"],
                patterns: ["**/*"],
                hidden: true
              ],
              exclude: [
                directories: [],
                patterns: [],
                hidden: true
              ],
              acl: :public_read,
              bypass: true,
              cache_control: "max-age=#{86400 * 30}",
              expires_after: 86400 * 30
項目 説明
include directories: アップロード対象のディレクトリ
patterns: Glob patternでアップロード対象の絞込。複数指定可。
hidden: 隠しファイルを含めるかどうかをtrue, falseで指定
exclude 除外対象のファイル。includeと同じようにディレクトリとパターンを指定。
acl アップロードしたオブジェクトの権限。アセットとして公開されるので通常はpublic_readにする。
cache_control Cache-Controlヘッダに指定する値
expires_after Expiresヘッダに指定するキャッシュ期限切れまでの秒数

config/dev.exs

config :cdn, bucket: "foobar.assets",
             cloudfront_url: "https://foobar.cloudfront.net",
             bypass: true
項目 説明
bucket アップロード対象のS3バケット
cloudfront_url S3と紐付けられているCloudFrontのURL
bypass trueの場合ビュー用のヘルパーでURLを補完しない。
e.g. cdn("/css/app.css") => "/css/app.css"

config/prod.exs

config :cdn,  bucket: System.get_env("ASSET_BUCKET") || "foobar.production.assets",
              cloudfront_url: System.get_env("ASSET_HOST") || "https://foobar.cloudfront.net",
              bypass: false
項目 説明
bypass falseの場合ビュー用ヘルパーでURLを補完する。
e.g. cdn("/css/app.css") => "https://foobar.cloudfront.net/css/app.css"
  • AWSのアクセスキーを環境変数にセット
export AWS_ACCESS_KEY_ID=foo
export AWS_SECRET_ACCESS_KEY=bar

Usage

  • アセットアップロード

mix cdn.push

  • 削除

mix cdn.empty

image

  • テンプレートで静的ファイルの読み込み

web/web.ex

def view do
~中略~
  # 追加
  import Cdn.Helpers

end

app.html.eex

<script src="<%= cdn static_path(@conn, "/js/vendor.js") %>"></script>

# bypass=trueの場合
#=> "<script src="/js/vendor.js"></script>"

# bypass=falseの場合
#=> "<script src="https://foobar.cloudfront.net/js/vendor.js"></script>"

まとめ

  • PhoenixでS3 + CloudFrontでアセットを配信出来るようにした
  • Elixir内で完結するので他のツール使いたくない場合はいいかも
  • 今気づいたけどasset_syncって似たようなライブラリが既にありますね(遅)