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.