如何在Monaco Editor中注册带独立extraLibs的自定义TypeScript语言?
在Monaco Editor中注册独立配置的TypeScript衍生语言实例
要实现多个隔离的TypeScript编辑器实例,核心是为每个实例注册独立的自定义语言,复用原生TS的全部能力,同时配置专属的语言服务宿主来隔离extraLibs等参数。
实现思路
- 复用原生TS基础配置:复制默认TypeScript的语法高亮、分词规则、语言服务逻辑,确保衍生语言和原生TS行为完全一致。
- 注册自定义语言ID:为每个隔离实例创建唯一的语言ID(如
typescriptA),避免全局配置冲突。 - 独立语言服务宿主:为每个自定义语言实现专属的语言服务宿主,提供独立的
extraLibs、文件系统模拟,实现配置隔离。
完整代码示例
// 复制并创建自定义TypeScript语言的核心函数 const createCustomTSLanguage = (languageId) => { const defaultTS = monaco.languages.typescript; // 1. 复用原生TS的语法高亮和语言配置 monaco.languages.setMonarchTokensProvider(languageId, defaultTS.typescriptMonarchLanguage); monaco.languages.setLanguageConfiguration(languageId, defaultTS.typescriptLanguageConfiguration); // 2. 创建独立的语言服务宿主,用于隔离extraLibs const createIsolatedHost = (extraLibs = {}) => ({ getCompilationSettings: () => ({ target: monaco.languages.typescript.ScriptTarget.ESNext, module: monaco.languages.typescript.ModuleKind.CommonJS, allowJs: false, }), getScriptFileNames: () => [`${languageId}.ts`, ...Object.keys(extraLibs)], getScriptVersion: () => '1', getScriptSnapshot: (filename) => { if (filename === `${languageId}.ts`) return null; // 编辑器内容由model提供 return monaco.languages.typescript.ScriptSnapshot.fromString(extraLibs[filename]); }, getCurrentDirectory: () => '/', getDefaultLibFileName: (options) => defaultTS.getDefaultLibFilePath(options), fileExists: (filename) => filename === `${languageId}.ts` || !!extraLibs[filename], readFile: (filename) => { const snap = this.getScriptSnapshot(filename); return snap ? snap.getText(0, snap.getLength()) : ''; }, readDirectory: () => [], }); // 3. 注册自定义语言及独立的语言服务 monaco.languages.register({ id: languageId }); monaco.languages.registerLanguageService({ id: languageId, getLanguageService: (context) => { return defaultTS.createLanguageService({ ...context, host: createIsolatedHost(context.configuration.extraLibs), }); }, getLanguageServiceDefaults: () => { const defaults = new monaco.languages.typescript.LanguageServiceDefaultsImpl( languageId, defaultTS.getDefaultCompilerOptions(), defaultTS.getDiagnosticsOptions() ); // 扩展方法用于设置专属extraLibs defaults.setExtraLibs = (extraLibs) => { defaults.setCompilerOptions({ ...defaults.getCompilerOptions(), extraLibs }); }; return defaults; }, }); }; // 注册两个隔离的TS衍生语言 createCustomTSLanguage('typescriptA'); createCustomTSLanguage('typescriptB'); // 实例化编辑器A,配置专属类型定义 const editorA = monaco.editor.create(document.getElementById('editorA'), { value: `const user: UserA = { id: 1, name: 'Alice', role: 'admin' };`, language: 'typescriptA', }); monaco.languages.typescript.typescriptADefaults.setExtraLibs({ '/customTypesA.d.ts': ` interface UserA { id: number; name: string; role: 'admin' | 'user'; } ` }); // 实例化编辑器B,配置另一份专属类型定义 const editorB = monaco.editor.create(document.getElementById('editorB'), { value: `const user: UserB = { uuid: '123', fullName: 'Bob', permissions: ['read', 'write'] };`, language: 'typescriptB', }); monaco.languages.typescript.typescriptBDefaults.setExtraLibs({ '/customTypesB.d.ts': ` interface UserB { uuid: string; fullName: string; permissions: string[]; } ` });
关键说明
- 完全复刻TS行为:通过复用原生TS的
typescriptMonarchLanguage和语言服务实现,确保语法高亮、智能提示、诊断功能和原生编辑器完全一致。 - 配置隔离:每个自定义语言拥有独立的
LanguageServiceDefaultsImpl实例,通过专属的语言服务宿主加载各自的extraLibs,不会和其他实例共享配置。 - 扩展性:可以在
createIsolatedHost中扩展更多自定义配置(如编译选项、诊断规则),实现更精细的实例隔离。
内容的提问来源于stack exchange,提问作者PeiSong
相关产品推荐
相关产品推荐

