2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ReactAdvent Calendar 2024

Day 4

Next.js 15(あるいは 14.2.8)から Server Actions で Top-level await が使えるようになっていた

Last updated at Posted at 2024-11-02

ES2022 から ECMAScript 仕様に Top-level await が導入されました。これは従来 async な関数の中でしか呼べなかった await を、モジュールのトップレベルでも利用可能にしたものです。これまで IIFE パターン等で解決していたものをずいぶんスマートに書けるようになりました。

import { xxx } from "xxx";

...

// async 関数の外でも await を使用できる
const yyy = await xxx();

Next.js も 13.4.5 から Top-level await をサポートしています。1 コンポーネントのトップレベルで行いたい処理が Promise なケースでは便利に使えそうです。

一方、Next.js 14.2.7 の Server Actions 内で Top-level Await を使うとこのようなエラーになってしまいました。

SSA-Error-on-Next-14.2.7.png

これは残念な結果です。Server Actions のトップレベル(関数外)で定義された変数の初期化処理を考えてみましょう。たとえば、データベースへの接続処理などです。非同期コードが必要な場合、冗長な回避策を講じることになります。

// 再代入するため let で宣言することになるし、
// conn が null であるパターンの考慮も必要になる
let conn: Connection | null = null;

// しかも IIFE は冗長
(async () => conn = await xxx())();

一方、Top-level await が使用できれば静的でスマートな記述ができるはずです。

const conn: Connection = await xxx();

同感の人は多かったのか、2023 年の 8 月には Issue #54282 として起票されていました。

Next.js 15 でやってみる

去る 2024 年 10 月 24 日の Next.js Conf にて、Next.js 15 がリリースされました。

Next.js 15 のリリース内容を確認すると、#64508 Improve top level await coverage という PR が見られます。Webpack の出力ターゲットを ES2015 に変更して async function を出力可能にしたという内容です。Server Actions でもうまくいくか、試してみましょう。

page.tsx
"use client";

import { useActionState, JSX } from "react";
import { action } from "../lib/actions";

export default function Home(): JSX.Element {
  const [state, dispatch] = useActionState(action, 0);

  return (
    <div>
      <form action={dispatch}>
        <input type="text" name="input1" />
        <input type="submit" />
      </form>
      Server Actions called {state} times.
    </div>
  );
}

actions.ts
"use server";

const sleep = (ms: number): Promise<string> => new Promise(resolve => setTimeout(() => { resolve("sleeped") }, ms));

// Top-level Await
const data = await sleep(1000);

export async function action(state: Readonly<number>, formData: Readonly<FormData>) {
    console.log("Server Actions!", state, formData.get("input1"));

    console.log(data);

    return state + 1;
}

SSA-Success-on-Next-15.0.2.gif

やりました! なお、サンプルコードの全文はこちらのレポジトリに格納しています。

実は Next.js 14 にもバックポートされていた

本稿を書くために改めて検証したところ、Next.js 14.2.8 から Server Actions で Top-level await が使えるようになっていました。どうやら Next.js 15 からのバックポートが行われたようです。

とはいえ、Next.js v15 には Server Actions のセキュリティ強化も含まれますから、Server Actions ユーザはこれに関わらず早期の対応を予定するとよいでしょう。

参考リンク

  1. ただし TypeScript プロジェクトでは tsconfig.json でターゲットを ES2022 にする必要があります。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?