Skip to content

Every page loads the 530 kB shared-home chunk, and shared-product / shared-common are never created #96

Open

Description

@fadyehabamer

While working on a few fixes I looked at the client build. Every storefront page loads the shared-home chunk, and two of the chunks vite.config.ts asks for are never created. I'm sharing the measurements rather than a PR, because the chunking setup is yours to decide.

Measured on master at af71eb8 (Vite 8.2.2), with pnpm build.

What I found

1. shared-home is the largest client chunk, and every page loads it.

Chunk Minified gzip -9 brotli
shared-home 530 kB 161 kB 137 kB

The product, category, tag and static page routes, the cart route, index.client and hydrate all import it (grep -l shared-home dist/client/assets/*.js). The modulePreload.resolveDependencies filter keeps anything matching shared-, so it's also preloaded on every page. This is the chunk behind the build's "Some chunks are larger than 500 kB" warning.

2. shared-product and shared-common are never emitted. manualChunks returns them for ProductCard / ProductDetails / ProductGallery / AddToCartForm and for the engine's Breadcrumb / Image / Link / … modules, but dist/client/assets has only shared-home-*.js. The product page components end up inside shared-home instead.

3. What's inside shared-home. These figures are from rollup-plugin-visualizer's raw data for the client environment, as rendered sizes before minification, grouped by package:

Rendered Package / module
253 kB @salla.sa/twilight-theme-engine
162 kB swiper
83 kB @salla.sa/twilight-components-react
74 kB i18next
64 kB ky
52 kB sonner
45 kB @tanstack/query-core
42 kB @tanstack/virtual-core
19 kB app/components/icons.tsx
15 kB app/components/product/AddToCartForm.tsx
12 kB app/components/product/ProductDetails.tsx
10 kB app/components/common/ProductOptionsPanel.tsx
9 kB app/components/product/ProductGallery.tsx

So the "home" chunk mixes three things:

  • libraries every page needs (i18next, ky, sonner, TanStack Query)
  • the product page components
  • home-only code such as Swiper and the home blocks

Because every page needs the first group, every page also downloads the other two.

How I got the per-environment numbers: the visualizer writes dist/stats.html once per environment, so the server build overwrites the client's. Locally I set emitFile: true, filename: 'stats.json', template: 'raw-data' on it, which writes dist/client/stats.json and dist/server/stats.json. I didn't commit that.

Possible directions

Only if you want them; I haven't tried these against your CWV numbers.

  • Check why the shared-product / shared-common rules have no effect under Rolldown. The build's hint points at build.rolldownOptions.output.codeSplitting as the native replacement for manualChunks.
  • Give the libraries every route needs (i18next, ky, sonner, @tanstack/query-core) their own vendor chunk. Then shared-home would hold only home code, and could stay off the resolveDependencies preload list on other pages.
  • Track the result with the size budget from ci(devops): add a bundle size budget with pnpm size #63.

Related: no-deep-component-import

The build warns that CartItem.tsx and AddToCartForm.tsx import ../common/ProductOptionsPanel instead of the ../common barrel. I tried following the advice, and it backfires here:

  • components/common/index.ts also re-exports BlockHookSlot, which imports @salla.sa/twilight-theme-engine/home.
  • So importing from the barrel makes the cart and product components load the engine's home module in dev and in tests. Four test files (CartItem, CartPage, AddToCartForm, sold-out-sticky-bar) failed on the setup's @salla.sa/twilight-components-react mock.
  • The production bundle was unchanged (1 byte), so it saves nothing.

I'd keep the deep import. The rule has no per-line opt-out, only disabledRules, so it may be worth a note for whoever owns the best-practices plugin.

I'm happy to help with a PR once you've picked a direction.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions