diff --git a/examples/with-msw/.env.development b/examples/with-msw/.env.development new file mode 100644 index 0000000000000000000000000000000000000000..629e10c5c5389c08cd15c50b327db697efb062d1 --- /dev/null +++ b/examples/with-msw/.env.development @@ -0,0 +1 @@ +NEXT_PUBLIC_API_MOCKING=enabled diff --git a/examples/with-msw/.env.production b/examples/with-msw/.env.production new file mode 100644 index 0000000000000000000000000000000000000000..629e10c5c5389c08cd15c50b327db697efb062d1 --- /dev/null +++ b/examples/with-msw/.env.production @@ -0,0 +1 @@ +NEXT_PUBLIC_API_MOCKING=enabled diff --git a/examples/with-msw/README.md b/examples/with-msw/README.md index d7c1368e462c7b6b48fd21088e87ff035aefa6eb..df99517b4c0116e710eb12ad67257107d623cef3 100644 --- a/examples/with-msw/README.md +++ b/examples/with-msw/README.md @@ -8,7 +8,7 @@ In this example we integrate Mock Service Worker with Next by following the next 1. Setup a [Service Worker instance](./mocks/browser.js) that would intercept all runtime client-side requests via `setupWorker` function. 1. Setup a ["server" instance](./mocks/server.js) to intercept any server/build time requests (e.g. the one happening in `getServerSideProps`) via `setupServer` function. -Mocking is enabled using the `NEXT_PUBLIC_API_MOCKING` environment variable, which for the sake of the example is saved inside `.env` instead of `.env.development`. In a real app you should move the variable to `.env.development` because mocking should only be done for development. +Mocking is enabled using the `NEXT_PUBLIC_API_MOCKING` environment variable. By default, mocking is enabled for both development and production. This allows you to have working preview deployments before implementing an actual API. To disable MSW for a specific environment, change the environment variable value in the file corresponding to the environment from `enabled` to `disabled`. ## Deploy your own diff --git a/examples/with-msw/package.json b/examples/with-msw/package.json index 967337fb2234c82b1f9e946192abdd8cbd8d6fc4..a1749b8a957e4ccad7e7f67076e72d4269e6b8d7 100644 --- a/examples/with-msw/package.json +++ b/examples/with-msw/package.json @@ -8,9 +8,9 @@ }, "license": "MIT", "dependencies": { - "msw": "^0.21.2", + "msw": "^0.24.2", "next": "latest", - "react": "^16.13.1", - "react-dom": "^16.13.1" + "react": "^17.0.1", + "react-dom": "^17.0.1" } } diff --git a/examples/with-msw/pages/_app.js b/examples/with-msw/pages/_app.js index 5202969b2f603d9785e85436afd8cdbf21929b56..b20c39be7b7671cc68eec1a138f27d0b08cd7d07 100644 --- a/examples/with-msw/pages/_app.js +++ b/examples/with-msw/pages/_app.js @@ -1,6 +1,4 @@ -// Enable API mocking in all environments except production. -// This is recommended for real-world apps. -if (process.env.NODE_ENV !== 'production') { +if (process.env.NEXT_PUBLIC_API_MOCKING === 'enabled') { require('../mocks') } diff --git a/examples/with-msw/pages/index.js b/examples/with-msw/pages/index.js index 823fba68a1f419f806285d23fa05b4796f313e4b..f22c03b0b41f4b6f3fa0576588b0718b5350ede8 100644 --- a/examples/with-msw/pages/index.js +++ b/examples/with-msw/pages/index.js @@ -1,6 +1,6 @@ import { useState } from 'react' -export default function Home({ book, inProduction }) { +export default function Home({ book }) { const [reviews, setReviews] = useState(null) const handleGetReviews = () => { @@ -10,18 +10,6 @@ export default function Home({ book, inProduction }) { .then(setReviews) } - if (inProduction) { - return ( -
-

- This example does not work in production, as MSW is not intended for - use in production. In a real-world app, your request will hit the - actual backend instead. -

-
- ) - } - return (
{book.title} @@ -44,21 +32,12 @@ export default function Home({ book, inProduction }) { export async function getServerSideProps() { // Server-side requests are mocked by `mocks/server.js`. - // In a real-world app this request would hit the actual backend. - try { - const res = await fetch('https://my.backend/book') - const book = await res.json() + const res = await fetch('https://my.backend/book') + const book = await res.json() - return { - props: { - book, - }, - } - } catch (error) { - return { - props: { - inProduction: true, - }, - } + return { + props: { + book, + }, } } diff --git a/examples/with-msw/public/mockServiceWorker.js b/examples/with-msw/public/mockServiceWorker.js index e94d7a8f30569437a33ff6916aee00133953005e..d4d30cc9a749c1cae2df39ab705e3f019229e1e7 100644 --- a/examples/with-msw/public/mockServiceWorker.js +++ b/examples/with-msw/public/mockServiceWorker.js @@ -7,7 +7,7 @@ /* eslint-disable */ /* tslint:disable */ -const INTEGRITY_CHECKSUM = 'd1e0e502f550d40a34bee90822e4bf98' +const INTEGRITY_CHECKSUM = '65d33ca82955e1c5928aed19d1bdf3f9' const bypassHeaderName = 'x-msw-bypass' let clients = {} @@ -74,11 +74,22 @@ self.addEventListener('message', async function (event) { } }) -self.addEventListener('fetch', async function (event) { +self.addEventListener('fetch', function (event) { const { clientId, request } = event const requestClone = request.clone() const getOriginalResponse = () => fetch(requestClone) + // Bypass navigation requests. + if (request.mode === 'navigate') { + return + } + + // Bypass mocking if the current client isn't present in the internal clients map + // (i.e. has the mocking disabled). + if (!clients[clientId]) { + return + } + // Opening the DevTools triggers the "only-if-cached" request // that cannot be handled by the worker. Bypass such requests. if (request.cache === 'only-if-cached' && request.mode !== 'same-origin') { @@ -89,20 +100,15 @@ self.addEventListener('fetch', async function (event) { new Promise(async (resolve, reject) => { const client = await event.target.clients.get(clientId) - if ( - // Bypass mocking when no clients active - !client || - // Bypass mocking if the current client has mocking disabled - !clients[clientId] || - // Bypass mocking for navigation requests - request.mode === 'navigate' - ) { + // Bypass mocking when the request client is not active. + if (!client) { return resolve(getOriginalResponse()) } // Bypass requests with the explicit bypass header if (requestClone.headers.get(bypassHeaderName) === 'true') { const modifiedHeaders = serializeHeaders(requestClone.headers) + // Remove the bypass header to comply with the CORS preflight check delete modifiedHeaders[bypassHeaderName]