## 事象
[[Vue3]]のREADMEに従って作成したプロジェクトを開いても、[[Volar]]が機能しない ([[LSP]]として何も反応しない)。ただ、`LspInfo`コマンドを実行すると、[[Volar]]がattachされていることは確認できる。
[[nvim-lspconfig]]に関する設定部分は以下。
```lua
{
"neovim/nvim-lspconfig",
dependencies = {
{ "hrsh7th/cmp-nvim-lsp" },
{ "hrsh7th/nvim-cmp" },
{ "hrsh7th/cmp-buffer" },
{ "hrsh7th/cmp-path" },
{ "hrsh7th/cmp-cmdline" },
{ "b0o/schemastore.nvim" },
{ "onsails/lspkind.nvim" },
{ "L3MON4D3/LuaSnip" },
{ "saadparwaiz1/cmp_luasnip" },
},
config = function()
-- 中略
----------------------------------
-- lspconfig
----------------------------------
local lspconfig = require("lspconfig")
require("lspconfig.ui.windows").default_options.border = "single"
local capabilities = require("cmp_nvim_lsp").default_capabilities()
capabilities.textDocument.completion.completionItem.snippetSupport = true
-- 中略 --
-- [Volar] localのnode_modulesを優先する
local util = require("lspconfig.util")
local function get_typescript_server_path(root_dir)
local home = os.getenv("HOME")
local global_ts = home .. "/.local/share/mise/installs/node/18/lib/node_modules/typescript/lib"
local found_ts = ""
local function check_dir(path)
found_ts = util.path.join(path, "node_modules", "typescript", "lib")
if util.path.exists(found_ts) then
return path
end
end
if util.search_ancestors(root_dir, check_dir) then
return found_ts
else
return global_ts
end
end
local function organize_imports()
local params = {
command = "_typescript.organizeImports",
arguments = { vim.api.nvim_buf_get_name(0) },
title = "",
}
vim.lsp.buf.execute_command(params)
end
local function is_vue_or_nuxt()
-- wxt.config.tsはvue以外もあるけど...
return util.root_pattern("vite.config.ts", "nuxt.config.ts", "nuxt.config.js", "wxt.config.ts")
end
-- VueやNuxtのプロジェクトでのみ有効にする
lspconfig.volar.setup({
filetypes = { "typescript", "javascript", "javascriptreact", "typescriptreact", "vue", "json" },
capabilities = capabilities,
root_dir = is_vue_or_nuxt(),
on_new_config = function(new_config, new_root_dir)
new_config.init_options.typescript.tsdk = get_typescript_server_path(new_root_dir)
end,
})
-- VueやNuxtのプロジェクトでなければtsserverを使う
lspconfig.tsserver.setup({
capabilities = capabilities,
single_file_support = false,
root_dir = function(fname)
-- VueやNuxtのプロジェクトではVolarに任せるので無効にする
if is_vue_or_nuxt()(fname) then
return nil
end
return util.root_pattern("tsconfig.json")(fname)
end,
commands = {
OrganizeImports = {
organize_imports,
},
},
})
```
## 原因
[[Volar]]がv2.0になり、[[TypeScript]]の[[LSP]]を内包しなくなったから。
## 解決方法
### [[Hybrid Mode]]を使用する場合
[[Volar]]をsetupしたあと、[[tsserver]]のsetupで`plugins`に[[@vue typescript-plugin]]を指定する。ここではグローバルにインストールした`@vue/language-server`が依存する`@vue/typescript-plugin`を指定している。そのため、別途`@vue/typescript-plugin`をインストールする必要はない。
```lua
{
"neovim/nvim-lspconfig",
config = function()
-- 中略
----------------------------------
-- lspconfig
----------------------------------
local lspconfig = require("lspconfig")
require("lspconfig.ui.windows").default_options.border = "single"
local capabilities = require("cmp_nvim_lsp").default_capabilities()
capabilities.textDocument.completion.completionItem.snippetSupport = true
-- 中略 --
local home = os.getenv("HOME")
local function organize_imports()
local params = {
command = "_typescript.organizeImports",
arguments = { vim.api.nvim_buf_get_name(0) },
title = "",
}
vim.lsp.buf.execute_command(params)
end
lspconfig.volar.setup({
capabilities = capabilities,
})
lspconfig.tsserver.setup({
capabilities = capabilities,
single_file_support = false,
init_options = {
plugins = {
{
name = "@vue/typescript-plugin",
location = home
.. "/.local/share/mise/installs/node/20/lib/node_modules/@vue/language-server",
languages = { "javascript", "typescript", "vue" },
},
},
},
commands = {
OrganizeImports = {
organize_imports,
},
},
filetypes = {
"javascript",
"typescript",
"vue",
},
})
```
### [[Hybrid Mode]]を使用しない場合
[[Volar]]だけで[[Vue]]も[[TypeScript]]も対応できる構成となり、設定は一番シンプル。気になるのは、[[tsserver]]の機能が先行したとき、[[Volar]]の対応が少し遅れるかもしれないくらい。
```lua
{
"neovim/nvim-lspconfig",
config = function()
-- 中略
----------------------------------
-- lspconfig
----------------------------------
local lspconfig = require("lspconfig")
require("lspconfig.ui.windows").default_options.border = "single"
local capabilities = require("cmp_nvim_lsp").default_capabilities()
capabilities.textDocument.completion.completionItem.snippetSupport = true
-- 中略 --
lspconfig.volar.setup({
capabilities = capabilities,
filetypes = { "typescript", "javascript", "javascriptreact", "typescriptreact", "vue" },
init_options = {
vue = {
hybridMode = false,
},
},
})
```
## 参考
- [Version 2 stop working with nvim lsp · Issue \#3925 · vuejs/language\-tools](https://github.com/vuejs/language-tools/issues/3925)
- [nvim\-lspconfig/doc/server\_configurations\.md at master · neovim/nvim\-lspconfig](https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md#tsserver)
- [docs: update readme with neovim lspconfig setup by RayGuo-ergou · Pull Request #4134 · vuejs/language-tools](https://github.com/vuejs/language-tools/pull/4134/files)