Trying to bundle my component library to be compatible with RSC
Unanswered
Yellow and black potter wasp posted this in #help-forum
Yellow and black potter waspOP
I am trying to bundle my own component library via tsup https://tsup.egoist.dev/
this creates the following output:
however it seems the
in my index.ts I basically re-export all my components:
But I cannot import any of them in my NextJS server components without marking the entire component as
import { defineConfig } from 'tsup'
import fs from 'fs/promises'
export default defineConfig({
clean: true,
format: ['esm', 'cjs'],
entry: ['src/index.ts'],
outDir: 'dist',
dts: true,
external: ['react', 'react-dom'],
async onSuccess() {
await fs.copyFile('src/tailwind.css', 'dist/tailwind.css')
await fs.copyFile('static/gellix.woff2', 'dist/gellix.woff2')
}
})
this creates the following output:
dist: gellix.woff2 index.cjs index.d.cts index.d.ts index.js tailwind.css
however it seems the
use client
directives in my components are lost. in my index.ts I basically re-export all my components:
export * from '@/components/ui/accordion'
export * from '@/components/ui/alert'
export * from '@/components/ui/alert-dialog'
export * from '@/components/ui/aspect-ratio'
export * from '@/components/ui/avatar'
export * from '@/components/ui/badge'
...
But I cannot import any of them in my NextJS server components without marking the entire component as
'client ony'
. How do I get around this. I do not want to make wrapper client components in my NextJS application for all of the components from my design system5 Replies
Yellow and black potter waspOP
This is the error that I get when importing a component from my design system into a nextjs server component:
The badge component in my component library does not use any client side directives:
⨯ TypeError: (0 , import_react.createContext) is not a function
at __TURBOPACK__module__evaluation__ (app/page.tsx:1:1)
at __TURBOPACK__module__evaluation__ (.next/server/chunks/ssr/[root-of-the-server]__7f2aaf77._.js:54:47)
at Object.<anonymous> (.next/server/app/page.js:22:3)
> 1 | import { Badge } from "@grey/design-system";
| ^
2 |
3 | export default function Home() {
4 | return ( {
page: '/'
}
The badge component in my component library does not use any client side directives:
import * as React from 'react'
import { Slot } from '@radix-ui/react-slot'
import { cva, type VariantProps } from 'class-variance-authority'
import { cn } from '@/lib/utils'
const badgeVariants = cva(
'inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden',
{
variants: {
variant: {
default:
'border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90',
secondary:
'border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90',
destructive:
'border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
outline:
'text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground'
}
},
defaultVariants: {
variant: 'default'
}
}
)
function Badge({
className,
variant,
asChild = false,
...props
}: React.ComponentProps<'span'> &
VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
const Comp = asChild ? Slot : 'span'
return (
<Comp
data-slot='badge'
className={cn(badgeVariants({ variant }), className)}
{...props}
/>
)
}
export { Badge, badgeVariants }
Yellow and black potter waspOP
I added
it feels kinda gross, but seems to work. not sure if there is a better solution
import { defineConfig } from 'tsup'
import fs from 'fs/promises'
export default defineConfig({
clean: true,
format: ['esm', 'cjs'],
entry: ['src/index.ts'],
outDir: 'dist',
dts: true,
external: ['react', 'react-dom'],
async onSuccess() {
await fs.copyFile('src/tailwind.css', 'dist/tailwind.css')
await fs.copyFile('static/gellix.woff2', 'dist/gellix.woff2')
},
+ esbuildOptions(options) {
+ options.banner = {
+ js: '"use client"'
+ }
+ },
})
it feels kinda gross, but seems to work. not sure if there is a better solution
a possible solution may be to use a transpiler like swc or tsc instead of a bundler like tsup?
or maybe rollup: https://github.com/huozhi/rollup-preserve-directives
could see if this works with tsup too: https://github.com/Seojunhwan/esbuild-plugin-preserve-directives