Nextjs/server modules included in the client bundle
michielmetcake opened this issue · 20 comments
We're running into compiling our code to es5 because the client code includes next/server
modules. This increases the bundle size unnecessary.
Example here: https://github.com/michielmetcake/tss-react/tree/main/src/test/apps/ssr
Run yarn analyze
and check the client bundle.
Hello @michielmetcake,
I'm not sure that I understand, what's for sure is that next/server
is never imported in tss-react.
I think I'm only importing what's need to be imported and nothing more.
If you can prove me I'm wrong by providing a clean Next.js project with only tss-react setup I'll swiftly address the issue.
My test app isn't great to analyze what's included, there is to much noise.
Beside, when I run yarn analyze
I don't see any server
I might be missunderstanding what you're saying though...
Thanks for your reply @garronej
If you zoom in a bit more. Then you'll see the next/server
modules. It's inherited from the next/document
In your example I see pretty-bytes.js
which is part of next/server
Well indeed next/document
is imported.
But I mean next/document
has to be imported, there's no way around it.
Look it's imported in the reference Next.js setup for MUI: https://github.com/mui/material-ui/blob/0c6003420b0edab42dc0f411bbb51c16aac2697e/examples/nextjs-with-typescript/pages/_document.tsx
Am I missing somethin?
The example provided is not having the document in the app. Because your augmentDocumentWithEmotionCache
function is used in both _document
and _app
it's having the next/document
imported in the _app
. And this is causing issues with server scripts ending up in the client. I think the solution would be to split the functions into two files so the logic for the _app
and _document
are separate.
Okay!
Now it makes perfect sense, thank you for sorting this out!
I'll see what I can do
I'll make a proposal for you. I'm at 90%, will create a PR tomorrow :-)
Thanks for maintaining this!
Created a solution here: #148
I still see some next/server packages in the _app bundle.
Damn it :(
Do you agree that it works in this demo repo?
#149 (comment) (real question here, I want to be sure that we are on the same page and that I'm not missing something. If you could run analyze on this it would be great).
I think the best (maybe only way) of fixing it would be 2 different functions.
If there is no other way, I'll merge your PR but I think there is a way to make it work with dynamic imports.
If it worked in my test repo, I just need to figure out why it doesn’t in your case and address the issue.
Maybe in your case dynamic import doesn’t work because Next is using the CJS distribution instead of the ESM...
A step by step reproduction path would greatly help.
Yes It's the same. I've a branche here based on the main branch of this repo.
I think you shouldn't pass data or imports from the _app
to the _document
. The other way around is allowed because you can enrich the app in the document.
Yes allright I realized my mistake.
Thanks for your help. (See my answer on your PR)
Fixed in 4.7 with dependency injection: https://docs.tss-react.dev/migration-guides/v4.6-greater-than-v4.7
Thanks @garronej. I still see some issues with this release as a result of importing app code into the document. I see a few deps shipped in the _app
bundle which I don't expect there. Like next/dist/compiled/stream-browserify
, html-tokensize
and readble-stream
.
1 function to both serve the _Document
and _App
is a nice idea. But I think the best way is to split them into two so the code and deps for the _app
stay in the _app
and code for the _document
stay in the _document
.
Damn it,
I was so sure it would do it that I didn't took the time to test.
My bad, I'm back at it.
Hi,
I solved it for good this time, actually tested the thing.
I figured out that it was emotion/server that was responsable of all the dead code that was shiped to the client.
Just implemented the lazy loading aproach again and, bingo.
No API change hurray.
When the problem wasn't addressed:
In both cases the _app bundle size is down from ~160Kb to ~11Kb
Thanks for all the effort. When implementing the v4.7.1 i still see some unwanted behaviour.
I still think there are some unneeded packages in the _app
that aren't used. I've made an comparison branch here. Where I've split the augmentDocumentWithEmotionCache
and withAppEmotionCache
into their own files. And this results in a much smaller _app
chunk.
The code split bundlesize result:
ssr-code-split % yarn bundlesize
yarn run v1.22.19
$ /Users/michielhennekam/projects/tss-react/src/test/apps/ssr-code-split/node_modules/.bin/bundlesize
PASS ./.next/static/chunks/pages/_app-8511534f44c5e2f3.js: 32.47KB < maxSize 35KB (gzip)
✨ Done in 0.87s.
The v4.7.1 bundlesize result:
ssr % yarn bundlesize
yarn run v1.22.19
$ bundlesize
FAIL ./.next/static/chunks/pages/_app-c9e9f789bc733662.js: 85.31KB > maxSize 35KB (gzip)
error Command failed with exit code 1.
Hi @michielmetcake ,
Thank you for the feedback.
I'm very surprized, I conducted carefull tests yesterday.
I compared the size of the _app bundle before any patch: 160Kb
Your solution with two functions (tss-react: "4.6.2-rc.1"): 10.26Kb
The current solution (4.7.1): 11.39Kb
I mean, before 4.7.1 all my sollutions where dumb, it didn't significantly decreced the bundle size but now, things have been tested....
Could it be that it's bundlesize that isn't evaluating properly the actual bundle size.
Or maybe you have cache and still using the old version...?
Hi @michielmetcake , Thank you for the feedback. I'm very surprized, I conducted carefull tests yesterday. I compared the size of the _app bundle before any patch: 160Kb Your solution with two functions (tss-react: "4.6.2-rc.1"): 10.26Kb The current solution (4.7.1): 11.39Kb
I mean, before 4.7.1 all my sollutions where dumb, it didn't significantly decreced the bundle size but now, things have been tested....
Could it be that it's bundlesize that isn't evaluating properly the actual bundle size. Or maybe you have cache and still using the old version...?
Well I noticed it because we want to use this package in the production version of our app. But it's blocking us now because some files from the _app chunk
are not transpiled to es5. Which I wasn't expecting because with the two split functions it's all fine.
I went into the trouble of testing your branch: https://github.com/michielmetcake/tss-react/tree/v4.71-vs-code-split
I get the same result with code splitting and lazy loading:
As far as I can see the bundle size problem is fixed.
Now what you seem to be experiencing is an other issue that I'd be happy to address in a new issue if you can provide me with a reproduction path.
I understand you'd prefer that I merge your code splitting implementation and get it over with already but let me explain why I'm trying to avoid this senario:
- Pepole are not tolerant at all to breaking changes. All the more so coming from a library they use because they have no other choice. TSS shiping to the frontend a bunch of dead code is a bug, and a big one at that (thank you for spotting it!). It had to be fixed for everyone, not only the ones willing to update their setup.
- The code splitting approach introduces duplication of source of truth for the key that has to be provided to both the _app and the _document.
If you can follow up by providing a reporoduction repo for the issu you are currently experiencing great. Otherwise remember that you always have the option to copy your augmentDocumentWithEmotionCache
and withAppEmotionCache
and paste it into your project.
After all TSS is providing an helper here just because I figured out that the logic for setting up SSR for emotion can be abstracted away but MUI and Emotion expect you to do it by hand....