msw: Package path ./browser is not exported from package (Next.js)

Prerequisites

Environment check

  • I’m using the latest msw version
  • I’m using Node.js version 14 or higher

Browsers

Chromium (Chrome, Brave, etc.)

Reproduction repository

https://github.com/xereda/nextjs-msw-example

Reproduction steps

  • clone the above repository;
  • install the dependencies (yarn install);
  • run the server (yarn dev);

Current behavior

yarn dev                             yarn dev                                                                                                                 17.8m  ter 21 nov 2023 14:52:22
yarn run v1.22.19
warning ../package.json: No license field
$ next dev
   ▲ Next.js 14.0.3
   - Local:        http://localhost:3000

warning ../package.json: No license field
 ✓ Ready in 2.4s
 ○ Compiling / ...
 ⨯ ./src/mocks/browser.js:2:0
Module not found: Package path ./browser is not exported from package /home/xereda/repositories/nextjs-msw-example/node_modules/msw (see exports field in /home/xereda/repositories/nextjs-msw-example/node_modules/msw/package.json)
  1 | // mocks/browser.js
> 2 | import { setupWorker } from "msw/browser";
  3 | import { handlers } from "./handlers";
  4 |
  5 | if (process.env.NODE_ENV === "development" && typeof window !== "undefined") {

https://nextjs.org/docs/messages/module-not-found

Import trace for requested module:
./src/pages/_app.js

Expected behavior

Service mock enabled.

About this issue

  • Original URL
  • State: closed
  • Created 7 months ago
  • Reactions: 14
  • Comments: 16 (3 by maintainers)

Most upvoted comments

This issue appears to be due to NextJS attempting to import /browser from the Node environment for SSR. I resolved this issue by using dynamic import only in the browser environment.

if (typeof window !== 'undefined') {
  const { setupWorker } = await import('msw/browser');
  …

I found duplicate issue here

https://github.com/mswjs/msw/issues/1801

try this in your next.config.js

/** @type {import('next').NextConfig} */
const nextConfig = {
   webpack: (config, { isServer }) => {
      if (isServer) {
         // next server build => ignore msw/browser
         if (Array.isArray(config.resolve.alias)) { // in Next the type is always object, so this branch isn't necessary. But to keep TS happy, avoid @ts-ignore and prevent possible future breaking changes it's good to have it
            config.resolve.alias.push({ name: "msw/browser", alias: false })
            } else {
            config.resolve.alias["msw/browser"] = false
            }
         } else {
            // browser => ignore msw/node
            if (Array.isArray(config.resolve.alias)) {
            config.resolve.alias.push({ name: "msw/node", alias: false })
            } else {
            config.resolve.alias["msw/node"] = false
            }
         }
      return config;
   }};

module.exports = nextConfig

For the record, this also happens with Nuxt.js and Vite, in conjunction with Histoire (a Storybook replacement).

SSR is disabled in our configuration. This is the only package displaying this problem, so I still figure it may be connected to MSW. I’ll post a comment/PR if I can pinpoint exactly how.