From 8553c574db07d56b473a93260a7c334f57e5665b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Bosi?= <71827178+bosiraphael@users.noreply.github.com> Date: Mon, 22 Jun 2026 17:09:25 +0200 Subject: [PATCH] Improve twenty-ui packaging for standalone publishing (#21946) Quick packaging wins to move twenty-ui closer to a standalone publishable library. - Move `react`/`react-dom` to `peerDependencies` (`^19.0.0`) so consumers provide a single React and we avoid duplicate-React bugs. They stay in `devDependencies` for the in-repo build, and `vite.config.ts` now derives the Rollup `external` list from peer deps too so React stays externalized instead of bundled. - Declare `type-fest` in `dependencies`. It was a phantom dep (resolved only via root hoisting) and its types are referenced by the emitted json-visualizer `.d.ts`, so standalone consumers need it. - Move build-only `glob` to `devDependencies` and add `typescript` (both used only by `generateBarrels.ts`). - Make `tsconfig.json` self-contained by inlining the base compiler options, and point the Vite `cacheDir`/`optimizeDeps.exclude` at package-local paths. Verified: typecheck, build (React confirmed externalized in `dist`, not inlined), dts emission, and unit tests all pass. Review in cubic --- packages/twenty-ui/package.json | 12 ++++++++---- packages/twenty-ui/vite.config.individual.ts | 5 ++++- packages/twenty-ui/vite.config.ts | 10 +++++----- yarn.lock | 6 +++++- 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/packages/twenty-ui/package.json b/packages/twenty-ui/package.json index c0fbc76005..3fd9aee988 100644 --- a/packages/twenty-ui/package.json +++ b/packages/twenty-ui/package.json @@ -49,9 +49,12 @@ "@vitejs/plugin-react-swc": "^4.3.1", "@vitest/browser-playwright": "^4.1.0", "esbuild": "^0.28.1", + "glob": "^11.1.0", "jest": "29.7.0", "jest-environment-jsdom": "30.0.0-beta.3", "prettier": "^3.1.1", + "react": "^19.2.0", + "react-dom": "^19.2.0", "sass": "^1.83.0", "sass-embedded": "^1.83.0", "size-limit": "^12.1.0", @@ -59,6 +62,7 @@ "storybook-addon-pseudo-states": "^10.3.3", "ts-jest": "^29.1.1", "tsx": "^4.19.3", + "typescript": "^5.9.3", "vite-plugin-checker": "^0.10.2", "vite-plugin-dts": "^4.5.4", "vite-plugin-sass-dts": "^1.3.31", @@ -75,15 +79,15 @@ "clsx": "^2.1.1", "date-fns": "^4.4.0", "framer-motion": "^11.18.0", - "glob": "^11.1.0", - "react": "^19.2.0", - "react-dom": "^19.2.0", "react-responsive": "^9.0.2", "react-router-dom": "^6.4.4", + "type-fest": "^4.10.1", "zod": "^4.1.11" }, "peerDependencies": { - "monaco-editor": ">= 0.25.0 < 1" + "monaco-editor": ">= 0.25.0 < 1", + "react": "^19.0.0", + "react-dom": "^19.0.0" }, "scripts": { "build": "npx vite build" diff --git a/packages/twenty-ui/vite.config.individual.ts b/packages/twenty-ui/vite.config.individual.ts index d21fa425d1..b34f2bbd1a 100644 --- a/packages/twenty-ui/vite.config.individual.ts +++ b/packages/twenty-ui/vite.config.individual.ts @@ -6,7 +6,10 @@ import tsconfigPaths from 'vite-tsconfig-paths'; import packageJson from './package.json'; -const depNames = Object.keys(packageJson.dependencies || {}); +const depNames = Object.keys({ + ...(packageJson.dependencies || {}), + ...(packageJson.peerDependencies || {}), +}); const isExternal = (id: string): boolean => depNames.some((dep) => id === dep || id.startsWith(dep + '/')); diff --git a/packages/twenty-ui/vite.config.ts b/packages/twenty-ui/vite.config.ts index bb7a7833b8..a7f58d46b4 100644 --- a/packages/twenty-ui/vite.config.ts +++ b/packages/twenty-ui/vite.config.ts @@ -57,9 +57,10 @@ export default defineConfig(({ command }) => { const BUNDLED_DEPS = ['@tabler/icons-react']; - const externalDeps = Object.keys(packageJson.dependencies || {}).filter( - (dep) => !BUNDLED_DEPS.includes(dep), - ); + const externalDeps = Object.keys({ + ...(packageJson.dependencies || {}), + ...(packageJson.peerDependencies || {}), + }).filter((dep) => !BUNDLED_DEPS.includes(dep)); return { resolve: { @@ -88,7 +89,6 @@ export default defineConfig(({ command }) => { }, }, optimizeDeps: { - exclude: ['../../node_modules/.vite', '../../node_modules/.cache'], // Pre-bundle React up front so Vite's dep optimizer doesn't re-bundle it // mid-run during browser-mode Storybook tests — re-bundling rotates the // optimized chunk hash and 404s in-flight dynamic imports (vite 8 / rolldown). @@ -101,7 +101,7 @@ export default defineConfig(({ command }) => { ], }, root: __dirname, - cacheDir: '../../node_modules/.vite/packages/twenty-ui', + cacheDir: 'node_modules/.vite', assetsInclude: ['src/**/*.svg'], plugins: [ react(), diff --git a/yarn.lock b/yarn.lock index b5810cd0b8..e649898940 100644 --- a/yarn.lock +++ b/yarn.lock @@ -54426,6 +54426,8 @@ __metadata: storybook-addon-pseudo-states: "npm:^10.3.3" ts-jest: "npm:^29.1.1" tsx: "npm:^4.19.3" + type-fest: "npm:^4.10.1" + typescript: "npm:^5.9.3" vite-plugin-checker: "npm:^0.10.2" vite-plugin-dts: "npm:^4.5.4" vite-plugin-sass-dts: "npm:^1.3.31" @@ -54435,6 +54437,8 @@ __metadata: zod: "npm:^4.1.11" peerDependencies: monaco-editor: ">= 0.25.0 < 1" + react: ^19.0.0 + react-dom: ^19.0.0 languageName: unknown linkType: soft @@ -54611,7 +54615,7 @@ __metadata: languageName: node linkType: hard -"type-fest@npm:^4.18.2, type-fest@npm:^4.21.0, type-fest@npm:^4.26.1, type-fest@npm:^4.27.0, type-fest@npm:^4.31.0, type-fest@npm:^4.39.1, type-fest@npm:^4.41.0, type-fest@npm:^4.6.0": +"type-fest@npm:^4.10.1, type-fest@npm:^4.18.2, type-fest@npm:^4.21.0, type-fest@npm:^4.26.1, type-fest@npm:^4.27.0, type-fest@npm:^4.31.0, type-fest@npm:^4.39.1, type-fest@npm:^4.41.0, type-fest@npm:^4.6.0": version: 4.41.0 resolution: "type-fest@npm:4.41.0" checksum: 10c0/f5ca697797ed5e88d33ac8f1fec21921839871f808dc59345c9cf67345bfb958ce41bd821165dbf3ae591cedec2bf6fe8882098dfdd8dc54320b859711a2c1e4