import { defineConfig } from 'tsup'; export default defineConfig({ /* One entry per component folder — this is what produces the per-component subpath exports. `scripts/gen-exports.mjs` derives package.json#exports from the same folder layout, so the two stay in sync automatically. */ entry: [ 'src/index.ts', 'src/lib/index.ts', 'src/hooks/index.ts', 'src/icons/index.ts', 'src/components/*/index.ts', ], outDir: 'dist', format: ['esm', 'cjs'], target: 'es2022', dts: true, tsconfig: 'tsconfig.build.json', clean: true, treeshake: true, /* Code-splitting pulls shared internals (cn, variant presets, the bundled Radix primitives) into shared chunks instead of copying them into every component. tsup 8.5 does this for CJS as well as ESM — measured: the DismissableLayer implementation appears in exactly one `.js` chunk and one `.cjs` chunk, and every overlay entry requires that same file. That is what keeps the module-level state Radix relies on (the dismissable layer stack, react-remove-scroll's sidecar, aria-hidden's counter) a single instance even though the package is bundled rather than resolved from node_modules. `test/dist-layering.test.tsx` is the guard on that claim, and it is not theoretical: flipping this to `false` puts DismissableLayer in 12 separate files and both of its cases fail. */ splitting: true, /* React must come from the consuming app, never from the kit. */ external: ['react', 'react-dom', 'react/jsx-runtime'], /* The kit publishes ZERO runtime dependencies: everything below is compiled into `dist` instead of landing in a consumer's install and lock file. `radix-ui` and its whole transitive tree are dev-time inputs here, not downstream obligations. Two things are load-bearing: 1. The pattern must be `/^radix-ui(\/|$)/`, not `/^radix-ui$/` — components import the per-primitive subpaths (`radix-ui/slot`, `radix-ui/dialog`), and a bare-name-only regex silently leaves every one of them external. 2. Components must NEVER import the `radix-ui` barrel. The barrel is a single module reachable from all 21 of them, so esbuild puts it in one shared chunk and a component that only wants `Slot` drags in all of Radix — measured at 434 kB for Button, against 10 kB via the subpath. `eslint.config.js` fails the build on a barrel import for this reason. */ noExternal: [ /^radix-ui(\/|$)/, /^@radix-ui\//, /^@floating-ui\//, 'aria-hidden', 'react-remove-scroll', 'react-remove-scroll-bar', 'react-style-singleton', 'use-sidecar', 'use-callback-ref', 'get-nonce', 'detect-node-es', 'tslib', ], /* No sourcemaps: `scripts/add-use-client.mjs` prepends a line to the entry files after the fact, which would leave every mapping off by one. Shipping no map is more honest than shipping a wrong one, and keeps the tarball small. */ sourcemap: false, });