Help us understand the problem. What is going on with this article?

Vim で Prettier かけながら、TypeScript の型チェックを行う(with vim-lsp)

この記事は Vim Advent Calendar 2019 向けに書かれました。
もう一つネタがあって記事を書いていたのですが、
なんか微妙な出来だったので Advent Calendar とは別として投稿しようかなと思っています。

はじめに

この記事は

  • Vim を使っている
  • vim-lsp を使っている
  • TypeScript を書いている
  • prettier/eslint を連携させたい!

な人向けの記事です。

本題

vim-lsp を使って TypeScript の開発をしているならば、
使っている言語サーバは typescript-language-server ではありませんか?

よく出来ていますよね。快適です。

しかし、自分は下記の点が物足りませんでした。

Prettier でフォーマットできない

今どきのフロントエンドの現場であれば、Prettier を使うことが多いと思います。
当然ながら typescript-language-server によるフォーマットは Prettier によるそれではありません。

eslint のエラーが検出できない

typescript-language-server を使えば型エラーが即座にわかります。最高!
しかし、動作するコードでも lint を通らなければコミットはできません。
コードを書いている最中に unfixable な eslint エラーを知れたら嬉しいですよね。

解決方法

efm-langserver、もしくは diagnostic-languageserver を利用しましょう。

これらは linter/formatter などの CLI ツールを、LSP のインターフェースでラップしてくれる言語サーバです。
つまり、vim-lsp から eslint などを利用できるようになります。

しかし、はっきりいって設定はちょっと難しいです。
そのため、ここに eslint 向けの設定を書いてしまいます。
prettiereslint --fix 経由で実行することとしましょう。
eslint 経由で prettier を走らせる方法は他の記事をご参照ください。

設定方法

diagnostic-languageserver のインストール

npm i -g diagnostic-languageserver

eslint_d のインストール

npm i -g eslint_d
※ これを入れると、リントのパフォーマンスが劇的に向上します。

vim-lsp に設定を追加

  autocmd! vimrc User lsp_setup call lsp#register_server({
        \   'name': 'diagnostic-languageserver',
        \   'cmd': { info -> ['diagnostic-languageserver', '--stdio'] },
        \   'whitelist': [
        \     'typescript',
        \     'typescript.tsx',
        \     'typescriptreact',
        \     'javascript',
        \     'javascript.jsx',
        \     'javascriptreact',
        \   ],
        \   'initialization_options': {
        \     'linters': {
        \       'eslint': {
        \         'sourceName': 'eslint',
        \         'command': 'eslint_d',
        \         'args': ['--stdin', '--stdin-filename=%filename', '--no-color'],
        \         'rootPatterns': ['.eslintrc', '.eslintrc.js'],
        \         'formatLines': 1,
        \         'formatPattern': [
        \           '^\s*(\d+):(\d+)\s+([^ ]+)\s+(.*?)\s+([^ ]+)$',
        \           {
        \             'line': 1,
        \             'column': 2,
        \             'message': [4, ' [', 5, ']' ],
        \             'security': 3
        \           }
        \         ],
        \         'securities': {
        \            'error': 'error',
        \            'warning': 'warning'
        \         },
        \       },
        \     },
        \     'filetypes': {
        \       'javascript': 'eslint',
        \       'javascript.tsx': 'eslint',
        \       'javascriptreact': 'eslint',
        \       'typescript': 'eslint',
        \       'typescript.tsx': 'eslint',
        \       'typescriptreact': 'eslint',
        \     },
        \     'formatters': {
        \       'eslint': {
        \         'rootPatterns': ['.eslintrc', '.eslintrc.js'],
        \         'command': 'eslint_d',
        \         'args': ['--fix', '--fix-to-stdout', '--stdin', '--stdin-filename=%filename'],
        \         'isStdout': v:true,
        \         'isStderr': v:true,
        \       }
        \     },
        \     'formatFiletypes': {
        \       'javascript': 'eslint',
        \       'javascript.tsx': 'eslint',
        \       'javascriptreact': 'eslint',
        \       'typescript': 'eslint',
        \       'typescript.tsx': 'eslint',
        \       'typescriptreact': 'eslint'
        \     }
        \   }
        \ })

※ 完全におまじないですね。
※ diagnostic-languageserver 向けの設定しか提供できず悔しいです。
※ efm-langserver に関しても設定をいろいろ試している最中です。うまく動いたら移行予定だし、記事を書きます!

vim-lsp でフォーマットする

eslint のエラーは勝手に表示されますが、フォーマットは下記のコマンドを実行する必要があります。

:LspDocumentFormat

まとめ

これで vim-lsp を利用して、

  • TypeScript の賢い補完や型チェック、定義ジャンプを利用する
  • 合わせて、eslint による lint 結果を表示する
  • Prettier でフォーマットをかける

をすべて同時に満たすことができます。

vim-lsp は一つの filetype に複数の言語サーバを走らせることが可能で、強みです。
これに対応しているのは、coc.nvimvim-lspくらいしか知りません。

この設定を行って快適なフロントエンド開発をやっていきましょう!

以下、ハマった点など

TypeScript/JavaScript 両方への対応

eslint に STDIN 経由でファイルを渡した場合、そのテキストが TypeScript なのか JavaScript なのか eslint さんには判別できません。
そのため、--stdin-filename にファイル名を渡してやる必要がありました。

eslint を毎回起動してるとめちゃくちゃ遅いし重い問題への対応

最初、eslint_d を使わずに設定をしていましたが、死ぬほど遅かったです。
いろいろ調査していると、eslint_d というものを見つけて組み合わせて解決しました。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした