IDE нормального человека или почему мы выбрали Monaco

    Памятка от редактора


    В прошлой статье мы рассказали про релиз панели управления Voximplant, не забыв упомянуть обновленную IDE. Сегодня мы посвящаем этому инструменту отдельный лонгрид – наша коллега Geloosa заботливо описала как процесс выбора технологии, так и имплементацию с вкладками, автокомплитом и кастомными стилями. Садитесь удобнее, отложите остальные дела и заходите в подкат, где любопытных ждут кишки Monaco – не поскользнитесь, их там много :) Приятного чтения.


    Какую библиотеку выбрать для редактора кода?


    Npm выдает 400+ результатов по запросу «code editor». По большей части это UI-обертки нескольких самых популярных либ, сделанные для определенного фреймворка или проекта, плагины для тех же либ или их форки с доработками под себя, а также либы не для редактирования кода в браузере, просто попавшие в выдачу по ключевым словам. Так, к счастью, выбор значительно сужается. Еще несколько либ – а-ля CodeFlask, легковесные, но малофункциональные, предназначенные для небольших сниппетов и интерактивных примеров, но не для полноценной веб-IDE с функциональностью, к которой мы привыкли в десктопных редакторах.

    В конечном итоге у нас осталось 3 библиотеки на выбор: Ace, CodeMirror и Monaco Editor. Самая ранняя из них – CodeMirror – была частной инициативой берлинца Марина Хавербеке (Marijn Haverbeke), которому понадобился редактор кода для упражнений в его онлайн-учебнике Eloquent JavaScript. Первая версия редактора выпущена в 2007 году. В 2010-м на JSConf.eu в том же Берлине была представлена первая версия Ace, который тогда разрабатывала Ajax.org для своей облачной IDE Cloud9 (собственно, Ace и расшифровывается как Ajax.org Cloud9 Editor). В 2016-м Cloud9 был куплен Амазоном и сейчас является частью AWS. Самый поздний, Monaco Editor, является компонентом VS Code и опубликован Microsoft в конце 2015-го.

    У каждого редактора есть свои сильные и слабые стороны, каждый используется не в одном крупном проекте. К примеру, CodeMirror используется в инструментах разработчика Chrome и Firefox, IDE в Bitbucket, в RunKit у npm; Ace – в Codecademy, Khan Academy, MODX; Monaco – в IDE GitLab и CodeSandbox. Ниже приведена сравнительная таблица, которая, возможно, поможет вам выбрать библиотеку, наиболее подходящую для вашего проекта.

    Библиотеки
    Ace CodeMirror Monaco
    Разработчик Cloud9 IDE (Ajax.org),
    ныне – часть AmazonMozilla
    Marijn Haverbeke Microsoft
    Поддержка браузеров Firefox ^3.5
    Chrome
    Safari ^4.0
    IE ^8.0
    Opera ^11.5
    Firefox ^3.0
    Chrome
    Safari ^5.2
    IE ^8.0
    Opera ^9.2
    Firefox ^4.0
    Chrome
    Safari (v — ?)
    IE ^11.0
    Opera ^15.0
    Поддержка языков
    (подсветка синтаксиса)
    >120 >100 >20
    Кол-во символов в
    последних версиях на
    cndjs.com
    366 608 (v1.4.3) 394 269 (v5.44.0) 2 064 949 (v0.16.2)
    Вес последних версий,
    gzip
    2.147 KB 1.411 KB 10.898 KB
    Рендеринг DOM DOM DOM и частично <canvas>
    (для скролла и minimap)
    Документация 7 из 10: нет поиска, не всегда понятно,
    что возвращают методы, есть сомнения
    в полноте и актуальности
    (в доке работают не все ссылки)
    6 из 10: слита с юзергайдом,
    поиск по Ctrl+F,
    есть сомнения в полноте
    9 из 10: красивая, с поиском и
    перекрестными ссылками
    -1 балл за отсутствие пояснений
    к некоторым флагам, применение которых
    не вполне очевидно из названия
    Quickstart, демки How-to – текстовые документы с примерами кода,
    отдельно есть демки с примерами кода
    (правда, они разбросаны по разным страницам,
    не все работают и ищутся они проще всего через гугл),
    есть демка, где можно пощупать разные фичи,
    но управлять ими предлагается через UI-контролы,
    то есть потом надо еще отдельно искать методы
    для их подключения
    How-to прямо-таки бедные,
    в основном все разбросано по github
    и stackoverflow, зато есть демки фич с примерами
    кода для их реализации
    Объединены в формате плейграунда:
    код с комментами и рядом демо, можно
    сразу попробовать и оценить
    многие возможности
    Активность сообщества Средняя Высокая Средняя
    Активность разработчиков Средняя Средняя Высокая

    Бессмысленно сравнивать библиотеки по размеру, потому что все зависит от того, что и как подключать для конкретного проекта: грузить готовый файл с одним из билдов (которые тоже разнятся) или прогонять npm-пакет через какой-то сборщик. А самое важное – в каком объеме используется редактор: подгружаются ли все стили и темы, сколько и каких аддонов и плагинов использовано. Например, в CodeMirror большая часть функциональности, которая работает в Monaco и Ace из коробки, доступна только с аддонами. В таблице приведено количество символов в последних версиях на CDN и вес их сжатых файлов для общего представления, о каких порядках идет речь.

    Во всех библиотеках примерно одинаковый набор базовых фич: автоформатирование кода, сворачивание строк, cut/copy/paste, горячие клавиши, возможность добавления новых синтаксисов для подсветки и тем, проверка синтаксиса (в CodeMirror – только через аддоны, в Ace – пока только для JavaScript/CoffeeScript/CSS/XQuery), подсказки и автокомплит (в CodeMirror – через аддоны), продвинутый поиск по коду (в CodeMirror – через аддоны), методы для реализации табов и сплит-режима, дифф-режим и инструмент для мержа (в CodeMirror – либо с плюсам и минусами в одном окне, либо двухпанельный через аддон, в Ace – отдельная либа). Для CodeMirror в силу его возраста написано много аддонов, но их количество будет влиять и на вес, и на скорость редактора. Monaco многое умеет из коробки, причем, на мой взгляд, лучше и в большем объеме, чем Ace и CodeMirror.

    Мы остановились на Monaco по нескольким причинам:

    1. Наиболее развиты инструменты, которые мы сочли критично важными для нашего проекта:
      • IntelliSense — подсказки и автокомплит;
      • умная навигация по коду в контекстном меню и через minimap;
      • двухпанельный дифф-режим из коробки.

    2. Написан на TypeScript. Наша панель управления написана на Vue+Typescript, поэтому поддержка TS была важна. К слову, Ace с недавнего времени тоже поддерживает TS, но изначально он был написан на JS. Для CodeMirror есть типы в DefinitelyTyped.
    3. В нем наиболее активно идет разработка (возможно, потому что он вышел не так давно), быстрее правятся баги и мержатся пул-реквесты. Для сравнения, с CodeMirror у нас был печальный опыт, когда баги не правились годами и мы ставили костыль на костыле и костылем погоняли.
    4. Удобная автосгенеренная (что дает надежду на ее полноту) документация с перекрестными ссылками между интерфейсами и методами.
    5. На наш вкус, наиболее красивый UI (наверное, тоже связано с временем создания) и лаконичный API.
    6. Поспрашивав знакомых разработчиков, какой из редакторов вызывал больше головной боли, в лидерах оказались Ace и CodeMirror.

    Отдельно стоит сказать про скорость работы. Затратный синтаксический анализ происходит в параллельном потоке воркера. Плюс все вычисления ограничиваются размером вьюпорта (все типы, цвета, отрисовка рассчитываются только для тех строк, которые видны). Тормозить начинает, только если коде под 100 000 строк — подсказки могут вычисляться по несколько секунд. Ace, который тоже использует воркеры для тяжелых вычислений, оказался быстрее: в коде такой же длины подсказки появляются практически моментально, да и с 200 000 строками он быстро справляется (на официальном сайте заявлено, что даже 4 млн строк не должны оказаться проблемой, хотя у меня разогнались винты, стал тормозить ввод и исчезли подсказки после 1-го миллиона). CodeMirror, где параллельных вычислений нет, совсем с трудом тянет такие объемы: может мелькать и текст, и подсветка синтаксиса. Поскольку в реальном мире 100 000 строк в файле — редкость, мы закрыли на это глаза. Даже с 40-50 тысячами строк Monaco справляется прекрасно.

    Подключение Monaco и использование основных фич (на примере интеграции с Vue)


    Подключение


    Здесь я буду давать примеры кода из vue-компонентов и использовать соответствующую терминологию. Но все это легко переносится в любой другой фреймворк или чистый JS.

    Исходник Monaco можно скачать на официальном сайте и положить себе в проект, можно забрать с CDN, можно подключить к проекту через npm. Я расскажу про третий вариант и сборку с помощью webpack.

    Ставим monaco-editor и плагин для сборки:

    npm i -S monaco-editor
    npm i -D monaco-editor-webpack-plugin

    В конфиг вебпака добавляем:

    const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
    
    module.exports = {
      // ...
      plugins: [
        // ...
        new MonacoWebpackPlugin()
      ]
    };

    Если вы используете Vue и vue-cli-service для сборки, добавляем во vue.config.js:

    const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
    
    module.exports = {
      // ...
      configureWebpack: (config) => {
        // ...
        config.plugins.push(new MonacoWebpackPlugin());
      }
    };

    Если вам не нужны все языки и фичи Monaco, для уменьшения размера бандла можно передать в MonacoWebpackPlugin объект с настройками:

    new MonacoWebpackPlugin({
      output: '', // папка, куда собирать скрипты воркеров
      languages: ['markdown'], // массив строк с названиями языков, для которых нужна подсветка 
      features: ['format', 'contextmenu'] // массив строк с нужными фичами
    })

    Полный список фич и языков для плагина здесь.

    Создаем и настраиваем редактор


    Импортируем editor и вызываем editor.create(el: HTMLElement, config?: IEditorConstructionOptions), передавая в качестве первого аргумента элемент DOM, в котором хотим создать редактор.

    В компоненте редактора:

    <template>
      <div ref='editor' class='editor'></div>
    </template>
    
    <script>
      import {editor} from 'monaco-editor';
      import {Component, Prop, Vue} from 'vue-property-decorator';
    
      @Component()
      export default class Monaco extends Vue {
        private editor = null;
    
        mounted() {
          this.editor = editor.create(this.$refs.editor);
        }
      }
    </script>
    
    <style>
      .editor {
        margin: auto;
        width: 60vw;
        height: 200px;
      }
    </style>

    Контейнеру для редактора нужно обязательно задавать высоту, чтобы она не оказалась нулевой. Если вы создадите редактор в пустом div-е (с нулевой высотой – ваш К.О.), Monaco пропишет такую же высоту инлайн-стилем у окна редактора.

    Второй необязательный аргумент editor.create – конфиг редактора. В нем более сотни опций, полное описание интерфейса IEditorConstructionOptions есть в документации.

    Для примера зададим язык, тему и изначальный текст и включим перенос строк (по дефолту они не переносятся):

    const config = {
      value: `function hello() {
        alert('Hello world!');
      }`,
      language: 'javascript',
      theme: 'vs-dark',
      wordWrap: 'on'
    };
    
    this.editor = editor.create(this.$refs.editor, config);

    Функция editor.create возвращает объект с интерфейсом IStandaloneCodeEditor. Через него теперь можно управлять всем происходящим в редакторе, в том числе изменять первоначальные настройки:

    // выключаем перенос строк и переключаем редактор в read-only режим
    this.editor.updateOptions({wordWrap: 'off', readOnly: true}); 

    Теперь о боли: updateOptions принимает объект с интерфейсом IEditorOptions, а не IEditorConstructionOptions. Они немного отличаются: IEditorConstructionOptions шире, в него входят свойства данного инстанса редактора и некоторые глобальные. Свойства инстанса меняются через updateOptions, глобальные — через методы глобального editor. И соответственно, те, что меняются глобально, меняются для всех инстансов. Среди таких параметров — theme. Создадим 2 инстанса с разными темами; y обоих будет та, которая задана в последнем (здесь — темная). Глобальный метод editor.setTheme('vs') также сменит тему у обоих. Это скажется даже на тех окнах, что находятся на другой странице вашего SPA. Таких мест немного, но за ними надо следить.

    <template>
      <div ref='editor1' class='editor'></div>
      <div ref='editor2' class='editor'></div>
    </template>
    
    <script>
      // ...
      this.editor1 = editor.create(this.$refs.editor1, {theme: 'vs'});
      this.editor2 = editor.create(this.$refs.editor2, {theme: 'vs-dark'});
      // ...
    </script>


    Удаление редактора


    При уничтожении окна Monaco надо вызвать метод dispose, иначе не очистятся все листенеры и созданные после этого окна могут работать некорректно, реагируя на некоторые события по несколько раз:

    beforeDestroy() {
      this.editor && this.editor.dispose();
    }

    Вкладки


    Вкладки открытых в редакторе файлов используют одно и то же окно Monaco. Для переключения между ними используются методы IStandaloneCodeEditor: getModel для сохранения и setModel для обновления модели редактора. Модель хранит текст, позицию курсора, историю действий для undo-redo. Для создания модели нового файла используется глобальный метод editor.createModel(text: string, language: string). Если файл пустой, можно не создавать модель и передать null в setModel:

    Посмотреть код
    <template>
      <div class='tabs'>
          <div class='tab' v-for="tab in tabs" :key'tab.id' @click='() => switchTab(tab.id)'>
            {{tab.name}}
          </div>
      </div>
      <div ref='editor' class='editor'></div>
    </template>
    
    <script>
      import {editor} from 'monaco-editor';
      import {Component, Prop, Vue} from 'vue-property-decorator';
    
      @Component()
      export default class Monaco extends Vue {
        private editor = null;
        private tabs: [
          {id: 1, name: 'tab 1', text: 'const tab = 1;', model: null, active: true},
          {id: 2, name: 'tab 2', text: 'const tab = 2;', model: null, active: false}
        ];
    
        mounted() {
          this.editor = editor.create(this.$refs.editor);
        }
    
        private switchTab(id) {
          const activeTab = this.tabs.find(tab => tab.id === id);
          
          if (!activeTab.active) { 
            // создаем модель редактора (если ее нет и есть текст) или берем текущую
            const model = !activeTab.model && activeTab.text
              ? editor.createModel(activeTab.text, 'javascript')
              : activeTab.model;
    
            // активируем новую вкладку и сохраняем модель предыдущей активной вкладки
            this.tabs = this.tabs.map(tab => ({
              ...tab, 
              model: tab.active ? this.editor.getModel() : tab.model,
              active: tab.id === id
            }));
            // обновляем модель редактора
            this.editor.setModel(model);
          }
        }
    </script>


    Дифф-режим


    Для дифф-режима нужно использовать другой метод editor при создании окна редактора — createDiffEditor:

    <template>
      <div ref='diffEditor' class='editor'></div>
    </template>
    // ...
    mounted() {
      this.diffEditor = editor.createDiffEditor(this.$refs.diffEditor, config);
    }
    // ...

    Он принимает те же параметры, что editor.create, но конфиг должен иметь интерфейс IDiffEditorConstructionOptions, который несколько отличается от конфига обычного редактора, в частности, в нем нет value. Тексты для сравнения задаются после создания через setModel возвращенного IStandaloneDiffEditor:

    this.diffEditor.setModel({
      original: editor.createModel('const a = 1;', 'javascript'),
      modified: editor.createModel('const a = 2;', 'javascript')
    });


    Контекстное меню, палитра команд и горячие клавиши


    Monaco использует свое, не браузерное, контекстное меню, где есть умная навигация, мультикурсор для изменения всех вхождений и командная палитра как в VS Code (Command palette) с кучей полезных команд и горячих клавиш, ускоряющих написание кода:

                                   Monaco context menu


                                   Monaco command palette


    Контекстное меню расширяется через метод addAction (он есть и в IStandaloneCodeEditor, и в IStandaloneDiffEditor), принимающий объект IActionDescriptor:

    Посмотреть код
    // ...  
    <div ref='diffEditor' :style='{display: isDiffOpened ? "block" : "none"}'></div>
    // ...
    
    // импортируем KeyCode и KeyMod для привязки горячих клавиш
    import {editor, KeyCode, KeyMod} from "monaco-editor";
    // ...
    private editor = null;
    private diffEditor = null;
    private isDiffOpened = false;
    
    private get activeTab() {
      return this.tabs.find(tab => tab.active);
    }
    
    mounted() {
      this.diffEditor = editor.createDiffEditor(this.$refs.diffEditor);
      this.editor = editor.create(this.$refs.editor);
      this.editor.addAction({
        // идент группы, в которой появится новый пункт.
        contextMenuGroupId: '1_modification', 
        // всего их три: 1 - 'navigation', 2 - '1_modification', 3 - '9_cutcopypaste';
        // можно создать свои
        contextMenuOrder: 3, // очередность пункта меню в рамках группы
        label: 'Show diff',
        id: 'showDiff',
        keybindings: [KeyMod.CtrlCmd + KeyMod.Shift + KeyCode.KEY_D], // горячие клавиши
        // функция, вызываемая при клике или
        // нажатии указанных клавиш
        run: this.showDiffEditor 
      });
    }
    
    // показываем дифф для активной вкладки
    private showDiffEditor() {
      this.diffEditor.setModel({
        original: this.activeTab.initialText,
        modified: this.activeTab.editedText
      });
      this.isDiffOpened = true;
    }


    Чтобы только привязать сочетание клавиш к действию, не показывая его в контекстном меню, используется тот же метод, только не указывается contextMenuGroupId у действия:

    Посмотреть код
    // ...
    // кастомные действия
    private myActions = [
      {
        contextMenuGroupId: '1_modification',
        contextMenuOrder: 3,
        label: <string>this.$t('scenarios.showDiff'),
        id: 'showDiff',
        keybindings: [KeyMod.CtrlCmd + KeyMod.Shift + KeyCode.KEY_D],
        run: this.showDiffEditor
      },
      // действие, запускаемое по Ctrl + C + L и невидимое в контекстном меню
      {
        label: 'Get content length',
        id: 'getContentLength',
        keybindings: [KeyMod.CtrlCmd + KeyCode.Key_C + KeyCode.Key_L],
        run: () =>  this.editor && alert(this.editor.getValue().length)
      }
    ];
    
    mounted() {
      this.editor = editor.create(this.$refs.editor);
      this.myActions.forEach(this.editor.addAction); // добавляем все кастомные действия 
    }


    В палитру команд попадут все добавленные действия.

    Подсказки и автокомплит


    Для этих целей в Monaco использован IntelliSense, что круто. По ссылке можно почитать и посмотреть на скринах, сколько полезной инфы он умеет показывать. Если для вашего языка еще нет автокомплита, его можно добавить через registerCompletionItemProvider. А для JS и TS уже есть метод addExtraLib, позволяющей загрузить определения на TypeScript для подсказок и автокомплита:

    // ...
    import {languages} from "monaco-editor";
    // ...
    // объект, в который будет записан интерфейс для последующего удаления либы
    private myAddedLib = null;
    
    mounted() {
      // languages используется глобально всеми инстансами Monaco
      this.myAddedLib = languages.typescript.javascriptDefaults.addExtraLib('interface MyType {prop: string}', 'myLib');
    }
    
    beforeDestroy() {
      // удаляем определения, если нужно
      this.myAddedLib && this.myAddedLib.dispose();
    }

    В первом параметре строкой передаются определения, во втором, необязательном, — название либы.

    Кастомные языки и темы


    В Monaco есть модуль Monarch для определения синтаксиса своих языков. Синтаксис описывается вполне стандартно: задается соответствие между регулярками и токенами, характерными для данного языка.

    Посмотреть код
    // ...
    // описываем язык, синтаксис которого состоит из:
    private myLanguage = {
      defaultToken: 'text',
      // круглых скобок,
      brackets: [{
        open: '(',
        close: ')',
        token: 'bracket.parenthesis'
      }],
      // слов, обозначающих времена года,
      keywords: [
        'autumn',
        'winter',
        'spring',
        'summer'
      ],
      // дат и имен людей
      tokenizer: {
        root: [{
            regex: /\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}/,
            action: {
              token: 'date'
            }
          },
          {
            regex: /(boy|girl|man|woman|person)(\s[A-Za-z]+)/,
            action: ['text', 'variable']
          }
        ]
      }
    };
    
    mounted() {
      // теперь регистрируем новый язык
      languages.register({
        id: 'myLanguage'
      });
      // и устанавливаем определения для него
      languages.setMonarchTokensProvider('myLanguage', this.myLanguage);
      // ...
    }


    Также для своих токенов можно создать тему — объект с интерфейсом IStandaloneThemeData — и установить ее в глобальный editor:

    // ...
    private myTheme = {
      base: 'vs', // тема, от которой наследуется подсветка токенов
      inherit: true,
      // переопределения старых и определения новых токенов
      rules: [
        {token: 'date', foreground: '22aacc'},
        {token: 'variable', foreground: 'ff6600'},
        {token: 'text', foreground: 'd4d4d4'},
        {token: 'bracket', foreground: 'd4d4d4'}
      ]
    };
    
    mounted() {
      editor.defineTheme('myTheme', this.myTheme);
      // ...
    }

    Теперь текст на описанном языке будет выглядеть так:


    Применять эту фичу можно, насколько хватит фантазии. Например, мы сделали в своей панели для разработчиков просмотрщик логов звонков. Логи зачастую длинные и непонятные, но когда они показываются с подсветкой синтаксиса, умным поиском, сворачиванием/разворачиванием строк, нужными командами (например, Prettify params), выделением всех строк звонка по его id или переводом времени в логе в другой часовой пояс, то копаться в них становится намного проще (скриншот кликабелен):


    Заключение


    Резюмируя, скажу, что Monaco — огонь. После нескольких месяцев работы с ним у меня исключительно приятные воспоминания. Если вы выбираете редактор для кода, обязательно зайдите на его Playground и поиграйтесь с кодом, посмотрите, что еще он умеет. Возможно, это именно то, что вы ищете.
    Voximplant
    159,18
    Облачная платформа голосовой и видеотелефонии
    Поделиться публикацией

    Комментарии 13

      +5
      Тоже используем Monaco как редактор кода.
      Важно упомянуть, что для поддержки IntelliSense и Autocomplete в языках, для которых невозможен движок на клиентской стороне (Python, C#), нужен доп. LanguageServer.
        +1

        Ага, спасибо, за дополнение. Мы делали IDE для js-скриптов, с другими пока поработать на довелось, поэтому не упомянула. Но, как я понимаю, его можно написать на чем угодно и общать с Монако через веб-сокет по Server Language Protocol?

          0
          его можно написать на чем угодно и общать с Монако через веб-сокет по Server Language Protocol?

          Да, все верно — можно подключить Monaco Editor через LSP к LanguageServer, скормить серверу свой solution и получать с сервера IntelliSense и Autocomplete.
          Подробности по поддержке языков можно найти здесь: langserver.org
          Для C# мы использовали OmniSharp, для Python «python-language-server» от Microsoft.
          В Microsoft с «python-language-server» работает Михаил Архипов, он консультировал нас.
        +5
        Спасибо за статью, не знал, что Monaco — это редактор из vscode.
        «IntelliSense — подсказки и автокомплит» выглядит очень интересно.
          0
          Сейчас внедряю Ace, посмотрим на сколько сложно будет.
            +1
            У меня был прямо противоположный опыт. Начал с CodeMirror, но, к сожалению, не удовлетворил Intellisense. Перешёл на Монако. Очень геморройно было интегрировать. Постоянно вылазили дикие краши внутри движка. В одном случае полез в сорс и нашёл вызов функции с параметрами, которые заведомо приводят к возврату null, при этом вызывающая функция без проверок пытается обратится к полям возвращаемого значения, что и приводило к крашу. Тесты, похоже, там и не валялись. Кроме этого пришлось импортировать скомпилированный движок через HTML и он весил около мега, а когда импортировал его в JS он вдруг наподключал аж 3 мега. Может я его неправильно готовил, но я шёл по документации и примерам.
              0

              Да, вес Монако действительно большой, но с крашами ни разу не встречались. Было в одном месте, что либо ts кидал ошибку при компиляции, либо она возникала в рантайме, потому что неверно были написаны типы для Monarch (этот модуль изначально был на is и типы к нему писались после). Но порадовало то, что, в отличие от того же CodeMirror, быстро реагировали на тикеты на гитхабе. И разок я им кидала пул-реквест и запускалась куча тестов, так что они там есть и большом количестве. Но не берусь сказать, как было раньше, наверное, вы интегрировали его по крайней мере около года назад?

              –2
              Мне почему то казалось, что нормальные люди предпочитают Intelij… А оказывается вон оно как на самом деле…
                +1
                Соглашусь. Большую IDE установил и работаешь.
                Пробовал использовать VSCode для go. В итоге ставишь миллион плагинов, чтоб продуктивно работать либо зубришь команды.
                Перешёл goland, в котором одно блаженство программировать.
                Зачем отказываться от благ? Так и до vim скатиться можно.
                  +1
                  На мой взгляд у webide своя ниша:
                  • онлайн обучение программированию, при этом тебе не нужно ничего устанавливать на свой компьютер, потом запаковывать и отправлять на проверку — уже всё есть на сервере
                  • беглый просмотр кода, например в админке сайта быстро проверить какую-то штуку. как на гитхабе, тебе не обязательно скачивать проект, достаточно найти нужный файл и открыть его с подсветкой синтаксиса прямо в браузере.
                  • лёгкий редактор/просмотр кода для того чтобы в админке подправить/посмотреть json-конфиг или lua-сценарий

                  Возможны также другие кейсы, где это пригодиться. Собственно все эти тысячи звёзд на гитхабе и говорят, что кейсов хватает.
                  +3

                  Здесь речь именно об IDE, которую можно запустить в браузере. IntelliJ, к сожалению, пока туда не затащить.

                  +2
                  CodeMirror используется в инструментах разработчика Chrome

                  Теперь понятно почему они еле ворочаются в больших файлах
                    0

                    Тоже применил Monaco. Но сходу выхватил три проблемы (обертка vue-monaco):


                    1. Если через реактивное свойство меняешь код, слетают все кастомные стили, которые ты наложил на строки. Использую для отображения исполняемой строки в режиме дебага. Приходится пересоздавать компонент.
                    2. Есть занятный функцилнал с маркерами. Так и не смог его задействовать. Ну не работают и все тут...
                    3. Ресайз нужно костылировать. Не понял почему… но вот так.

                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                    Самое читаемое