Note de l'éditeur
Dans le 
dernier article, nous avons parlé de la sortie du panneau de contrôle Voximplant, sans oublier de mentionner l'IDE mis à jour. Aujourd'hui, nous consacrons un 
long parcours séparé à cet outil - notre collègue 
Geloosa a soigneusement décrit à la fois le processus de choix d'une technologie et la mise en œuvre avec des onglets, des styles de 
saisie automatique et personnalisés. Asseyez-vous plus commodément, mettez de côté le reste de vos affaires et allez au tacle, où les tripes de Monaco attendent les curieux - ne glissez pas, il y en a beaucoup :) Bonne lecture.
Quelle bibliothèque choisir pour l'éditeur de code?
Npm produit plus de 400 résultats pour l'éditeur de code. Pour la plupart, ce sont des enveloppes d'interface utilisateur de plusieurs des bibliothèques les plus populaires faites pour un cadre ou un projet particulier, des plug-ins pour les mêmes bibliothèques ou leurs fourches avec des modifications pour eux-mêmes, ainsi que pour ne pas modifier le code dans le navigateur, ils sont simplement entrés dans la sortie par mots-clés. Donc, heureusement, le choix est beaucoup plus restreint. Quelques 
bibliothèques supplémentaires - à la 
CodeFlask , légères, mais pas très fonctionnelles, conçues pour de petits extraits et des exemples interactifs, mais pas pour un IDE Web à part entière avec les fonctionnalités auxquelles nous sommes habitués dans les éditeurs de bureau.
Au final, nous avons le choix entre 3 bibliothèques: 
Ace , 
CodeMirror et 
Monaco Editor . Le plus ancien d'entre eux, CodeMirror, était une initiative privée de Berliner 
Marijn Haverbeke , qui avait besoin d'un éditeur de code d'exercice dans son tutoriel en ligne, 
Eloquent JavaScript . La première version de l'éditeur a été publiée en 2007. En 2010, la première version d'Ace a été présentée à JSConf.eu dans le même Berlin, qu'Ajax.org a ensuite développé pour son cloud IDE Cloud9 (en fait, Ace signifie Ajax.org Cloud9 Editor). En 2016, Cloud9 a été acheté par Amazon et fait maintenant partie d'AWS. Le dernier, Monaco Editor, est un composant de VS Code et a été publié par Microsoft fin 2015.
Chaque éditeur a ses propres forces et faiblesses; chacun est utilisé dans plus d'un grand projet. Par exemple, CodeMirror est utilisé dans les outils de développement Chrome et Firefox, un IDE dans Bitbucket, dans RunKit dans npm; Ace - à la Codecademy, Khan Academy, MODX; Monaco - dans l'IDE GitLab et CodeSandbox. Voici un tableau de comparaison qui peut vous aider à choisir la bibliothèque qui convient le mieux à votre projet.
|  | Bibliothèques | 
|  | As | CodeMirror | Monaco | 
| Développeur | IDE Cloud9 (Ajax.org), fait maintenant partie d'AmazonMozilla
 | Marijn haverbeke | Microsoft | 
| Prise en charge du navigateur | 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
 | 
| Prise en charge linguistique (coloration syntaxique)
 | > 120 | > 100 | > 20 | 
| Nombre de caractères dans dernières versions sur
 cndjs.com
 | 366 608 (v1.4.3) | 394 269 (v5.44.0) | 2 064 949 (v0.16.2) | 
| Le poids des dernières versions, gzip
 | 2.147 KB | 1,411 KB | 10.898 KB | 
| Rendu | Dom | Dom | DOM et partiellement <canvas> (pour le défilement et la minicarte)
 | 
| La documentation | 7 sur 10: pas de recherche, pas toujours clair que les méthodes reviennent, il y a des doutes
 en complétude et pertinence
 (tous les liens ne fonctionnent pas dans le dock)
 | 6 sur 10: fusionné avec le guide d'utilisation, recherche par Ctrl + F,
 il y a des doutes quant à l'exhaustivité
 | 9 sur 10: beau, avec recherche et référence croisée
 -1 point pour manque d'explication
 à certains drapeaux dont l'application
 pas tout à fait évident d'après le nom
 | 
| Démonstrations de démarrage rapide | Comment - documents texte avec des exemples de code, séparément, il y a des démos avec des exemples de code
 (c'est vrai, ils sont dispersés sur différentes pages,
 tout le monde ne fonctionne pas et ils sont recherchés plus facilement via Google),
 il y a une démo où vous pouvez toucher différentes fonctionnalités,
 mais il est proposé de les gérer via les contrôles de l'interface utilisateur,
 c'est-à-dire que nous devons encore rechercher séparément les méthodes
 pour les connecter
 | Comment sont vraiment pauvres essentiellement tout est dispersé sur github
 et stackoverflow, mais il y a des démos de fonctionnalités avec des exemples
 code pour leur mise en œuvre
 | Combiné sous la forme d'une aire de jeux: code avec des commentaires et un certain nombre de démos, vous pouvez
 essayez immédiatement d'évaluer
 de nombreuses possibilités
 | 
| Activité communautaire | Moyenne | Élevé | Moyenne | 
| Activité développeur | Moyenne | Moyenne | Élevé | 
Cela n'a aucun sens de comparer les bibliothèques par taille, car tout dépend de quoi et comment se connecter pour un projet particulier: chargez le fichier fini avec l'une des versions (qui varient également) ou exécutez le package npm via une sorte de collecteur. Et le plus important est la quantité d'utilisation de l'éditeur: si tous les styles et thèmes sont chargés, combien et quels modules complémentaires et plug-ins sont utilisés. Par exemple, dans CodeMirror, la plupart des fonctionnalités qui fonctionnent à Monaco et Ace prêt à l'emploi ne sont disponibles qu'avec des modules complémentaires. Le tableau montre le nombre de caractères dans les versions récentes sur le CDN et le poids de leurs fichiers compressés pour une idée générale des ordres impliqués.
Toutes les bibliothèques ont à peu près le même ensemble de fonctionnalités de base: mise en forme automatique du code, lignes de pliage, couper / copier / coller, touches de raccourci, possibilité d'ajouter de nouvelles syntaxes pour la mise en évidence et la commande, vérification de la syntaxe (dans CodeMirror uniquement via des modules complémentaires, dans Ace jusqu'à présent uniquement pour JavaScript / CoffeeScript / CSS / XQuery), les info-bulles et la saisie semi-automatique (dans CodeMirror - via les modules complémentaires), la recherche avancée par code (dans CodeMirror - via les modules complémentaires), les méthodes d'implémentation des onglets et du mode partagé, le mode diff et un outil de fusion (dans CodeMirror - soit avec des avantages et des inconvénients dans une seule fenêtre, soit avec deux panneaux via un addon, Ace - Lieb séparée). En raison de son âge, de nombreux modules complémentaires ont été écrits pour CodeMirror, mais leur nombre affectera à la fois le poids et la vitesse de l'éditeur. Monaco peut faire beaucoup de choses hors de la boîte, et, à mon avis, mieux et dans un volume plus important que Ace et CodeMirror.
Nous avons séjourné à Monaco pour plusieurs raisons:
- Les outils les plus développés que nous avons jugés critiques pour notre projet:
 - IntelliSense - conseils et saisie semi-automatique;
- navigation intelligente dans les codes dans le menu contextuel et sur la minicarte;
- mode diff à deux panneaux hors de la boîte.
 
 
- Écrit en TypeScript. Notre panneau de contrôle est écrit en Vue + Typescript, donc le support TS était important. Soit dit en passant, Ace prend également en charge TS récemment, mais il a été initialement écrit en JS. Pour CodeMirror, il existe des types dans DefinitelyTyped .
- Il y est développé le plus activement (peut-être parce qu'il a été publié il n'y a pas si longtemps), les bogues sont corrigés plus rapidement et les requêtes de pool sont combattues. À titre de comparaison, avec CodeMirror, nous avons eu une triste expérience, lorsque les bugs n'ont pas été corrigés pendant des années et que nous avons mis une béquille sur une béquille et conduit une béquille.
- Documentation pratique générée automatiquement (qui donne de l'espoir pour son exhaustivité) avec des références croisées entre les interfaces et les méthodes.
- À notre goût, la plus belle interface utilisateur (probablement aussi liée à l'heure de création) et une API concise.
- Après avoir demandé aux amis des développeurs quels éditeurs causaient le plus de maux de tête, Ace et CodeMirror étaient les leaders.
Séparément, il faut parler de la vitesse de travail. L'analyse coûteuse a lieu dans un thread de travail parallèle. De plus, tous les calculs sont limités par la taille de la fenêtre d'affichage (tous les types, couleurs et rendus sont calculés uniquement pour les lignes visibles). Il ne commence à freiner que si le code contient 100 000 lignes - les invites peuvent être calculées pendant plusieurs secondes. Ace, qui utilise également des travailleurs pour le calcul intensif, s'est avéré être plus rapide: dans un code de la même longueur, des invites apparaissent presque instantanément et il gère rapidement 200 000 lignes (sur le site officiel, il est indiqué que même 4 millions de lignes ne devraient pas être un problème, bien que les vis ont été accélérées, l'entrée a commencé à ralentir et les invites ont disparu après le 1er million). CodeMirror, où il n'y a pas de calculs parallèles, peut à peine tirer de tels volumes: il peut scintiller à la fois le texte et la coloration syntaxique. Étant donné que 100 000 lignes dans un fichier sont rares dans le monde réel, nous avons fermé les yeux sur cela. Même avec 40 à 50 000 lignes, Monaco fait un excellent travail.
Connexion de Monaco et utilisation des fonctionnalités de base (par exemple, intégration avec Vue)
Connexion
Ici, je vais donner des exemples de code des composants vue et utiliser la terminologie appropriée. Mais tout cela est facilement porté sur n'importe quel autre framework ou JS pur.
Le code source de Monaco peut être téléchargé sur le site officiel et mis dans votre projet, vous pouvez le récupérer sur CDN, vous pouvez vous connecter au projet via npm. Je vais parler de la troisième option et construire en utilisant webpack.
Nous mettons monaco-editor et un plug-in pour l'assemblage:
npm i -S monaco-editor npm i -D monaco-editor-webpack-plugin 
Dans la configuration du webpack, ajoutez:
 const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin'); module.exports = {  
Si vous utilisez Vue et vue-cli-service pour construire, ajoutez à vue.config.js:
 const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin'); module.exports = {  
Si vous n'avez pas besoin de toutes les langues et fonctionnalités de Monaco, pour réduire la taille du bundle, vous pouvez transférer 
MonacoWebpackPlugin objet avec les paramètres vers 
MonacoWebpackPlugin :
 new MonacoWebpackPlugin({ output: '',  
Une liste complète des fonctionnalités et des langues du plugin est 
ici .
Créer et personnaliser un éditeur
Nous importons 
editor et appelons 
editor.create(el: HTMLElement, config?: IEditorConstructionOptions) , en passant l'élément DOM dans lequel nous voulons créer l'éditeur comme premier argument.
Dans le composant éditeur:
 <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> 
Le conteneur de l'éditeur doit obligatoirement régler la hauteur pour qu'elle ne se révèle pas nulle. Si vous créez l'éditeur dans une div vide (avec une hauteur nulle - votre K.O.), Monaco écrira la même hauteur dans un style en ligne dans la fenêtre de l'éditeur.
Le deuxième argument facultatif de 
editor.create est la configuration de l'éditeur. Il y a plus d'une centaine d'options, une description complète de l'interface 
IEditorConstructionOptions est dans la documentation.
Pour un exemple, nous allons définir la langue, le thème et le texte initial et activer l'habillage de ligne (par défaut, ils ne sont pas encapsulés):
 const config = { value: `function hello() { alert('Hello world!'); }`, language: 'javascript', theme: 'vs-dark', wordWrap: 'on' }; this.editor = editor.create(this.$refs.editor, config); 
La fonction 
editor.create renvoie un objet avec l'interface 
IStandaloneCodeEditor . Grâce à lui, vous pouvez désormais contrôler tout ce qui se passe dans l'éditeur, y compris la modification des paramètres initiaux:
 
Maintenant, pour la douleur: 
updateOptions accepte un objet avec l'interface 
IEditorOptions , pas IEditorConstructionOptions. Ils sont légèrement différents: IEditorConstructionOptions est plus large, il inclut les propriétés de cette instance de l'éditeur et certaines globales. 
updateOptions propriétés d' 
updateOptions sont modifiées via 
updateOptions , global - via les méthodes de l' 
editor global. Et en conséquence, ceux qui changent globalement changent pour toutes les instances. Parmi ces options est le 
theme . Créez 2 instances avec des thèmes différents; y des deux sera celui donné dans le dernier (sombre ici). La 
editor.setTheme('vs') globale 
editor.setTheme('vs') changera également le sujet pour les deux. Cela affectera même les fenêtres qui se trouvent sur une autre page de votre SPA. Il y a peu de tels endroits, mais vous devez les suivre.
 <template> <div ref='editor1' class='editor'></div> <div ref='editor2' class='editor'></div> </template> <script> </script> 
Supprimer l'éditeur
Lorsque vous détruisez une fenêtre Monaco, vous devez appeler la méthode 
dispose , sinon tous les écouteurs ne seront pas effacés et les fenêtres créées après cela pourraient ne pas fonctionner correctement, réagissant plusieurs fois à certains événements:
 beforeDestroy() { this.editor && this.editor.dispose(); } 
Onglets
Les onglets ouverts dans l'éditeur de fichiers utilisent la même fenêtre Monaco. Pour basculer entre eux, les méthodes IStandaloneCodeEditor sont utilisées: 
getModel pour l'enregistrement et 
setModel pour la mise à jour du 
setModel de l'éditeur. Le modèle stocke le texte, la position du curseur et l'historique des actions à annuler. Pour créer un modèle d'un nouveau fichier, la 
editor.createModel(text: string, language: string) est utilisée. Si le fichier est vide, vous ne pouvez pas créer de modèle et passer 
null à 
setModel :
Afficher le code <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) { </script> 
 Mode Diff
Pour le mode diff, vous devez utiliser une autre méthode d' 
editor lors de la création de la fenêtre d'éditeur - 
createDiffEditor :
 <template> <div ref='diffEditor' class='editor'></div> </template> // ... mounted() { this.diffEditor = editor.createDiffEditor(this.$refs.diffEditor, config); } // ... 
Il prend les mêmes paramètres que 
editor.create , mais la config doit avoir une interface 
IDiffEditorConstructionOptions , qui est légèrement différente de la config éditeur classique, en particulier, elle n'a pas de 
value . Les textes de comparaison sont définis après la création de l' 
IStandaloneDiffEditor retourné via 
setModel :
 this.diffEditor.setModel({ original: editor.createModel('const a = 1;', 'javascript'), modified: editor.createModel('const a = 2;', 'javascript') }); 
Menu contextuel, palette de commandes et touches de raccourci
Monaco utilise son menu contextuel sans navigateur, où il y a une navigation intelligente, un multi-curseur pour changer toutes les occurrences et une palette de commandes comme dans VS Code (palette de commandes) avec un tas de commandes et de raccourcis utiles qui accélèrent l'écriture de code:
  Menu contextuel de Monaco 
  Palette de commandes Monaco 
Le menu contextuel est développé via la méthode 
addAction (il est disponible à la fois dans 
IStandaloneCodeEditor et 
IStandaloneDiffEditor ), qui accepte un objet 
IActionDescriptor :
Afin de ne lier qu'un raccourci à une action sans l'afficher dans le menu contextuel, la même méthode est utilisée, seul le 
contextMenuGroupId l'action n'est pas spécifié:
La palette de commandes comprendra toutes les actions ajoutées.
Conseils et saisie semi-automatique
À ces fins, Monaco utilise 
IntelliSense , ce qui est cool. Vous pouvez lire et voir sur les captures d'écran le lien combien d'informations utiles il peut montrer. Si votre langue n'a pas encore de saisie semi-automatique, vous pouvez l'ajouter via 
registerCompletionItemProvider . Et pour JS et TS, il existe déjà une méthode 
addExtraLib qui vous permet de charger des définitions TypeScript pour les info-bulles et la 
addExtraLib -automatique:
 
Dans le premier paramètre, la ligne transmet les définitions, dans le second, facultatif, le nom de la lib.
Langues et thèmes personnalisés
Monaco dispose d'un module 
Monarch pour déterminer la syntaxe de ses langues. La syntaxe est décrite de façon assez standard: la correspondance entre les habitués et les jetons caractéristiques de cette langue est établie.
Vous pouvez également créer un thème pour vos jetons - un objet avec l'interface 
IStandaloneThemeData - et l'installer dans l' 
editor global:
 
Maintenant, le texte dans la langue décrite ressemblera à ceci:
Vous pouvez appliquer cette fonctionnalité tant que vous avez suffisamment d'imagination. Par exemple, nous avons créé une visionneuse du journal des appels dans notre panneau pour les développeurs. Les journaux sont souvent longs et incompréhensibles, mais lorsqu'ils sont affichés avec une coloration syntaxique, une recherche intelligente, des lignes de pliage / expansion, les commandes nécessaires (par exemple, Prettify params), mettant en évidence toutes les lignes d'appel par leur identifiant ou traduisant l'heure du journal dans un fuseau horaire différent, puis creuser cela devient beaucoup plus facile en eux (la capture d'écran est cliquable):
Conclusion
En résumé, je dirai que Monaco est le feu. Après des mois de travail avec lui, j'ai des souvenirs exceptionnellement agréables. Si vous choisissez un éditeur pour le code, assurez-vous d'aller sur son 
Playground et de jouer avec le code, voir ce qu'il peut faire d'autre. C'est peut-être exactement ce que vous recherchez.