[DevXP] Improve Linaria pre-build speed (#18382)
## Summary This PR improves Linaria/WYW pre-build speed and continues the migration of `twenty-ui` components away from runtime `ThemeContext` reads toward static CSS variables and theme constants. ### Linaria/WYW profiling plugin improvements (`twenty-shared`) - **Babel JIT warmup**: added a `buildStart` warmup step that triggers WYW's Babel JIT compilation before the real build starts, so the first real file doesn't pay the cold-start penalty - **`configResolved` hook**: detects dev vs prod mode and resolves the correct warmup file path relative to `config.root` - **Dev-only per-file logging**: slow file warnings are now gated behind `isDevMode`, keeping production/CI build output clean - **`closeBundle` summary**: moved the final top-slow-files report to `closeBundle` for accurate end-of-build reporting - **Removed noisy progress interval logging** in favor of the warmup log + final summary ### Migration from `ThemeContext` to static CSS variables / constants Across `twenty-ui`, replaced runtime `useTheme()` reads with: - `themeCssVariables` CSS custom properties (colors, spacing) - Hard-coded design-system constants (`ICON.size.md` → `16`, `ICON.stroke.sm` → `1.6`) so components no longer need a React context at render time — enabling Linaria static extraction **Components migrated:** - `Button`, `AnimatedButton`, `LightButton`, `LightIconButton`, `AnimatedLightIconButton`, `ButtonIcon`, `ButtonSoon` - `ProgressBar` (Framer Motion width animation → CSS `transition`) - `Info`, `HorizontalSeparator`, `LinkChip` - `MenuPicker`, `MenuItemLeftContent`, `MenuItemIconWithGripSwap`, `NavigationBarItem` - `JsonArrow`, `JsonNestedNode` - `ModalHeader` ### Other - Added `aria-valuenow` to `ProgressBar` for accessibility - `VisibilityHidden` component updated to inline accessibility styles
This commit is contained in:
@@ -4,21 +4,37 @@ import { themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
type TableCellProps = {
|
||||
align?: 'left' | 'center' | 'right';
|
||||
color?: string;
|
||||
gap?: string;
|
||||
height?: string;
|
||||
maxWidth?: string;
|
||||
minWidth?: string;
|
||||
overflow?: string;
|
||||
padding?: string;
|
||||
textOverflow?: string;
|
||||
whiteSpace?: string;
|
||||
clickable?: boolean;
|
||||
};
|
||||
|
||||
const StyledTableCell = styled.div<TableCellProps>`
|
||||
align-items: center;
|
||||
color: ${({ color }) => color || themeCssVariables.font.color.secondary};
|
||||
cursor: ${({ clickable }) => (clickable === true ? 'pointer' : 'default')};
|
||||
display: flex;
|
||||
height: ${themeCssVariables.spacing[8]};
|
||||
gap: ${({ gap }) => gap ?? 'normal'};
|
||||
height: ${({ height }) => height ?? themeCssVariables.spacing[8]};
|
||||
justify-content: ${({ align }) =>
|
||||
align === 'right'
|
||||
? 'flex-end'
|
||||
: align === 'center'
|
||||
? 'center'
|
||||
: 'flex-start'};
|
||||
padding: 0 ${themeCssVariables.spacing[2]};
|
||||
max-width: ${({ maxWidth }) => maxWidth ?? 'none'};
|
||||
min-width: ${({ minWidth }) => minWidth ?? 'auto'};
|
||||
overflow: ${({ overflow }) => overflow ?? 'visible'};
|
||||
padding: ${({ padding }) => padding ?? `0 ${themeCssVariables.spacing[2]}`};
|
||||
text-align: ${({ align }) => align ?? 'left'};
|
||||
text-overflow: ${({ textOverflow }) => textOverflow ?? 'clip'};
|
||||
white-space: ${({ whiteSpace }) => whiteSpace ?? 'normal'};
|
||||
`;
|
||||
|
||||
export { StyledTableCell as TableCell };
|
||||
|
||||
@@ -4,6 +4,7 @@ import { themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
const StyledTableHeader = styled.div<{
|
||||
align?: 'left' | 'center' | 'right';
|
||||
onClick?: () => void;
|
||||
padding?: string;
|
||||
}>`
|
||||
gap: ${themeCssVariables.spacing[1]};
|
||||
align-items: center;
|
||||
@@ -18,7 +19,7 @@ const StyledTableHeader = styled.div<{
|
||||
: align === 'center'
|
||||
? 'center'
|
||||
: 'flex-start'};
|
||||
padding: 0 ${themeCssVariables.spacing[2]};
|
||||
padding: ${({ padding }) => padding ?? `0 ${themeCssVariables.spacing[2]}`};
|
||||
text-align: ${({ align }) => align ?? 'left'};
|
||||
cursor: ${({ onClick }) => (onClick ? 'pointer' : 'default')};
|
||||
`;
|
||||
|
||||
@@ -4,15 +4,24 @@ import { MOBILE_VIEWPORT, themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
|
||||
const StyledTableRow = styled.div<{
|
||||
isSelected?: boolean;
|
||||
isExpanded?: boolean;
|
||||
onClick?: () => void;
|
||||
to?: string;
|
||||
gridAutoColumns?: string;
|
||||
gridTemplateColumns?: string;
|
||||
mobileGridAutoColumns?: string;
|
||||
height?: string;
|
||||
cursor?: string;
|
||||
hoverBackgroundColor?: string;
|
||||
}>`
|
||||
background-color: ${({ isSelected }) =>
|
||||
isSelected ? themeCssVariables.accent.quaternary : 'transparent'};
|
||||
background-color: ${({ isSelected, isExpanded }) =>
|
||||
isSelected
|
||||
? themeCssVariables.accent.quaternary
|
||||
: isExpanded === true
|
||||
? themeCssVariables.background.transparent.light
|
||||
: 'transparent'};
|
||||
border-radius: ${themeCssVariables.border.radius.sm};
|
||||
cursor: ${({ cursor }) => cursor ?? 'default'};
|
||||
display: grid;
|
||||
grid-auto-columns: ${({ gridAutoColumns }) => gridAutoColumns ?? '1fr'};
|
||||
grid-template-columns: ${({ gridTemplateColumns }) =>
|
||||
@@ -23,6 +32,7 @@ const StyledTableRow = styled.div<{
|
||||
mobileGridAutoColumns ?? gridAutoColumns ?? '1fr'};
|
||||
}
|
||||
|
||||
height: ${({ height }) => height ?? 'auto'};
|
||||
grid-auto-flow: column;
|
||||
transition: background-color
|
||||
calc(${themeCssVariables.animation.duration.normal} * 1s);
|
||||
@@ -30,11 +40,13 @@ const StyledTableRow = styled.div<{
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
background-color: ${({ onClick, to }) =>
|
||||
onClick || to
|
||||
background-color: ${({ onClick, to, hoverBackgroundColor }) =>
|
||||
hoverBackgroundColor ??
|
||||
(onClick || to
|
||||
? themeCssVariables.background.transparent.light
|
||||
: 'transparent'};
|
||||
cursor: ${({ onClick, to }) => (onClick || to ? 'pointer' : 'default')};
|
||||
: 'transparent')};
|
||||
cursor: ${({ onClick, to, cursor }) =>
|
||||
cursor ?? (onClick || to ? 'pointer' : 'default')};
|
||||
}
|
||||
|
||||
&[data-clickable='true'] {
|
||||
@@ -44,6 +56,7 @@ const StyledTableRow = styled.div<{
|
||||
|
||||
type TableRowProps = {
|
||||
isSelected?: boolean;
|
||||
isExpanded?: boolean;
|
||||
isClickable?: boolean;
|
||||
onClick?: () => void;
|
||||
to?: string;
|
||||
@@ -52,10 +65,14 @@ type TableRowProps = {
|
||||
gridAutoColumns?: string;
|
||||
gridTemplateColumns?: string;
|
||||
mobileGridAutoColumns?: string;
|
||||
height?: string;
|
||||
cursor?: string;
|
||||
hoverBackgroundColor?: string;
|
||||
};
|
||||
|
||||
export const TableRow = ({
|
||||
isSelected,
|
||||
isExpanded,
|
||||
isClickable,
|
||||
onClick,
|
||||
to,
|
||||
@@ -65,9 +82,13 @@ export const TableRow = ({
|
||||
gridAutoColumns,
|
||||
gridTemplateColumns,
|
||||
mobileGridAutoColumns,
|
||||
height,
|
||||
cursor,
|
||||
hoverBackgroundColor,
|
||||
}: React.PropsWithChildren<TableRowProps>) => (
|
||||
<StyledTableRow
|
||||
isSelected={isSelected}
|
||||
isExpanded={isExpanded}
|
||||
onClick={onClick}
|
||||
gridAutoColumns={gridAutoColumns}
|
||||
gridTemplateColumns={gridTemplateColumns}
|
||||
@@ -75,6 +96,9 @@ export const TableRow = ({
|
||||
style={style}
|
||||
data-clickable={isClickable}
|
||||
mobileGridAutoColumns={mobileGridAutoColumns}
|
||||
height={height}
|
||||
cursor={cursor}
|
||||
hoverBackgroundColor={hoverBackgroundColor}
|
||||
to={to}
|
||||
as={to ? Link : 'div'}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user