1- import React , { FC , useEffect , useState , useRef , useCallback , useMemo } from 'react' ;
2- import * as monaco from "monaco-editor" ;
3- import Editor , { loader } from "@monaco-editor/react" ;
4- loader . config ( { monaco } ) ;
5- import { configureMonacoYaml } from 'monaco-yaml'
6- import yamlWorker from "./yaml.worker.js?worker" ;
1+ import React , { FC , useEffect , useState , useRef , useCallback , useMemo , Suspense } from 'react' ;
2+ import { Box , Spinner } from '@chakra-ui/react' ;
73
8- // @ts -ignore
9- window . MonacoEnvironment = {
10- getWorker ( moduleId : any , label : string ) {
11- switch ( label ) {
12- case 'yaml' :
13- return new yamlWorker ( ) ;
14- default :
15- throw new Error ( `Unknown label ${ label } ` ) ;
16- }
17- } ,
4+ // Lazy load Monaco Editor and related modules
5+ const LazyEditor = React . lazy ( ( ) => import ( "@monaco-editor/react" ) ) ;
6+
7+ // Dynamic imports for Monaco setup
8+ const loadMonaco = async ( ) => {
9+ const [ monaco , { configureMonacoYaml } , yamlWorker ] = await Promise . all ( [
10+ import ( "monaco-editor" ) ,
11+ import ( 'monaco-yaml' ) ,
12+ import ( "./yaml.worker.js?worker" )
13+ ] ) ;
14+ return { monaco, configureMonacoYaml, yamlWorker } ;
1815} ;
1916
2017// Global configuration to prevent multiple setups
2118let yamlConfigured = false ;
2219let stylesInjected = false ;
20+ let monacoLoaded = false ;
2321
24- const configureYamlOnce = ( schemaUri ?: string ) => {
22+ const configureYamlOnce = async ( schemaUri ?: string ) => {
2523 if ( yamlConfigured ) return ;
2624
25+ const { monaco, configureMonacoYaml, yamlWorker } = await loadMonaco ( ) ;
26+
27+ // Configure Monaco environment
28+ if ( ! monacoLoaded ) {
29+ // @ts -ignore
30+ window . MonacoEnvironment = {
31+ getWorker ( moduleId : any , label : string ) {
32+ switch ( label ) {
33+ case 'yaml' :
34+ return new yamlWorker . default ( ) ;
35+ default :
36+ throw new Error ( `Unknown label ${ label } ` ) ;
37+ }
38+ } ,
39+ } ;
40+ monacoLoaded = true ;
41+ }
42+
2743 const schemas = schemaUri ? [ {
2844 uri : schemaUri ,
2945 fileMatch : [ '*' ] ,
@@ -93,7 +109,7 @@ export const CodeEditor: FC<CodeEditorProps> = (props) => {
93109 debouncedOnChange ( value ) ;
94110 } , [ debouncedOnChange ] ) ;
95111
96- const onValidate = useCallback ( ( markers : any [ ] ) => {
112+ const onValidate = useCallback ( async ( markers : any [ ] ) => {
97113 const yamlMarkerErrors = markers . map ( ( marker : any ) => marker . message ) ;
98114 setYamlErrors ( yamlMarkerErrors ) ;
99115 onValidation ( markers . length > 0 ) ;
@@ -110,6 +126,8 @@ export const CodeEditor: FC<CodeEditorProps> = (props) => {
110126 const model = editorRef . current . getModel ( ) ;
111127 if ( ! model ) return ;
112128
129+ const { monaco } = await loadMonaco ( ) ;
130+
113131 const decorations = markers . map ( ( marker : any ) => {
114132 const lineLength = model . getLineLength ( marker . startLineNumber ) || 1 ;
115133
@@ -139,10 +157,11 @@ export const CodeEditor: FC<CodeEditorProps> = (props) => {
139157 }
140158 } , [ onValidation ] ) ;
141159
142- const handleEditorDidMount = useCallback ( ( editor : monaco . editor . IStandaloneCodeEditor ) => {
160+ const handleEditorDidMount = useCallback ( async ( editor : any ) => {
143161 editorRef . current = editor ;
144162 injectErrorStyles ( ) ;
145- } , [ ] ) ;
163+ await configureYamlOnce ( schemaUri ) ;
164+ } , [ schemaUri ] ) ;
146165
147166 // Configure YAML once when component mounts
148167 useEffect ( ( ) => {
@@ -162,38 +181,50 @@ export const CodeEditor: FC<CodeEditorProps> = (props) => {
162181
163182 return (
164183 < div style = { { border : "1px solid #ccc" } } className = { className } >
165- < Editor
166- options = { {
167- readOnly : disabled ,
168- lineDecorationsWidth : 5 ,
169- lineNumbersMinChars : 0 ,
170- glyphMargin : false ,
171- folding : false ,
172- lineNumbers : 'off' ,
173- minimap : {
174- enabled : false
175- } ,
176- fontSize : 11 ,
177- // Performance optimizations
178- wordWrap : 'off' ,
179- scrollBeyondLastLine : false ,
180- renderLineHighlight : 'none' ,
181- occurrencesHighlight : 'off' ,
182- renderControlCharacters : false ,
183- renderWhitespace : 'none' ,
184- automaticLayout : true ,
185- // Reduce some visual overhead
186- hideCursorInOverviewRuler : true ,
187- overviewRulerBorder : false ,
188- } }
189- width = { width }
190- height = { height }
191- language = { language }
192- value = { value }
193- onValidate = { onValidate }
194- onChange = { handleOnChange }
195- onMount = { handleEditorDidMount }
196- />
184+ < Suspense fallback = {
185+ < Box
186+ display = "flex"
187+ alignItems = "center"
188+ justifyContent = "center"
189+ width = { width }
190+ height = { height }
191+ >
192+ < Spinner size = "md" />
193+ </ Box >
194+ } >
195+ < LazyEditor
196+ options = { {
197+ readOnly : disabled ,
198+ lineDecorationsWidth : 5 ,
199+ lineNumbersMinChars : 0 ,
200+ glyphMargin : false ,
201+ folding : false ,
202+ lineNumbers : 'off' ,
203+ minimap : {
204+ enabled : false
205+ } ,
206+ fontSize : 11 ,
207+ // Performance optimizations
208+ wordWrap : 'off' ,
209+ scrollBeyondLastLine : false ,
210+ renderLineHighlight : 'none' ,
211+ occurrencesHighlight : 'off' ,
212+ renderControlCharacters : false ,
213+ renderWhitespace : 'none' ,
214+ automaticLayout : true ,
215+ // Reduce some visual overhead
216+ hideCursorInOverviewRuler : true ,
217+ overviewRulerBorder : false ,
218+ } }
219+ width = { width }
220+ height = { height }
221+ language = { language }
222+ value = { value }
223+ onValidate = { onValidate }
224+ onChange = { handleOnChange }
225+ onMount = { handleEditorDidMount }
226+ />
227+ </ Suspense >
197228 </ div >
198229 ) ;
199230} ;
0 commit comments