Description
I'm integrating a C language LSP service into my Next.js project using @monaco-editor/react
and monaco-languageclient
. Everything works fine in bun run dev
development mode, with no SSR errors and the LSP service functioning correctly.
However, when I build and run the project in production using bun run build
and bun run start
, I encounter the error: Error: Missing service editorService
in the browser console. This prevents the LSP service from working.
Reproduction Steps:
- Clone my GitHub repository: https://github.com/cfngc4594/monaco-editor-lsp-next
- Navigate to the
docker
directory:cd docker
- Run
docker compose up -d
to start the LSP container. This will build and run theclangd
language server. - Navigate back to the project root directory:
cd ..
- Run
bun install
to install dependencies. - Run
bun run build
to build the project. - Run
bun run start
to start the production server. - Open the project in a browser and check the console for the error.
Expected Behavior:
- The LSP service should function correctly in production mode, just like in development mode, without the
Error: Missing service editorService
error.
Actual Behavior:
- The console displays the
Error: Missing service editorService
error, and the LSP service does not work.
Environment Information:
Versions of monaco-editor
and monaco-languageclient
were chosen after multiple attempts to find a stable and working configuration
Versions of vscode-languageclient
and vscode-ws-jsonrpc
are latest, but they work well in development stage
monaco-editor
version: 0.36.1monaco-languageclient
version: 5.0.1vscode-languageclient
version: ^9.0.1vscode-ws-jsonrpc
version: ^3.4.0
Code Snippet:
// src/app/page.tsx
"use client";
import {
toSocket,
WebSocketMessageReader,
WebSocketMessageWriter,
} from "vscode-ws-jsonrpc";
import { useEffect } from "react";
import dynamic from "next/dynamic";
import normalizeUrl from "normalize-url";
import { Skeleton } from "@/components/ui/skeleton";
const DynamicEditor = dynamic(
async () => {
const monaco = await import("monaco-editor");
const { loader, Editor } = await import("@monaco-editor/react");
loader.config({ monaco });
return Editor;
},
{ ssr: false }
);
export default function Home() {
useEffect(() => {
const url = normalizeUrl("ws://localhost:4594/clangd");
const webSocket = new WebSocket(url);
webSocket.onopen = async () => {
const socket = toSocket(webSocket);
const reader = new WebSocketMessageReader(socket);
const writer = new WebSocketMessageWriter(socket);
const { MonacoLanguageClient } = await import("monaco-languageclient");
const { ErrorAction, CloseAction } = await import(
"vscode-languageclient"
);
const languageClient = new MonacoLanguageClient({
name: "C Language Client",
clientOptions: {
documentSelector: ["c"],
errorHandler: {
error: () => ({ action: ErrorAction.Continue }),
closed: () => ({ action: CloseAction.DoNotRestart }),
},
},
connectionProvider: {
get: () => Promise.resolve({ reader, writer }),
},
});
languageClient.start();
reader.onClose(() => languageClient.stop());
};
webSocket.onerror = (event) => {
console.error("WebSocket error observed:", event);
};
webSocket.onclose = (event) => {
console.log("WebSocket closed:", event);
};
return () => {
webSocket.close();
};
}, []);
return (
<div className="h-screen flex flex-col">
<DynamicEditor
theme="vs-dark"
defaultLanguage="c"
defaultValue="# include<stdio.h>"
path="file:///main.c"
onValidate={(markers) => {
markers.forEach((marker) =>
console.log("onValidate:", marker.message)
);
}}
options={{ automaticLayout: true }}
loading={<Skeleton className="h-full w-full p-4" />}
/>
</div>
);
}
Additional Context:
"I understand that many developers wish to use Monaco Editor with LSP functionality in Next.js. @monaco-editor/react
has already optimized for SSR, making it a popular choice for Next.js users. However, the SSR issues introduced by integrating LSP often lead to developers abandoning the integration.
Currently, I have not found any successful examples of integrating LSP with @monaco-editor/react
in Next.js across the entire web. We are now only one step away from success. I plan to develop an open-source online judge for my school (as the school's original online judge is as basic as a notepad, lacking syntax highlighting and other essential features). I've also noticed that most open-source OJs do not prioritize student programming experience and LSP integration. LeetCode seems to offer LSP functionality, but it requires a premium membership. Therefore, I intend to create an open-source code editor OJ with LSP integration. I believe this will be incredibly helpful for college students who are new to programming, especially during exams.
I already have a repository that integrates an LSP code editor using React, which also utilizes @monaco-editor/react
. You can find it here: https://github.com/cfngc4594/monaco-editor-lsp-react. I hope this can be beneficial to others."