diff --git a/.github/workflows/ci-ui.yaml b/.github/workflows/ci-ui.yaml index 391baa35e2..27df639e0a 100644 --- a/.github/workflows/ci-ui.yaml +++ b/.github/workflows/ci-ui.yaml @@ -29,7 +29,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - task: [lint, typecheck, test] + task: [lint, typecheck, test, size, pack-size] steps: - name: Fetch custom Github Actions and base branch history uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/forms/number/constants/NumberDataModelSelectOptions.ts b/packages/twenty-front/src/modules/settings/data-model/fields/forms/number/constants/NumberDataModelSelectOptions.ts index ecca1ed9c4..0cfb2b57da 100644 --- a/packages/twenty-front/src/modules/settings/data-model/fields/forms/number/constants/NumberDataModelSelectOptions.ts +++ b/packages/twenty-front/src/modules/settings/data-model/fields/forms/number/constants/NumberDataModelSelectOptions.ts @@ -1,19 +1,15 @@ import { type FieldNumberVariant } from '@/object-record/record-field/ui/types/FieldMetadata'; import { type MessageDescriptor } from '@lingui/core'; import { msg } from '@lingui/core/macro'; -import { type ForwardRefExoticComponent, type RefAttributes } from 'react'; import { IconLetterK, IconNumber9, IconPercentage, type IconComponent, - type IconComponentProps, } from 'twenty-ui/icon'; type NumberDataModelSelectOptions = { - Icon: ForwardRefExoticComponent< - IconComponentProps & RefAttributes - >; + Icon: IconComponent; label: MessageDescriptor; value: FieldNumberVariant; }; diff --git a/packages/twenty-ui/.size-limit.json b/packages/twenty-ui/.size-limit.json index e5be2efeef..40c37d2625 100644 --- a/packages/twenty-ui/.size-limit.json +++ b/packages/twenty-ui/.size-limit.json @@ -18,7 +18,7 @@ { "name": "testing", "path": "dist/testing.mjs", - "limit": "188 kB" + "limit": "50 kB" }, { "name": "data-display", @@ -38,7 +38,7 @@ { "name": "surfaces", "path": "dist/surfaces.mjs", - "limit": "100 kB" + "limit": "70 kB" }, { "name": "feedback", @@ -53,7 +53,7 @@ { "name": "layout", "path": "dist/layout.mjs", - "limit": "60 kB" + "limit": "25 kB" }, { "name": "navigation", @@ -63,17 +63,17 @@ { "name": "json-visualizer", "path": "dist/json-visualizer.mjs", - "limit": "173 kB" + "limit": "30 kB" }, { "name": "theme", "path": "dist/theme.mjs", - "limit": "55 kB" + "limit": "25 kB" }, { "name": "theme-constants", "path": "dist/theme-constants.mjs", - "limit": "20 kB" + "limit": "12 kB" }, { "name": "utilities", @@ -83,6 +83,6 @@ { "name": "style.css", "path": "dist/style.css", - "limit": "40 kB" + "limit": "20 kB" } ] diff --git a/packages/twenty-ui/package.json b/packages/twenty-ui/package.json index 1fc8b1777d..a2dfc1dce4 100644 --- a/packages/twenty-ui/package.json +++ b/packages/twenty-ui/package.json @@ -1,6 +1,6 @@ { "name": "twenty-ui", - "version": "1.0.0-alpha.0", + "version": "1.0.0-alpha.1", "description": "Twenty's shared React UI component library.", "license": "AGPL-3.0", "repository": { @@ -92,22 +92,9 @@ }, "files": [ "dist", - "accessibility", - "assets", - "data-display", - "feedback", - "icon", - "input", - "json-visualizer", - "layout", - "navigation", - "styles", - "surfaces", - "testing", - "theme", - "theme-constants", - "typography", - "utilities" + "!dist/individual", + "!dist/individual/**", + "!dist/**/*.map" ], "exports": { ".": { diff --git a/packages/twenty-ui/project.json b/packages/twenty-ui/project.json index 6ed5f3a7c9..eeee3375c5 100644 --- a/packages/twenty-ui/project.json +++ b/packages/twenty-ui/project.json @@ -5,44 +5,7 @@ "projectType": "library", "tags": ["scope:shared"], "targets": { - "build": { - "dependsOn": ["^build"], - "outputs": [ - "{projectRoot}/dist", - "{projectRoot}/accessibility/package.json", - "{projectRoot}/accessibility/dist", - "{projectRoot}/assets/package.json", - "{projectRoot}/assets/dist", - "{projectRoot}/data-display/package.json", - "{projectRoot}/data-display/dist", - "{projectRoot}/feedback/package.json", - "{projectRoot}/feedback/dist", - "{projectRoot}/icon/package.json", - "{projectRoot}/icon/dist", - "{projectRoot}/input/package.json", - "{projectRoot}/input/dist", - "{projectRoot}/json-visualizer/package.json", - "{projectRoot}/json-visualizer/dist", - "{projectRoot}/layout/package.json", - "{projectRoot}/layout/dist", - "{projectRoot}/navigation/package.json", - "{projectRoot}/navigation/dist", - "{projectRoot}/styles/package.json", - "{projectRoot}/styles/dist", - "{projectRoot}/surfaces/package.json", - "{projectRoot}/surfaces/dist", - "{projectRoot}/testing/package.json", - "{projectRoot}/testing/dist", - "{projectRoot}/theme/package.json", - "{projectRoot}/theme/dist", - "{projectRoot}/theme-constants/package.json", - "{projectRoot}/theme-constants/dist", - "{projectRoot}/typography/package.json", - "{projectRoot}/typography/dist", - "{projectRoot}/utilities/package.json", - "{projectRoot}/utilities/dist" - ] - }, + "build": { "dependsOn": ["^build"], "outputs": ["{projectRoot}/dist"] }, "generateBarrels": { "executor": "nx:run-commands", "cache": true, @@ -74,6 +37,20 @@ "options": { "cwd": "{projectRoot}", "command": "npx size-limit" }, "configurations": { "why": { "command": "npx size-limit --why" } } }, + "pack-size": { + "executor": "nx:run-commands", + "cache": true, + "dependsOn": ["build"], + "inputs": [ + "{projectRoot}/dist", + "{projectRoot}/package.json", + "{projectRoot}/scripts/checkPackSize.ts" + ], + "options": { + "cwd": "{projectRoot}", + "command": "tsx scripts/checkPackSize.ts" + } + }, "clean": { "executor": "nx:run-commands", "options": { "command": "rimraf {projectRoot}/dist" } diff --git a/packages/twenty-ui/scripts/checkPackSize.ts b/packages/twenty-ui/scripts/checkPackSize.ts new file mode 100644 index 0000000000..0d00bcd6bf --- /dev/null +++ b/packages/twenty-ui/scripts/checkPackSize.ts @@ -0,0 +1,47 @@ +import { execSync } from 'child_process'; +import * as path from 'path'; +import { fileURLToPath } from 'url'; + +const MAX_UNPACKED_BYTES = 30 * 1024 * 1024; +const PACKAGE_PATH = path.resolve( + path.dirname(fileURLToPath(import.meta.url)), + '..', +); + +const formatMegabytes = (bytes: number) => + `${(bytes / (1024 * 1024)).toFixed(2)} MB`; + +type NpmPackResult = { + filename: string; + size: number; + unpackedSize: number; + entryCount: number; +}; + +const output = execSync('npm pack --dry-run --json', { + cwd: PACKAGE_PATH, + encoding: 'utf-8', + maxBuffer: 64 * 1024 * 1024, +}); + +const [packResult] = JSON.parse(output) as NpmPackResult[]; +if (packResult === undefined) { + throw new Error('npm pack did not return any package information'); +} + +const { size, unpackedSize, entryCount } = packResult; + +if (unpackedSize > MAX_UNPACKED_BYTES) { + process.stderr.write( + `twenty-ui unpacked size ${formatMegabytes(unpackedSize)} exceeds budget ${formatMegabytes( + MAX_UNPACKED_BYTES, + )} (tarball ${formatMegabytes(size)}, ${entryCount} files)\n`, + ); + process.exit(1); +} + +process.stdout.write( + `twenty-ui pack OK: tarball ${formatMegabytes(size)}, unpacked ${formatMegabytes( + unpackedSize, + )}, ${entryCount} files\n`, +); diff --git a/packages/twenty-ui/scripts/generateBarrels.ts b/packages/twenty-ui/scripts/generateBarrels.ts index 814f94fc4c..4458263b30 100644 --- a/packages/twenty-ui/scripts/generateBarrels.ts +++ b/packages/twenty-ui/scripts/generateBarrels.ts @@ -250,20 +250,17 @@ const computePackageJsonFilesAndExportsConfig = ( return { exports, typesVersions: { '*': typesVersionsEntries }, - files: ['dist', ...entrypoints], + files: [ + 'dist', + '!dist/individual', + '!dist/individual/**', + '!dist/**/*.map', + ], }; }; -const computeProjectNxBuildOutputsPath = (moduleDirectories: string[]) => { - const dynamicOutputsPath = moduleDirectories - .map(getLastPathFolder) - .flatMap((barrelName) => - ['package.json', 'dist'].map( - (subPath) => `{projectRoot}/${barrelName}/${subPath}`, - ), - ); - - return ['{projectRoot}/dist', ...dynamicOutputsPath]; +const computeProjectNxBuildOutputsPath = () => { + return ['{projectRoot}/dist']; }; const EXCLUDED_EXTENSIONS = [ @@ -531,8 +528,7 @@ const main = () => { const moduleIndexFiles = generateModuleIndexFiles(exportsByBarrel); const packageJsonConfig = computePackageJsonFilesAndExportsConfig(moduleDirectories); - const nxBuildOutputsPath = - computeProjectNxBuildOutputsPath(moduleDirectories); + const nxBuildOutputsPath = computeProjectNxBuildOutputsPath(); updateNxProjectConfigurationBuildOutputs(nxBuildOutputsPath); writeInPackageJson(packageJsonConfig); diff --git a/packages/twenty-ui/src/accessibility/index.ts b/packages/twenty-ui/src/accessibility/index.ts index 0c3e751b47..767ee9d3d9 100644 --- a/packages/twenty-ui/src/accessibility/index.ts +++ b/packages/twenty-ui/src/accessibility/index.ts @@ -9,4 +9,5 @@ export { VisibilityHidden } from './components/VisibilityHidden'; export { VisibilityHiddenInput } from './components/VisibilityHiddenInput'; +export { handleClickableElementKeyDown } from './utils/handleClickableElementKeyDown'; export { VISIBILITY_HIDDEN } from './utils/visibility-hidden'; diff --git a/packages/twenty-ui/tsconfig.lib.json b/packages/twenty-ui/tsconfig.lib.json index ead3d78666..3e2cf990d3 100644 --- a/packages/twenty-ui/tsconfig.lib.json +++ b/packages/twenty-ui/tsconfig.lib.json @@ -2,7 +2,7 @@ "extends": "./tsconfig.json", "compilerOptions": { "declaration": true, - "declarationMap": true, + "declarationMap": false, "noEmit": false }, "include": [ diff --git a/packages/twenty-ui/vite.config.ts b/packages/twenty-ui/vite.config.ts index a7f58d46b4..b382469510 100644 --- a/packages/twenty-ui/vite.config.ts +++ b/packages/twenty-ui/vite.config.ts @@ -55,7 +55,7 @@ export default defineConfig(({ command }) => { tsconfigPath: tsConfigPath, }; - const BUNDLED_DEPS = ['@tabler/icons-react']; + const BUNDLED_DEPS: string[] = []; const externalDeps = Object.keys({ ...(packageJson.dependencies || {}), @@ -68,7 +68,6 @@ export default defineConfig(({ command }) => { '@ui/': path.resolve(__dirname, 'src') + '/', '@assets/': path.resolve(__dirname, 'src/assets') + '/', '@styles/': path.resolve(__dirname, 'src/styles') + '/', - '@tabler/icons-react': '@tabler/icons-react/dist/esm/icons/index.mjs', }, }, css: {