## 概要
[[Vue Language Tools]]のv3がリリースされたとのことで、[[Neovim]]環境をv2からv3に移行してみた。
<div class="link-card-v2">
<div class="link-card-v2-site">
<img class="link-card-v2-site-icon" src="https://github.githubassets.com/favicons/favicon.svg" />
<span class="link-card-v2-site-name">GitHub</span>
</div>
<div class="link-card-v2-title">
Neovim
</div>
<div class="link-card-v2-content">
⚡ High-performance Vue language tooling based-on Volar.js - vuejs/language-tools
</div>
<img class="link-card-v2-image" src="https://opengraph.githubassets.com/226ec5d235c0c068e8f5b0364cf875f79a4351764be8b885310af140c8fe3c19/vuejs/language-tools" />
<a href="https://github.com/vuejs/language-tools/wiki/Neovim"></a>
</div>
上記は[[mason.nvim]]がメインストリームの案内だが、本ノートは[[mise]]がメインストリームとなっている。
## 環境
| 対象 | バージョン |
| ------------------ | ---------- |
| [[macOS]] | 15.5 |
| [[Neovim]] | 0.11.2 |
| [[nvim-lspconfig]] | d8f03bf |
| [[mise]] | 2025.7.1 |
| 対象 | 対応前バージョン | 対応後バージョン |
| ------------------------------------------------------- | -------- | -------- |
| [[TypeScript Language Server]] (ts_ls) | 4.3.4 | ❌ |
| [[vtsls]] | ❌ | 0.2.9 |
| [[@vue language-server\|@vue/language-server]] (vue_ls) | 2.2.10 | 3.0.1 |
| [[@vue typescript-plugin\|@vue/typescript-plugin]] | 2.2.10 | ❌ |
## 変更点
- [[TypeScript Language Server]] (ts_ls) の代わりに [[vtsls]] を使う
- [[@vue typescript-plugin|@vue/typescript-plugin]] の明示的な依存は削除し、代わりに[[@vue language-server|@vue/language-server]]の暗黙的な依存を使用する
## 変更後の関連イメージ
![[20250708_08_39_41.webp]]
![[TypeScript-Vue-LSP-Neovim.canvas|TypeScript-Vue-LSP-Neovim]]
> [!attention]
> あってるかは自信ない。
## 変更前の設定
### 前提
各LSP設定ファイルのパスは `nvim/after/lsp` 配下である。パスの由来は以下を参照。
<div class="link-card-v2">
<div class="link-card-v2-site">
<img class="link-card-v2-site-icon" src="https://publish-01.obsidian.md/access/35d05cd1bf5cc500e11cc8ba57daaf88/favicon-64.png" />
<span class="link-card-v2-site-name">Minerva</span>
</div>
<div class="link-card-v2-title">
📝nvim-lspconfigでruntimepath配下のluaディレクトリ配下に配置したLSP設定が読み込まれない
</div>
<div class="link-card-v2-content">Neovim 0.11環境でnvim-lspconfigのLSP設定がruntimepath配下のlua/lspディレクトリから読み込まれず、root_markersが上書きされる問題の原因はruntimepathの順序である。解決策は~/.config/nvim/after/luaへ移動することである。</div>
<img class="link-card-v2-image" src="https://publish-01.obsidian.md/access/35d05cd1bf5cc500e11cc8ba57daaf88/Notes/attachments/troubleshooting.webp" />
<a data-href="📝nvim-lspconfigでruntimepath配下のluaディレクトリ配下に配置したLSP設定が読み込まれない" class="internal-link"></a>
</div>
%%[[📝nvim-lspconfigでruntimepath配下のluaディレクトリ配下に配置したLSP設定が読み込まれない]]%%
### `ts_ls.lua`
```lua
return {
workspace_required = true,
root_markers = { "tsconfig.json", "jsconfig.json" },
init_options = {
plugins = {
{
name = "@vue/typescript-plugin",
location = os.getenv("HOME")
.. "/.local/share/mise/installs/npm-vue-typescript-plugin/latest/lib/node_modules/@vue/typescript-plugin ",
languages = { "javascript", "typescript", "vue" },
},
},
},
filetypes = {
"javascript",
"typescript",
"vue",
},
}
```
### `vue_ls.lua`
```lua
return {}
```
## インストール/アンインストール
### [[vtsls]]のインストール
```console
mise use -g npm:@vtsls/language-server
```
### [[TypeScript Language Server]]のアンインストール
[[VSCode]]のビルトイン拡張である[[TypeScript and JavaScript Language Features]]を[[LSP]]としてラップしている[[vtsls]]があるので不要。[[TypeScript]]はバッチリ。
```console
mise rm npm:typescript-language-server
```
### [[@vue typescript-plugin|@vue/typescript-plugin]]のアンインストール
[[@vue language-server|@vue/language-server]]の依存関係に[[@vue typescript-plugin|@vue/typescript-plugin]]が含まれており、そちらを使ったほうがバージョン差異も出ない。そのため不要。
```console
mise rm npm:@vue/typescript-plugin
```
### [[@vue language-server|@vue/language-server]]のアップデート
```console
mise up npm:@vue/language-server
```
## 変更後の設定
`ts_ls.lua` は削除する。
> [!add] #2025/08/07 追記
> [vue_lsがts_lsにも対応したらしい](https://github.com/neovim/nvim-lspconfig/pull/3986)
### `vtsls.lua`
```lua
local vue_language_server_path = os.getenv("HOME")
.. "/.local/share/mise/installs/npm-vue-language-server/latest/lib/node_modules/@vue/language-server"
local vue_plugin = {
name = "@vue/typescript-plugin",
location = vue_language_server_path,
languages = { "vue" },
configNamespace = "typescript",
}
return {
-- root_markersはデフォルトだと .git も含まれており、Denoプロジェクトでも有効になってしまうのを避けるため設定し直している
root_markers = { "package.json", "tsconfig.json", "jsconfig.json" },
workspace_required = true,
settings = {
vtsls = {
tsserver = {
globalPlugins = {
vue_plugin,
},
},
},
},
filetypes = { "typescript", "javascript", "javascriptreact", "typescriptreact", "vue" },
}
```
### `vue_ls.lua`
> [!add] #2025/07/15 追記
> [85379d0](https://github.com/neovim/nvim-lspconfig/commit/85379d0) のコミットで[[nvim-lspconfig]]の[[@vue language-server|vue_ls]]対応がされたため、`vue_ls.lua` の中身は `return {}` で動くようになった。よって以下のコードは不要。
```lua
return {
on_init = function(client)
client.handlers["tsserver/request"] = function(_, result, context)
local clients = vim.lsp.get_clients({ bufnr = context.bufnr, name = "vtsls" })
if #clients == 0 then
vim.notify("Could not found `vtsls` lsp client, vue_lsp would not work without it.", vim.log.levels.ERROR)
return
end
local ts_client = clients[1]
local param = unpack(result)
local id, command, payload = unpack(param)
ts_client:exec_cmd({
title = "vue_request_forward", -- You can give title anything as it's used to represent a command in the UI, `:h Client:exec_cmd`
command = "typescript.tsserverRequest",
arguments = {
command,
payload,
},
}, { bufnr = context.bufnr }, function(_, r)
local response_data = { { id, r.body } }
client:notify("tsserver/response", response_data)
end)
end
end,
}
```
### 他
`vim.lsp.enable({...})` で `vtsls` と `vue_ls` の指定が必要。
## トラブルシューティング
### executing vim.schedule lua callbackエラー
```error
Error 15:10:45 msg_show.lua_error Error executing vim.schedule lua callback: /Users/tadashi-aikawa/.config/nvim/after/lsp/vue_ls.lua:21: attempt to index local 'r' (a nil value)
stack traceback:
/Users/tadashi-aikawa/.config/nvim/after/lsp/vue_ls.lua:21: in function 'handler'
...im-macos-arm64/share/nvim/runtime/lua/vim/lsp/client.lua:681: in function ''
vim/_editor.lua: in function <vim/_editor.lua:0>
```
エラーメッセージでは分かりにくいが `vue_language_server_path` が間違っているとこのエラーになる。特に以下2点を確認する。
- `~/...` ではなく `os.getenv("HOME") .. "/..."` でホームディレクトリを指定しているか?
- パスは[[@vue language-server|@vue/language-server]]のrootを指しているか?
正しいパスだとこんな感じになる。最初は[[Language Server]]の実行ファイルを指定してハマった...。
```console
$ ll ~/.local/share/mise/installs/npm-vue-language-server/latest/lib/node_modules/@vue/language-server
drwxr-xr-x@ - 5 Jul 19:35 bin
.rw-r--r--@ 11 5 Jul 19:35 index.d.ts
.rw-r--r--@ 14k 5 Jul 19:35 index.js
drwxr-xr-x@ - 5 Jul 19:35 lib
.rw-r--r--@ 1.1k 5 Jul 19:35 LICENSE
.rw-r--r--@ 12 5 Jul 19:35 node.d.ts
.rw-r--r--@ 6.5k 5 Jul 19:35 node.js
drwxr-xr-x@ - 5 Jul 19:35 node_modules
.rw-r--r--@ 742 5 Jul 19:35 package.json
.rw-r--r--@ 49 5 Jul 19:35 protocol.d.ts
.rw-r--r--@ 860 5 Jul 19:35 protocol.js
```
## 参考
- [Versions 3 Upgrade guide for none-vscode editors. · vuejs/language-tools · Discussion #5456](https://github.com/vuejs/language-tools/discussions/5456)