From c021662d1e7bbdabd2b5cb9bea28ea05c11de7e0 Mon Sep 17 00:00:00 2001 From: Jens Meindertsma Date: Thu, 8 Oct 2020 20:19:29 +0200 Subject: [PATCH] Fix with-msw example (#17695) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When using the `with-msw` example I noticed it increased my bundle size in production, even through MSW is meant to be used in development only. **Build size before implementing MSW** ``` Page Size First Load JS ┌ λ / 479 B 58.9 kB ├ /_app 0 B 58.4 kB └ ○ /404 3.44 kB 61.9 kB + First Load JS shared by all 58.4 kB ├ chunks/f6078781a05fe1bcb0902d23dbbb2662c8d200b3.b1b405.js 10.3 kB ├ chunks/framework.cb05d5.js 39.9 kB ├ chunks/main.a140d5.js 7.28 kB ├ chunks/pages/_app.b90a57.js 277 B └ chunks/webpack.e06743.js 751 B λ (Server) server-side renders at runtime (uses getInitialProps or getServerSideProps) ○ (Static) automatically rendered as static HTML (uses no initial props) ● (SSG) automatically generated as static HTML + JSON (uses getStaticProps) (ISR) incremental static regeneration (uses revalidate in getStaticProps) ``` **Build size after implementing MSW according to the `with-msw` example** ``` Page Size First Load JS ┌ λ / 479 B 71.6 kB ├ /_app 0 B 71.1 kB └ ○ /404 3.44 kB 74.6 kB + First Load JS shared by all 71.1 kB ├ chunks/f6078781a05fe1bcb0902d23dbbb2662c8d200b3.b1b405.js 10.3 kB ├ chunks/framework.cb05d5.js 39.9 kB ├ chunks/main.a140d5.js 7.28 kB ├ chunks/pages/_app.c58a6f.js 13 kB └ chunks/webpack.e06743.js 751 B λ (Server) server-side renders at runtime (uses getInitialProps or getServerSideProps) ○ (Static) automatically rendered as static HTML (uses no initial props) ● (SSG) automatically generated as static HTML + JSON (uses getStaticProps) (ISR) incremental static regeneration (uses revalidate in getStaticProps) ``` There was a 12.7 kB large increase in the `_app` First Load JS which increased the pages' First Load JS size. I tracked the problem down to the following code: ```js if (process.env.NEXT_PUBLIC_API_MOCKING === 'enabled') { require('../mocks') } ``` Removing this reduces the `_app` First Load JS to what it was previously. The `NEXT_PUBLIC_API_MOCKING` environment variable is defined in the `.env.development` file, as this means that Next.js will only activate MSW during development/testing, which is what MSW is intended for. After discussing with @kettanaito, the author of MSW, I did some investigation. This dynamic require statement is intended to allow tree-shaking of the MSW package for production. Unfortunately this did not seem to be working. To fix this, I changed the code to the following: ```js if (process.env.NODE_ENV !== 'production') { require('../mocks') } ``` This means I could remove the `NEXT_PUBLIC_API_MOCKING` environment variable from `.env.development`, as it is no longer used. It is important to note that this still achieves the same functionality as before: MSW runs in development / testing, and not in production. If MSW must be enabled in production for some reason, the following code can be used to run MSW regardless of the environment: ```js if (true) { require('../mocks') } ``` If possible, I'd love to hear from the Next.js maintainers regarding the tree-shaking process when using environment variables. Lastly, I made the necessary changes to have the example work in production mode as well, because there is no real backend. Of course there is a comment explaining what should be changed in a real world app. --- examples/with-msw/.env | 4 ---- examples/with-msw/package.json | 2 +- examples/with-msw/pages/_app.js | 4 +++- examples/with-msw/pages/index.js | 35 +++++++++++++++++++++++++------- 4 files changed, 32 insertions(+), 13 deletions(-) delete mode 100644 examples/with-msw/.env diff --git a/examples/with-msw/.env b/examples/with-msw/.env deleted file mode 100644 index f2f2baa1e38dd..0000000000000 --- a/examples/with-msw/.env +++ /dev/null @@ -1,4 +0,0 @@ -# Enable API mocking in all environments, this is only for the sake of the example. -# In a real app you should move this variable to `.env.development`, as mocking the -# API should only be done for development. -NEXT_PUBLIC_API_MOCKING="enabled" \ No newline at end of file diff --git a/examples/with-msw/package.json b/examples/with-msw/package.json index d55b6641ec28e..967337fb2234c 100644 --- a/examples/with-msw/package.json +++ b/examples/with-msw/package.json @@ -8,7 +8,7 @@ }, "license": "MIT", "dependencies": { - "msw": "^0.21.0", + "msw": "^0.21.2", "next": "latest", "react": "^16.13.1", "react-dom": "^16.13.1" diff --git a/examples/with-msw/pages/_app.js b/examples/with-msw/pages/_app.js index b20c39be7b767..5202969b2f603 100644 --- a/examples/with-msw/pages/_app.js +++ b/examples/with-msw/pages/_app.js @@ -1,4 +1,6 @@ -if (process.env.NEXT_PUBLIC_API_MOCKING === 'enabled') { +// Enable API mocking in all environments except production. +// This is recommended for real-world apps. +if (process.env.NODE_ENV !== 'production') { require('../mocks') } diff --git a/examples/with-msw/pages/index.js b/examples/with-msw/pages/index.js index f22c03b0b41f4..823fba68a1f41 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 }) { +export default function Home({ book, inProduction }) { const [reviews, setReviews] = useState(null) const handleGetReviews = () => { @@ -10,6 +10,18 @@ export default function Home({ book }) { .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} @@ -32,12 +44,21 @@ export default function Home({ book }) { export async function getServerSideProps() { // Server-side requests are mocked by `mocks/server.js`. - const res = await fetch('https://my.backend/book') - const book = await res.json() + // 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() - return { - props: { - book, - }, + return { + props: { + book, + }, + } + } catch (error) { + return { + props: { + inProduction: true, + }, + } } }