Skip to content
Merged
Show file tree
Hide file tree
Changes from 75 commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
db08483
upd
dimaMachina Jul 12, 2025
d60f43b
upd
dimaMachina Jul 12, 2025
3e77a21
upd next.js
dimaMachina Jul 13, 2025
0dcb565
upd
dimaMachina Jul 13, 2025
c0dc5d2
upd
dimaMachina Jul 13, 2025
c844ca2
upd
dimaMachina Jul 13, 2025
5d54aaf
upd
dimaMachina Jul 13, 2025
085ede6
upd
dimaMachina Jul 13, 2025
dcfbe07
upd
dimaMachina Jul 13, 2025
952317c
upd
dimaMachina Jul 13, 2025
1b9c683
upd
dimaMachina Jul 13, 2025
30f2c9f
upd
dimaMachina Jul 13, 2025
016b11f
upd
dimaMachina Jul 13, 2025
f819731
upd
dimaMachina Jul 13, 2025
13ffc92
upd
dimaMachina Jul 13, 2025
8bfc621
upd
dimaMachina Jul 13, 2025
bd2ebed
Merge branch 'main' into react-router-graphiql
dimaMachina Jul 13, 2025
4131d6e
upd
dimaMachina Jul 13, 2025
6da5710
upd
dimaMachina Jul 13, 2025
6921f3e
upd
dimaMachina Jul 13, 2025
f9565c7
upd
dimaMachina Jul 13, 2025
cce9c61
upd
dimaMachina Jul 13, 2025
3a9b4f2
upd
dimaMachina Jul 13, 2025
a845b6e
upd
dimaMachina Jul 13, 2025
75d408b
upd
dimaMachina Jul 13, 2025
5b9b251
upd
dimaMachina Jul 13, 2025
04da1ce
make monaco nullable
dimaMachina Jul 13, 2025
61c90cc
all right
dimaMachina Jul 13, 2025
7be0599
all right
dimaMachina Jul 13, 2025
de21435
all right
dimaMachina Jul 13, 2025
49f1ef9
upd
dimaMachina Jul 13, 2025
78f8890
changeset
dimaMachina Jul 13, 2025
597c4c3
upd
dimaMachina Jul 13, 2025
8ce2575
upd yarn
dimaMachina Jul 13, 2025
c8b119d
comment
dimaMachina Jul 13, 2025
94884cf
Update packages/graphiql-react/src/utility/monaco-ssr.ts
dimaMachina Jul 13, 2025
4cc5e93
upd
dimaMachina Jul 13, 2025
14778bb
upd
dimaMachina Jul 13, 2025
f8291c4
upd
dimaMachina Jul 13, 2025
4c956f4
upd changeset
dimaMachina Jul 13, 2025
b251edf
fix build
dimaMachina Jul 13, 2025
05fed09
prettier
dimaMachina Jul 13, 2025
e892092
update README.md
dimaMachina Jul 13, 2025
cf24a84
fix typecheck
dimaMachina Jul 13, 2025
382b920
skip temp
dimaMachina Jul 13, 2025
733a7b1
try
dimaMachina Jul 13, 2025
eb1663b
remove “Module '@emotion/is-prop-valid' not found” warning emitted by…
dimaMachina Jul 13, 2025
a5bef92
upd
dimaMachina Jul 13, 2025
9a63885
upd
dimaMachina Jul 13, 2025
09419e5
upd
dimaMachina Jul 13, 2025
7d5a4c2
try this
dimaMachina Jul 13, 2025
c43a086
use lite
dimaMachina Jul 13, 2025
66496da
try
dimaMachina Jul 14, 2025
3eb9601
try `monaco-graphql/esm/monaco-editor`
dimaMachina Jul 14, 2025
74a6f93
try editor.api.js
dimaMachina Jul 14, 2025
43f58f2
try import in monaco
dimaMachina Jul 14, 2025
6dad0e1
and now
dimaMachina Jul 14, 2025
f9344d0
upd
dimaMachina Jul 14, 2025
6df4604
upd yarn
dimaMachina Jul 14, 2025
2e21fce
try
dimaMachina Jul 14, 2025
3a806e3
cleanup
dimaMachina Jul 14, 2025
6f83ee8
cleanup
dimaMachina Jul 14, 2025
025f223
rm
dimaMachina Jul 14, 2025
6c4db9f
rm editor.api.js import
dimaMachina Jul 14, 2025
94a72be
upd
dimaMachina Jul 14, 2025
6768d85
specify ext for monaco-graphql, because it fails on esm.sh
dimaMachina Jul 14, 2025
d7e1c62
try
dimaMachina Jul 14, 2025
d904653
try
dimaMachina Jul 14, 2025
0b5ee89
Merge branch 'main' into react-router-graphiql
dimaMachina Jul 14, 2025
4956732
cleanup
dimaMachina Jul 14, 2025
089bb1f
cleanup
dimaMachina Jul 14, 2025
454af65
cleanup
dimaMachina Jul 14, 2025
796a044
fix vitest
dimaMachina Jul 15, 2025
670578f
prettier
dimaMachina Jul 15, 2025
2998cb6
increase timeout
dimaMachina Jul 15, 2025
46ca064
increase more timeout
dimaMachina Jul 15, 2025
7087491
more timeout
dimaMachina Jul 15, 2025
592fc3e
increase default query timeout for 6s
dimaMachina Jul 15, 2025
8b25eb3
Update .changeset/chilled-peaches-wonder.md
dimaMachina Jul 15, 2025
0133218
for 7s
dimaMachina Jul 15, 2025
064893b
for 8s
dimaMachina Jul 15, 2025
3142b73
Update .changeset/chilled-peaches-wonder.md
dimaMachina Jul 15, 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
23 changes: 23 additions & 0 deletions .changeset/chilled-peaches-wonder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
'@graphiql/react': patch
'monaco-graphql': patch
'graphql-language-service': minor
'graphiql': minor
---

feat(graphql-language-service): export `getContextAtPosition`
feat(graphiql): dynamically import `monaco-editor` and `monaco-graphql`

When using GraphiQL in Next.js app, you no longer need to use `next/dynamic`:

```diff
-import dynamic from 'next/dynamic'
-const GraphiQL = dynamic(() => import('graphiql').then(mod => mod.GraphiQL), {
- ssr: false
-})
+import { GraphiQL } from 'graphiql'
```

When using GraphiQL with [React Router’s SSR mode](https://reactrouter.com/api/framework-conventions/react-router.config.ts#ssr),
you no longer need to mark the GraphiQL component as a [client module](https://reactrouter.com/api/framework-conventions/client-modules)
by adding `.client` to the file name.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const RESTRICTED_IMPORTS = [
name: 'monaco-editor',
message:
'`monaco-editor` imports all languages; use `monaco-graphql/esm/monaco-editor` instead to import only `json` and `graphql` languages',
allowTypeImports: true,
},
];

Expand Down
9 changes: 5 additions & 4 deletions examples/graphiql-cdn/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,11 @@
rel="stylesheet"
href="https://esm.sh/@graphiql/plugin-explorer/dist/style.css"
/>
<!-- Note: the ?standalone flag bundles the module along with all of its `dependencies`, excluding `peerDependencies`, into a single JavaScript file. -->
<!-- `@emotion/is-prop-valid` is a shim to remove the console error `module "@emotion /is-prop-valid" not found`. Upstream issue: https://github.com/motiondivision/motion/issues/3126 -->
<!--
* Note:
* The ?standalone flag bundles the module along with all of its `dependencies`, excluding `peerDependencies`, into a single JavaScript file.
* `@emotion/is-prop-valid` is a shim to remove the console error ` module "@emotion /is-prop-valid" not found`. Upstream issue: https://github.com/motiondivision/motion/issues/3126
-->
<script type="importmap">
{
"imports": {
Expand All @@ -55,10 +58,8 @@
}
</script>
<script type="module">
// Import React and ReactDOM
import React from 'react';
import ReactDOM from 'react-dom/client';
// Import GraphiQL and the Explorer plugin
import { GraphiQL, HISTORY_PLUGIN } from 'graphiql';
import { createGraphiQLFetcher } from '@graphiql/toolkit';
import { explorerPlugin } from '@graphiql/plugin-explorer';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
'use client';

import type { FC } from 'react';
import dynamic from 'next/dynamic';
import { GraphiQL } from 'graphiql';
import 'graphiql/setup-workers/webpack';
import 'graphiql/style.css';

// dynamically import our GraphiQL component
const GraphiQL = dynamic(() => import('graphiql').then(mod => mod.GraphiQL), {
ssr: false,
});

async function fetcher(graphQLParams: Record<string, unknown>) {
const response = await fetch('https://graphql.earthdata.nasa.gov/api', {
method: 'POST',
Expand All @@ -22,8 +17,6 @@ async function fetcher(graphQLParams: Record<string, unknown>) {
return response.json();
}

const Page: FC = () => {
export const GraphiQLPage: FC = () => {
return <GraphiQL fetcher={fetcher} />;
};

export default Page;
4 changes: 3 additions & 1 deletion examples/graphiql-nextjs/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import type { Metadata } from 'next';
import './globals.css';

export const metadata: Metadata = {
title: 'GraphiQL Next.js Example',
description: 'Example of using GraphiQL with the Next.js App Router',
// Empty object adds open graph and twitter meta-tags
openGraph: {},
};

const RootLayout: FC<Readonly<{ children: ReactNode }>> = ({ children }) => {
Expand Down
7 changes: 7 additions & 0 deletions examples/graphiql-nextjs/src/app/page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { Metadata } from 'next';

export { GraphiQLPage as default } from './graphiql';

export const metadata: Metadata = {
title: 'GraphiQL Next.js Example',
};
1 change: 1 addition & 0 deletions packages/graphiql-react/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ React hooks.

- **`useStorage`**: Provides a storage API that can be used to persist state in the browser (by default using `localStorage`).
- **`useTheme`**: Manages the current theme and provides a method to update it.
- **`useMonaco`**: Access `monaco-editor` exports and the `monaco-graphql` instance. Designed for safe use in SSR environments.
- **`useGraphiQL`**: Access the current state.
- **`useGraphiQLActions`**: Trigger actions that mutate the state. This hook **never** rerenders.

Expand Down
47 changes: 24 additions & 23 deletions packages/graphiql-react/src/components/operation-editor.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { getSelectedOperationName } from '@graphiql/toolkit';
import type { DocumentNode } from 'graphql';
import { getOperationFacts } from 'graphql-language-service';
import {
getOperationFacts,
getContextAtPosition,
} from 'graphql-language-service';
import { FC, useEffect, useRef } from 'react';
import { useStorage } from '../stores';
import { useMonaco, useStorage } from '../stores';
import { useGraphiQL, useGraphiQLActions } from './provider';
import {
debounce,
Expand All @@ -12,24 +15,18 @@ import {
pick,
cleanupDisposables,
cn,
Uri,
Range,
} from '../utility';
import type { MonacoEditor, EditorProps, SchemaReference } from '../types';
import {
KEY_BINDINGS,
URI_NAME,
STORAGE_KEY,
MONACO_GRAPHQL_DIAGNOSTIC_SETTINGS,
MONACO_GRAPHQL_API,
} from '../constants';
import {
type editor as monacoEditor,
languages,
Range,
Uri,
} from '../monaco-editor';
import * as monaco from '../monaco-editor';
import { getContextAtPosition } from 'graphql-language-service/esm/parser';
import { toGraphQLPosition } from 'monaco-graphql/esm/utils';
import type * as monaco from 'monaco-editor';
import { toGraphQLPosition } from 'monaco-graphql/esm/utils.js';

interface OperationEditorProps extends EditorProps {
/**
Expand Down Expand Up @@ -179,7 +176,7 @@ export const OperationEditor: FC<OperationEditorProps> = ({
: null;
}

const runAtCursorRef = useRef<monacoEditor.IActionDescriptor['run']>(null!);
const runAtCursorRef = useRef<monaco.editor.IActionDescriptor['run']>(null!);

useEffect(() => {
runAtCursorRef.current = editor => {
Expand Down Expand Up @@ -209,7 +206,12 @@ export const OperationEditor: FC<OperationEditorProps> = ({
};
}, [operationName, operations, run, setOperationName]);

const { monacoGraphQL, monaco } = useMonaco();

useEffect(() => {
if (!monaco || !monacoGraphQL) {
return;
}
const operationUri = Uri.file(`${uriInstanceId}${URI_NAME.operation}`);
const variablesUri = Uri.file(`${uriInstanceId}${URI_NAME.variables}`);
/**
Expand All @@ -218,10 +220,7 @@ export const OperationEditor: FC<OperationEditorProps> = ({
*/
const { validateVariablesJSON } = MONACO_GRAPHQL_DIAGNOSTIC_SETTINGS;
validateVariablesJSON![operationUri.toString()] = [variablesUri.toString()];
MONACO_GRAPHQL_API.setDiagnosticSettings(
MONACO_GRAPHQL_DIAGNOSTIC_SETTINGS,
);
globalThis.__MONACO = monaco;
monacoGraphQL.setDiagnosticSettings(MONACO_GRAPHQL_DIAGNOSTIC_SETTINGS);
const model = getOrCreateModel({
uri: operationUri.path.replace('/', ''),
value: initialQuery,
Expand Down Expand Up @@ -266,16 +265,16 @@ export const OperationEditor: FC<OperationEditorProps> = ({
model,
];
return cleanupDisposables(disposables);
}, []); // eslint-disable-line react-hooks/exhaustive-deps -- only on mount
}, [monaco, monacoGraphQL]); // eslint-disable-line react-hooks/exhaustive-deps -- only on mount

useEffect(() => {
if (!schema) {
if (!schema || !monaco || !monacoGraphQL) {
return;
}
MONACO_GRAPHQL_API.setSchemaConfig([
monacoGraphQL.setSchemaConfig([
{ uri: `${uriInstanceId}${URI_NAME.schema}`, schema },
]);
MONACO_GRAPHQL_API.setExternalFragmentDefinitions([
monacoGraphQL.setExternalFragmentDefinitions([
...externalFragments.values(),
]);
if (!referencePlugin) {
Expand All @@ -285,7 +284,7 @@ export const OperationEditor: FC<OperationEditorProps> = ({
let currentSchemaReference: SchemaReference | null = null;

const disposables = [
languages.registerDefinitionProvider('graphql', {
monaco.languages.registerDefinitionProvider('graphql', {
provideDefinition(model, position, _token) {
const graphQLPosition = toGraphQLPosition(position);
const context = getContextAtPosition(
Expand Down Expand Up @@ -321,7 +320,7 @@ export const OperationEditor: FC<OperationEditorProps> = ({
currentSchemaReference = null;
},
}),
languages.registerReferenceProvider('graphql', {
monaco.languages.registerReferenceProvider('graphql', {
provideReferences(model, { lineNumber, column }, _context, _token) {
if (!currentSchemaReference) {
return;
Expand All @@ -343,6 +342,8 @@ export const OperationEditor: FC<OperationEditorProps> = ({
setVisiblePlugin,
externalFragments,
uriInstanceId,
monacoGraphQL,
monaco,
]);

return (
Expand Down
19 changes: 7 additions & 12 deletions packages/graphiql-react/src/components/provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
ExecutionProps,
PluginProps,
SchemaProps,
monacoStore,
} from '../stores';
import { StorageStore, useStorage } from '../stores/storage';
import { ThemeStore } from '../stores/theme';
Expand All @@ -27,11 +28,9 @@ import {
import {
DEFAULT_PRETTIFY_QUERY,
DEFAULT_QUERY,
JSON_DIAGNOSTIC_OPTIONS,
STORAGE_KEY,
} from '../constants';
import { getDefaultTabState } from '../utility/tabs';
import { languages } from '../monaco-editor';

interface InnerGraphiQLProviderProps
extends EditorProps,
Expand Down Expand Up @@ -117,6 +116,12 @@ useEffect(() => {
}, [response])`,
);
}

useEffect(() => {
const { actions } = monacoStore.getState();
void actions.initialize();
}, []);

return (
<StorageStore storage={storage}>
<ThemeStore defaultTheme={defaultTheme} editorTheme={editorTheme}>
Expand Down Expand Up @@ -330,16 +335,6 @@ const InnerGraphiQLProvider: FC<InnerGraphiQLProviderProps> = ({
};
}, []);

useEffect(() => {
/**
* Set diagnostics options for JSON
*
* Setting it on mount fix Uncaught TypeError: Cannot read properties of undefined (reading 'jsonDefaults')
* @see https://github.com/graphql/graphiql/pull/4042#issuecomment-3017167375
*/
languages.json.jsonDefaults.setDiagnosticsOptions(JSON_DIAGNOSTIC_OPTIONS);
}, []);

return (
<GraphiQLContext.Provider value={storeRef}>
{children}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
cleanupDisposables,
cn,
} from '../utility';
import { useMonaco } from '../stores';

interface RequestHeadersEditorProps extends EditorProps {
/**
Expand All @@ -29,12 +30,16 @@ export const RequestHeadersEditor: FC<RequestHeadersEditorProps> = ({
pick('initialHeaders', 'shouldPersistHeaders', 'uriInstanceId'),
);
const ref = useRef<HTMLDivElement>(null!);
const monaco = useMonaco(state => state.monaco);
useChangeHandler(
onEdit,
shouldPersistHeaders ? STORAGE_KEY.headers : null,
'headers',
);
useEffect(() => {
if (!monaco) {
return;
}
const model = getOrCreateModel({
uri: `${uriInstanceId}${URI_NAME.requestHeaders}`,
value: initialHeaders,
Expand All @@ -49,7 +54,7 @@ export const RequestHeadersEditor: FC<RequestHeadersEditorProps> = ({
model,
];
return cleanupDisposables(disposables);
}, []); // eslint-disable-line react-hooks/exhaustive-deps -- only on mount
}, [monaco]); // eslint-disable-line react-hooks/exhaustive-deps -- only on mount

return (
<div
Expand Down
19 changes: 12 additions & 7 deletions packages/graphiql-react/src/components/response-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,22 @@ import {
pick,
cleanupDisposables,
cn,
Range,
} from '../utility';
import { KEY_BINDINGS, URI_NAME } from '../constants';
import type { EditorProps } from '../types';
import type { editor as monacoEditor, Position } from '../monaco-editor';
import { Range, languages } from '../monaco-editor';
import type * as monaco from 'monaco-editor';
import { useMonaco } from '../stores';

type ResponseTooltipType = ComponentType<{
/**
* A position in the editor.
*/
position: Position;
position: monaco.Position;
/**
* Word that has been hovered over.
*/
word: monacoEditor.IWordAtPosition;
word: monaco.editor.IWordAtPosition;
}>;

interface ResponseEditorProps extends EditorProps {
Expand All @@ -44,6 +45,7 @@ export const ResponseEditor: FC<ResponseEditorProps> = ({
pick('fetchError', 'validationErrors', 'responseEditor', 'uriInstanceId'),
);
const ref = useRef<HTMLDivElement>(null!);
const monaco = useMonaco(state => state.monaco);
useEffect(() => {
if (fetchError) {
responseEditor?.setValue(fetchError);
Expand All @@ -54,6 +56,9 @@ export const ResponseEditor: FC<ResponseEditorProps> = ({
}, [responseEditor, fetchError, validationErrors]);

useEffect(() => {
if (!monaco) {
return;
}
const model = getOrCreateModel({
uri: `${uriInstanceId}${URI_NAME.response}`,
value: '',
Expand All @@ -70,7 +75,7 @@ export const ResponseEditor: FC<ResponseEditorProps> = ({
let lastRoot: Root | undefined;
let timerId: ReturnType<typeof setTimeout> | undefined;

const provideHover: languages.HoverProvider['provideHover'] = (
const provideHover: monaco.languages.HoverProvider['provideHover'] = (
$model,
position,
) => {
Expand Down Expand Up @@ -129,13 +134,13 @@ export const ResponseEditor: FC<ResponseEditorProps> = ({
};
const languageId = model.getLanguageId();
const disposables = [
languages.registerHoverProvider(languageId, { provideHover }),
monaco.languages.registerHoverProvider(languageId, { provideHover }),
editor.addAction({ ...KEY_BINDINGS.runQuery, run }),
editor,
model,
];
return cleanupDisposables(disposables);
}, []); // eslint-disable-line react-hooks/exhaustive-deps -- only on mount
}, [monaco]); // eslint-disable-line react-hooks/exhaustive-deps -- only on mount

return (
<section
Expand Down
Loading
Loading