A high-performance GraphQL compilation tool built in Rust for building Relay applications with optimized queries and type generation.
—
The Relay Compiler includes a full Language Server Protocol (LSP) implementation that provides IDE integration with real-time GraphQL validation, auto-completion, hover information, and go-to-definition functionality.
{ .api }
relay-compiler lsp [OPTIONS]{ .api }
--config <PATH> # Config file path
--output <KIND> # Verbosity level (default: quiet-with-errors)
--locate-command <SCRIPT> # Script for GraphQL entity location lookup{ .api }
type OutputKind = "debug" | "quiet" | "quiet-with-errors" | "verbose";# Start with default configuration discovery
relay-compiler lsp
# Start with specific configuration
relay-compiler lsp --config ./relay.config.json
# Start with debug output for troubleshooting
relay-compiler lsp --output debug
# Start with custom entity location script
relay-compiler lsp --locate-command "./scripts/find-graphql-definition.sh"The Relay LSP integrates with the official Relay extension for VS Code. The binary resolution logic is shared between the CLI and the extension.
Installation:
relay-compiler is installed in your projectrelay.config.jsonAny editor that supports LSP can integrate with the Relay language server:
nvim-lspconfig or vim-lsplsp-mode or eglotLSP packageThe language server provides immediate feedback on GraphQL syntax and semantic errors:
{ .api }
interface ValidationFeatures {
syntaxErrors: boolean; // GraphQL syntax validation
schemaValidation: boolean; // Schema conformance checking
relaySpecificRules: boolean; // Relay-specific validation rules
fragmentValidation: boolean; // Fragment usage validation
}Context-aware completions for:
Rich hover tooltips showing:
Navigate from usage to definition for:
Real-time error and warning reporting:
{ .api }
interface DiagnosticTypes {
errors: string[]; // Compilation errors
warnings: string[]; // Potential issues
deprecations: string[]; // Deprecated field usage
suggestions: string[]; // Code improvement suggestions
}For implementation-first GraphQL schemas, you can provide a custom script to locate GraphQL entity definitions.
{ .api }
--locate-command <SCRIPT>The locate command script receives entity information and should return location details:
# Script input (stdin):
# JSON object with entity information
{
"type": "field" | "type" | "directive",
"name": "string",
"parent": "string",
"schema": "path/to/schema"
}
# Script output (stdout):
# JSON object with location information
{
"file": "path/to/file",
"line": 42,
"column": 15
}#!/bin/bash
# find-graphql-definition.sh
input=$(cat)
entity_type=$(echo "$input" | jq -r '.type')
entity_name=$(echo "$input" | jq -r '.name')
case "$entity_type" in
"field")
# Search for field definition in resolvers
location=$(grep -n "resolve.*$entity_name" src/resolvers/*.js | head -1)
;;
"type")
# Search for type definition
location=$(grep -n "type $entity_name" src/schema/*.js | head -1)
;;
esac
if [[ -n "$location" ]]; then
file=$(echo "$location" | cut -d':' -f1)
line=$(echo "$location" | cut -d':' -f2)
echo "{\"file\": \"$file\", \"line\": $line, \"column\": 1}"
fiThe language server uses the same configuration as the CLI compiler. All configuration options apply to LSP functionality.
{
"language": "typescript",
"src": "./src",
"schema": "./schema.graphql",
"schemaExtensions": ["./src/schema-extensions"],
"featureFlags": {
"enable_fragment_argument_transform": "enabled"
}
}The LSP automatically detects which project context applies based on the file being edited:
{
"sources": {
"./apps/web/src": "web",
"./apps/mobile/src": "mobile"
},
"projects": {
"web": {
"language": "typescript",
"schema": "./apps/web/schema.graphql"
},
"mobile": {
"language": "typescript",
"schema": "./apps/mobile/schema.graphql"
}
}
}The LSP can load and display schema documentation from various sources:
{ .api }
interface SchemaDocumentationLoader {
loadFieldDocumentation(typeName: string, fieldName: string): Promise<string>;
loadTypeDocumentation(typeName: string): Promise<string>;
loadDirectiveDocumentation(directiveName: string): Promise<string>;
}Extend LSP functionality with custom data providers:
{ .api }
interface LSPExtraDataProvider {
getFieldDefinitionSourceInfo(
typeName: string,
fieldName: string
): Promise<FieldDefinitionSourceInfo>;
getFieldSchemaInfo(
typeName: string,
fieldName: string
): Promise<FieldSchemaInfo>;
}
interface FieldDefinitionSourceInfo {
filePath: string;
line: number;
column: number;
}
interface FieldSchemaInfo {
description?: string;
deprecationReason?: string;
defaultValue?: any;
}use relay_lsp::{LSPExtraDataProvider, FieldDefinitionSourceInfo, FieldSchemaInfo};
pub struct CustomDataProvider {
schema_registry: SchemaRegistry,
}
impl LSPExtraDataProvider for CustomDataProvider {
async fn get_field_definition_source_info(
&self,
type_name: &str,
field_name: &str,
) -> Option<FieldDefinitionSourceInfo> {
// Custom logic to locate field definitions
self.schema_registry.find_field_source(type_name, field_name)
}
async fn get_field_schema_info(
&self,
type_name: &str,
field_name: &str,
) -> Option<FieldSchemaInfo> {
// Custom logic to provide field information
self.schema_registry.get_field_info(type_name, field_name)
}
}The LSP provides comprehensive error handling and reporting:
{ .api }
interface LSPErrors {
ConfigurationError: string; // Invalid configuration
SchemaLoadError: string; // Schema loading failures
ValidationError: string; // GraphQL validation failures
FileSystemError: string; // File access issues
LocateCommandError: string; // Custom locate script failures
}The LSP is optimized for large codebases:
{ .api }
FORCE_NO_WATCHMAN=1 # Disable Watchman, use filesystem pollingWhen Watchman is available, the LSP uses it for efficient file watching. Otherwise, it falls back to filesystem polling.
relay-compiler lsp --output debugDebug mode provides detailed logging for:
The LSP writes logs to stderr, making it compatible with most LSP clients that capture and display server logs.
Install with Tessl CLI
npx tessl i tessl/npm-relay-compiler