diff --git a/.changeset/avatar-use-client.md b/.changeset/avatar-use-client.md new file mode 100644 index 0000000..ba43095 --- /dev/null +++ b/.changeset/avatar-use-client.md @@ -0,0 +1,20 @@ +--- +'@code-sherpas/pharos-react': patch +--- + +Mark the published ESM bundle as client-only via a `"use client"` banner. + +Avatar (D14) calls `createContext(...)` three times at module top level +(shape / loading / group). Without the banner, Next.js evaluates the +Pharos module during its RSC build-time analysis pass and fails with +`TypeError: (0 , c.createContext) is not a function` while collecting +page data for any route whose layout transitively imports an Avatar. + +The banner is the same convention every React DS ships with +(MUI / Chakra / Radix / shadcn). The atoms that have no hooks +(Card / Separator) lose server-render-ability as a side effect; this is +acceptable since they were never advertised as server-safe and React DS +libraries are universally client-only today. + +The Avatar source file also carries its own `"use client"` directive so +the intent is visible to anyone reading the source. diff --git a/src/components/Avatar.tsx b/src/components/Avatar.tsx index 0a39103..55f93ad 100644 --- a/src/components/Avatar.tsx +++ b/src/components/Avatar.tsx @@ -1,3 +1,20 @@ +'use client'; + +/* The `'use client'` directive at the top of this file is load-bearing. + * Avatar runs `createContext(...)` three times at module top level (shape / + * loading / group). Without the directive, Next.js evaluates the module in + * its build-time RSC analysis pass, where React is wired in a way that + * makes `createContext` blow up with + * `TypeError: (0 , c.createContext) is not a function` during page-data + * collection. The directive marks the module as client-only in the + * published bundle (esbuild / Vite preserve the banner verbatim) and the + * RSC analysis stops at the import boundary. + * + * The other Pharos atoms (Button / Spinner / etc.) do not need this + * because their hook calls happen inside the component body, not at module + * scope — module evaluation is side-effect free for them. + */ + import { createContext, useCallback, diff --git a/vite.config.ts b/vite.config.ts index 7527dc5..5e8d4b8 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -33,6 +33,19 @@ export default defineConfig({ '@base-ui/react', /^@base-ui\/react\//, ], + output: { + // Bundle banner that marks the published ESM module as client-only. + // Avatar (D14) calls `createContext` at module top level; without + // this directive, Next.js evaluates the module during RSC + // build-time analysis and fails with + // `TypeError: (0 , c.createContext) is not a function` while + // collecting page data. The whole library shipping as client-only + // matches what every React DS does (MUI, Chakra, Radix, shadcn). + // The atoms that have no hooks (Card / Separator) lose + // server-render-ability as a side effect — acceptable; consumers + // were never asked to render them as Server Components anyway. + banner: "'use client';", + }, }, cssCodeSplit: false, sourcemap: true,