JavaScriptでテキストエディタを作る

Toshiyuki Takahashi

Sendai Frontend Meetup #5

このスライドの見方

作るもの

技術スタック

言語/フレームワーク

動作環境

Hello World

pic.twitter.com/UZU5bX3sMQ

— Toshiyuki Takahashi (@tototoshi) May 3, 2020

動作原理

日本語入力難しい

JavaScriptでIMEの入力開始イベント(compositionstart)が取れるのだけど、そのイベントよりも先に入力内容のkeydownイベントが飛んでくるのしんどすぎる。

— Toshiyuki Takahashi (@tototoshi) May 3, 2020

シンタックスハイライト

シンタックスハイライトできた pic.twitter.com/XKY7KY7fE3

— Toshiyuki Takahashi (@tototoshi) May 4, 2020

シンタックスハイライト

シンタックスハイライト

window.onload = function() {
  console.log("Hello");
};
[
      {
        "elements": [
          { "types": [], "text": "window.onload = ", "id": 146 },
          { "types": ["keyword"], "text": "function", "id": 147 },
          { "types": [], "text": "() {", "id": 148 }
        ],
        "id": 242
      },
      {
        "elements": [
          { "types": [], "text": "  console.log(", "id": 149 },
          { "types": ["quote"], "text": "\"Hello\"", "id": 150 },
          { "types": [], "text": ");", "id": 151 }
        ],
        "id": 246
      },
      {
        "elements": [
          { "types": [], "text": "}", "id": 152 }
        ],
        "id": 248
      }
]

シンタックスハイライト

<div class="editor-content">
  <div class="line"><span class="line-content"><span class="">window.onload = </span><span
        class="keyword">function</span><span class="">() {</span></span></div>
  <div class="line cursor"><span class="line-content"><span class=""> console.log(</span><span
        class="quote">"Hello"</span><span class="">);</span><span class="cursor" tabindex="0"
        contenteditable="true"></span></span></div>
  <div class="line"><span class="line-content"><span class="">}</span></span></div>
</div>

いろいろ追加

undoとコピペができるようになった。 pic.twitter.com/Cj0D3BxdV1

— Toshiyuki Takahashi (@tototoshi) May 5, 2020

いろいろ追加

マウス操作

自作エディタ、マウス操作が少しできるようになった pic.twitter.com/vHd7R2U91f

— Toshiyuki Takahashi (@tototoshi) May 9, 2020

マウス操作

遅い🐢

富豪的な作りをしてるので3000行くらいになると遅くて無理っぽくなる。なにかしら最適化しないとダメそう。

— Toshiyuki Takahashi (@tototoshi) May 5, 2020

なぜ遅いのか

最適化

自作エディタ、最適化頑張ったらなんとか数千行なら耐えられるようになった。 pic.twitter.com/ZKPALnqXki

— Toshiyuki Takahashi (@tototoshi) May 16, 2020

最適化

最初が完全に富豪設計だったから大した話ではないんだけど、ビューのデータ構造を毎回生成するんじゃなくて直接編集するようにしたり、Reactの最適化、シンタックスハイライトのパーサーをWeb Workerに乗せたりした。

— Toshiyuki Takahashi (@tototoshi) May 16, 2020

万単位の要素を毎回renderしてるとReactめちゃくちゃ遅いのでとにかくrender減らすのを頑張る感じ。

— Toshiyuki Takahashi (@tototoshi) May 16, 2020

最適化(React)

最適化(Web Worker)

最適化(Web Worker)

Before

最適化(Web Worker)

After

コードの複雑化

Scala.js

Scala.js

Scala.jsでElectron、昨日は起動しただけだったけどipcとかも試してみて普通にできた。そりゃあできるだろって感じですが...

— Toshiyuki Takahashi (@tototoshi) May 20, 2020

CommonJSとかES Moduleで吐き出せるのでそれを普通にJSとしてビルドしてやれば良い。

— Toshiyuki Takahashi (@tototoshi) May 20, 2020

.d.ts 的なやつ

@JSImport("react-dom", JSImport.Namespace)
@js.native
object ReactDom extends js.Object {
  def render(reactElement: ReactElement,
             domElement: dom.Element): Unit = js.native
}

その他

仕上げ

自作エディタ、Scala.jsにした。そんでelectronに乗せた。 pic.twitter.com/SCc1idYfTZ

— Toshiyuki Takahashi (@tototoshi) May 19, 2020

Source Code

https://github.com/tototoshi/scala-js-electron-text-editor

まとめ