khusamov / ide

Экспериментальная микро среда разработки (IDE) на ReactJS, Monaco Editor и RollupJS
0 stars 0 forks source link

Разобрать статью про Монако #18

Open khusamov opened 2 years ago

khusamov commented 2 years ago

https://habr.com/ru/company/raiffeisenbank/blog/568102/

Отличительная черта Monaco в том, что он запускает TypeScript-анализатор вместе с собой и обеспечивает не только подсветку синтаксиса, но и работающий из коробки IntelliSense с возможностью передать ему дополнительные файлы типов (*.d.ts).

Сначала определим глобальную конфигурацию редактора:

monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({
  noSemanticValidation: true,
    noSyntaxValidation: false
});

monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
  jsx: monaco.languages.typescript.JsxEmit.React,
  allowNonTsExtensions: true,
  moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,
  module: monaco.languages.typescript.ModuleKind.CommonJS,
  noEmit: true,
  esModuleInterop: true,
});

По сути — это обычная конфигурация из tsconfig.json. При этом поля typeRoots или outDir, связанные с конфигурацией файловой системы, никакого эффекта не окажут, так как файловой системы в браузере нет. Это упущение можно исправить, и кратко я расскажу об этом в конце.

Напишем загрузчик дополнительных типов для подсветки синтаксиса:

loaStaticdDTS = async (libName: string) => {
  const response = await fetch(`/${libName}.d.ts`)
  const dts = await response.text();
  monaco.editor.createModel(dts, 'typescript', monaco.Uri.parse(`file:///node_modules/@types/${libName}/index.d.ts`));
    monaco.languages.typescript.typescriptDefaults.addExtraLib(dts, `file:///node_modules/@types/${libName}/index.d.ts`);
}

На самом деле можно использовать только 5-ю строку кода, если мы просто хотим, чтобы заработали подсветка синтаксиса и импорт. Однако мы хотим также просматривать содержимое файла d.ts, поэтому надо добавить и 4-ю строчку. В качестве пути до файла нам нужно передать file:///node_modules/@types/${libName}/index.d.ts — это позволит запустить короткий импорт по названию библиотеки. Без этого движок редактора безуспешно попытается найти библиотеку по стандартному пути.

khusamov commented 2 years ago

image

Ключ typeRoots в такой конфигурации эффекта не окажет — для этого необходимо наличие файловой системы, а из браузерной версии редактора такой функционал убран.

Добавим модель с содержимым нашего будущего редактора:

monaco.editor.createModel(`console.log('Hello world')`, 'typescript', monaco.Uri.parse(`file:///index.tsx`));

Логика такая же, как и при добавлении библиотеки. Мы можем добавить любое количество файлов — главное правильно указывать их относительные пути, тогда подсветка синтаксиса и импорты заработают автоматически. В нашем случае мы добавим только один файл — с типом языка typescript.

Изменить тип языка можно так:

monaco.editor.setModelLanguage(model, 'typescript');

В этом коде model — значение, возвращаемое методом createModel. По сути, модель схожа с открытой вкладкой в редакторе VS Code.

Если все пути прописаны правильно, мы получим:

image

Последним шагом создадим экземпляр редактора:

const editor = monaco.editor.create(ref, {
    theme: "vs-dark",
  automaticLayout: true,
  model: this.model
});

В коде:

ref — ссылка на DOM-узел, полученный, например, через useRef

theme — цветовая схема

automaticLayout — автоматически подстраивает размеры редактора при изменении размеров родителя

model — созданная ранее модель, которая будет отображаться

Еще мы можем включать или отключать отображение миникарты, поддержку мультикурсорности и многие другие параметры редактора.

Читать и передавать значение сборщику мы сможем так:

editor.onDidChangeModelContent(() => ESService.build(editor.getModel().getValue()));
khusamov commented 2 years ago

https://github.com/Tetragius/editor

https://editor-tetragius.vercel.app/

https://www.npmjs.com/package/memfs

https://builder-demo.vercel.app/