Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

react-loader and other dependencies are included in the client bundle #141

Open
marcusforsberg opened this issue Jan 2, 2024 · 2 comments
Labels

Comments

@marcusforsberg
Copy link

Describe the bug

While migrating to Presentation/Loaders, I noticed that the client side bundle size dramatically increased. Analyzing the bundle on a fresh clone of this repo shows that react-loader and related dependencies are included in the client bundle, for example:

  • async-cache-dedupe
  • @sanity/react-loader
  • safe-stable-stringify
  • @sanity/client/*
  • @portabletext/react (since the production site should be entirely server side rendered)
  • CustomPortableText.tsx (same as above)
  • HomePagePreview.tsx
  • queries.ts
  • @sanity/overlays
  • stega.browser.js

To Reproduce

Steps to reproduce the behavior:

  1. Clone this repository
  2. Install @next/bundle-analyzer as per its readme
  3. Run ANALYZE=true npm run build
  4. Look at the client.html file
  5. Also notice the output from next build which shows a 121kb "First Load JS" for the homepage route, higher than expected.

Expected behavior

react-loader, @sanity/client, @sanity/overlays and other dependencies related to live previews and visual editing are expected to be lazy loaded only when draft mode is enabled, thus not affecting the size of the bundle shipped to website visitors.

Screenshots

This is app/(personal)/page:

Screenshot 2024-01-02 at 08 19 49

This is app/(personal)/layout:

Screenshot 2024-01-02 at 08 20 46

Which versions of Sanity are you using?

@sanity/cli (global) 3.20.2 (latest: 3.23.4)
@sanity/demo 1.0.2 (up to date)
@sanity/image-url 1.0.2 (up to date)
@sanity/overlays 2.2.0 (latest: 2.3.0)
@sanity/preview-url-secret 1.3.4 (latest: 1.4.0)
@sanity/react-loader 1.6.1 (latest: 1.6.4)
@sanity/vision 3.21.3 (latest: 3.23.4)
sanity 3.21.3 (latest: 3.23.4)

What operating system are you using?

MacOS Sonoma 14.1.2

Which versions of Node.js / npm are you running?

10.2.4
v18.19.0

Additional context

I know you're actively working on this starter and the API:s in general so this may well be something you are aware of and working on, but I thought I'd open this in case it is of any help. 😊 To my eye, everything in this starter looks good, i.e it uses next/dynamic throughout, so I'm really not sure why so much would be included in the bundle. Could this be a Next.js issue?

@stipsan stipsan added the triaged label Jan 2, 2024
@stipsan
Copy link
Member

stipsan commented Jan 2, 2024

Hi! When we tested this way back it wasn't part of the bundle, could be a regression?
In any case we have reproduced the problem and different patterns (using React.lazy directly instead of next/dynamic etc). The docs suggest Next should be able to infer that components that are lazy loaded in draft mode doesn't need to be in the production bundle.
Could you open an issue on Vercel's end?

I don't think the repro needs to be more complicated than:

// app/layout.tsx
import dynamic from 'next/dynamic'
import { draftMode } from 'next/headers'

const HeavyDraftModeComponent = dynamic(() => import('./HeavyDraftModeComponent'))

export default function Layout() {
  if(draftMode().isEnabled) {
    return <HeavyDraftModeComponent />
  }  
  return 'Production Mode'
}

// app/HeavyDraftModeComponent.tsx
'use client'

// In Real World apps it imports heavy client libraries that are only used client side in Draft Mode, and server-only in production

console.log('Should only log in Draft Mode')

export default function HeavyDraftModeComponent() {
  return 'Draft Mode'
}

@JohnGemstone
Copy link
Contributor

JohnGemstone commented Jan 15, 2024

I ran into a similar issue with finding my own components (meant for prerender only) in the client bundle, to fix I used dynamic to import the heavy components inside the preview component
https://github.com/sanity-io/template-nextjs-personal-website/blob/main/components/pages/home/HomePagePreview.tsx#L9

e.g.

// HomePagePreview.tsx
'use client'

import dynamic from "next/dynamic";
import { type QueryResponseInitial } from '@sanity/react-loader'

import { homePageQuery } from '@/sanity/lib/queries'
import { useQuery } from '@/sanity/loader/useQuery'
import { HomePagePayload } from '@/types'

// import HomePage from './HomePage'
const HomePage = dynamic(() => import("./HomePage"))

type Props = {
  initial: QueryResponseInitial<HomePagePayload | null>
}

export default function HomePagePreview(props: Props) {
  const { initial } = props
  const { data, encodeDataAttribute } = useQuery<HomePagePayload | null>(
    homePageQuery,
    {},
    { initial },
  )

  if (!data) {
    return (
      <div className="text-center">
        Please start editing your Home document to see the preview!
      </div>
    )
  }

  return <HomePage data={data} encodeDataAttribute={encodeDataAttribute} />
}

This solves my issue of 'react-icons' (a massive library) getting leaked onto the client. As for the other sanity packages, I'm not sure yet, but I'll report back if I find a solution.

Cheers

EDIT: I've been trying to figure out how to prevent my sanity queries (along with zod and groqd) from getting into the client but haven't had any luck, probably tried about 12 different variations of dynamic and lazy but they always seem to leak. Thankfully the queries and types aren't that big, but it would be nice to not have them on the frontend. So if anyone knows a way please share, thanks!

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants