Nota do Editor
No
último artigo, falamos sobre o lançamento do painel de controle do Voximplant, sem esquecer de mencionar o IDE atualizado. Hoje, dedicamos uma
longa pausa a essa ferramenta - nosso colega
Geloosa descreveu cuidadosamente o processo de escolha de uma tecnologia e a implementação com guias, estilos de preenchimento automático e personalizados. Sente-se de forma mais conveniente, deixe de lado o resto dos seus assuntos e vá para o ataque, onde as tripas de Mônaco estão esperando pelos curiosos - não escorregue, há muitas delas :) Aproveite a leitura.
Qual biblioteca escolher para o editor de código?
Npm produz mais de 400 resultados para o editor de código. Na maioria das vezes, eles são invólucros da interface do usuário de várias das bibliotecas mais populares criadas para uma estrutura ou projeto específico, plug-ins para as mesmas bibliotecas ou seus garfos com modificações próprias, além de não serem para editar o código no navegador, eles simplesmente entram na saída por palavras-chave. Então, felizmente, a escolha é muito mais restrita. Mais algumas bibliotecas - como o
CodeFlask , leve, mas não muito funcional, projetada para pequenos trechos e exemplos interativos, mas não para um IDE da Web completo com a funcionalidade que estamos acostumados nos editores de desktop.
No final, temos três bibliotecas para escolher:
Ace ,
CodeMirror e
Monaco Editor . O primeiro deles, CodeMirror, foi uma iniciativa privada do
berliner Marijn Haverbeke , que precisava de um editor de código de exercício em seu tutorial online, o
Eloquent JavaScript . A primeira versão do editor foi lançada em 2007. Em 2010, a primeira versão do Ace foi apresentada no JSConf.eu no mesmo Berlim, que o Ajax.org desenvolveu para a sua nuvem IDE Cloud9 (na verdade, Ace significa Editor do Ajax.org Cloud9). Em 2016, o Cloud9 foi comprado pela Amazon e agora faz parte da AWS. O mais recente, o Monaco Editor, é um componente do VS Code e foi publicado pela Microsoft no final de 2015.
Cada editor tem suas próprias forças e fraquezas e é usado em mais de um grande projeto. Por exemplo, o CodeMirror é usado nas ferramentas de desenvolvedor do Chrome e Firefox, um IDE no Bitbucket, no RunKit em npm; Ace - na Codecademy, Khan Academy, MODX; Mônaco - no IDE do GitLab e no CodeSandbox. A seguir, é apresentado um gráfico de comparação que pode ajudá-lo a escolher a biblioteca mais adequada ao seu projeto.
| Bibliotecas |
| Ace | CodeMirror | Mônaco |
Desenvolvedor | IDE Cloud9 (Ajax.org), agora parte do AmazonMozilla | Marijn haverbeke | Microsoft |
Suporte do navegador | 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 |
Suporte de idioma (destaque da sintaxe) | > 120 | > 100 | > 20 |
Número de caracteres em versões mais recentes em cndjs.com | 366 608 (v1.4.3) | 394.269 (v5.44.0) | 2.064.949 (v0.16.2) |
O peso das últimas versões, gzip | 2.147 KB | 1.411 KB | 10.898 KB |
Renderização | Dom | Dom | DOM e parcialmente <canvas> (para rolagem e minimapa) |
A documentação | 7 de 10: nenhuma pesquisa, nem sempre clara que os métodos retornem, existem dúvidas em plenitude e relevância (nem todos os links funcionam no dock) | 6 em 10: mesclado com o guia do usuário, pesquise por Ctrl + F, existem dúvidas sobre completude | 9 de 10: linda, com pesquisa e referência cruzada -1 ponto por falta de explicação para algumas bandeiras cuja aplicação não é muito óbvio do nome |
Demonstrações de início rápido | Como fazer - documentos de texto com exemplos de código, separadamente, há demos com exemplos de código (verdade, eles estão espalhados em páginas diferentes, nem todo mundo trabalha e é pesquisado com mais facilidade pelo Google), há uma demonstração em que você pode tocar em diferentes recursos, mas propõe-se gerenciá-los por meio de controles da interface, ou seja, ainda devemos procurar separadamente métodos para conectá-los | Como fazer são realmente pobres basicamente tudo está espalhado no github e stackoverflow, mas há demonstrações de recursos com exemplos código para sua implementação | Combinado no formato de um playground: código com comentários e várias demonstrações, você pode tente imediatamente avaliar muitas possibilidades |
Atividade comunitária | Média | Alta | Média |
Atividade do desenvolvedor | Média | Média | Alta |
Não faz sentido comparar bibliotecas por tamanho, porque tudo depende do que e como conectar-se a um projeto específico: carregue o arquivo finalizado com uma das construções (que também variam) ou execute o pacote npm através de algum tipo de coletor. E o mais importante é quanto o editor é usado: se todos os estilos e temas estão carregados, quantos e quais complementos e plug-ins são usados. Por exemplo, no CodeMirror, a maioria das funcionalidades que funcionam no Mônaco e no Ace prontamente estão disponíveis apenas com complementos. A tabela mostra o número de caracteres nas versões recentes na CDN e o peso de seus arquivos compactados para uma idéia geral de quais pedidos estão envolvidos.
Todas as bibliotecas têm aproximadamente o mesmo conjunto de recursos básicos: formatação automática de código, linhas dobradas, recortar / copiar / colar, teclas de atalho, capacidade de adicionar novas sintaxes para realçar e ordenar, verificação de sintaxe (no CodeMirror apenas através de complementos, no Ace até agora apenas para JavaScript / CoffeeScript / CSS / XQuery), dicas de ferramenta e preenchimento automático (no CodeMirror - através de complementos), pesquisa avançada por código (no CodeMirror - através de complementos), métodos para implementar guias e modo de divisão, modo diferencial e uma ferramenta de mesclagem (no CodeMirror - com vantagens e desvantagens em uma janela ou em dois painéis através de um complemento, Ace - Lieb separado). Devido à sua idade, muitos complementos foram criados para o CodeMirror, mas seu número afetará o peso e a velocidade do editor. O Mônaco pode fazer muitas coisas prontas e, na minha opinião, melhor e em um volume maior que o Ace e o CodeMirror.
Ficamos no Mônaco por várias razões:
- As ferramentas mais desenvolvidas que consideramos críticas para o nosso projeto:
- IntelliSense - dicas e preenchimento automático;
- navegação inteligente de código no menu de contexto e através do minimapa;
- modo diferencial de dois painéis pronto para uso.
- Escrito em TypeScript. Nosso painel de controle está escrito em Vue + Typescript, portanto, o suporte ao TS era importante. A propósito, Ace recentemente também suporta TS, mas foi originalmente escrito em JS. Para CodeMirror, existem tipos em DefinitelyTyped .
- Ele é desenvolvido ativamente (possivelmente porque foi lançado há pouco tempo), os bugs são corrigidos mais rapidamente e as solicitações de pool são combatidas. Para comparação, com o CodeMirror, tivemos uma experiência triste, quando os bugs não eram corrigidos por anos e colocávamos uma muleta em uma muleta e a dirigíamos.
- Documentação conveniente gerada automaticamente (que dá esperança de que esteja completa) com referências cruzadas entre interfaces e métodos.
- Para nosso gosto, a interface do usuário mais bonita (provavelmente também relacionada ao horário da criação) e uma API concisa.
- Depois de perguntar aos amigos dos desenvolvedores qual dos editores causou mais dores de cabeça, Ace e CodeMirror foram os líderes.
Separadamente, deve-se dizer sobre a velocidade do trabalho. A análise cara ocorre em um encadeamento de trabalho paralelo. Além disso, todos os cálculos são limitados pelo tamanho da janela de exibição (todos os tipos, cores e renderização são calculados apenas para as linhas visíveis). Ele começa a frear apenas se o código contiver 100.000 linhas - os prompts podem ser calculados por vários segundos. O Ace, que também usa trabalhadores para computação pesada, mostrou-se mais rápido: no código do mesmo tamanho, os avisos aparecem quase instantaneamente e lida rapidamente com 200.000 linhas (no site oficial, afirma-se que mesmo 4 milhões de linhas não devem ser um problema, embora os parafusos foram acelerados, a entrada começou a desacelerar e as instruções desapareceram após o primeiro milhão). O CodeMirror, onde não há cálculos paralelos, dificilmente pode extrair esses volumes: pode piscar tanto o texto quanto a sintaxe. Como 100.000 linhas em um arquivo são raras no mundo real, fechamos os olhos para isso. Mesmo com 40 a 50 mil linhas, o Mônaco faz um excelente trabalho.
Conectando o Mônaco e usando recursos básicos (por exemplo, integração com o Vue)
Ligação
Aqui vou dar exemplos de código dos componentes vue e usar a terminologia apropriada. Mas tudo isso é facilmente transportado para qualquer outra estrutura ou JS puro.
O código-fonte do Mônaco pode ser baixado no site oficial e inserido no seu projeto, você pode buscá-lo na CDN, pode se conectar ao projeto via npm. Vou falar sobre a terceira opção e construir usando o webpack.
Colocamos o monaco-editor e um plug-in para montagem:
npm i -S monaco-editor npm i -D monaco-editor-webpack-plugin
Na configuração do webpack, adicione:
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin'); module.exports = {
Se você usar o Vue e o vue-cli-service para construir, adicione ao vue.config.js:
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin'); module.exports = {
Se você não precisar de todos os idiomas e recursos do Monaco, para reduzir o tamanho do pacote, poderá transferir
MonacoWebpackPlugin
objeto com as configurações para o
MonacoWebpackPlugin
:
new MonacoWebpackPlugin({ output: '',
Uma lista completa de recursos e idiomas para o plugin está
aqui .
Crie e personalize um editor
Importamos o
editor
e chamamos
editor.create(el: HTMLElement, config?: IEditorConstructionOptions)
, passando o elemento DOM no qual queremos criar o editor como o primeiro argumento.
No componente do 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>
O contêiner do editor deve necessariamente definir a altura para que não seja zero. Se você criar o editor em uma div vazia (com altura zero - seu K.O.), o Monaco gravará a mesma altura em um estilo embutido na janela do editor.
O segundo argumento opcional para
editor.create
é a configuração do editor. Há mais de uma centena de opções, uma descrição completa da interface
IEditorConstructionOptions está na documentação.
Por exemplo, definiremos o idioma, o tema e o texto inicial e ativaremos o agrupamento de linhas (por padrão, eles não são agrupados):
const config = { value: `function hello() { alert('Hello world!'); }`, language: 'javascript', theme: 'vs-dark', wordWrap: 'on' }; this.editor = editor.create(this.$refs.editor, config);
A função
editor.create
retorna um objeto com a interface
IStandaloneCodeEditor . Através dele, agora você pode controlar tudo o que acontece no editor, incluindo a alteração das configurações iniciais:
Agora, o problema:
updateOptions
aceita um objeto com a interface
IEditorOptions , não IEditorConstructionOptions. Eles são um pouco diferentes: IEditorConstructionOptions é mais amplo, inclui as propriedades dessa instância do editor e algumas globais.
updateOptions
propriedades da
updateOptions
são alteradas por meio de
updateOptions
, global - por meio dos métodos do
editor
global. E, consequentemente, aqueles que mudam globalmente mudam para todas as instâncias. Entre essas opções está o
theme
. Crie 2 instâncias com temas diferentes; y de ambos será o dado no último (escuro aqui). O
editor.setTheme('vs')
global
editor.setTheme('vs')
também mudará de assunto para ambos. Isso afetará até mesmo as janelas que estão em outra página do seu SPA. Existem alguns lugares assim, mas você precisa segui-los.
<template> <div ref='editor1' class='editor'></div> <div ref='editor2' class='editor'></div> </template> <script> </script>
Excluir editor
Ao destruir uma janela de Mônaco, você deve chamar o método de
dispose
, caso contrário, todos os ouvintes não serão limpos e as janelas criadas depois disso poderão não funcionar corretamente, reagindo a alguns eventos várias vezes:
beforeDestroy() { this.editor && this.editor.dispose(); }
Guias
As guias abertas no editor de arquivos usam a mesma janela do Mônaco. Para alternar entre eles, os métodos IStandaloneCodeEditor são usados:
getModel
para salvar e
setModel
para atualizar o modelo do editor. O modelo armazena texto, posição do cursor, histórico de ações para desfazer refazer. Para criar um modelo de um novo arquivo, o método global
editor.createModel(text: string, language: string)
é usado. Se o arquivo estiver vazio, você não poderá criar um modelo e passar
null
para
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 Diff
Para o modo diff, você precisa usar outro método de
editor
ao criar a janela do editor -
createDiffEditor
:
<template> <div ref='diffEditor' class='editor'></div> </template> // ... mounted() { this.diffEditor = editor.createDiffEditor(this.$refs.diffEditor, config); } // ...
Ele usa os mesmos parâmetros que o
editor.create
, mas a configuração deve ter uma interface
IDiffEditorConstructionOptions , que é um pouco diferente da configuração regular do editor, em particular, não possui
value
. Os textos para comparação são definidos após a criação do
IStandaloneDiffEditor retornado via
setModel :
this.diffEditor.setModel({ original: editor.createModel('const a = 1;', 'javascript'), modified: editor.createModel('const a = 2;', 'javascript') });
Menu de contexto, paleta de comandos e teclas de atalho
O Monaco usa seu menu de contexto que não é do navegador, onde há navegação inteligente, um cursor múltiplo para alterar todas as ocorrências e uma paleta de comandos, como no VS Code (paleta de comandos), com vários comandos e atalhos úteis que aceleram a escrita do código:
Menu de contexto Mônaco
Paleta de comandos do Mônaco
O menu de contexto é expandido através do método
addAction
(está disponível no
IStandaloneCodeEditor
e no
IStandaloneDiffEditor
), que aceita um objeto
IActionDescriptor :
Para vincular apenas um atalho a uma ação sem mostrá-lo no menu de contexto, o mesmo método é usado, apenas o
contextMenuGroupId
ação não é especificado:
A paleta de comandos incluirá todas as ações adicionadas.
Dicas e preenchimento automático
Para esses fins, o Monaco usa o
IntelliSense , o que é legal. Você pode ler e ver nas imagens o link de quantas informações úteis ele pode mostrar. Se o seu idioma ainda não tiver um preenchimento automático, você poderá adicioná-lo através do
registerCompletionItemProvider . E para JS e TS, já existe um método
addExtraLib
que permite carregar definições TypeScript para dicas de ferramentas e preenchimento automático:
No primeiro parâmetro, a linha passa as definições, no segundo, opcional, o nome da lib.
Temas e idiomas personalizados
O Mônaco possui um módulo
Monarch para determinar a sintaxe de seus idiomas. A sintaxe é descrita de maneira bastante padronizada: a correspondência entre os regulares e os tokens característicos desse idioma é definida.
Você também pode criar um tema para seus tokens - um objeto com a interface
IStandaloneThemeData - e instalá-lo no
editor
global:
Agora o texto no idioma descrito ficará assim:
Você pode aplicar esse recurso, desde que tenha imaginação suficiente. Por exemplo, criamos um visualizador de log de chamadas em nosso painel para desenvolvedores. Os logs geralmente são longos e incompreensíveis, mas quando são exibidos com destaque de sintaxe, pesquisa inteligente, linhas dobráveis / expansíveis, os comandos necessários (por exemplo, parâmetros de Prettify), destacando todas as linhas de chamada por seu ID ou traduzindo a hora no log para um fuso horário diferente e, em seguida, escavar torna-se muito mais fácil neles (a captura de tela é clicável):
Conclusão
Em resumo, direi que Mônaco é fogo. Depois de meses trabalhando com ele, tenho lembranças excepcionalmente agradáveis. Se você escolher um editor para o código, não deixe de ir ao
Playground e brincar com o código, veja o que mais ele pode fazer. Talvez seja exatamente isso que você está procurando.