From 64a2758ee4fa46bf86dba95d8819897fb8eafaaf Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Fri, 1 May 2026 13:12:45 +0200 Subject: [PATCH] fix(contributors): defer .all-contributorsrc read until first render The module-level `readFileSync` call ran at import time, which broke Storybook (Chromatic) since `MdComponents` re-exports `Contributors`. Webpack stubs `fs` in the browser, so importing the module crashed with `(0 , fs_ignored_.readFileSync) is not a function` and Chromatic could not extract stories. Wrap the read in a memoized getter so importing the module is side-effect free; the read still happens once per SSG worker on first render. --- src/components/Contributors/index.tsx | 41 ++++++++++++++++++--------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/src/components/Contributors/index.tsx b/src/components/Contributors/index.tsx index 4d94945de28..a3c3a55ec83 100644 --- a/src/components/Contributors/index.tsx +++ b/src/components/Contributors/index.tsx @@ -17,22 +17,35 @@ type AllContributorsRc = { contributors: (Contributor & { contributions?: string[] })[] } -// Read `.all-contributorsrc` (bot-maintained) once at module load. -const raw = readFileSync(join(process.cwd(), ".all-contributorsrc"), "utf-8") -const { contributors: rawContributors } = JSON.parse(raw) as AllContributorsRc - -// Trim to the fields the card actually renders and shuffle once per SSG worker. -const shuffledContributors: Contributor[] = shuffle( - rawContributors.map(({ login, name, avatar_url, profile }) => ({ - login, - name, - avatar_url, - profile, - })) -) +let shuffledContributors: Contributor[] | undefined + +// Read `.all-contributorsrc` (bot-maintained) on first render and cache. +// Deferred (not module-load) so non-Next bundlers like Storybook can import +// this module without evaluating Node's `fs`. +const getShuffledContributors = (): Contributor[] => { + if (!shuffledContributors) { + const raw = readFileSync( + join(process.cwd(), ".all-contributorsrc"), + "utf-8" + ) + const { contributors: rawContributors } = JSON.parse( + raw + ) as AllContributorsRc + + shuffledContributors = shuffle( + rawContributors.map(({ login, name, avatar_url, profile }) => ({ + login, + name, + avatar_url, + profile, + })) + ) + } + return shuffledContributors +} const Contributors = ({ contributors }: ContributorsProps = {}) => ( - + ) export default Contributors