Replace GraphiQL+Monaco with a cm6-graphql editor (prototype)#11616
Merged
Conversation
…ype) GraphiQL uses @graphiql/react 0.37.4 which has static imports of monaco-editor utilities, causing ~2.4MB of Monaco to be eagerly downloaded on every page load due to Rolldown's chunk optimization. This replaces the GraphiQL component in the CMS GraphQL query admin with a lightweight CodeMirror-based editor: - cm6-graphql provides GraphQL syntax highlighting, schema-aware autocompletion, and inline validation - Schema is fetched once via introspection on first render - Query execution is handled with a simple fetch - All peer deps (CodeMirror 6, graphql-language-service) were already present in the bundle Result: Monaco is completely absent from the production build. GraphQLQueryEditor loads lazily at 84KB only when navigating to the CMS GraphQL query admin pages. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…idth Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…raphiql/toolkit graphiql and @graphiql/toolkit are no longer used anywhere. DevModeGraphiql now uses the same CodeMirror-based editor as the CMS admin, with useLayoutEffect to ensure tokens are set before the introspection fetch fires. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The graphiql layout was hardcoding /packs/dev-mode-graphiql.js (the production output path). In dev mode, Vite serves entries at their source path, so the JS was 404ing. Added dev_mode_graphiql_entry_path helper matching the application_entry_path pattern. Also removed the stylesheet_link_tag for dev-mode-graphiql.css — there are no CSS imports left in DevModeGraphiql.tsx — and deleted the now- orphaned dev-mode-graphiql.scss file. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Without this, @vitejs/plugin-react-swc throws "can't detect preamble" when component files (like GraphQLQueryEditor.tsx) attempt to use React Refresh hooks. Mirrors what cdn_spa_shell.html.erb already does. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Silent render errors leave a blank screen. ErrorBoundary will display the error message and stack trace instead so we can see what's wrong. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Blank screen was a Vite module cache issue after rapid changes — hard reload resolves it. ErrorBoundary stays since it makes render errors visible rather than silently blanking. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Without this, the /graphiql dev page has no Bootstrap or app styles. Vite injects CSS imports as <style> tags in dev mode. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
| if (this.state.error) { | ||
| return ( | ||
| <div style={{ padding: '1rem', fontFamily: 'monospace', whiteSpace: 'pre-wrap', color: 'red' }}> | ||
| <strong>Error rendering GraphQL editor:</strong> |
Contributor
There was a problem hiding this comment.
disallow literal string: Error rendering GraphQL editor:
CodeMirror 6 defaults to content height. Adding EditorView.theme with height: 100% and overflow: auto on the scroller makes them fill whatever container they're placed in. Variables editor keeps its line-count height. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- "Query" label above the query editor - aria-labelledby on both editors' content areas via EditorView.contentAttributes - Run query button moved to a centered strip between the two panels Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
flex-grow: 1 shares remaining space but not from a common baseline. flex: 1 1 0 sets flex-basis to 0 so both columns grow from nothing and end up exactly equal regardless of content. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds cms.graphqlQueries.editor.* keys to en.json and uses useTranslation to render them, removing all i18next/no-literal-string suppressions. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Visits the convention root page, waits for the React app to mount, then samples PerformanceResourceTiming to sum the compressed transfer sizes of all eagerly-loaded JS and CSS. Fails if the total exceeds 700 KB. Without a large dependency like Monaco in the initial bundle the payload sits well under 500 KB compressed; with Monaco it exceeds 900 KB. The threshold is set between those two states with headroom on each side. The minitest-system CI job already runs yarn build before test:system, so the test measures real production-minified assets. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Contributor
Code Coverage Report: Only Changed Files listed
Minimum allowed coverage is |
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Purpose
GraphiQL's dependency on
@graphiql/react0.37+ pulls inmonaco-editoras a static import, and Rolldown's chunk optimizer co-locates Monaco with the modulepreload polyfill in an eagerly-loaded shared chunk. The result is ~2.4 MB of Monaco downloaded on every page load — for a feature only CMS admins use.This replaces the GraphiQL component in the CMS GraphQL query admin with a lightweight CodeMirror-based editor. The CMS admin still gets:
What's gone: the schema docs explorer. We decided that was an acceptable tradeoff given how rarely CMS admins need it for this specific use case.
Changes
💻 Engineer-facing
GraphQLQueryEditor.tsx— three CodeMirror instances (query, variables, response) plus fetch-based execution; all peer deps were already in the bundlecm6-graphql,@codemirror/autocomplete, and@codemirror/lintadded (~242 KB new code, all lazily loaded)graphiqland@graphiql/toolkitno longer imported anywhere in the CMS admin (both packages still present inpackage.jsonforDevModeGraphiql.tsx)Risks
This is a prototype. The GraphiQL replacement covers the happy path but hasn't been tested under edge cases (network errors during query execution, malformed variables JSON, etc.). Worth a closer look before merging to main.
🚢
🤖 Generated with Claude Code