Closed8

Next.js on GAEで失敗したデプロイ設定を供養する

catnosecatnose

Next.jsをGAEにデプロイするにあたり、 とある方法を取るとうまくいくはずなのに何故かうまくいきませんでした(未解決)。後から振り返られるように何をやったのかを載せておきます。

catnosecatnose

app.yamlの設定(ここは問題なし)

同じ内容のapp.yamlでも他の方法だとうまく動いたので、おそらく失敗の原因ではないと思われます。

app.yaml
env: standard # スタンダード環境(省略可)

runtime: nodejs14 # Node.js 14を使う

instance_class: F4

service: default # GAEのサービスの名前。frontendとかでも良いかも

handlers:
  - url: /_next/static
    static_dir: .next/static
  - url: /(.*\.(gif|png|jpg|ico|txt|svg))$
    static_files: public/\1
    upload: public/.*\.(gif|png|jpg|ico|txt|svg)$
  - url: /.*
    script: auto
    secure: always

default_expiration: "12h" # 静的ファイルのキャッシュ期間

env_variables:
  NODE_ENV: "production"

automatic_scaling:
  min_instances: 0 # 動かしてないときはインスタンスを0にする

package.json

package.json
{
   "scripts": {
     "dev": "next dev",
+    "build": "next build",
+    "gcp-build": "npm run build",
+    "start": "next start -p $PORT",  
   },
}

解説1:パッケージのインストールはGAE側でやってくれる

GAEへデプロイする際にはgcloud app deployというコマンドを実行することになります。ここがすごく分かりづらいのですが、GAEスタンダード環境でNode.jsランタイムを使った場合、デプロイ時にGAE側でパッケージのインストールを行なってくれます。

アプリをデプロイすると、Node.js ランタイムは、npm install コマンドを使用して、すべての dependencies を自動的にインストールします(yarn.lock ファイルが存在する場合は yarn install コマンドを使用します)。
依存関係の指定

つまり、デプロイを行う際にはnpm installコマンドを実行するステップは不要なはずです。

yarn.lockがあればyarn installになる

上に書かれている通り、プロジェクト内にyarn.lockがあればnpm installの代わりにyarn installを実行してくれます。

解説2: npm run buildは自動ではされないのでgcp-buildとして指定

ただし、GAE側ではデプロイ時にnpm run buildの実行はしてくれません。そのままアプリを動かすと以下のようなエラーが発生します。

Error: Could not find a production build in the '/workspace/.next' directory. Try building your app with 'next build' before starting the production server.

GAEではpackage.jsonのscriptsgcp-buildが含まれていると、そちらをビルド時に合わせて実行してくれるので"gcp-build": "npm run build"を追記しておきます。

カスタムビルドステップについて

解説3: npm startはGAEで実行される

Next.jsでビルドしたアプリを動かすにはnext startを実行することになります。GAEではpackage.jsonstartスクリプトが書かれていると、アプリ起動時に実行してくれます。

デフォルトでは、ランタイムは node server.js を実行してアプリケーションを起動します。package.json ファイルで start スクリプトを指定すると、ランタイムは代わりに指定された起動スクリプトを実行します。
アプリケーションの起動

.gcloudignoreの設定

.gcloudignore
.gcloudignore
.gitignore

node_modules/

ビルド後のソースコードをgcloud app deployにアップロードするのであれば.gcloudignoreにビルド前のファイル(/components/pages、その他のソースファイル)も含めることができます。

しかし、今回のケースだとNext.jsのビルドはGAE側で行われるため、それらのファイルを.gcloudignoreに含めるとビルドに失敗します。

これでデプロイするとなぜか静的ファイルが読み込まれない

gcloud app deploy app.yaml --project=プロジェクト名

で、これでデプロイをしたところ、デプロイ自体は成功したのですが、なぜか静的ファイル(JS、CSSなどの.next/staticに吐き出されるファイル)が404になり、全くスタイルがあたらない状態になってしまいました。

何が原因なのかは分かってません

shin1ktshin1kt

ほぼ同じ症状に悩まされていました。(こちらは、Nuxt + Yarn)
とりあえず一旦諦めて他の方法に切り替えるきっかけにできました。ありがとうございました。
(cloudbuild時にbuildする方法も参考にさせていただきました)

catnosecatnose

コメントありがとうございます!お役に立てたようで良かったです。

ふーみんふーみん

だいぶ今更ですが、静的ファイルはbuild時に生成されたものはコピーされず、app deploy時にGCSのステージングバケットにアップロードされたものを利用するらしいので、最初からビルドしてapp deployで一緒にアップロードしてあげないといけないみたいです^^;

https://issuetracker.google.com/issues/254981462

catnosecatnose

ほぇ〜、そういうことなんですね!
情報ありがとうございます!

このスクラップは2021/03/22にクローズされました