Closed7

Next.js上でMSWを、useSWRでSuspenseを有効にしているページでも初期表示で動作させる

OpionOpion

公式であるように

// windowがないときに server.listen()
} else {
  const { worker } = require('./browser');
  worker.start();
}

として

import 'mock.tsのパス'

としても、Suspenseを利用しているページにURLを直接アクセス叩いてアクセスすると

AxiosError: Request failed with status code 404
This error happened while generating the page. Any console logs will be displayed in the terminal window.
GET http://localhost:XXXX/foo
ステータス 500 Internal Server Error

のようにエラーを返される。

OpionOpion
  • URL直叩きでなく、何もAPIを叩いていないページから遷移してくると動作する
  • suspenseを切ったときも動作する
  • API単体で切り出してボタン経由で叩くと動作する

から、どうやらモックが準備できたタイミングより前に叩いているのが原因っぽい。

OpionOpion

そのため以下のようにHOCとして書いたところ、それでも動作しなかった。
consoleでは mock enabled のような表記のあとにAPI通信でエラーが発生していた。

export const MswWrapper: FC<Props> = ({ children }) => {
  const [enabled, setEnabled] = useState(false);

  useEffect(() => {
    if (enabled) return;
    if (process.env.NODE_ENV !== 'development') return setEnabled(true);

    (async () => {
      const { worker } = await import('./browser');
      worker.start();
      setEnabled(true);
    })();
  }, [enabled, setEnabled]);

  if (process.env.NODE_ENV === 'production') return children;
  return <>{enabled && children}</>;
};

OpionOpion

そのためmockが有効になるタイミングとmockAPIが実際に叩けるタイミングにズレがあり、その僅かな差の間に通信が差し込まれてエラーになった、と仮定した。

よって若干待つ処理を入れたところ、動作した。

    (async () => {
      const { worker } = await import('./browser');
      worker.start();
      // モックが有効になるまで時間がかかるので少し待つ
      await new Promise((_) => setTimeout(_, 1000));
      setup();
    })();
OpionOpion

まったく綺麗ではないけれど開発環境でしか影響しないしいったんこれでいいや……という気持ち半分、それでも綺麗に書きたい気持ち半分。
どなたか正しく美しく動作するコードあれば教えてください…… :bow:

OpionOpion

なんてことはなく、StartReturnType が内部的にPromise型だったのを見落としていただけだった。
しょーーーーーもないエラーで詰まってたっぽいですかなしい

declare type StartReturnType = Promise<ServiceWorkerRegistration | undefined>;

interface SetupWorkerApi {
    start: (options?: StartOptions) => StartReturnType;
(async () => {
   const { worker } = await import('./browser');
   await worker.start();
   setup();
})();
OpionOpion
return <>{enabled && children}</>;

これSEO死にます(useEffectの中でしかenabledはtrueにならないのでcrawlerが解釈できない。envを見てchildrenを即座に流せるようにしないといけない)

このスクラップは2022/11/08にクローズされました