apollographql / apollo-client-nextjs

Apollo Client support for the Next.js App Router
https://www.npmjs.com/package/@apollo/experimental-nextjs-app-support
MIT License
358 stars 25 forks source link

"First Load JS" Seems to include Apollo on the client regardless of using RSC implementation #95

Closed blakewilson closed 2 months ago

blakewilson commented 7 months ago

Hi all, thanks for this great library.

I am trying to incorporate the RSC Apollo implementation as described here:

https://www.apollographql.com/blog/announcement/frontend/using-apollo-client-with-next-js-13-releasing-an-official-library-to-support-the-app-router/#server-components

I'm able to fetch data fine (see the posts page), but I noticed Apollo is being shipped to the client, regardless if it's an RSC or not.

I'm only using the client on the posts page, and from the build logs, you can see that the posts page is ~90kb larger than the home page:

Screenshot 2023-09-13 at 1 02 48 PM

Am I doing something wrong here?

Here is a reproduction repo.

phryneas commented 7 months ago

That is weird - but looks like a bug in NextJs's bundling.

You don't have a single client component in that project, so I don't see a reason why any third-party library should ever be sent to the browser.

theodesp commented 7 months ago

@blakewilson there is a distinct difference here when using the registerApolloClient as per example:

https://github.com/apollographql/apollo-client-nextjs/blob/main/examples/app-dir-experiments/app/ApolloClient.ts

So If you use it like this:

export const { getClient } = registerApolloClient(() => {
  return new ApolloClient({
    cache: new InMemoryCache(),
    link: new HttpLink({
      uri: "https://faustexample.wpengine.com/graphql",
    }),
  });
});

The bundle size is properly slimmed:

Route (app)                                Size     First Load JS
┌ ○ /                                      5.34 kB        83.8 kB
├ ○ /api/hello                             0 B                0 B
├ ○ /favicon.ico                           0 B                0 B
└ ○ /posts                                 137 B          78.6 kB
+ First Load JS shared by all              78.5 kB
  ├ chunks/596-c294a7d39d9fe754.js         26.1 kB
  ├ chunks/fd9d1056-a99b58d3cc150217.js    50.5 kB
  ├ chunks/main-app-5064061fd36ee5d1.js    221 B
  └ chunks/webpack-dae38a8f51101118.js     1.68 kB

Route (pages)                              Size     First Load JS
─ ○ /404                                   182 B          76.5 kB
+ First Load JS shared by all              76.3 kB
  ├ chunks/framework-8883d1e9be70c3da.js   45.1 kB
  ├ chunks/main-183d48c5a18cff9a.js        29.4 kB
  ├ chunks/pages/_app-52924524f99094ab.js  195 B
  └ chunks/webpack-dae38a8f51101118.js     1.68 kB

○  (Static)  automatically rendered as static HTML (uses no initial props)
phryneas commented 7 months ago

@theodesp I might be blind, but isn't that what they are doing? https://github.com/blakewilson/app-router-apollo-bundle-size/blob/main/src/lib/client.ts

mvandergrift commented 7 months ago

@phryneas The OP's code is building a RSC client that returns a NextSSRApolloClient/NextSSRInMemoryCache instead of an ApolloClient/InMemoryCache.

export const { getClient } = registerApolloClient(() => {
  return new NextSSRApolloClient({
    cache: new NextSSRInMemoryCache(),
    link: new HttpLink({
      // https://studio.apollographql.com/public/spacex-l4uc6p/
      uri: "https://faustexample.wpengine.com/graphql",
      // you can disable result caching here if you want to
      // (this does not work if you are rendering your page with `export const dynamic = "force-static"`)
      // fetchOptions: { cache: "no-store" },
    }),
  });

My assumption is that the packager is shipping the additional code used for the SSR implementation.

The post he references shows an example where the RSC client is built using the NextSSR client. Is this incorrect or at least not ideal?

https://www.apollographql.com/blog/announcement/frontend/using-apollo-client-with-next-js-13-releasing-an-official-library-to-support-the-app-router/#client-components-with-server-side-rendering

Thanks!

phryneas commented 7 months ago

@mvandergrift huh, good point, that's not ideal, I'll make sure that gets cleaned up. But at the same time: it's only suboptimal, it should not have any consequences for the bundling.

mvandergrift commented 7 months ago

@phryneas

Yeah, there's something weird going on with nextjs bundling. Any reference to the @apollo/experimental-nextjs-app-support/ssr and the entire barrel gets imported and shipped to the client (~90kB).

Looking at the code in apollo-client-next, I removed all of the exports from ssr/index.ts except NextSSRApolloClient and NextSSRInMemoryCache. This fixed things; the RSC package size didn't increase. However, the bundler gets confused if you export ApolloNextAppProvider, hooks, or resetNextSSRApolloSIngletons. All of these have the "use client" pragma in common.

I guess that next is correctly ignoring the "use client" modules during the build, but Webpack is including them in the bundle anyway.

blakewilson commented 7 months ago

@theodesp @phryneas @mvandergrift Thanks yall. It does seem that using ApolloClient/InMemoryCache properly reduces the bundle size. I guess the guide that I followed was using the wrong implementation. I think it would be helpful to get that guide updated for others that may fall into the same trap 🤞

My particular issue is resolved, however, it does seem like there is a greater issue here regarding Next bundling and the ssr barrel export that @mvandergrift mentions.

@phryneas I'll leave this issue open for now in case any follow up is needed re:next bundling, but feel free to close it if you feel it doesn't apply. Thanks!

louisthomaspro commented 7 months ago

I faced the same issue. @blakewilson, your solution works, thanks!

phryneas commented 2 months ago

I'm doing some housekeeping so I'm closing some older issues that haven't seen activity in a while. If this is still relevant, please feel free to reopen the issue.

github-actions[bot] commented 2 months ago

Do you have any feedback for the maintainers? Please tell us by taking a one-minute survey. Your responses will help us understand Apollo Client usage and allow us to serve you better.