Skip to content

Commit

Permalink
Build with React Compiler (#1173)
Browse files Browse the repository at this point in the history
  • Loading branch information
emmatown authored Jun 10, 2024
1 parent a3787a9 commit 34dee8c
Show file tree
Hide file tree
Showing 31 changed files with 623 additions and 393 deletions.
6 changes: 6 additions & 0 deletions .changeset/rotten-buckets-explode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@keystatic/core': patch
'@keystar/ui': patch
---

Build with React Compiler
12 changes: 11 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,17 @@ module.exports = {
},
],
'react/no-unknown-property': OFF,
'react-compiler/react-compiler': ERROR,
'react-compiler/react-compiler': [
ERROR,
{
reportableLevels: new Set([
'InvalidJS',
'InvalidReact',
// uncomment if you want to see these cases
// 'CannotPreserveMemoization',
]),
},
],
},
overrides: [
{
Expand Down
11 changes: 11 additions & 0 deletions babel.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,16 @@
"@babel/plugin-transform-runtime",
"@babel/plugin-proposal-explicit-resource-management",
["@babel/plugin-transform-private-property-in-object", { "loose": true }]
],
"overrides": [
{
"test": ["packages/keystatic/src/**/*", "design-system/pkg/src/**/*"],
"plugins": [
[
"babel-plugin-react-compiler",
{ "runtimeModule": "#react-compiler-runtime" }
]
]
}
]
}
3 changes: 2 additions & 1 deletion design-system/pkg/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1585,7 +1585,8 @@
}
},
"imports": {
"#test-utils": "./src/test-utils/index.ts"
"#test-utils": "./src/test-utils/index.ts",
"#react-compiler-runtime": "./src/react-compiler-runtime.ts"
},
"preconstruct": {
"entrypoints": [
Expand Down
83 changes: 50 additions & 33 deletions design-system/pkg/src/button/ButtonGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import {
ForwardedRef,
forwardRef,
ForwardRefExoticComponent,
MutableRefObject,
ReactNode,
Ref,
useCallback,
useMemo,
useRef,
} from 'react';

Expand All @@ -30,39 +32,14 @@ import {

import { ButtonGroupProps } from './types';

function consumeForReactTooling(..._vals: unknown[]) {}

/**
* Handles overflow for a grouping of buttons whose actions are related to each
* other.
*/
export const ButtonGroup: ForwardRefExoticComponent<
ButtonGroupProps & { ref?: Ref<HTMLDivElement> }
> = forwardRef(function ButtonGroup(
props: ButtonGroupProps,
forwardedRef: ForwardedRef<HTMLDivElement>
function getCheckForOverflow(
domRef: MutableRefObject<HTMLDivElement | null>,
orientation: string,
_scale: string,
setHasOverflow: (value: () => Generator<any, void, unknown>) => void,
_children: ReactNode
) {
let { scale } = useProvider();
props = useProviderProps(props);
props = useSlotProps(props, 'buttonGroup');

let {
align = 'start',
children,
isDisabled,
orientation = 'horizontal',
...otherProps
} = props;

let styleProps = useStyleProps(otherProps);
let domRef = useObjectRef(forwardedRef);
let [hasOverflow, setHasOverflow] = useValueEffect(false);

// Avoid widows, horizontal orientations may switch to vertical when there
// isn't enough space for all buttons in a single row. There's no "wrap"
// event, so we have to measure.
let checkForOverflow = useCallback(() => {
consumeForReactTooling(children, scale);
return () => {
let computeHasOverflow = () => {
if (domRef.current && orientation === 'horizontal') {
let buttonGroupChildren = Array.from(
Expand Down Expand Up @@ -92,6 +69,46 @@ export const ButtonGroup: ForwardRefExoticComponent<
yield computeHasOverflow();
});
}
};
}

/**
* Handles overflow for a grouping of buttons whose actions are related to each
* other.
*/
export const ButtonGroup: ForwardRefExoticComponent<
ButtonGroupProps & { ref?: Ref<HTMLDivElement> }
> = forwardRef(function ButtonGroup(
props: ButtonGroupProps,
forwardedRef: ForwardedRef<HTMLDivElement>
) {
let { scale } = useProvider();
props = useProviderProps(props);
props = useSlotProps(props, 'buttonGroup');

let {
align = 'start',
children,
isDisabled,
orientation = 'horizontal',
...otherProps
} = props;

let styleProps = useStyleProps(otherProps);
let domRef = useObjectRef(forwardedRef);
let [hasOverflow, setHasOverflow] = useValueEffect(false);

// Avoid widows, horizontal orientations may switch to vertical when there
// isn't enough space for all buttons in a single row. There's no "wrap"
// event, so we have to measure.
let checkForOverflow = useMemo(() => {
return getCheckForOverflow(
domRef,
orientation,
scale,
setHasOverflow,
children
);
}, [domRef, orientation, scale, setHasOverflow, children]);

// There are two main reasons we need to remeasure:
Expand Down
23 changes: 15 additions & 8 deletions design-system/pkg/src/list-view/ListView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,20 @@ const ROW_HEIGHTS = {
},
} as const;

function consumeValueForReactTooling(_val: unknown) {}
function createLayout<T>(
collator: Intl.Collator,
scale: 'medium' | 'large',
density: keyof typeof ROW_HEIGHTS,
isEmpty: boolean,
_overflowMode: string | undefined
) {
return new ListLayout<T>({
estimatedRowHeight: ROW_HEIGHTS[density][scale],
padding: 0,
collator,
loaderHeight: isEmpty ? undefined : ROW_HEIGHTS[density][scale],
});
}

function useListLayout<T>(
state: ListState<T>,
Expand All @@ -63,13 +76,7 @@ function useListLayout<T>(
let collator = useCollator({ usage: 'search', sensitivity: 'base' });
let isEmpty = state.collection.size === 0;
let layout = useMemo(() => {
consumeValueForReactTooling(overflowMode);
return new ListLayout<T>({
estimatedRowHeight: ROW_HEIGHTS[density][scale],
padding: 0,
collator,
loaderHeight: isEmpty ? undefined : ROW_HEIGHTS[density][scale],
});
return createLayout<T>(collator, scale, density, isEmpty, overflowMode);
}, [collator, scale, density, isEmpty, overflowMode]);

layout.collection = state.collection;
Expand Down
17 changes: 17 additions & 0 deletions design-system/pkg/src/react-compiler-runtime.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { useState } from 'react';

const $empty = Symbol.for('react.memo_cache_sentinel');

export function c(size: number) {
// eslint-disable-next-line react-compiler/react-compiler
// eslint-disable-next-line react-hooks/rules-of-hooks
return useState(() => {
const $ = new Array(size);
for (let ii = 0; ii < size; ii++) {
$[ii] = $empty;
}
// @ts-ignore
$[$empty] = true;
return $;
})[0];
}
4 changes: 3 additions & 1 deletion design-system/pkg/src/typography/text/useTextStyles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ export function useTextStyles(
overflow && overflowMap[overflow],
trimStyles,
];

// the compiler ESLint plugin complains that "Hooks may not be referenced as normal values, they must be called."
// which this is definitely not doing, pretty sure it's a bug that's been fixed in react main
// eslint-disable-next-line react-compiler/react-compiler
return useStyleProps({
...otherProps,
UNSAFE_className: [
Expand Down
1 change: 1 addition & 0 deletions dev-projects/next-app/keystatic.config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ export default config({
path: 'single-file-posts/**',
slugField: 'title',
format: { contentField: 'content' },
entryLayout: 'content',
schema: {
title: fields.slug({ name: { label: 'Title' } }),
content: fields.document({
Expand Down
2 changes: 1 addition & 1 deletion dev-projects/next-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"license": "MIT",
"private": true,
"scripts": {
"build": "next build",
"build": "cd ../.. && pnpm preconstruct build && cd dev-projects/next-app && next build",
"dev": "next dev",
"start": "next start"
},
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,15 @@
"@types/node": "16.11.13",
"@typescript-eslint/eslint-plugin": "^5.29.0",
"@typescript-eslint/parser": "^5.29.0",
"babel-plugin-react-compiler": "^0.0.0-experimental-938cd9a-20240601",
"cross-env": "^7.0.3",
"eslint": "^8.18.0",
"eslint-config-next": "^12.1.6",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jest": "^26.5.3",
"eslint-plugin-react": "^7.30.0",
"eslint-plugin-react-compiler": "^0.0.0-experimental-c8b3f72-20240517",
"eslint-plugin-react-compiler": "^0.0.0-experimental-51a85ea-20240601",
"eslint-plugin-react-hooks": "^4.6.0",
"jest": "^30.0.0-alpha.2",
"jest-environment-jsdom": "^30.0.0-alpha.2",
Expand Down
3 changes: 2 additions & 1 deletion packages/keystatic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@
"default": "./src/component-blocks/cloud-image-preview.tsx"
},
"#markdoc": "./src/markdoc.js",
"#base64": "./src/base64.ts"
"#base64": "./src/base64.ts",
"#react-compiler-runtime": "./src/react-compiler-runtime.ts"
}
}
Loading

0 comments on commit 34dee8c

Please sign in to comment.