You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何封装自定义语言的Monaco Editor为React组件?解决require未定义问题

解决Monaco Editor自定义语言引入时的"require is not defined"问题

问题背景

要把带自定义语言mylang(JS文件)的Monaco Editor封装成React组件,前端基于HTML开发且兼容React。目前组件能正常运行,但引入自定义语言定义文件后出现"require is not defined"错误,删掉require又没法识别编辑器。

问题原因

  1. 加载顺序错误:原代码里mylang.js在Monaco的loader.js之前引入,此时require函数还没被loader.js定义,直接调用就会报错。
  2. 自定义语言的加载时机不对:mylang.js外层用了require(['vs/editor/editor.main'], ...)包裹,但它本身的加载时机早于Monaco的初始化,导致内部逻辑无法正常执行。

解决方案

  1. 移除HTML中直接引入mylang.js的代码,改用Monaco的require机制在Monaco主文件加载完成后动态加载自定义语言。
  2. 修改mylang.js的结构,去掉外层的require包裹,直接执行语言注册逻辑——因为此时Monaco已经初始化完成,全局monaco变量可用。
  3. 改用React的ref获取编辑器容器节点,替代getElementById,更符合React组件规范。
  4. 把编辑器初始化逻辑放到componentDidMount生命周期中,确保DOM节点已挂载完成。

修改后的代码示例

HTML代码

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>React Monaco Editor Example</title>
    <script src="https://unpkg.com/react@17.0.2/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/monaco-editor@0.25.2/min/vs/loader.js"></script>
  </head>
  <body>
    <div id="root"></div>
    <script>
      // 配置Monaco模块路径
      require.config({ paths: { vs: "https://unpkg.com/monaco-editor@0.25.2/min/vs" } });

      class MonacoEditor extends React.Component {
        constructor(props) {
          super(props);
          this.state = {
            editorValue: "",
          };
          // 创建ref用于获取编辑器容器DOM节点
          this.editorContainerRef = React.createRef();
        }

        componentDidMount() {
          // 先加载Monaco主编辑器文件
          require(["vs/editor/editor.main"], () => {
            // 加载自定义语言定义文件
            require(["./mylang.js"], () => {
              // 初始化编辑器
              const editor = monaco.editor.create(this.editorContainerRef.current, {
                value: "",
                language: "mylang",
                lineNumbers: false
              });

              // 监听编辑器内容变化,同步到组件状态
              editor.onDidChangeModelContent(() => {
                this.setState({ editorValue: editor.getValue() });
              });
            });
          });
        }

        render() {
          return React.createElement(
            'div',
            null,
            React.createElement('div', { ref: this.editorContainerRef, style: { height: '400px', width: '800px' } }),
            React.createElement('pre', null, this.state.editorValue)
          );
        }
      }

      // 渲染React组件到根节点
      ReactDOM.render(React.createElement(MonacoEditor, null), document.getElementById("root"));    
    </script>
  </body>
</html>

自定义语言文件mylang.js

// 直接注册自定义语言,此时monaco全局变量已存在
monaco.languages.register({ id: 'mylang' });

// 定义语言关键字
const mylangKeywords = [
  'continue', 'for', 'and', 'or'
  // 补充你的其他关键字
];

// 设置语法高亮规则(基于Monarch)
monaco.languages.setMonarchTokensProvider('mylang', {
  keywords: mylangKeywords,
  tokenizer: {
    root: [
      [/[a-zA-Z_$][\w$]*/, {
        cases: {
          '@keywords': 'keyword',
          '@default': 'identifier'
        }
      }],
      // 补充其他语法规则
    ]
  }
});

// 注册代码补全提供者(可选)
monaco.languages.registerCompletionItemProvider('mylang', {
  provideCompletionItems: () => {
    return {
      suggestions: mylangKeywords.map(keyword => ({
        label: keyword,
        kind: monaco.languages.CompletionItemKind.Keyword,
        insertText: keyword
      }))
    };
  }
});

关键说明

  • 通过Monaco的require链加载,确保mylang.js在Monaco完全初始化后才执行,避免require未定义或monaco全局变量不存在的问题。
  • 使用React的ref替代DOM查找,避免组件渲染时容器节点还未挂载的情况。
  • 把编辑器初始化放到componentDidMount中,保证DOM节点已准备好,能正常创建编辑器实例。

内容的提问来源于stack exchange,提问作者DavidNeedsHelp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 09:37:06