Skip to content

Commit

Permalink
Fix with-msw example (#17695)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Jens Meindertsma authored Oct 8, 2020
1 parent bbc1a21 commit c021662
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 13 deletions.
4 changes: 0 additions & 4 deletions examples/with-msw/.env

This file was deleted.

2 changes: 1 addition & 1 deletion examples/with-msw/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 3 additions & 1 deletion examples/with-msw/pages/_app.js
Original file line number Diff line number Diff line change
@@ -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')
}

Expand Down
35 changes: 28 additions & 7 deletions examples/with-msw/pages/index.js
Original file line number Diff line number Diff line change
@@ -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 = () => {
Expand All @@ -10,6 +10,18 @@ export default function Home({ book }) {
.then(setReviews)
}

if (inProduction) {
return (
<div>
<p>
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.
</p>
</div>
)
}

return (
<div>
<img src={book.imageUrl} alt={book.title} width="250" />
Expand All @@ -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,
},
}
}
}

0 comments on commit c021662

Please sign in to comment.