エムスリーテックブログ

エムスリー(m3)のエンジニア・開発メンバーによる技術ブログです

EmacsでWebサービスを開発して8ヶ月が経ちました

この記事はエムスリー Advent Calendar 2018 の16日目の記事です。

こんにちは、エンジニアリンググループ新卒1年目の青木です。クラウド電子カルテ「M3 DigiKar」の開発に携わっています。We are hiring!!

今回は私のチームが開発しているWebサービス「M3 DigiKar」の Emacs での開発方法を紹介します。

f:id:blue0513:20181211002853p:plain:w200
皆さんお馴染みのエディタ Emacs

はじめに

「M3 DigiKar」は JavaScript、Ruby on Rails 等を用いて開発されています。そのため今回の記事では、それらの言語に関して「Syntax Check、Linter、補完、定義参照、Spell Check」等の機能を Emacs でどのように設定しているかを紹介することとします。

共通設定

まず言語によらず有用であろう package やその設定を紹介します。

検索・補完・定義参照

やはり検索や補完、定義参照が効かないと一流のエディタとは言えません。(cf. Emacsの補完&検索を超強化する)

company.el

いわずとしれたEmacsのインテリセンス用 package の大御所です。3rd party 製の package 開発も盛んで、LSP(Language Server Protocol)などへの対応も進んできています。 (cf. auto-complete.el)

;; 常に ON
(global-company-mode)

ivy.el & counsel.el & swiper.el

f:id:blue0513:20181211001332g:plain

いわゆるインクリメンタルサーチを支援してくれる package です。M-x を用いたコマンドの検索だけでなく、C-s による文字列検索や find-file など様々な部分をカバーしてくれる超有能な package なので是非使ってみてください!

;; counsel: M-x
;; swiper: M-x swiper
;; find-file: C-x C-f 
(ivy-mode 1)

dumb-jump.el

f:id:blue0513:20181211001448g:plain

どの言語でも いい感じに 定義箇所までコマンド1つでの移動を可能にする package です。tag 等の生成も不要なので簡単に扱えます。開発効率が30%以上は向上すると思います。

;; 実行: M-x dumb-jump-go
(setq dumb-jump-mode t)

Syntax Check & Lint

コンパイルしたり CI にかけてから Syntax Error とか Lint Error とかいう文字列に辟易するのは効率が悪い!ということでリアルタイムの Syntax Cheker や Linter は必須です。

flycheck.el

f:id:blue0513:20181211001515p:plain

絶対いれたほうがいいです 。各言語ごとに標準装備された(または 3rd party が開発した)Syntax Check Program や Linter と連携してリアルタイムで Warning や Error を吐いてくれます。

ここでは設定の基本のキだけ記載しますが、JS や Rails での詳細設定も後述します。

;; 自動起動
(setq flycheck-check-syntax-automatically 
  '(save idle-change mode-enabled))
    
;; コード変更後、3秒後にチェックする
(setq flycheck-idle-change-delay 3)

Spell Check

クラウド電子カルテの開発中によく直面する問題は タイポ です。医療専門用語が多いため、打ち慣れない文字列(exemption、redemption等)を入力する必要が多々あり、スペルチェッカーには大変お世話になりました。

flyspell.el

flycheck と同様にリアルタイムでスペルミスを訂正してくれる有能 package です。ユーザ定義の辞書ファイルの作成も可能なので、プロダクト特有の単語でも問題なくチェックしてくれます。

;; prog-mode なら常に ON
(add-hook 'prog-mode-hook 'flyspell-mode)

;; ispell の後継である aspell を使う。
;; CamelCase でもいい感じに spellcheck してくれる設定を追加
;; See: https://stackoverflow.com/a/24878128/8888451
(setq-default ispell-program-name "aspell")
(eval-after-load "ispell"
  '(add-to-list 'ispell-skip-region-alist '("[^\000-\377]+")))
(setq ispell-program-name "aspell"
  ispell-extra-args
  '("--sug-mode=ultra" "--lang=en_US" "--run-together" "--run-together-limit=5" "--run-together-min=2"))

Visualize

エディタを見たときに「ここが変更されている」や「変数名がおかしい」等に即座に気付ければ、その分ストレスフリーに開発できます。

git-gutter-plus.el

f:id:blue0513:20181211001536p:plain

Git 管理下の project で変更箇所を fringe で表示してくれる優れもの。

;; 常に ON
(global-git-gutter+-mode 1)

;; modify された箇所で実行すると、diff を inline で見ることができる
(global-set-key (kbd "C-x C-v") 'git-gutter+-show-hunk-inline-at-point)

color-identifiers-mode.el

f:id:blue0513:20181211001555j:plain

変数ごとに色分けし表示してくれるので、特定変数の使用箇所などが一目でわかります。

;; 起動後 ON にする
(add-hook 'after-init-hook 'global-color-identifiers-mode)

rainbow-delimiters.el

f:id:blue0513:20181211001610p:plain

対応するカッコをそのスコープごとに色分けしてくれます。不幸にもカッコが多くなってしまったときなどに便利。

;; prog-mode のとき常に ON にする
(add-hook 'prog-mode-hook 'rainbow-delimiters-mode)

JavaScript の設定

JavaScript(React や AngularJS)開発でのおすすめ package やその設定を紹介します。

Mode

React や AngularJS (そして Rails)が混在した project でコーディングする際、適切な mode を選べば Syntax Highlight や Auto Indent などの恩恵を受けることができます。特に M3 DigiKar は それら3つを同時に扱う必要がある ので、必須 mode です。

web-mode.el

web-mode は 多くの web template engine(ERB, React/JSX, Angularjs, Go Template etc)に対応している major mode です。React と AngularJS が混在していても Emacs 側でいい感じに取り扱ってくれるのでかなり重宝します。

;; See: https://qiita.com/kwappa/items/6bde1fe2bbeedc85023e

;; .js, .jsx を web-mode で開く
(add-to-list 'auto-mode-alist '("\\.js[x]?$" . web-mode))

;; .js でも JSX 編集モードに
(defvar web-mode-content-types-alist
  '(("jsx" . "\\.js[x]?\\'")))

;; コメントアウトの設定
(add-hook 'web-mode-hook
  '(lambda ()
    (add-to-list 'web-mode-comment-formats '("jsx" . "//" ))))

Syntax Check & Lint

コンパイルしたり CI にかけてから Syntax Error とか Lint Error とかいう文字列に辟易するのは効率が悪い!ということでリアルタイムの Syntax Cheker や Linter は必須です。(本日二度目)

flycheck.el

f:id:blue0513:20181211001629j:plain

M3 DigiKar では Linter として eslint を。型チェックとして flowtype を導入しているので、それらもリアルタイムにチェックします。

;; eslint 用の linter を登録
(flycheck-add-mode 'javascript-eslint 'web-mode)

;; flowtype 用の linter を登録
(flycheck-add-mode 'javascript-eslint 'web-mode)

;; 作業している project の node-module をみて、適切に
;; linter の設定を読み込む
(eval-after-load 'web-mode
  '(add-hook 'web-mode-hook #'add-node-modules-path))

Others

その他、開発でちょっと役立つ package です。

eslint-auto.el

f:id:blue0513:20181211002506g:plain

開いている buffer に対して eslint --fix (Lint Error の自動修正)を非同期で実行してくれます。

;; 実行: M-x eslint-fix-file
(defun eslint-fix-file ()
  (interactive)
  (call-process-shell-command
   (mapconcat 'shell-quote-argument
          (list "eslint" "--fix" (buffer-file-name)) " ") nil 0))

;; 実行後、buffer を revert する
;; 実行: M-x eslint-fix-file-and-revert
(defun eslint-fix-file-and-revert ()
  (interactive)
  (eslint-fix-file)
  (revert-buffer t t))

Ruby on Rails の設定

Ruby on Rails 開発でのおすすめ package やその設定を紹介します。

Mode

ruby-mode は当然として、rails 特有の Syntax Highlight や Snippet を効率よく利用したいので、いい感じの Minor Mode を設定します。

rspec-mode.el & rinari.el

;; ruby-mode 時に rinari-minor-mode も発火させる
(require 'rinari)
(add-hook 'ruby-mode-hook 'rinari-minor-mode)

;; rspec-mode 用の snippet を認識させる
(eval-after-load 'rspec-mode
  '(rspec-install-snippets))

Syntax Check & Lint

コンパイルしたり CI にかけてから Syntax Error とか Lint Error とかいう文字列に辟易するのは効率が悪い!ということでリアルタイムの Syntax Cheker や Linter は必須です。(本日三度目)

flycheck.el

f:id:blue0513:20181211001822j:plain

ruby の Syntax Checker & Linter だったら rubocop 一択ですので、それを flycheck と連携させます。

;; flycheck と rubocop を連携させる
(require 'rubocop)
(add-hook 'ruby-mode-hook 'rubocop-mode)
(add-hook 'ruby-mode-hook
  '(lambda ()
    (setq flycheck-checker 'ruby-rubocop)))

;; See: https://qiita.com/watson1978/items/debafdfc49511fb173e9
;; 独自に checker を定義する(お好みで)
(flycheck-define-checker ruby-rubocop
"A Ruby syntax and style checker using the RuboCop tool."
  :command ("rubocop" "--format" "emacs"
    (config-file "--config" flycheck-rubocoprc) source)
  :error-patterns
    ((warning line-start
      (file-name) ":" line ":" column ": " (or "C" "W") ": " (message) line-end)
    (error line-start
          (file-name) ":" line ":" column ": " (or "E" "F") ": " (message) line-end))
  :modes (ruby-mode motion-mode))

Others

その他、Rails 開発でちょっと役立つ package の紹介です。

rubocop-fix-file.el

f:id:blue0513:20181211001841g:plain

eslint-auto.elの rubocop 版です。必要に駆られて作りました。

;; M-x rubocop-fix-file
(add-to-list 'load-path "/path/to/rubocop-fix-file")
(require 'rubocop-fix-file)

inf-ruby.el

Ruby のプロセスと接続した REPL buffer を提供する package。さっと書いて、さっと実行するのに便利。

;; ruby の code-block を範囲選択して M-x ruby-send-block-and-go
(add-hook 'ruby-mode-hook 'inf-ruby-minor-mode)

その他の設定

その他、一般的ではないかもしれませんが開発で使用している便利な package や設定を紹介します。 

emacs-presentation-mode.el

f:id:blue0513:20181211001903g:plain 普段の font-size は 10pt くらいなんですが、それだと同僚とコードを見ながら相談がし辛いので、文字サイズを大きくしてやる必要があります。この package は 全ての buffer で文字サイズを拡大 してくれるので大変ありがたいです。

;; M-x presentation-mode
(add-to-list 'load-path "/path/to/emacs-presentation-mode")
(require 'presentation)

gitlab-open-mr.el

複数人で開発していると「このコードが書かれた経緯が知りたい」という場面に多々出会います。そういったときにgit blame して MR みて GitLab を開いて..... とするのは非常に効率が悪い! ということで必要に駆られて作りました。(cf. GitLabでもCommit Hashから該当MRを見つけたい)

;; vc-annotate 実行後に該当行で M-x gitlab-open-mr
(defun gitlab-open-mr ()
  (interactive)
  (let* ((rev-at-line (vc-annotate-extract-revision-at-line))
         (rev (car rev-at-line)))
    (shell-command (mapconcat 'shell-quote-argument
                  (list "gitlab-mr-from-commit" rev) " "))))

rspec-on-iterm.el & spec-jump.el

Rspec を実行するときに、一々指定するファイル名を打って実行する行を書いて......としたり、Model ファイルから Spec ファイルを探したり.....とするのは些末ですがストレスだったので必要に駆られて作りました。(cf. Emacsで該当のspecにパッと飛びたい)

;; M-x send-executable-text-to-iterm
;; M-x copy-executable-text
(add-to-list 'load-path "/path/to/rspec-on-iterm")
(require 'rspec-on-iterm)

;; M-x spec-jump
(add-to-list 'load-path "/path/to/spec-jump")
(require 'spec-jump)

おわりに

今回は Emacs で JS や Rails を効率的に開発するための設定を紹介しました。 紹介した package の数が多く、一つ一つの説明が薄くなってしまったのが悔やまれます.....!

WE NEED YOU!

エムスリーには言語やフレームワーク、DevOps だけでなく エディタが好きなエンジニア も多数所属しています! そんな多種多様なエンジニアが揃った環境に興味がある方は、ぜひお気軽にご連絡ください!