GAE 便利さに気づいてからめちゃくちゃ気に入っている。
最近開発が活発な Cloud Run や、Firebase のバックエンド実行環境でもある Cloud Functions が話題に登りがちだけど、2nd gen になってからの GAE はめちゃめちゃいいです。
トラフィック分割などの機能も揃っているしハマりも少ないので Function レベルのコードを動かしたいときでも GAE を選びたくなることがある。GCP ドキュメントのサーバーレス オプションの選択フローチャートでも、おおよそ GAE に行き着くんじゃないかな。
最近個人ポートフォリオサイトを Next.js & GAE Standard Env で作ったので、その話を書く。
当初は単にこのブログに AdSense を貼りたかったんだけど、独自ドメインにしたので、まずルートドメインの AdSense 審査を通す必要ができてしまった... なのでなんらかのコンテンツを pokutuna.com に置く必要に迫られたからなんだけども。
最小
package.json
{ ... "scripts": { "start": "next start -p $PORT", ... } }
app.yaml
runtime: nodejs12 handlers: - url: /.* script: auto secure: always redirect_http_response_code: 301
package.json
で next
を起動する際にポートを指定する、リクエストは全部アプリケーションで受ける。
GAE の Node ランタイムはアプリケーションを起動する際に start
スクリプトを実行するので、期待する PORT
環境変数のポートで待ってあげる。大抵 8080 なのでハードコードされてる例をたまに見るけど、結構 8081 で来るよ。
Node.js ランタイム環境 | Node.js 用 App Engine スタンダード環境に関するドキュメント
これぐらいで $ yarn build && gcloud app deploy
で動く
_next/static
以下の配信
このままだと、静的ファイルも Next.js のアプリケーションから返しているので効率が悪い。_next/static
以下へのアクセスを、ビルドディレクトリ .next/static
へ生成された静的ファイルへマッピングするようにする。
runtime: nodejs12 handlers: - url: /_next/static static_dir: .next/static - url: /.* script: auto secure: always redirect_http_response_code: 301
static_dir
, static_files
で GAE により配信される静的ファイルは、デフォルトで Cache-Control: public, max-age=600
で返る。どうせパスに BUILD_ID やハッシュ値が含まれるので、expiration: 365d
などしてめちゃ長くキャッシュさせてもよいかも。
app.yaml 構成ファイル | Node.js 用 App Engine スタンダード環境に関するドキュメント
public
以下の配信
Next.js 9.1 から public/
直下のファイルがそのままのパスで配信できるようになった。
単に public/
以下に置くだけで参照できるのは良いけど、URL から pages/
以下と区別するのはむつかしい。
以下のようにするのがおすすめ。
- JSX から参照する画像などは諦めて
/static/image.png
のように参照して、/static
以下をpublic/static
にマッピング robots.txt
などパスに制約があるファイルはstatic_files
で個別にマッピング
handlers: - url: /_next/static static_dir: .next/static - url: /static static_dir: public/static - url: /robots.txt static_files: public/robots.txt upload: public/robots.txt - url: /.* script: auto secure: always redirect_http_response_code: 301
もし public/static
のようなディレクトリを掘りたくないなら、静的ファイルっぽい拡張子を public/
以下へマッピングする手もある。
handlers
はリクエストごとに上から下へ評価されて最初にマッチするものに処理されるので、/_next/static
より後に書けば Next.js にビルドされるアセットと拡張子がかぶっていても問題ないはず、もし拡張子に漏れがあってもアプリケーションから返るのでぶっ壊れはしないだろう。
handlers: - url: /_next/static static_dir: .next/static - url: /(.*\.(gif|png|jpg|ico|svg|css|txt))$ static_files: public/\1 upload: public/.*\.(gif|png|jpg|ico|svg|css|txt)$ ...
アップロードするファイルを減らす
pages/
以下やらなんやらはビルドに含まれるのでディレクトリをデプロイする必要はない。.gcloudignore
で必要なものにしぼることでデプロイの高速化とイメージサイズの削減を見込める。
# ignore all /* # upload !/app.yaml !/package.json !/package-lock.json !/yarn.lock !/public/ !/.next/
しかし .next/
以下はビルドごとに太っていく。ビルドディレクトリをきれいにする件についてはこういう issue があるみたいですね。
[RFC] cleaning distDir on next build · Discussion #6009 · vercel/next.js
ぼくはこういう Makefile で都度消してデプロイしてます。
PROJECT := YOUR_PROJECT_ID GCLOUD := gcloud --project $(PROJECT) .PHONY: build build: yarn build .PHONY: clean clean: rm -rf .next/ .PHONY: deploy deploy: clean build $(GCLOUD) app deploy