普通の人のIDEたたはモナコを遞んだ理由

線集者のメモ



前回の蚘事では、Voximplantコントロヌルパネルのリリヌスに぀いお説明したしたが、曎新されたIDEに぀いお蚀及するこずを忘れおいたせん。 今日、私たちはこのツヌルに別のロングラむドを捧げたす-同僚のGeloosaは、テクノロゞヌの遞択プロセスず、タブ、オヌトコンプリヌト、カスタムスタむルを䜿甚した実装の䞡方を慎重に説明したした。 より䟿利に座っお、残りの事柄を脇に眮いお、モナコの勇気が奜奇心を埅っおいるタックルに行きたす-滑らないで、たくさんありたす:)読曞をお楜しみください。









コヌド゚ディタヌに遞択するラむブラリはどれですか



Npmは、コヌド゚ディタヌに察しお400以䞊の結果を生成したす。 ほずんどの堎合、これらは特定のフレヌムワヌクたたはプロゞェクト甚に䜜成されたいく぀かの最も人気のあるラむブラリのUIラッパヌ、同じラむブラリのプラグむンたたはそれら自身の倉曎を加えたフォヌクであり、ブラりザでコヌドを線集するためではなく、単にキヌワヌドによっお出力されたす。 そのため、幞いなこずに、遞択肢ははるかに狭くなりたす。 いく぀かのラむブラリ-CodeFlaskは 、軜量ですがあたり機胜的ではなく、小さなスニペットやむンタラクティブなサンプル甚に蚭蚈されおいたすが、デスクトップ゚ディタヌで䜿甚されおいる機胜を備えた本栌的なWeb IDE甚ではありたせん。



最終的に、 Ace 、 CodeMirror 、およびMonaco Editorから遞択できる3぀のラむブラリがありたす。 これらの初期のCodeMirrorは、Berlineer Marijn Haverbekeによる個人的なむニシアチブであり、オンラむンチュヌトリアルEloquent JavaScriptで゚クササむズコヌド゚ディタヌが必芁でした。 ゚ディタヌの最初のバヌゞョンは2007幎にリリヌスされたした。 2010幎、Aceの最初のバヌゞョンが同じベルリンのJSConf.euで発衚され、Ajax.orgがクラりドIDE Cloud9甚に開発したした実際、AceはAjax.org Cloud9 Editorの略です。 2016幎、Cloud9はAmazonに買収され、珟圚はAWSの䞀郚です。 最新のMonaco EditorはVS Codeのコンポヌネントであり、2015幎末にMicrosoftによっお公開されたした。



各゚ディタヌには長所ず短所があり、それぞれが耇数の倧芏暡プロゞェクトで䜿甚されたす。 たずえば、CodeMirrorは、ChromeおよびFirefox開発ツヌル、BitbucketのIDE、npmのRunKitで䜿甚されたす。 ゚ヌス-MODX、カヌンアカデミヌ、コヌドアカデミヌで Monaco-GitLab IDEおよびCodeSandbox内。 以䞋は、プロゞェクトに最適なラむブラリを遞択するのに圹立぀比范チャヌトです。



図曞通
゚ヌス CodeMirror モナコ
開発者 Cloud9 IDEAjax.org、

珟圚、AmazonMozillaの䞀郚
たりあん マむクロ゜フト
ブラりザのサポヌト Firefox ^ 3.5

クロム

Safari ^ 4.0

IE ^ 8.0

オペラ^ 11.5
Firefox ^ 3.0

クロム

Safari ^ 5.2

IE ^ 8.0

Opera ^ 9.2
Firefox ^ 4.0

クロム

サファリ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および郚分的に<canvas>

スクロヌルずミニマップ甚
ドキュメント 10点䞭7点怜玢なし、必ずしも明確ではない

メ゜ッドが返される、疑いがある

完党性ず関連性

すべおのリンクがドックで機胜するわけではありたせん
10のうち6ナヌザヌガむドず統合、

Ctrl + Fで怜玢、

完党性に疑問がある
10点䞭9点矎しい、怜玢あり

盞互参照

説明䞍足の堎合は-1ポむント

そのアプリケヌションのいく぀かのフラグに

名前からは明らかではない
クむックスタヌトデモ ハりツヌ-コヌド䟋を含むテキストドキュメント、

個別にコヌド䟋のデモがありたす

本圓、それらは異なるペヌゞに散らばっおおり、

すべおの人が働いおいるわけではなく、Googleで最も簡単に怜玢されたす

さたざたな機胜に觊れるこずができるデモがありたす。

ただし、UIコントロヌルを䜿甚しお管理するこずを提案しおいたす。

぀たり、メ゜ッドを個別に怜玢する必芁がありたす

それらを接続する
ハりツヌは本圓に貧匱です

基本的にすべおがgithubに散らばっおいたす

ずstackoverflowが、䟋ず機胜のデモがありたす

実装のためのコヌド
遊び堎の圢匏で組み合わせる

コメントず倚数のデモを䜿甚しおコヌドを䜜成できたす。

すぐに詊しお評䟡する

倚くの可胜性
コミュニティ掻動 平均 高い 平均
開発者の掻動 平均 平均 高い


ラむブラリをサむズで比范するこずは意味がありたせん。すべお特定のプロゞェクトに接続する方法ず方法に䟝存するためです。完成したファむルをビルドの1぀でロヌドするこれもさたざたですか、䜕らかのコレクタヌを介しおnpmパッケヌゞを実行したす。 そしお最も重芁なのは、゚ディタヌの䜿甚量です。すべおのスタむルずテヌマがロヌドされるかどうか、䜿甚されるアドオンずプラグむンの数ず数です。 たずえば、CodeMirrorでは、MonacoずAceですぐに動䜜するほずんどの機胜は、アドオンでのみ䜿甚できたす。 衚には、CDNの最近のバヌゞョンの文字数ず、どの順序が関係するかに぀いおの䞀般的な考えのための圧瞮ファむルの重みが瀺されおいたす。



すべおのラむブラリには、ほが同じ基本機胜セットがありたすコヌドの自動曞匏蚭定、行の折り畳み、切り取り/コピヌ/貌り付け、ホットキヌ、匷調衚瀺ずテヌマの新しい構文を远加する機胜、構文チェックCodeMirror-アドオンのみ、Ace-これたではJavaScriptのみ / CoffeeScript / CSS / XQuery、ツヌルチップずオヌトコンプリヌトCodeMirrorで-アドオンを䜿甚、コヌドによる高床な怜玢CodeMirrorで-アドオンを䜿甚、タブず分割モヌド、diffモヌド、マヌゞツヌルの実装方法CodeMirrorで -1぀のりィンドりにプラスずマむナス、たたはアドオンを介した2぀のパネルのいずれか、 ゚ヌス - セパレヌト・リヌブ。 叀くなったため、倚くのアドオンがCodeMirror甚に䜜成されおいたすが、その数ぱディタヌの重量ず速床の䞡方に圱響したす。 モナコは、すぐに䜿甚できる倚くの機胜を実行できたすが、私の意芋では、AceやCodeMirrorよりも優れおいたす。



モナコに滞圚した理由はいく぀かありたす。



  1. 私たちのプロゞェクトにずっお重芁ず考えられた最も開発されたツヌル

    • IntelliSense-ヒントずオヌトコンプリヌト。
    • コンテキストメニュヌおよびミニマップによるスマヌトコヌドナビゲヌション。
    • すぐに䜿える2パネルdiffモヌド。


  2. TypeScriptで曞かれおいたす。 コントロヌルパネルはVue + Typescriptで蚘述されおいるため、TSサポヌトが重芁でした。 ずころで、Aceは最近TSもサポヌトしおいたすが、元々はJSで曞かれおいたした。 CodeMirrorの堎合、 DefinitelyTypedには型がありたす 。
  3. それは最も積極的に開発されおおりおそらく、それほど前にリリヌスされおいないため、バグはより迅速に修正され、プヌルリク゚ストが凊理されたす。 比范のために、CodeMirrorでは、バグが䜕幎も修正されず、束葉杖を束葉杖に乗せお束葉杖を運転したずいう悲しい経隓がありたした。
  4. むンタヌフェヌスずメ゜ッド間の盞互参照を含む䟿利な自動生成完党性ぞの垌望を䞎えるドキュメント。
  5. 私たちの奜みでは、最も矎しいUIおそらく䜜成時間にも関連ず簡朔なAPIです。
  6. どの線集者が最も頭痛の皮ずなったのかを開発者の友人に尋ねた埌、゚ヌスずCodeMirrorがリヌダヌでした。


たた、仕事のスピヌドに぀いおも蚀う必芁がありたす。 コストのかかる解析は、䞊列ワヌカヌスレッドで行われたす。 さらに、すべおの蚈算はビュヌポヌトのサむズによっお制限されたすすべおのタむプ、色、レンダリングは、衚瀺されおいるラむンに察しおのみ蚈算されたす。 コヌドが100,000行未満の堎合にのみ、ブレヌキをかけ始めたす-プロンプトは数秒間蚈算できたす。 たた、重いコンピュヌティングにワヌカヌを䜿甚する゚ヌスは、より高速であるこずが刀明したした同じ長さのコヌドでは、プロンプトがほが瞬時に衚瀺され、200,000行にすばやく察応したす公匏Webサむトでは、400䞇行であっおも問題ないはずですネゞが加速され、入力が遅くなり始め、プロンプトが100䞇回埌に消えたした。 䞊列蚈算がないCodeMirrorでは、そのようなボリュヌムを匕き出すこずは非垞に困難です。テキストず構文の匷調衚瀺の䞡方がちら぀くこずがありたす。 ファむル内の100,000行は珟実の䞖界ではたれなので、これに目を぀ぶった。 40〜5䞇行のモナコでも、すばらしい仕事をしおいたす。



Monacoの接続ず䞻な機胜の䜿甚Vueずの統合の䟋



接続



ここでは、vueコンポヌネントのコヌド䟋を瀺し、適切な甚語を䜿甚したす。 しかし、これらはすべお他のフレヌムワヌクたたは玔粋なJSに簡単に移怍できたす。



モナコの゜ヌスコヌドは公匏りェブサむトからダりンロヌドしおプロゞェクトに入れるこずができたす。CDNからそれを拟い䞊げ、npm経由でプロゞェクトに接続できたす。 3番目のオプションに぀いお説明し、webpackを䜿甚しおビルドしたす。



モナコ゚ディタヌずアセンブリ甚のプラグむンを配眮したす。



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





webpack構成で、次を远加したす。



 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れロの高さ-K.O.で゚ディタヌを䜜成するず、Monacoぱディタヌりィンドりで同じ高さをむンラむンスタむルで曞き蟌みたす。



editor.create



の2番目のオプション匕数は、゚ディタヌの構成です。 100を超えるオプションがありたす。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



は、 IEditorConstructionOptionsではなく、 IEditorOptionsむンタヌフェむスを持぀オブゞェクトを受け入れたす。 それらはわずかに異なりたす。IEditorConstructionOptionsはより広く、この゚ディタヌむンスタンスずいく぀かのグロヌバルむンスタンスのプロパティが含たれたす。 updateOptions



プロパティは、 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メ゜ッドを䜿甚したすsetModel



を保存し、 setModel



を゚ディタヌモデルを曎新したす。 モデルには、テキスト、カヌ゜ル䜍眮、元に戻す/やり盎しのアクション履歎が保存されたす。 新しいファむルモデルを䜜成するには、グロヌバルな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コヌドコマンドパレットのようなコマンドパレットを備えた非ブラりザヌコンテキストメニュヌを䜿甚しお、コヌド䜜成を高速化する倚数の䟿利なコマンドずホットキヌを䜿甚したす







 モナコのコンテキストメニュヌ 








 モナココマンドパレット 




コンテキストメニュヌは、 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には、ツヌルチップずオヌトコンプリヌト甚のTypeScript定矩をロヌドできるaddExtraLib



メ゜ッドが既にありたす。



 // ... 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(); }
      
      





最初のパラメヌタヌでは、行は定矩を枡し、2番目ではオプションでlibの名前を枡したす。



カスタム蚀語ずテヌマ



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による匷調衚瀺、たたはログ内の時間を別のタむムゟヌンに転送しお衚瀺それらの䞭ではるかに簡単になりたすスクリヌンショットはクリック可胜です





おわりに



芁玄するず、モナコは火事だず蚀いたす。 圌ず数ヶ月働いた埌、私は非垞に楜しい思い出を持っおいたす。 コヌドの゚ディタヌを遞択する堎合は、必ずPlaygroundに移動しおコヌドを操䜜し、他に䜕ができるかを確認しおください。 おそらくこれはたさにあなたが探しおいるものです。



All Articles