Nota del editor
En el
último artículo, hablamos sobre el lanzamiento del panel de control de Voximplant, sin olvidar mencionar el IDE actualizado. Hoy dedicamos un
largo recorrido por separado a esta herramienta: nuestro colega
Geloosa describió cuidadosamente tanto el proceso de elegir una tecnología como la implementación con pestañas, autocompletar y estilos personalizados. Siéntate más convenientemente, deja a un lado el resto de tus asuntos y ve al aparejo, donde las tripas de Mónaco están esperando a los curiosos: no te resbales, hay muchos de ellos :) Disfruta leyendo.
¿Qué biblioteca elegir para el editor de código?
Npm produce más de 400 resultados para el editor de código. En su mayor parte, estos son contenedores UI de varias de las bibliotecas más populares hechas para un marco o proyecto en particular, complementos para las mismas bibliotecas o sus horquillas con modificaciones para ellos mismos, así como no para editar el código en el navegador, simplemente ingresaron a la salida por palabras clave. Entonces, afortunadamente, la elección es mucho más estrecha. Algunas
bibliotecas más: un
CodeFlask , ligero, pero no muy funcional, diseñado para pequeños fragmentos y ejemplos interactivos, pero no para un IDE web completo con la funcionalidad a la que estamos acostumbrados en los editores de escritorio.
Al final, tenemos 3 bibliotecas para elegir:
Ace ,
CodeMirror y
Monaco Editor . El primero de ellos, CodeMirror, fue una iniciativa privada de Berliner
Marijn Haverbeke , quien necesitaba un editor de código de ejercicio en su tutorial en línea,
Eloquent JavaScript . La primera versión del editor fue lanzada en 2007. En 2010, la primera versión de Ace se presentó en JSConf.eu en el mismo Berlín, que Ajax.org desarrolló para su nube IDE Cloud9 (de hecho, Ace significa Ajax.org Cloud9 Editor). En 2016, Cloud9 fue comprado por Amazon y ahora forma parte de AWS. El último, Monaco Editor, es un componente de VS Code y fue publicado por Microsoft a finales de 2015.
Cada editor tiene sus propias fortalezas y debilidades; cada una se usa en más de un gran proyecto. Por ejemplo, CodeMirror se usa en las herramientas para desarrolladores de Chrome y Firefox, un IDE en Bitbucket, en RunKit en npm; Ace - en Codecademy, Khan Academy, MODX; Mónaco: en el IDE de GitLab y CodeSandbox. La siguiente es una tabla de comparación que puede ayudarlo a elegir la biblioteca más adecuada para su proyecto.
| Bibliotecas |
| As | CodeMirror | Monaco |
Desarrollador | Cloud9 IDE (Ajax.org), ahora parte de AmazonMozilla | Marijn Haverbeke | Microsoft |
Soporte del navegador | Firefox ^ 3.5 Cromo Safari ^ 4.0 IE ^ 8.0 Opera ^ 11.5 | Firefox ^ 3.0 Cromo Safari ^ 5.2 IE ^ 8.0 Opera ^ 9.2 | Firefox ^ 4.0 Cromo Safari (v -?) IE ^ 11.0 Opera ^ 15.0 |
Soporte de idiomas (resaltado de sintaxis) | > 120 | > 100 | > 20 |
Número de caracteres en últimas versiones en cndjs.com | 366 608 (v1.4.3) | 394,269 (v5.44.0) | 2.064.949 (v0.16.2) |
El peso de las últimas versiones, gzip | 2.147 KB | 1.411 KB | 10.898 KB |
Renderizado | Dom | Dom | DOM y parcialmente <canvas> (para desplazamiento y minimapa) |
La documentación | 7 de 10: sin búsqueda, no siempre claro que los métodos vuelven, hay dudas en integridad y relevancia (no todos los enlaces funcionan en el muelle) | 6 de 10: fusionado con la guía del usuario, buscar por Ctrl + F, hay dudas sobre la integridad | 9 de 10: hermoso, con búsqueda y referencia cruzada -1 punto por falta de explicación a algunas banderas cuya aplicación no del todo obvio por el nombre |
Demostraciones de inicio rápido | Cómo hacerlo: documentos de texto con ejemplos de código, por separado hay demos con ejemplos de código (cierto, están dispersos en diferentes páginas, no todos trabajan y se buscan más fácilmente a través de Google), hay una demostración donde puedes tocar diferentes funciones, pero se propone administrarlos a través de controles de interfaz de usuario, es decir, aún debemos buscar métodos por separado para conectarlos | Cómo son realmente pobres básicamente todo está disperso en github y stackoverflow, pero hay demostraciones de características con ejemplos código para su implementación | Combinado en el formato de un patio de recreo: código con comentarios y una serie de demos, puedes inmediatamente intente y evalúe muchas posibilidades |
Actividad comunitaria | Media | Alta | Media |
Actividad del desarrollador | Media | Media | Alta |
No tiene sentido comparar bibliotecas por tamaño, porque todo depende de qué y cómo conectarse para un proyecto en particular: cargue el archivo terminado con una de las compilaciones (que también varían) o ejecute el paquete npm a través de algún tipo de recopilador. Y lo más importante es cuánto se usa el editor: si se cargan todos los estilos y temas, cuántos y qué complementos y complementos se usan. Por ejemplo, en CodeMirror, la mayor parte de la funcionalidad que funciona en Mónaco y Ace fuera de la caja solo está disponible con complementos. La tabla muestra el número de caracteres en versiones recientes en el CDN y el peso de sus archivos comprimidos para tener una idea general de qué órdenes están involucradas.
Todas las bibliotecas tienen aproximadamente el mismo conjunto de características básicas: formato automático de código, líneas plegables, cortar / copiar / pegar, teclas de acceso rápido, la capacidad de agregar nuevas sintaxis para resaltar y ordenar, verificación de sintaxis (en CodeMirror solo a través de complementos, en Ace hasta ahora solo para JavaScript / CoffeeScript / CSS / XQuery), información sobre herramientas y autocompletar (en CodeMirror - a través de complementos), búsqueda avanzada por código (en CodeMirror - a través de complementos), métodos para implementar pestañas y modo dividido, modo diferencial y una herramienta de combinación (en CodeMirror - ya sea con ventajas y desventajas en una ventana, o dos paneles a través de un complemento, Ace - Lieb independiente). Debido a su antigüedad, se han escrito muchos complementos para CodeMirror, pero su número afectará tanto el peso como la velocidad del editor. Mónaco puede hacer muchas cosas fuera de la caja y, en mi opinión, mejor y en un volumen mayor que Ace y CodeMirror.
Nos alojamos en Mónaco por varias razones:
- Las herramientas más desarrolladas que consideramos críticas para nuestro proyecto:
- IntelliSense - consejos y autocompletar;
- navegación de código inteligente en el menú contextual y a través del minimapa;
- modo diferencial de dos paneles fuera de la caja.
- Escrito en TypeScript. Nuestro panel de control está escrito en Vue + Typecript, por lo que el soporte de TS fue importante. Por cierto, Ace recientemente también es compatible con TS, pero originalmente fue escrito en JS. Para CodeMirror, hay tipos en DefinitelyTyped .
- Se está desarrollando más activamente en él (posiblemente porque se lanzó hace poco), los errores se corrigen más rápido y se resuelven las solicitudes de grupo. En comparación, con CodeMirror tuvimos una experiencia triste, cuando los errores no se corrigieron durante años y pusimos una muleta en una muleta y manejamos una muleta.
- Conveniente documentación autogenerada (que da esperanza para su integridad) con referencias cruzadas entre interfaces y métodos.
- Para nuestro gusto, la interfaz de usuario más hermosa (probablemente también relacionada con el tiempo de creación) y una API concisa.
- Después de preguntar a los amigos de los desarrolladores cuál de los editores causó más dolores de cabeza, Ace y CodeMirror fueron los líderes.
Por separado, debe decirse sobre la velocidad del trabajo. El análisis costoso se realiza en un subproceso de trabajo paralelo. Además, todos los cálculos están limitados por el tamaño de la ventana gráfica (todos los tipos, colores y renderizados se calculan solo para aquellas líneas que son visibles). Comienza a frenar solo si el código contiene 100,000 líneas; las indicaciones se pueden calcular durante varios segundos. Ace, que también utiliza trabajadores para computación pesada, resultó ser más rápido: en un código de la misma longitud, las indicaciones aparecen casi instantáneamente, y rápidamente hace frente a 200,000 líneas (en el sitio web oficial se afirma que incluso 4 millones de líneas no deberían ser un problema, aunque los tornillos se aceleraron, la entrada comenzó a disminuir y las indicaciones desaparecieron después del primer millón). CodeMirror, donde no hay cálculos paralelos, apenas puede extraer esos volúmenes: puede parpadear tanto el resaltado de texto como de sintaxis. Dado que 100,000 líneas en un archivo son raras en el mundo real, hicimos la vista gorda a esto. Incluso con 40-50 mil líneas, Mónaco hace un excelente trabajo.
Conexión de Mónaco y uso de funciones básicas (por ejemplo, integración con Vue)
Conexión
Aquí daré ejemplos de código de componentes vue y usaré la terminología adecuada. Pero todo esto se transfiere fácilmente a cualquier otro marco o JS puro.
El código fuente de Mónaco se puede descargar en el sitio web oficial y poner en su proyecto, puede recogerlo de CDN, puede conectarse al proyecto a través de npm. Hablaré sobre la tercera opción y compilar usando webpack.
Ponemos monaco-editor y un complemento para ensamblar:
npm i -S monaco-editor npm i -D monaco-editor-webpack-plugin
En la configuración del paquete web, agregue:
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin'); module.exports = {
Si usa Vue y vue-cli-service para compilar, agregue a vue.config.js:
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin'); module.exports = {
Si no necesita todos los idiomas y características de Mónaco, para reducir el tamaño del paquete, puede transferir
MonacoWebpackPlugin
objeto con la configuración a
MonacoWebpackPlugin
:
new MonacoWebpackPlugin({ output: '',
Una lista completa de características e idiomas para el complemento está
aquí .
Crea y personaliza un editor
Importamos
editor
y llamamos
editor.create(el: HTMLElement, config?: IEditorConstructionOptions)
, pasando el elemento DOM en el que queremos crear el editor como primer argumento.
En el componente editor:
<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>
El contenedor para el editor necesariamente debe establecer la altura para que no resulte ser cero. Si crea el editor en un div vacío (con altura cero, su K.O.), Mónaco escribirá la misma altura en un estilo en línea en la ventana del editor.
El segundo argumento opcional para
editor.create
es la configuración del editor. Hay más de un centenar de opciones, una descripción completa de la interfaz
IEditorConstructionOptions se encuentra en la documentación.
Por ejemplo, estableceremos el idioma, el tema y el texto inicial y habilitaremos el ajuste de línea (de forma predeterminada, no están ajustados):
const config = { value: `function hello() { alert('Hello world!'); }`, language: 'javascript', theme: 'vs-dark', wordWrap: 'on' }; this.editor = editor.create(this.$refs.editor, config);
La función
editor.create
devuelve un objeto con la interfaz
IStandaloneCodeEditor . A través de él, ahora puede controlar todo lo que sucede en el editor, incluido el cambio de la configuración inicial:
Ahora para el dolor:
updateOptions
acepta un objeto con la interfaz
IEditorOptions , no IEditorConstructionOptions. Son ligeramente diferentes: IEditorConstructionOptions es más amplio, incluye las propiedades de esta instancia del editor y algunas globales.
updateOptions
propiedades de la
updateOptions
se cambian a través de
updateOptions
, global, a través de los métodos del
editor
global. Y en consecuencia, aquellos que cambian globalmente cambian para todas las instancias. Entre estas opciones está el
theme
. Crea 2 instancias con diferentes temas; y de ambos será el dado en el último (oscuro aquí). El
editor.setTheme('vs')
global
editor.setTheme('vs')
también cambiará el tema para ambos. Esto afectará incluso aquellas ventanas que se encuentran en otra página de su SPA. Hay pocos lugares, pero debes seguirlos.
<template> <div ref='editor1' class='editor'></div> <div ref='editor2' class='editor'></div> </template> <script> </script>
Eliminar editor
Cuando destruye una ventana de Mónaco, debe llamar al método de
dispose
; de lo contrario, no se borrarán todos los oyentes y las ventanas creadas después de esto pueden no funcionar correctamente, reaccionando a algunos eventos varias veces:
beforeDestroy() { this.editor && this.editor.dispose(); }
Pestañas
Las pestañas abiertas en el editor de archivos usan la misma ventana de Mónaco. Para cambiar entre ellos, se utilizan los métodos IStandaloneCodeEditor:
getModel
para guardar y
setModel
para actualizar el modelo del editor. El modelo almacena texto, posición del cursor, historial de acciones para deshacer y rehacer. Para crear un modelo de un nuevo archivo, se utiliza el método global
editor.createModel(text: string, language: string)
. Si el archivo está vacío, no puede crear un modelo y pasar
null
a
setModel
:
Ver código <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>
Modo de diferencia
Para el modo diff, debe usar otro método de
editor
al crear la ventana del editor:
createDiffEditor
:
<template> <div ref='diffEditor' class='editor'></div> </template> // ... mounted() { this.diffEditor = editor.createDiffEditor(this.$refs.diffEditor, config); } // ...
Toma los mismos parámetros que
editor.create
, pero la configuración debe tener una interfaz
IDiffEditorConstructionOptions , que es ligeramente diferente de la configuración del editor normal, en particular, no tiene
value
. Los textos para la comparación se establecen después de crear el
IStandaloneDiffEditor devuelto a través de
setModel :
this.diffEditor.setModel({ original: editor.createModel('const a = 1;', 'javascript'), modified: editor.createModel('const a = 2;', 'javascript') });
Menú contextual, paleta de comandos y teclas de acceso rápido
Monaco usa su propio menú contextual, que no es del navegador, donde hay navegación inteligente, un cursor múltiple para cambiar todas las ocurrencias y una paleta de comandos como en VS Code (paleta de comandos) con un montón de comandos y accesos directos útiles que aceleran la escritura de códigos:
Menú contextual de Mónaco
Paleta de comandos de Mónaco
El menú contextual se expande a través del método
addAction
(está disponible tanto en
IStandaloneCodeEditor
como en
IStandaloneDiffEditor
), que acepta un objeto
IActionDescriptor :
Para vincular solo un acceso directo a una acción sin mostrarlo en el menú contextual, se utiliza el mismo método, solo no se especifica el
contextMenuGroupId
la acción:
La paleta de comandos incluirá todas las acciones agregadas.
Consejos y autocompletar
Para estos fines, Mónaco utiliza
IntelliSense , que es genial. Puede leer y ver en las capturas de pantalla el enlace sobre cuánta información útil puede mostrar. Si su idioma aún no tiene un autocompletado, puede agregarlo a través de
registerCompletionItemProvider . Y para JS y TS, ya existe un método
addExtraLib
que le permite cargar definiciones de TypeScript para información sobre herramientas y autocompletar:
En el primer parámetro, la línea pasa las definiciones, en el segundo, opcional, el nombre de la lib.
Idiomas y temas personalizados
Mónaco tiene un módulo
Monarca para determinar la sintaxis de sus idiomas. La sintaxis se describe de manera bastante estándar: se establece la correspondencia entre los habituales y los tokens que son característicos de este lenguaje.
También puede crear un tema para sus tokens, un objeto con la interfaz
IStandaloneThemeData , e instalarlo en el
editor
global:
Ahora el texto en el idioma descrito se verá así:
Puede aplicar esta función, siempre que tenga suficiente imaginación. Por ejemplo, creamos un visor de registro de llamadas en nuestro panel para desarrolladores. Los registros son a menudo largos e incomprensibles, pero cuando se muestran con resaltado de sintaxis, búsqueda inteligente, líneas plegables / expansivas, los comandos necesarios (por ejemplo, Prettify params), resaltando todas las líneas de llamada por su id o traduciendo el tiempo en el registro a una zona horaria diferente, luego cava se vuelve mucho más fácil en ellos (se puede hacer clic en la captura de pantalla):
Conclusión
En resumen, diré que Mónaco es fuego. Después de meses de trabajar con él, tengo recuerdos excepcionalmente agradables. Si elige un editor para el código, asegúrese de ir a su
Zona de juegos y jugar con el código, ver qué más puede hacer. Quizás esto es exactamente lo que estás buscando.