Skip to content

[graphiql]: support react 19, drop support react 16 and react 17 #3897

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 40 commits into from
May 2, 2025
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
1b6b507
upd
dimaMachina Apr 26, 2025
84ec2f8
upd
dimaMachina Apr 26, 2025
b3cc341
upd
dimaMachina Apr 26, 2025
178e594
upd
dimaMachina Apr 26, 2025
942afb1
upd
dimaMachina Apr 26, 2025
84b9983
exclude react-dom/client from bundle
dimaMachina Apr 26, 2025
e394bb6
bump react everywhere to v19
dimaMachina Apr 26, 2025
b2eb509
bump react everywhere to v19
dimaMachina Apr 26, 2025
58d9607
polish
dimaMachina Apr 26, 2025
9b0d339
fix failing text, to unblock canary
dimaMachina Apr 26, 2025
54b0dee
Merge branch 'main' into react19
dimaMachina Apr 26, 2025
3f3dc5e
upd
dimaMachina Apr 26, 2025
c58df79
Merge branch 'main' into react19
dimaMachina Apr 26, 2025
efc7c3f
try `minor` for graphiql/react, otherwise it pines to `1.0.0-next.2` …
dimaMachina Apr 26, 2025
07a0905
try workaround
dimaMachina Apr 26, 2025
c3b73f3
try workaround
dimaMachina Apr 26, 2025
adbdb8f
try workaround
dimaMachina Apr 26, 2025
a408e42
try workaround
dimaMachina Apr 26, 2025
4b34b10
this should fix vitest
dimaMachina Apr 26, 2025
284c2fa
try
dimaMachina Apr 27, 2025
2382b03
try
dimaMachina Apr 27, 2025
5242c56
lint
dimaMachina Apr 27, 2025
46b304f
try
dimaMachina Apr 27, 2025
6325cda
fix test
dimaMachina Apr 27, 2025
efbd430
try SOURCEMAP var
dimaMachina Apr 27, 2025
c1ab45d
try ESM_SH_BUILD var
dimaMachina Apr 27, 2025
d23559f
try
dimaMachina Apr 27, 2025
1b248df
rm some unneeded code
dimaMachina Apr 27, 2025
6fc5225
try to fix esbuild: package 'uWebSockets.js' not found
dimaMachina Apr 27, 2025
1d41eb0
update vite to see if it fix esbuild error?
dimaMachina Apr 27, 2025
cb95709
bump module "@emotion/is-prop-valid" not found to fix `module "@emoti…
dimaMachina Apr 28, 2025
9e856e6
upd
dimaMachina Apr 28, 2025
9efda10
upd
dimaMachina Apr 28, 2025
0f373b9
upd
dimaMachina Apr 28, 2025
78a8246
Merge branch 'main' into react19
dimaMachina Apr 30, 2025
c587f92
fix e2e
dimaMachina Apr 30, 2025
9fe2edb
add changeset
dimaMachina May 1, 2025
55c2aa3
add migration markdown file
dimaMachina May 1, 2025
ec81b20
fix
dimaMachina May 1, 2025
168c364
Merge branch 'v4' into react19
dimaMachina May 2, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changeset/gold-cooks-design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@graphiql/plugin-code-exporter': major
'@graphiql/plugin-explorer': major
'@graphiql/react': major
'graphiql': major
---

- support react 19, drop support react 16 and react 17
- replace deprecated `ReactDOM.unmountComponentAtNode()` and `ReactDOM.render()` with `root.unmount()` and `createRoot(container).render()`
6 changes: 4 additions & 2 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@ module.exports = {
excludedFiles: ['**/*.{md,mdx}/*.{ts,tsx}'],
// extends: ['plugin:@typescript-eslint/recommended-type-checked'],
rules: {
// '@typescript-eslint/no-redundant-type-constituents': 'error',
'@typescript-eslint/prefer-optional-chain': 'error',
'@typescript-eslint/no-unnecessary-type-assertion': 'error',
'@typescript-eslint/no-floating-promises': 'error',
Expand Down Expand Up @@ -482,15 +483,15 @@ module.exports = {
},
},
{
// Rule prefer await to then without React packages because it's ugly to have `async IIFE` inside `useEffect`
// Rule to prefer await to then without React packages because it's ugly to have `async IIFE` inside `useEffect`
files: ['packages/**'],
excludedFiles: ['packages/graphiql/**', 'packages/graphiql-react/**'],
rules: {
'promise/prefer-await-to-then': 'error',
},
},
{
files: ['packages/{graphiql-react,graphiql}/**'],
files: ['packages/{graphiql-react,graphiql}/**/*.{ts,tsx}'],
rules: {
'@typescript-eslint/no-restricted-imports': [
'error',
Expand All @@ -501,6 +502,7 @@ module.exports = {
},
],
'react-hooks/react-compiler': 'error',
'@typescript-eslint/no-deprecated': 'error',
},
},
{
Expand Down
8 changes: 4 additions & 4 deletions packages/graphiql-plugin-code-exporter/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,16 @@
"peerDependencies": {
"@graphiql/react": "^0.28.0",
"graphql": "^15.5.0 || ^16.0.0 || ^17.0.0",
"react": "^16.8.0 || ^17 || ^18",
"react-dom": "^16.8.0 || ^17 || ^18"
"react": "^18 || ^19",
"react-dom": "^18 || ^19"
},
"devDependencies": {
"@graphiql/react": "^0.28.0",
"@vitejs/plugin-react": "^4.3.1",
"graphql": "^16.9.0",
"postcss-nesting": "^10.1.7",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"typescript": "^4.6.3",
"vite": "^5.4.18"
}
Expand Down
8 changes: 4 additions & 4 deletions packages/graphiql-plugin-explorer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,15 @@
"peerDependencies": {
"@graphiql/react": "^0.28.0",
"graphql": "^15.5.0 || ^16.0.0 || ^17.0.0",
"react": "^16.8.0 || ^17 || ^18",
"react-dom": "^16.8.0 || ^17 || ^18"
"react": "^18 || ^19",
"react-dom": "^18 || ^19"
},
"devDependencies": {
"@graphiql/react": "^0.28.1",
"@vitejs/plugin-react": "^4.3.1",
"graphql": "^16.9.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"typescript": "^4.6.3",
"vite": "^5.4.18",
"vite-plugin-svgr": "^4.2.0"
Expand Down
12 changes: 6 additions & 6 deletions packages/graphiql-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,13 @@
},
"peerDependencies": {
"graphql": "^15.5.0 || ^16.0.0 || ^17.0.0",
"react": "^16.8.0 || ^17 || ^18",
"react-dom": "^16.8.0 || ^17 || ^18"
"react": "^18 || ^19",
"react-dom": "^18 || ^19"
},
"dependencies": {
"react-compiler-runtime": "19.1.0-rc.1",
"@graphiql/toolkit": "^0.11.0",
"@headlessui/react": "^1.7.15",
"@headlessui/react": "^2",
"@radix-ui/react-dialog": "^1.0.4",
"@radix-ui/react-dropdown-menu": "^2.0.5",
"@radix-ui/react-tooltip": "^1.0.6",
Expand All @@ -69,7 +69,7 @@
},
"devDependencies": {
"babel-plugin-react-compiler": "19.1.0-rc.1",
"@types/react-dom": "^18.3.1",
"@types/react-dom": "^19.1.2",
"@babel/helper-string-parser": "^7.19.4",
"@testing-library/dom": "^10.4.0",
"@testing-library/react": "^16.1.0",
Expand All @@ -79,8 +79,8 @@
"@vitejs/plugin-react": "^4.3.1",
"graphql": "^16.9.0",
"postcss-nesting": "^10.1.7",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"typescript": "^4.6.3",
"vite": "^5.4.18",
"vite-plugin-svgr": "^4.2.0"
Expand Down
39 changes: 16 additions & 23 deletions packages/graphiql-react/src/editor/response-editor.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { formatError } from '@graphiql/toolkit';
import type { Position, Token } from 'codemirror';
import { ComponentType, useEffect, useRef, JSX } from 'react';
// eslint-disable-next-line react/no-deprecated -- We can't refactor to root.unmount() from React 18 because we support React 16/17 too
import { unmountComponentAtNode, render } from 'react-dom';
import { createRoot } from 'react-dom/client';
import { useSchemaContext } from '../schema';

import {
Expand Down Expand Up @@ -84,38 +83,32 @@ export function useResponseEditor(

useEffect(() => {
let isActive = true;

void importCodeMirrorImports().then(CodeMirror => {
// Don't continue if the effect has already been cleaned up
if (!isActive) {
return;
}

// Handle image tooltips and custom tooltips
const tooltipDiv = document.createElement('div');
const tooltipRoot = createRoot(document.createElement('div'));
CodeMirror.registerHelper(
'info',
'graphql-results',
(token: Token, _options: any, _cm: CodeMirrorEditor, pos: Position) => {
const infoElements: JSX.Element[] = [];

const ResponseTooltipComponent = responseTooltipRef.current;
if (ResponseTooltipComponent) {
infoElements.push(
<ResponseTooltipComponent pos={pos} token={token} />,
);
}

if (ImagePreview.shouldRender(token)) {
infoElements.push(
<ImagePreview key="image-preview" token={token} />,
);
}
if (!infoElements.length) {
unmountComponentAtNode(tooltipDiv);
return null;
const ResponseTooltip = responseTooltipRef.current;
const infoElements: JSX.Element[] = [
ResponseTooltip && <ResponseTooltip pos={pos} token={token} />,
ImagePreview.shouldRender(token) && (
<ImagePreview key="image-preview" token={token} />
),
].filter((v): v is JSX.Element => Boolean(v));

if (infoElements.length) {
tooltipRoot.render(infoElements);
} else {
tooltipRoot.unmount();
}
render(infoElements, tooltipDiv);
return tooltipDiv;
},
);

Expand Down Expand Up @@ -151,7 +144,7 @@ export function useResponseEditor(
if (fetchError) {
responseEditor?.setValue(fetchError);
}
if (validationErrors.length > 0) {
if (validationErrors.length) {
responseEditor?.setValue(formatError(validationErrors));
}
}, [responseEditor, fetchError, validationErrors]);
Expand Down
25 changes: 15 additions & 10 deletions packages/graphiql-react/src/explorer/components/search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ import {
isObjectType,
} from 'graphql';
import { FC, useEffect, useRef, useState } from 'react';
import { Combobox } from '@headlessui/react';
import {
Combobox,
ComboboxInput,
ComboboxOptions,
ComboboxOption,
} from '@headlessui/react';
import { MagnifyingGlassIcon } from '../../icons';
import { useSchemaContext } from '../../schema';
import debounce from '../../utility/debounce';
Expand Down Expand Up @@ -85,7 +90,7 @@ export const Search: FC = () => {
}}
>
<MagnifyingGlassIcon />
<Combobox.Input
<ComboboxInput
autoComplete="off"
onChange={event => setSearchValue(event.target.value)}
placeholder={`${isMacOs ? '⌘' : 'Ctrl'} K`}
Expand All @@ -95,7 +100,7 @@ export const Search: FC = () => {
/>
</div>
{isFocused && (
<Combobox.Options data-cy="doc-explorer-list">
<ComboboxOptions data-cy="doc-explorer-list">
{results.within.length +
results.types.length +
results.fields.length ===
Expand All @@ -105,13 +110,13 @@ export const Search: FC = () => {
</li>
) : (
results.within.map((result, i) => (
<Combobox.Option
<ComboboxOption
key={`within-${i}`}
value={result}
data-cy="doc-explorer-option"
>
<Field field={result.field} argument={result.argument} />
</Combobox.Option>
</ComboboxOption>
))
)}
{results.within.length > 0 &&
Expand All @@ -121,25 +126,25 @@ export const Search: FC = () => {
</div>
) : null}
{results.types.map((result, i) => (
<Combobox.Option
<ComboboxOption
key={`type-${i}`}
value={result}
data-cy="doc-explorer-option"
>
<Type type={result.type} />
</Combobox.Option>
</ComboboxOption>
))}
{results.fields.map((result, i) => (
<Combobox.Option
<ComboboxOption
key={`field-${i}`}
value={result}
data-cy="doc-explorer-option"
>
<Type type={result.type} />.
<Field field={result.field} argument={result.argument} />
</Combobox.Option>
</ComboboxOption>
))}
</Combobox.Options>
</ComboboxOptions>
)}
</Combobox>
);
Expand Down
2 changes: 1 addition & 1 deletion packages/graphiql-react/vite.config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type { PluginOptions as ReactCompilerConfig } from 'babel-plugin-react-co
import packageJSON from './package.json';

export const reactCompilerConfig: Partial<ReactCompilerConfig> = {
target: '17',
target: '18',
sources(filename) {
if (filename.includes('__tests__')) {
return false;
Expand Down
8 changes: 4 additions & 4 deletions packages/graphiql/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@
},
"peerDependencies": {
"graphql": "^15.5.0 || ^16.0.0 || ^17.0.0",
"react": "^16.8.0 || ^17 || ^18",
"react-dom": "^16.8.0 || ^17 || ^18"
"react": "^18 || ^19",
"react-dom": "^18 || ^19"
},
"devDependencies": {
"babel-plugin-react-compiler": "19.1.0-rc.1",
Expand All @@ -75,8 +75,8 @@
"graphql-subscriptions": "^2.0.0",
"postcss": "8.4.31",
"postcss-import": "15.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"start-server-and-test": "^1.10.11",
"subscriptions-transport-ws": "0.11.0",
"typescript": "^4.6.3",
Expand Down
Loading
Loading