Skip to content

refactor: inline single-child _components/ wrappers into page.tsx#18078

Merged
wackerow merged 4 commits into
devfrom
refactor/inline-page-server-components
May 11, 2026
Merged

refactor: inline single-child _components/ wrappers into page.tsx#18078
wackerow merged 4 commits into
devfrom
refactor/inline-page-server-components

Conversation

@pettinarip
Copy link
Copy Markdown
Member

@pettinarip pettinarip commented Apr 30, 2026

Summary

Apply the server-first page composition convention across 8 routes that each delegated their entire UI to a single ./_components/<name>.tsx client wrapper:

  • staking
  • community
  • gas
  • layer-2
  • layer-2/learn
  • run-a-node
  • roadmap/_vision
  • contributing/translation-program/contributors

Each previous wrapper was "use client" only because of the custom useTranslation hook. Inlined the UI into the page-level async server component and swapped to next-intl's getTranslations. Where the wrapper used usePathname only to feed <Breadcrumbs>, replaced it with a literal SLUG constant.

Net effect: -217 lines, 7 client-bundle wrappers removed, all 8 pages now render as server components.

Why

A single nested wrapper turned each page into a stub that just forwarded params. Readers had to open two files to understand one route, and the wrapper reflexively pulled the entire UI into the client bundle when most of it could render on the server. app/[locale]/bug-bounty/page.tsx was the canonical counter-example; these 8 now follow it.

Notes

  • StakingHierarchy gained "use client" since its onClick handlers previously inherited client-ness from the removed staking wrapper.
  • 4 sibling routes (assets, acknowledgements, quizzes, staking/deposit-contract) were intentionally left alone — they use useColorModeValue, useState, useEffect, or click handlers, so the wrapper is justified per the convention.

Test plan

  • pnpm build succeeds
  • Each refactored route renders correctly in the deploy preview
  • Breadcrumbs appear on /contributing/translation-program/contributors, /layer-2/learn, and /roadmap/vision
  • Translation strings resolve (no raw keys visible) on all 8 pages, including locales other than en
  • No client-side React hydration errors in console

@netlify
Copy link
Copy Markdown

netlify Bot commented Apr 30, 2026

Deploy Preview for ethereumorg ready!

Name Link
🔨 Latest commit 4725d56
🔍 Latest deploy log https://app.netlify.com/projects/ethereumorg/deploys/6a01fd0cbdf718000732a665
😎 Deploy Preview https://deploy-preview-18078.ethereum.it
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
7 paths audited
Performance: 68
Accessibility: 96
Best Practices: 100
SEO: 98
PWA: 59
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

@pettinarip pettinarip force-pushed the refactor/inline-page-server-components branch 3 times, most recently from c33e3da to 8b56811 Compare April 30, 2026 13:36
Apply the server-first page composition convention across 8 routes:
staking, community, gas, layer-2, layer-2/learn, run-a-node,
roadmap/_vision, and contributing/translation-program/contributors.

Each page previously delegated to a single ./_components/<name>.tsx
client wrapper that only used useTranslation. Inlined the UI into the
page-level async server component, replacing the client useTranslation
hook with next-intl's getTranslations. Where the wrapper used
usePathname only to feed Breadcrumbs, replaced it with a literal SLUG
constant.

Add "use client" to StakingHierarchy since its onClick handlers
previously inherited client-ness from the staking wrapper.
@pettinarip pettinarip force-pushed the refactor/inline-page-server-components branch 2 times, most recently from c4b1f71 to 793b1ac Compare April 30, 2026 14:54
Copy link
Copy Markdown
Collaborator

@myelinated-wackerow myelinated-wackerow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice cleanup overall — the convention reads well and the wrappers were carrying their weight in client bundle for not much reason. One blocker before this can ship.

Cross-namespace t() calls in app/[locale]/gas/page.tsx

The old wrapper used the project's custom useTranslation hook (src/hooks/useTranslation.ts), which splits keys on : to support lookups across namespaces. next-intl's stock getTranslations does not, so two calls in gas/page.tsx will render their literal key strings in production:

  • Line 415: alt={t("page-community:page-community-explore-dapps-alt")}
  • Line 422: {t("page-community:page-community-explore-dapps")}

page-community-explore-dapps-alt and page-community-explore-dapps live in page-community.json, not page-gas.json, so the lookup misses inside the page-gas scope. getMessageFallback then returns the segment after the last ., which (since neither key contains a .) is the whole literal — the alt text and button label both render as "page-community:page-community-explore-dapps-..." strings.

Suggested fix:

const t = await getTranslations("page-gas")
const tCommunity = await getTranslations("page-community")
// ...
alt={tCommunity("page-community-explore-dapps-alt")}
// ...
{tCommunity("page-community-explore-dapps")}

The other seven migrations look clean on this front — multi-namespace useTranslation([...]) was correctly split into multiple getTranslations() calls with every call site rewritten.

Minor — ExpandableCard icon spacing

The svg prop change from React.FC to ReactNode is a reasonable simplification, and the only caller (run-a-node) was updated. One side-effect worth eyeballing on the deploy preview: the icon used to be rendered with a forced mr-6 (1.5rem) inside ExpandableCard; that's now replaced by gap-8 (2rem) on the parent HStack, so the icon-to-title spacing changes very slightly. Probably fine, but worth a quick look.

Reviewed by Claude Opus 4.7

image

Copy link
Copy Markdown
Member

@wackerow wackerow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed a patch for above issue -- good to go, thanks @pettinarip!

@wackerow wackerow merged commit 857e32b into dev May 11, 2026
8 of 9 checks passed
@wackerow wackerow deleted the refactor/inline-page-server-components branch May 11, 2026 16:05
@pettinarip pettinarip mentioned this pull request May 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants