🚀

新しくなった Amplify Hosting を利用してNext.js14のアプリの機能を試してみた

2023/11/24に公開

📌 はじめに

こんにちは!@Ryo54388667です!☺️
普段は都内でフロントエンドエンジニアとして業務をしてます!主にTypeScriptやNext.jsといった技術を触っています~

先日、AWS Amplify についてのアップグレード情報がありました!🎉

https://twitter.com/AWSAmplify/status/1724831823023263887

その中でも本業でも頻繁に利用しているAmplify Hosting(以下 Amplify)も新しくなったということで、早速いろいろと試してみました!

📌 確認対象の機能について

Amplify Hostingの動作を確認するため、可能な限り公式のアプリを利用することにします。
(アプリ側に挙動の問題が無いことを担保する意味もあります。)
必要があれば、Vercel公式の下記のPlaygroundの挙動と比較する。
https://app-router.vercel.app/

今回、確認する機能は以下の通りです。

  1. Edge Runtime の機能
  2. On-Demand ISR の機能
  3. SSR Streaming の機能
  4. (おまけ枠 : Server Actions の機能)

これらは以前、サポート外とされていた機能です。
現在、以前のサポートページは閉鎖されてしまいました。。😇
(追記)こちらに移動していました!

ソフトウェアのバージョン

パッケージ バージョン
next 14.0.0
react 18.2.0

📌 Amplify Hosting の留意点

確認作業をしている中で、つまづいた点があったのでを共有します!

下記のコマンドを入力し、プロジェクトを作成します。
公式から提供されるソースコードは非常に助かります!大感謝です!👏

npx create-next-app@latest <アプリのPJ名> --use-npm --example "https://github.com/vercel/app-playground"

このプロジェクトをAmplify と連携し、デフォルトの設定のままだと、ビルドフェーズでこけてしまいます😇

[ERROR]: !!! Build failed
2023-11-19T03:53:36.606Z [INFO]: Please check the supported SSR features to find if your build failure is related to an unsupported feature

これは、Next.js14のNode.jsのミニマムサポートは18.17になった関係で、Amplifyのデフォルトのイメージ(Amazon Linux:2)で不具合が起きるようです。

[Breaking] Minimum Node.js version is now 18.17
https://nextjs.org/blog/next-14

修正方法は下記の公式ドキュメントに従い、Amazon Linux: 2023 のイメージを選択することです!💪

Amplify Hosting now has Next.js 14 support as well. To use this new feature, set amplify:al2023 as the value for the custom build image if this is the app’s first deployment. Conversely, if the app has already been deployed, then select the Amazon Linux: 2023 image from the dropdown.
https://aws.amazon.com/jp/blogs/mobile/6-new-aws-amplify-launches-to-make-frontend-development-easier/

変更方法は非常に簡単です!GUI上で完結します!

//GUI
//手順
Amplify の対象のPJにアクセス > サイドバーのビルドの設定 > 
Build image settings のedit ボタンの押下 > 構築イメージのドロップダウンから選択 > 保存

これらの操作を行ったのち、再ビルドするとNext.js14のアプリをAmplifyにデプロイすることができます!

後日談ですが、確認作業前の準備段階で、けっこうな時間が溶けてしまいました。。😭 ツラい。。
とにもかくにも、確認の準備ができました!🎉

📌 各機能の確認

1. Edge Runtime の機能

概要

Next.jsではバージョン12.2以降、利用するランタイムをNode.jsまたは、Edgeに最適化された軽量のランタイムから選択できるようになりました。
https://nextjs.org/blog/next-12-2#edge-server-rendering-experimental

以前、Amplify SSRサポートのページではこちらのEdgeの機能は対象外との旨が記載されていました。
そこで今回は、AmplifyがEdge Runtimeに対応しているかどうか確認していきます!

レスポンスヘッダーについて

Node.jsを指定したページとEdgeRuntimeを指定したページで、レスポンスヘッダーのプロパティに差異があるかどうか確認します!Chromeのデベロッパーツール(Networkタブ > Headersセクション)を利用します。

  • /streaming/node/product/1 のレスポンスヘッダー
  • /streaming/edge/product/1 のレスポンスヘッダー

Edge Runtimeを指定したページでは下記のようなプロパティが存在しました!
X-Edge-Runtime: 1
このプロパティを詳しく調査しようと思ったのですが、あまり情報がありませんでした。
AWSのCloudFrontで付与されているプロパティと思われます。
確信は持ててないですが、Edge Runtimeを利用していると思しきプロパティがありました!👏

TTFB(Time To First Byte)について

一般的にはEdge Locationで処理を行うページはOriginで処理を行うページよりも応答速度は早くなるはずなので確認してみます。Chromeのデベロッパーツール(Networkタブ > Timingセクション)を利用します。下記のような画像の箇所を確認します。

参考: Waiting (TTFB)について

Waiting (TTFB). The browser is waiting for the first byte of a response. TTFB stands for Time To First Byte. This timing includes 1 round trip of latency and the time the server took to prepare the response.
https://developer.chrome.com/docs/devtools/network/reference/?utm_source=devtools#timing-explanation

Node.jsを指定したページとEdge Runtimeを指定したページのwaiting for server responseの時間(s)を比較しました。

Node.js Edge Runtime
平均値 1.428 1.281
中央値 1.43 1.29

※ 単位: 秒(s)

計測データ(10回)
Node.js Edge Runtime
1 1.52 1.33
2 1.47 1.36
3 1.75 1.24
4 1.49 1.14
5 1.33 1.25
6 1.31 1.34
7 1.39 1.38
8 1.17 1.29
9 1.61 1.29
10 1.24 1.19

今回、自分の環境だと、Edge RuntimeのほうがTTFBの値が良いという結果になりました。

💡 試してみた結果

以上より、EdgeRuntimeの機能が意図通り動いていると思われます!
ただ、TTFBの結果を見る限り劇的なパフォーマンスの改善には、なっていない気もします。
個人の所感ですが、Edgeの旨みがあるかといえば微妙です。。

2. On-Demand ISR の機能

概要

任意のタイミングでのキャッシュパージとページの再生成が可能な機能です。
Next.js12.2未満のときは、一定時間経過後にキャッシュパージを行い、ページを再生成する機能はありましたが、任意のタイミングでこの挙動を実現するとはできませんでした。

Starting with v12.2.0, Next.js supports On-Demand Incremental Static Regeneration to manually purge the Next.js cache for a specific page.
https://nextjs.org/docs/pages/building-your-application/data-fetching/incremental-static-regeneration#on-demand-revalidation

確認方法について

  1. /isr/2 でページを再生成させる。
    ==> このページは60s後の再検証が設定されています。60s後に2度ページを更新し、カウンターが「0s」 になることを確認します。
  2. /api/revalidate?path=/isr/[id] にアクセス(任意の再検証)
    ==> {"revalidated":true,"now":1700625412414,"cache":"no-store"} ==> 裏側でHTMLを再生成
    詳しくはアプリ側のコードを参照してください。
  3. /isr/2 にアクセス
    ==> 60sを待たずに、HTMLが再生成されていることを確認します。(カウンターが「0s」 になる)

上記の方法を確認してみました!(画像サイズの関係上、ガビガビですいません。。)

💡 試してみた結果

意図通り動いている!good!

3. SSR Streaming の機能

概要

SSRの問題点を解決するような新しいレンダリング技術。

  • HTML を送信する前に、すべてのデータがサーバーに読み込まれるのを待つ必要はなくなりました。代わりに、アプリのシェルを表示するのに十分な情報が得られたらすぐに HTML の送信を開始し、準備ができたら残りの HTML をストリーミングします。
  • ハイドレートを開始するためにすべての JavaScript が読み込まれるのを待つ必要はもうありません。代わりに、コード分割とサーバー レンダリングを併用できます。サーバーの HTML は保持され、関連するコードが読み込まれるときに React がそれをハイドレートします。
  • ページとの対話を開始するために、すべてのコンポーネントがハイドレートされるのを待つ必要はなくなりました。代わりに、選択的ハイドレーションを利用して、ユーザーが操作しているコンポーネントに優先順位を付け、早期にハイドレーションを行うことができます。
    https://github.com/reactwg/react-18/discussions/37

レスポンスヘッダーについて

公式のページとAmplifyでデプロイしたページのレスポンスヘッダーのプロパティに差異があるか確認してみます!Chromeのデベロッパーツール(Networkタブ > Headersセクション)を利用します。

  • Amplifyでデプロイしたページ
    /streaming/node/product/1 のレスポンスヘッダー
  • 公式ページ
    /streaming/node/product/1 のレスポンスヘッダー

結果的にはSSR Streamingとわかるようなデータはありませんでした😇
また、AWS LambdaのSSR Streamingの場合はtransfer-encoding: chunked が付与されているので、これが付与されているかを確認したのですが、こちらのデータも見当たりませんでした。

Suspenseのfallbackに指定されたローディングコンポーネントについて


動画を見ての通り、Suspenseのfallbackに指定したローディングアニメーションが表示されてません。公式のほうではスケルトンローディングのアニメーションが表示されてます。

TTFB(Time To First Byte)について

今回はSSR Streaming対応したLambda Web Adapterを利用したページとAmplifyでデプロイしたページのTTFBを比較します。
Vercel公式のページだとVercelのキャッシュ等の関係で正確な結果になりそうにないなと判断したので、不採用としました。Chromeのデベロッパーツール(Networkタブ > Timingセクション)を利用します。

今回はSSR Streaming対応したLambda Web Adapterを利用したページとAmplifyでデプロイしたページのwaiting for server responseの時間(ms)を比較します。

Ampify Lambda Web Adapter
平均値 1361 710.977
中央値 1330 679.56

※ 単位: ミリ秒(ms)

計測データ(10回)
Ampify Lambda Web Adapter
1 1500 974.13
2 1300 1060
3 1320 455.56
4 1230 1090
5 1460 919.7
6 1340 402.2
7 1350 671.36
8 1180 687.76
9 1740 521.57
10 1190 327.49

今回、自分の環境だと、AmplifyよりもLambda Web Adapter のほうがTTFBの値がすこぶる良いという結果になりました。

💡 試してみた結果

以上をみると、AmplifyではSSR Streaming は対応しているとは言い切れないです。。

4. Server Actions の機能(おまけ)

せっかくNext.js14 のアプリをデプロイしたので、StableになったServer Actionsの挙動も確認してみます。

// lib/actions.ts
"use server";
export async function deleteAction(formData: FormData) {
  try {
    console.log("Actions");
    console.log(formData);
    return { message: "Deleted" };
  } catch (error) {
    return { message: "Database Error: Failed to Delete." };
  }
}
//page.tsx
<form action={deleteAction}>
        <input type="hidden" name="id" value="Actions Value" />
        <button className="rounded-md border p-2">
          <span>Deleteボタン</span>
        </button>
</form>

💡 試してみた結果

ログ

サーバーにログがはかれていました!簡易的にではありますが、意図通りサーバー側で動いていそうです!もちろん、簡易的なものなので、作り込んだ機能だとうまくいかない可能性はあります。

📌 まとめ

新しくなった Amplify Hosting を利用してNext.js14のアプリのいくつかの機能を試してみました!

確認した機能 今回試してみた結果
1. Edge Runtime 🤔
2. On-Demand ISR 🙆‍♂️
3. SSR Streaming
4. Server Actions 🙆‍♂️

Next.js App Router のアプリケーションをどのサービスを利用してデプロイするのかはホットな話題だと思います。Amplifyも選択肢のひとつですね!

書き散らしたスクラップ

最後まで読んでいただきありがとうございます!
気ままにつぶやいているので、気軽にフォローをお願いします!🥺

https://twitter.com/Ryo54388667/

デベキャン

Discussion