Post

Next.js + MSW Service Worker Registration Fix Under a basePath

Next.js + MSW Service Worker Registration Fix Under a basePath

Upgrade MSW to 2.6.6.

背景

把 CRA 搬到 Next.js(App Router)後,我的網站部署在 /TeachCertAdm。 MSW 在啟動時一直報錯:

1
2
3
[MSW] Failed to register the Service Worker:
ServiceWorker script at http://localhost:3000/mockServiceWorker.js  
for scope http://localhost:3000/ encountered an error during installation.

這代表 SW 嘗試從根目錄 mockServiceWorker.js 註冊,但我的實際路徑在 /TeachCertAdm/ 下,導致路徑與 scope 不匹配。

解法要點

  1. Next.js 要設 basePath
  2. 強制 trailing slash(確保 /TeachCertAdm/ 結尾)
  3. MSW 用 basePath 組出正確的 SW URL 與 scope

設定一:next.config.mjs

1
2
3
4
5
6
7
8
9
const basePath = process.env.NEXT_PUBLIC_BASE_PATH || "";

const nextConfig = {
  reactCompiler: true,
  basePath,
  trailingSlash: true,
};

export default nextConfig;

設定二:.env.local

1
NEXT_PUBLIC_BASE_PATH=/TeachCertAdm

設定三:providers.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
"use client";

import { useEffect, useState } from "react";

export default function Providers({ children }) {
  const [ready, setReady] = useState(process.env.NODE_ENV !== "development");

  useEffect(() => {
    if (process.env.NODE_ENV !== "development") return;

    let active = true;

    (async () => {
      const { worker } = await import("../mocks/browser");
      const basePath = process.env.NEXT_PUBLIC_BASE_PATH || "";
      const scope = basePath ? `${basePath}/` : "/";
      await worker.start({
        serviceWorker: {
          url: `${basePath}/mockServiceWorker.js`,
          options: { scope },
        },
      });  
      if (active) setReady(true);
    })();

    return () => {  
      active = false;
    };
  }, []);
  
  if (!ready) return null;
  return children;
}

注意事項

  1. 開發時網址一定要用 http://localhost:3000/TeachCertAdm/, 結尾一定要有 /;
  2. 有改 next.config.mjs 或 .env.local 一定要 重啟 dev server

結論

錯誤的根本原因是 MSW 的 SW 路徑跑到 mockServiceWorker.js,
但實際部署在 /TeachCertAdm 下。
用 basePath + trailingSlash + 正確 scope 就能穩定解決。

This post is licensed under CC BY 4.0 by the author.