You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Since then the entire ecosystem has moved to the jsx transform, that includes our vite when using sanity dev|build|deploy, as well as publishing libraries with @sanity/pkg-utils, and most other build tooling like Parcel, tsup etc etc.
With the new transform it's not just a new function being used, it's from a different, standalone export, and its function argument semantics are different:
// React 18 requires a wrapper in function components to forward refs to the dom nodeconstLoadingIcon=React.forwardRef(function(props,ref){return<svgref={ref}/>})// React 19 supports ref as a propfunctionLoadingIcon(props){return<svgref={props.ref}/>}
The React 19 <LoadingIcon /> only works if the JSX transform is used (repl):
exportdefaultfunctionComponent(props){const{icon: Icon}=propsconstref=useRef()return<Iconref={ref}/>}// Called as <Component icon={LoadingIcon} />
import{createElement,useRef}from'react'exportdefaultfunctionComponent(props){constref=useRef()// Due to `createElement` being used, the `ref` won't be set since `LoadingIcon` isn't wrapped in `React.forwardRef`returncreateElement(props.icon,{ref})}
What to review
Is the linter rule addition that blocks React.createElement clear enough?
Testing
If tests pass we should be good.
Notes for release
Replaced React.createElement calls in internals with the JSX runtime, unlocking the React 19 performance improvements to JSX, as well as the ability to use ref as a prop instead of React.forwardRef wrappers.
efps — editor "frames per second". The number of updates assumed to be possible within a second.
Derived from input latency. efps = 1000 / input_latency
Detailed information
🏠 Reference result
The performance result of sanity@latest
Benchmark
latency
p75
p90
p99
blocking time
test duration
article (title)
38ms
41ms
43ms
159ms
177ms
10.3s
article (body)
15ms
17ms
23ms
83ms
286ms
5.5s
article (string inside object)
37ms
39ms
46ms
73ms
127ms
6.4s
article (string inside array)
40ms
41ms
44ms
154ms
132ms
6.8s
recipe (name)
19ms
20ms
25ms
42ms
0ms
7.1s
recipe (description)
17ms
18ms
21ms
39ms
0ms
4.4s
recipe (instructions)
5ms
7ms
9ms
30ms
0ms
3.2s
synthetic (title)
53ms
54ms
57ms
86ms
208ms
12.4s
synthetic (string inside object)
53ms
56ms
67ms
200ms
550ms
8.1s
🧪 Experiment result
The performance result of this branch
Benchmark
latency
p75
p90
p99
blocking time
test duration
article (title)
39ms
42ms
46ms
233ms
245ms
11.6s
article (body)
14ms
17ms
24ms
48ms
64ms
4.7s
article (string inside object)
38ms
40ms
44ms
192ms
273ms
6.7s
article (string inside array)
40ms
42ms
47ms
163ms
148ms
6.7s
recipe (name)
20ms
22ms
24ms
32ms
0ms
7.5s
recipe (description)
17ms
19ms
20ms
35ms
0ms
4.4s
recipe (instructions)
5ms
7ms
8ms
9ms
0ms
3.0s
synthetic (title)
53ms
58ms
69ms
127ms
588ms
13.6s
synthetic (string inside object)
53ms
54ms
62ms
120ms
213ms
7.5s
📚 Glossary
column definitions
benchmark — the name of the test, e.g. "article", followed by the label of the field being measured, e.g. "(title)".
latency — the time between when a key was pressed and when it was rendered. derived from a set of samples. the median (p50) is shown to show the most common latency.
p75 — the 75th percentile of the input latency in the test run. 75% of the sampled inputs in this benchmark were processed faster than this value. this provides insight into the upper range of typical performance.
p90 — the 90th percentile of the input latency in the test run. 90% of the sampled inputs were faster than this. this metric helps identify slower interactions that occurred less frequently during the benchmark.
p99 — the 99th percentile of the input latency in the test run. only 1% of sampled inputs were slower than this. this represents the worst-case scenarios encountered during the benchmark, useful for identifying potential performance outliers.
blocking time — the total time during which the main thread was blocked, preventing user input and UI updates. this metric helps identify performance bottlenecks that may cause the interface to feel unresponsive.
test duration — how long the test run took to complete.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Before the JSX transform were introduced it didn't really matter if you called
React.createElement
directly, or if you used JSX.With
as input, you got
as output. In that world you might as well call it directly, as it's functionally equivalent:
Since then the entire ecosystem has moved to the jsx transform, that includes our vite when using
sanity dev|build|deploy
, as well as publishing libraries with@sanity/pkg-utils
, and most other build tooling like Parcel, tsup etc etc.With the new transform it's not just a new function being used, it's from a different, standalone export, and its function argument semantics are different:
On top of that, React 19 introduces new features that are only available if the
jsx-runtime
transform is used, which isn't supported withcreateElement
.For example using
ref
as a prop, instead of usingReact.forwardRef
, requires it:The React 19
<LoadingIcon />
only works if the JSX transform is used (repl):When using
createElement
it fails (repl):What to review
Is the linter rule addition that blocks
React.createElement
clear enough?Testing
If tests pass we should be good.
Notes for release
Replaced
React.createElement
calls in internals with the JSX runtime, unlocking the React 19 performance improvements to JSX, as well as the ability to useref
as a prop instead ofReact.forwardRef
wrappers.