Vite PWA - Not able to register mock service worker in parallel with other service workers

751 views Asked by At

I have tried to get working mock service worker inside a react vite PWA project. I have setup a mock service worker by following their documentation. I have setup handlers like this:

import { rest } from 'msw'

export const handlers = [
  rest.post('/login', (req, res, ctx) => {
    // Persist user's authentication in the session
    console.log('req', req)
    sessionStorage.setItem('is-authenticated', 'true')

    return res(
      // Respond with a 200 status code
      ctx.status(200),
    )
  }),

  rest.get('/user', (_, res, ctx) => {
    // Check if the user is authenticated in this session
    const isAuthenticated = sessionStorage.getItem('is-authenticated')

    if (!isAuthenticated) {
      // If not authenticated, respond with a 403 error
      return res(
        ctx.status(403),
        ctx.json({
          errorMessage: 'Not authorized',
        }),
      )
    }

    // If authenticated, return a mocked user details
    return res(
      ctx.status(200),
      ctx.json({
        username: 'admin',
      }),
    )
  }),
]

I am setuping and starting worker like this:

async function main() {
  console.log(process.env.NODE_ENV)
  if (process.env.NODE_ENV === 'development') {
    await worker.start({ onUnhandledRequest: 'warn' })
    worker.printHandlers()
  }

  const queryClient = new QueryClient()

  const router = createBrowserRouter([
    {
      path: '/',
      element: <SignIn />,
    },
    {
      path: '/dashboard',
      element: <div>Hello dashboard here!</div>,
    },
  ])

  ReactDOM.createRoot(document.getElementById('root')!).render(
    <React.StrictMode>
      <QueryClientProvider client={queryClient}>
        <RouterProvider router={router} />
      </QueryClientProvider>
    </React.StrictMode>,
  )
}

I can see that msw is enabled in the browser. I can see that file is available at http://localhost:5173/mockServiceWorker.js. Also handlers are printed in the console:

{
    "shouldSkip": false,
    "ctx": {},
    "info": {
        "header": "POST /login",
        "path": "/login",
        "method": "POST",
        "callFrame": "http://localhost:5173/node_modules/.vite/deps/msw.js?v=3f9ea0d4:24895:40"
    }
}

But, when I am making a request from my app, like this for example:

const mutation = useMutation({
    mutationFn: (data: FormData) => {
      console.log('data', data)
      return axios.post('/login', data)
    },
    onSuccess: () => navigate('/dashboard'),
  })

I can see that nothing is intercepted from the msw. I have tried to create a codesanbox, but I couldn't get it working there. At least you can see how the files are looking and what kind of setup I have. How should I debug this, I have tried what there is suggested at msw documentation site, but with no luck? How can I get msw fixed so that it intercepts requests?

I see that the file registerSW.js in the dev-dist directory is doing something that is obstructing the registration of mockServiceWorker.js. The code in registerSW.js looks like this:

if('serviceWorker' in navigator) navigator.serviceWorker.register('/dev-sw.js?dev-sw', { scope: '/', type: 'classic' })

I see in browser Application tab that only dev-sw.js is registered as service worker. If I comment out that piece of code, mockServiceWorker gets registered.How can I register both service workers and not just one?

2

There are 2 answers

1
kettanaito On

It looks like your app already has a Service Worker. I believe you can only register 1 Service Worker per host. This may be why the mockServiceWorker.js fails to register, resulting in no request being intercepted.

To fix this, you can combine worker scripts using the importScripts standard API.

// dev-dist/sw.js
// I believe the paths here are resolved against the root
// of the website. Experiment with this. Let the errors guide you.
importScripts('/mockServiceWorker.js')

Perhaps raising this in the Vite community can give you a more appropriate answer as to the best way to combine the workers.

1
Calin Bogdan On

Registering multiple service workers in a single scope can be complex and tricky, but it's possible with some restrictions. However, multiple service workers will compete for control, leading to unpredictable behavior if not managed correctly.

For your particular issue where the Vite dev service worker (dev-sw.js) and the Mock Service Worker (mockServiceWorker.js) are conflicting, you could consider the following options:

Option 1: Different Scopes for Service Workers

  1. Change the scope of one or both service workers:

    • You could try registering the service workers with different scopes so they don't conflict.
    if ('serviceWorker' in navigator) {
        navigator.serviceWorker.register('/dev-sw.js?dev-sw', { scope: '/app/', type: 'classic' });
        navigator.serviceWorker.register('/mockServiceWorker.js', { scope: '/mock/', type: 'classic' });
    }
    
  2. Update your application’s requests:

    • Ensure that the paths you use when making requests in your application align with the scopes you've defined for the service workers.

Option 2: Conditional Registration

  • You can conditionally register the service workers based on the environment, registering only the service worker that you need.

    if ('serviceWorker' in navigator) {
        if (process.env.NODE_ENV === 'development') {
            navigator.serviceWorker.register('/mockServiceWorker.js', { scope: '/', type: 'classic' });
        } else {
            navigator.serviceWorker.register('/dev-sw.js?dev-sw', { scope: '/', type: 'classic' });
        }
    }
    

Option 3: Customize Vite’s Service Worker

  • Modify or disable Vite’s service worker:
    • If the Vite service worker isn’t critical for your development, you might consider modifying or disabling it temporarily to allow the MSW service worker to take precedence.

Debugging Tips

  • Check the scopes: Ensure that the service worker scopes are correctly set and don’t overlap unless intended.

  • Check the registrations: Inspect the Application tab in Chrome DevTools to verify that the service workers are correctly registered and activated.

  • Use the update on reload option: While debugging, use the "Update on reload" option in DevTools to ensure that the latest service worker is always being used.

  • Check for errors: Look for errors in the console that might indicate why a service worker isn’t registering or activating as expected.

Conclusion

Choosing the best option depends on your specific needs and how crucial each service worker is to your development process. Adjusting scopes, conditionally loading service workers, or tweaking Vite’s configuration are the paths I would explore to resolve the conflict between your service workers.