タイトルはもう面倒になった気持ちの表れ・・・。
今度の副業案件はVueということで、そのセットアップをしてみたが、なんかシュッといかず大変だったので、そのポイントをメモしておく。
最初に書いておくと、Svelteの場合は同様のプロジェクト構成でも困ったことないので、そういうとこやぞって思いながらやってた。
前提
- VSCodeではなくNeovim
- COCではなくNative LSP
- LSPのインストールはMason
まあそれなりにメジャーなセットアップなのではなかろうか。
この状態で、
- NuxtではなくVue 3単体
- SFCで
<script setup lang="ts">
なコンポーネントを書き - Viteでビルドする
っていう定番プロジェクトを、快適なDXではじめたかっただけなのに・・・という話。
LSPはVolar
いろんな経緯があったらしいが、どうやら最新のLSPはVolarというプロジェクトらしい。
volarjs/volar.js: 💙🌊 https://github.com/volarjs/volar.js
というより、VueのLSPまわりのツール群が、このVolar.jsをベースにしてるという表現が正しいとのこと。Volar.js自体は、もっとスコープの大きいやつっぽい。
vuejs/language-tools: ⚡ High-performance Vue language tooling based-on Volar.js https://github.com/vuejs/language-tools
Vue2の時代では、Veturというプロジェクトがその座にいたけど、Vue3ではLegacyになったらしい。
というわけで、VolarをLSPとしてインストールすればよい。
Masonを使ってる場合は、vue-language-server
ってのがそれ。v
なんたらって名前のLSPはいっぱいあってとても紛らわしいので注意。
ただこのVolarをインストールしたら、あとはmason-lsp-config
がいい感じにしてくれて終わり・・・とはいかない。
厳密には、.vue
ファイルではそれっぽい動作になるけど、.js
や.ts
ファイルから.vue
をimport
するところで拡張子を解決できずエラーになる。
というのも、LSPとしてvolar
が動くのは、filetype: vue
のときだけ。
なので、(java|type)script
なときにはtsserver
が動いてしまって、それでエラーになってる。
まあそんなに困ることはないので、これでも良いって判断もあるかもしれない。
.vue
ファイルを.ts
からimport
できるように
これを解決するためには、tsserver
に.vue
を認識させる必要がある。
が、ドキュメントには、VSCode向けのプラグインがあるよとだけ書かれてる。
TypeScript Vue Plugin (Volar) - Visual Studio Marketplace https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin
(いやいや他のエディタは?)
なんでこんな表現をしてるのかはわからんけど、個別にインストールしてtsconfig.json
にプラグインを追加すれば使えた。
"compilerOptions": {
"plugins": [
{ "name": "typescript-vue-plugin" }
]
}
これにて一件落着・・・かと思われた、が。
Volar Takeover mode
ただこのプラグイン、なんか注意書きがしてあり。
⚠️ It’s recommended to use take over mode instead of VSCode built-in TS plugin.
Takeoverモードっていうのは、
volar
が.vue
向けにTSのサーバーを起動する一方tsserver
も.ts
向けに別のインスタンスを起動する
という無駄を解消できるモードとのこと。つまりはvolar
で全部やるぜモードってことらしい。
Using Vue with TypeScript | Vue.js https://vuejs.org/guide/typescript/overview.html#volar-takeover-mode
推奨するならやっておくかということで、NeovimのLSPでこのモードを使うには、
require("mason-lspconfig").setup_handlers({
function(server)
local options = {}
if server == "volar" then
options.filetypes = {
"vue",
"typescript",
"javascript",
}
end
require("lspconfig")[server].setup(options)
end
})
というようにfiletypes
をいじるだけ。
ただこれと同時に、tsserver
を無効化しておく必要があって、こっちが大変。(さもないと結局2重に起動しちゃうから)
なんせその.ts
ファイルが、Vueのプロジェクトにおける.ts
ファイルか?を判断しないといけないが、それをどうやる?VSCodeはワークスペースごとに設定の余地があるのでそこでtoggleできるらしいけど。
いくつかパターンを考えてみたけど・・・、
typescript-language-server
をアンインストールしてしまうtsserver
のfiletypes
からtypescript
を消すfolke/neoconf.nvim
をいれる- Takeoverモードを諦める
どれもぱっとしない。
neoconf.nvim
はクリーンな案に見えるけど、なんでこのためだけに依存を増やして設定書いてファイルをコミットしないといけない・・・?ってのが正直な気持ち。
Using Volar’s Takeover mode in Neovim’s Native LSP Client https://theosteiner.de/using-volars-takeover-mode-in-neovims-native-lsp-client
.ts
ファイルで.vue
をimport
したいのなんて、正直マウントする瞬間くらいなので、すっぱり諦めるのも妥当だと個人的には思う。
ちなみにこのTakeoverモードは、巨大なプロジェクトになると欲しくなってくるらしく、そうならないように祈るばかりである。
モノレポでエラー
まだ終わらない。
ここまでの設定では、モノレポで次のようなエラーが出る。
RPC[Error] code_name = InternalError, message = “Request initialize failed with message: Can’t find typescript.js or tsserverlibrary.js
VolarがTypeScriptのLSを立てようとして、見つけられなくて、エラーになってる。
どうやらローカルのpackage.json
の隣のnode_modules
しか探してくれない(どのレイヤーの問題?)らしく、モノレポみたくそこにnode_modules
がない場合に困る。
で、それを解決するには、パスを自分で指定するか、関数を書くしかないらしい。
volar (Vue) - nvim-lspconfig https://nvim-lsp.github.io/configurations/volar/
いやいや面倒すぎる・・・!となったので、怠惰な私はシンボリックリンクを貼って済ませた。
ln -s ../../node_modules/ node_modules
とりあえず動いてるし、モチベーションも無なので、これでなんか問題が出たらその時に対処しようと思う。
まとめ
- Masonで
vue-language-server
を入れるのは必須.vue
ファイル内さえそれっぽく動けばいいなら、これで終わり
- モノレポの場合は、なんらかの方法でパスを通す必要がある
- 推奨のTakeoverモードを使いたいなら、なんらかの方法で
.ts
に対するtsserver
を無効に - Takeoverモードを使用しないなら、
typescript-vue-plugin
で済ませてもいい.ts
で.vue
を解決できなくてもいいならこれも不要
正直なところ、印象はよくないな〜。
これだけやってもまだ他のフレームワークのTSサポートより弱いし・・。