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