monorepo

Documents patterns for extracting workspace packages in a pnpm and tsup monorepo.

2|Updated Jun 8, 2026
One-click install
npx skills add https://github.com/lunaticwithaduck/easytech3d --skill monorepo-lunaticwithaduck
Or copy as Structured Prompt for Agent▼
Please help me install this Agent Skill.
Skill: monorepo
Source: https://github.com/lunaticwithaduck/easytech3d/tree/main/.claude/skills/monorepo
Command: npx skills add https://github.com/lunaticwithaduck/easytech3d --skill monorepo-lunaticwithaduck

SYSTEM DOCUMENTATION & REQUIREMENTS

What problem does it solve? Extracting features from a Next.js app into shared workspace packages triggers a recurring cluster of failures: tsup dts emission errors, Tailwind v4 CSS not resolving across packages, lost 'use client' directives, CVA variant typing collapsing under strict TypeScript, and pnpm peer-dependency boundary issues. This Skill captures the working resolutions for each of these problems in this codebase. ## Core Features & Use Cases - Package boundary design: Rules for co-locating generator scripts, mirroring tsup entries with package.json subpath exports, and spotting mis-classified primitives before extraction. - Build and bundling fixes: Two-phase dts strategy with transpilePackages, .js extensions for relative imports, and banner-based 'use client' preservation. - Tailwind v4 cross-package setup: @source directive requirements and pure-token theme.css patterns so utility classes from package primitives are emitted. - Strict TypeScript interactions: Fixes for CVA Omit<> collapse, exactOptionalPropertyTypes forwarding, Radix boolean coercion, motion.button spread casts, and noUncheckedIndexedAccess guards. - Use Case: When moving a design-system primitive from apps/web/src into packages/webui, follow the documented checklist to avoid empty styles, dts failures, and server-component import errors. ## Quick Start Ask the assistant to apply the monorepo skill when extracting a feature from apps/web into a new workspace package and have it verify exports, dts, Tailwind @source, and strict-TS variant typing.

Frequently Asked Questions about monorepo

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
How do I extract a feature into a pnpm workspace package with tsup?▼

Create the package with matching tsup entry points and package.json subpath exports, co-locate any generator scripts inside the package, and move app-specific composed components out before extraction. Use transpilePackages in the consumer's next.config.ts as an escape valve while dts is disabled.

Why are Tailwind v4 styles missing from components in a workspace package?▼

Tailwind v4 only scans the consumer's source by default, so utility classes inside package primitives are not emitted. Add an @source directive pointing at the package's src directory in the consumer's globals.css, and keep the shared theme.css as pure tokens without the tailwindcss import.

Why does tsup dts fail on relative imports with .ts extensions?▼

rollup-dts, the dts emitter tsup uses, rejects .ts extensions in import specifiers. Every relative import inside a package's src must use the .js extension even when the source file is TypeScript, while bundler-mode app code does not require this.

How do I preserve 'use client' directives when bundling with tsup?▼

tsup merges per-file 'use client' directives away during bundling, causing server-component import errors in Next.js. For client-heavy packages, add a banner with the 'use client' directive in tsup.config.ts so the entire bundle is marked as client code.

Why does Omit on CVA variant props resolve to an empty type?▼

CVA's variant config is optional, so Parameters<typeof variant>[0] includes undefined, and keyof of that union collapses to never, making Omit resolve to {}. Wrap the extraction in NonNullable once at the variant-type alias to restore the variant props.

Does exactOptionalPropertyTypes break prop forwarding to Radix and motion?▼

Yes. Forwarded optional props need explicit | undefined in their signatures, Radix roots require coercion like disabled ?? false at the call site, and motion.button spread props need a cast to Record<string, unknown> to bypass the stricter HTMLMotionProps comparison.