vuejs / language-tools

⚡ High-performance Vue language tooling based-on Volar.js
https://marketplace.visualstudio.com/items?itemName=Vue.volar
MIT License
5.76k stars 388 forks source link

Version 2 stop working with nvim lsp #3925

Closed RayGuo-ergou closed 6 months ago

RayGuo-ergou commented 6 months ago

Update: check readme.


tldr:

local mason_registry = require('mason-registry')
local ts_plugin_path = mason_registry.get_package('vue-language-server'):get_install_path() .. '/node_modules/@vue/language-server/node_modules/@vue/typescript-plugin'

local servers = {
  tsserver = {
    init_options = {
      plugins = {
        {
          name = '@vue/typescript-plugin',
          location = ts_plugin_path,
          -- If .vue file cannot be recognized in either js or ts file try to add `typescript` and `javascript` in languages table.
          languages = { 'vue' },
        },
      },
    },
    filetypes = { 'typescript', 'javascript', 'javascriptreact', 'typescriptreact', 'vue' },
  },
  volar = {},
}

local mason_lspconfig = require('mason-lspconfig')

-- Auto cmd (LspAttach) to setup keybind, codelens, and formatting stuff
-- I assume everyone should have this configured already but just for reference
-- @see https://github.com/RayGuo-ergou/dotfiles/blob/cdf866790b1daa27444bd9991025740c8eb74c5b/nvim/lua/ergou/util/lsp.lua#L43
Util.lsp.lsp_autocmd()

local capabilities = vim.lsp.protocol.make_client_capabilities()
-- If you need cmp
capabilities = vim.tbl_deep_extend('force', capabilities, require('cmp_nvim_lsp').default_capabilities())
mason_lspconfig.setup({
ensure_installed = vim.tbl_keys(servers),
handlers = {
    function(server_name)
    local server = servers[server_name] or {}
    server.capabilities = vim.tbl_deep_extend('force', {}, capabilities, server.capabilities or {})
    require('lspconfig')[server_name].setup(server)
    end,
},
})

Hi,

I am having issue to run volar@2.0.1 with neovim lsp.

cmd: vue-language-server --stdio

With 1.8.27: image image image

With 2.0.1: image image image

RayGuo-ergou commented 6 months ago

Can I see your config? I cannot get goto definition and error diagnostics working in templates

These two files for LSP.

https://github.com/RayGuo-ergou/dotfiles/blob/41e0702e359740af617e7d12c47bee3a85119c2f/nvim/lua/ergou/util/lsp.lua

https://github.com/RayGuo-ergou/dotfiles/blob/41e0702e359740af617e7d12c47bee3a85119c2f/nvim/lua/ergou/plugins/lsp.lua

amritk commented 6 months ago

Here is my working config if anyone needs:

lspconfig.tsserver.setup({
  on_init = on_init,
  on_attach = on_attach,
  capabilities = capabilities,
  filetypes = {
    "typescript",
    "javascript",
    "vue",
  },
  init_options = {
    plugins = {
      {
        name = "@vue/typescript-plugin",
        location = "/home/amritk/.asdf/installs/nodejs/20.10.0/lib/node_modules/@vue/typescript-plugin",
        languages = { "javascript", "typescript", "vue" },
      },
    },
    typescript = {
      serverPath = "/home/amritk/.asdf/shims/tsserver",
      tsdk = "/home/amritk/.asdf/installs/nodejs/20.10.0/lib/node_modules/typescript/lib",
    },
  },
})

lspconfig.volar.setup({
  init_options = {
    typescript = {
      serverPath = "/home/amritk/.asdf/shims/tsserver",
      tsdk = "/home/amritk/.asdf/installs/nodejs/20.10.0/lib/node_modules/typescript/lib",
    },
  },
  capabilities = capabilities,
  on_init = on_init,
  on_attach = on_attach,
  filetypes = {
    "vue",
  },
})

edit: just updated my config based on the comments below, not sure if this doubles the LSP? or is there a way to only use volar on the template + style. Maybe @CofCat456 can help clarify?

remvn commented 5 months ago

From what I understand, <script> tag is now using tsserver with a plugin <template> and <style> is still using volar lsp (tried disable volar and they dont work) Will they somehow move into tsserver as a plugin too? or we will keep using 2 separate lsp?

CofCat456 commented 5 months ago

據我了解,標籤現在正在與插件一起<script>使用,並且仍在使用 volar lsp (嘗試禁用 volar,但它們不起作用) 它們是否也會以某種方式移動到 tsserver 作為插件?或者我們將繼續使用 2 個單獨的 lsp?tsserver <template>``<style>

You need to use Volar lsp to work with template normally. e.g., v-if

So both lsp are necessary.

nevenduranec commented 5 months ago

How does volar resolve alises in jsconfig.json? On version < 2 it works but on latest v2 it's not working (monorepo, the jsconfig.js is not in the project top level root) (neovim 0.9.5).

Edit:

Goto definition and lsp references don't work as well (gd when the cursor is on the workd axios for example import axios from 'axios').

catgoose commented 5 months ago

How does volar resolve alises in jsconfig.json? On version < 2 it works but on latest v2 it's not working (monorepo, the jsconfig.js is not in the project top level root) (neovim 0.9.5).

Edit:

Goto definition and lsp references don't work as well (gd when the cursor is on the workd axios for example import axios from 'axios').

Are you using auto import and vue component from unplugin?

RayGuo-ergou commented 5 months ago

Heads up after 2.0.7.

catgoose commented 5 months ago

Heads up after 2.0.7.

  • Even in the change log it says hybrid mode is disabled by default. However, I think that's only the case for vscode, with only lsp it seems default to be true: source.

  • 4061 has been reverted, thus mason volar path + typescript-plugin would not work. For @catgoose can you try install @vue/language-server globally with npm? I tried with npm and it should have {language server}/node_modules/@vue/language-server/node_modules/@vue/typescript-plugin. ( mason indeed uses npm to install things from my memory )

I got everything working. My issue was I use unplugin vue components and I didn't add component.d.ts to tconfig.app.json

CofCat456 commented 5 months ago

過後請注意2.0.7

  • 即使在更改日誌中,它也表示預設混合模式會失效。但是,我認為這只是 vscode 的情況,只有 lsp 似乎預設為 true: source。 因此,如果您想終止混合模式,請嘗試:
    volar = {
    filetypes = { 'typescript', 'javascript', 'javascriptreact', 'typescriptreact', 'vue' },
    init_options = {
      vue = {
        hybridMode = false,
      },
    },
    },
    -- tsserver = {}
  • 重構(語言伺服器):重新匯出@vue/typescript-plugin #4061已被恢復因此,mason volar路徑+typescript-plugin將失效。@catgoose您可以@vue/language-server使用全局安裝npm嗎?我嘗試使用 npm ,它應該有{language server}/node_modules/@vue/language-server/node_modules/@vue/typescript-plugin。 ( mason 確實使用 npm 來安裝我記憶中的東西)

Can I ask about your test results. Does hybridMode work in neovim?

I tried to turn off tsserver to use hybridMode, but it doesn't seem to work.

RayGuo-ergou commented 5 months ago

I indeed tested none-hybrid mode with following diff:

- tsserver = {
-      init_options = {
-        plugins = {},
-      },
-      filetypes = { 'typescript', 'javascript', 'javascriptreact', 'typescriptreact', 'vue' },
-    },

- volar = {},
+ volar = {
+      filetypes = { 'typescript', 'javascript', 'javascriptreact', 'typescriptreact', 'vue' },
+      init_options = {
+        vue = {
+          hybridMode = false,
+        },
+      },
+    },

Result: image image image

CofCat456 commented 5 months ago

@RayGuo-ergou It looks good, but this means if we want to use the non-hybrid mode, we must configure it like the previous takeover mode, letting Volar handle .ts files, right?

RayGuo-ergou commented 5 months ago

but this means if we want to use the non-hybrid mode, we must configure it like the previous takeover mode, letting Volar handle .ts files, right?

In general yes, but actually if you would like to use tsserver for none-vue project is also dealable for neovim users as the biggest advantage of using neovim is we have a program language to make our editor to the shape we want. (e.g. check if app.vue or src/app.vue exist in root).

catgoose commented 5 months ago

but this means if we want to use the non-hybrid mode, we must configure it like the previous takeover mode, letting Volar handle .ts files, right?

In general yes, but actually if you would like to use tsserver for none-vue project is also dealable for neovim users as the biggest advantage of using neovim is we have a program language to make our editor to the shape we want. (e.g. check if app.vue or src/app.vue exist in root).

Oh nice we can use takeover mode again? It seemed to work so much better for my setup. I use neoconf to accomplish takeover.

RayGuo-ergou commented 5 months ago

we can use takeover mode again?

Yes none-hybrid == take over 😜

catgoose commented 5 months ago
hybridMode = false,

This is kind of a nitpick but why use hybridMode pascal case when everything else uses snake case?

RayGuo-ergou commented 5 months ago

We use snake case in lua e.g. this time from nvim-lspconfig, but the init_options is send options to lsp. Every lsp may have different code style, pascal case is used in volar project.

gegoune commented 5 months ago

This is all pretty confusing. :) Should I revert my changes I made upgrading to 2.x?

@@ -112,17 +112,21 @@ local servers = {
   tsserver = {
-    root_dir = function(fname)
-      if util.root_pattern('vite.config.ts')(fname) then return nil end
-      return util.root_pattern('tsconfig.json', 'package.json', 'jsconfig.json', '.git')(fname)
-    end,
     init_options = {
+      plugins = {
+        {
+          name = '@vue/typescript-plugin',
+          location = '/Users/gegoune/.pnpm-global/5/node_modules/@vue/typescript-plugin',
+          languages = { 'typescript', 'vue' },
+        },
+      },
       preferences = {
         disableSuggestions = true,
         importModuleSpecifierPreference = 'non-relative',
       },
     },
+    filetypes = { 'javascript', 'typescript', 'vue' },
     settings = {
       completions = {
         completeFunctionCalls = true,

Mainly, should we once again disable tsserver for Vue projects and enable hybridMode in Volar?

nevenduranec commented 5 months ago

How does volar resolve alises in jsconfig.json? On version < 2 it works but on latest v2 it's not working (monorepo, the jsconfig.js is not in the project top level root) (neovim 0.9.5). Edit: Goto definition and lsp references don't work as well (gd when the cursor is on the workd axios for example import axios from 'axios').

Are you using auto import and vue component from unplugin?

No, it's a plain old vue 2 project, no typescript at all.

wcheek commented 5 months ago

There is some official documentation for what config is necessary for fixing this issue. Seems like the volar team didn't give their community dependents much of a heads-up...

TLDR. I've added this to my init.lua and solved the issue for "@vue/language-server": "^2.0.7"

local lspconfig = require("lspconfig")

-- Allows volar to run embedded tsserver
lspconfig.volar.setup({
    filetypes = { 'typescript', 'javascript', 'javascriptreact', 'typescriptreact', 'vue' },
  init_options = {
    vue = {
      hybridMode = false,
    },
  },
})

Edit: Actually, this gave me some LSP capabilities but not all.

I found another suggested config in nvim-lspconfig documentation that seems to be working. You will have to install @vue/typescript-plugin globally and edit the location for your case.

-- init.lua
local lspconfig = require("lspconfig")

lspconfig.volar.setup({})
lspconfig.tsserver.setup({
  init_options = {
    plugins = {
      {
        name = "@vue/typescript-plugin",
        location = "C:\\Users\\wcheek\\AppData\\Roaming\\npm\\node_modules\\@vue\\typescript-plugin\\",
        languages = { "javascript", "typescript", "vue" },
      },
    },
  },
  filetypes = {
    "javascript",
    "typescript",
    "vue",
  },
})
Jtcruthers commented 5 months ago

I have a bunch of projects with both Vue2 and Vue3 and got the default tsserver working well with Mason and Neoconf. I installed tsserver, volar, and vuels (vetur) with Mason.

In all of my Vue2 projects, I disable both tsserver and volar via the local .neoconf.json:

{
  "lspconfig": {
    "tsserver": false,
    "volar": false
  }
}

Then in all of my Vue3 projects, I disable vuels and set a boolean to add the plugin in my local .neoconf.json:

{
  "is-volar-project": true,
  "lspconfig": {
    "vuels": false
  }
}

I globally install the latest @vue/typescript-plugin.

Then in my neovim lua config, I use mason-lspconfig to config tsserver with the plugin:

require("mason-lspconfig").setup_handlers {
  function(server_name)
    require("lspconfig")[server_name].setup {
      capabilities = lsp_capabilities,
    }
  end,
   ["tsserver"] = function()
    local neoconf = require("neoconf")

    local init_options = {}
    if neoconf.get("is-volar-project") then
      init_options = {
        plugins = {
          {
            name = "@vue/typescript-plugin",
            location = "/path/to/global/node_modules/@vue/typescript-plugin",
            languages = {"javascript", "typescript", "vue"},
          },
        },
      }
    end

    require("lspconfig").tsserver.setup {
      filetypes = { "vue", "javascript", "javascriptreact", "javascript.jsx", "typescript", "typescriptreact", "typescript.tsx" },
      compilerOptions = {
        noErrorTruncate = true
      },
      init_options = init_options,
    }
  end
}

This is working well for me. Vue2 projects use the vuels lsp, Vue3 projects use volar and tsserver with the @vue/typescript-plugin, and non-Vue ts projects do not import the vue plugin. Only callout is the global installation of the plugin's version has to match the version of volar installed via Mason.

Jarmos-san commented 5 months ago

I'm not a major fan of polluting and bloating my hard disk and hence did not want to resort to installing neither typescript nor the plugin @vue/typescript-plugin globally! Yeah I know HDD space is cheap and all but its just my personal preference and that's how I like my development environment to be.

Any way, looks like the Vue projects requires both typescript and @vue/typescript-plugin installed (which btw should already be installed as dev dependencies). And as long as you follow the instructions in the README it should work flawlessly. For further reference here are the Neovim configurations I use for my Vue projects and the screenshots of one such project I'm currently working on.

image image image

I'm pretty sure there might be some caveats to the way I've configure Neovim (for now) but I couldn't find time to investigate further. Regardless, I guess as long as it works as I expect it to I will keep procrastinating! :laughing:

k0mpreni commented 4 months ago

Did it still fully work? I still don't get full lsp, mostly missing the types on components and error for missing required components. For the types it always takes the shims on a project. I checked and it's working on vscode (I know it can mean anything) on this project and working with brand new vue project. This is why I'm confused.

Here is my config: https://github.com/k0mpreni/nvim-lua/blob/7c130638d2f2d55f7dfd6bf3ebbbb154853481fb/after/plugin/lsp.lua#L18

Using mason: typescript-language-server 4.3.3 vue-language-server 2.0.13

I tried the readme config and the setup from catgoose, without success.

edit: added plugin versions

Jarmos-san commented 4 months ago

@k0mpreni try adding these lines to your Neovim config:

lspconfig.volar.setup({
   filetypes = {'typescript', 'javascript', 'javascriptreact', 'typescriptreact', 'vue', 'json'},
   init_options = {
       vue = {
          hybridMode = false
       },
   }
})

It is based on the recommended configurations which you would find in the README (see my previous comment for source).

k0mpreni commented 4 months ago

Tried it as well @Jarmos-san , unfortunately same result, the type definition are from the shims and not from the component itself.

RayGuo-ergou commented 4 months ago

image

Is this what are you referring to?

mostly missing the types on components and error for missing required components

One thing i can think of is: are the files included in tsconfig.json?

btw if you want to set hybridMode = false you should remove vue from tsserver, otherwise you will have 2 typescript server running at same time.

k0mpreni commented 4 months ago

Is this what are you referring to?

Exactly to those. It also seems that you have the shims as types no? Component types are mostly useful for me as I want to have errors when I'm missing a required prop and if possible the props completion. Is it working for you @RayGuo-ergou ?

One thing i can think of is: are the files included in tsconfig.json?

Yes, it's in the tsconfig.json indeed. I also have it working in vscode with hybridMode on (had to put a specific tsdk as my project is not using typescript v5 yet).

RayGuo-ergou commented 4 months ago

Component types are mostly useful for me as I want to have errors when I'm missing a required prop and if possible the props completion. Is it working for you

Yes they are working for me. image

image

defineProps({
  msg: {
    type: String,
    required: true,
  },
})

had to put a specific tsdk as my project is not using typescript v5 yet

This might be the reason, the tsdk running on LSP does nothing to your project, as a LSP is just a stand along server maybe give typescript: "^5" a try.

RayGuo-ergou commented 4 months ago

image image

btw have not used vscode for ages but it seems give the same shim type.

k0mpreni commented 4 months ago

Ok so it seems that it's just a ts version issue. Strange however that in vscode when I explicitly say volar to use typescript v5 it's working, but not with the nvim config. Best would be to update my project to ts v5 anyway. Thanks!

RayGuo-ergou commented 4 months ago

If you are using hybrid mode, the option tsdk in tsserver does not exit. If you want to declare the typescirpt path you should use tsserver.path.

see: https://github.com/typescript-language-server/typescript-language-server/blob/b224b878652438bcdd639137a6b1d1a6630129e4/docs/configuration.md?plain=1#L11

https://github.com/typescript-language-server/typescript-language-server/blob/b224b878652438bcdd639137a6b1d1a6630129e4/docs/configuration.md?plain=1#L41

k0mpreni commented 4 months ago

Ok so this is also doing the trick meanwhile I upgrade my project to v5. Can ditch vscode again thanks a lot!

For future reference: If your project is not using a compatible version of TS with volar Here is my config: https://github.com/k0mpreni/nvim-lua/blob/5948d7c8346f23863da68019929775b63321328c/after/plugin/lsp.lua#L17

If it's compatible, you don't need to override tsserver.path

ulises-castro commented 2 months ago

Context: This is a Vue 3 project without typescript.

This worked for me:

Notice I'm using some custom on_attach with Lspsaga.

-- Using Lspsaga If you like to ignore this, comment `on_attach = on_attach` 
local on_attach = function(client, bufnr)
  local opts = { noremap = true, silent = true, buffer = bufnr }
  keymap.set("n", "<leader>rn", "<cmd>Lspsaga rename<CR>", opts) -- smart rename
  vim.keymap.set("n", "K", "<cmd>Lspsaga hover_doc")
end

-- No need to set `hybridMode` to `true` as it's the default value
lspconfig.volar.setup({
  on_attach = on_attach,
  filetypes = { "typescript", "javascript", "javascriptreact", "typescriptreact", "vue" },
  init_options = {
    vue = {
      hybridMode = false,
    },
  },
})
suinming commented 6 days ago

I am using vetur for vue2 project and volar for vue3 project. Using a simple function to detect the vue version.

config = function()
    local capabilities = require("mini.completion").completefunc_lsp()
    local lspconfig = require("lspconfig")
    local util = require("lspconfig.util")
    local mason_registry = require("mason-registry")
    local vue_language_server_path = mason_registry.get_package("vue-language-server"):get_install_path()
        .. "/node_modules/@vue/language-server"
    -- js, ts
    lspconfig.ts_ls.setup({
        init_options = {
            plugins = {
                {
                    name = "@vue/typescript-plugin",
                    location = vue_language_server_path,
                    languages = { "vue" },
                },
            },
        },
        filetypes = { "typescript", "javascript", "javascriptreact", "typescriptreact", "vue" },
    })
    -- vue
    local function get_vue_version()
        local root_dir = util.find_git_ancestor(vim.fn.getcwd()) or vim.fn.getcwd()
        local package_json = root_dir .. "/package.json"

        if vim.fn.filereadable(package_json) == 1 then
            local package_data = vim.fn.json_decode(vim.fn.readfile(package_json))
            local vue_version = package_data["dependencies"] and package_data["dependencies"]["vue"]
                or package_data["devDependencies"] and package_data["devDependencies"]["vue"]

            if vue_version then
                -- Strip any non-numeric characters like ^ or ~ from the version string
                local cleaned_version = vim.fn.matchstr(vue_version, [[\v\d+]])
                local version = tonumber(cleaned_version)
                return version
            end
        end
        return nil
    end

    local vue_version = get_vue_version()

    if vue_version == 3 then
        -- use volar for vue 3
        lspconfig.volar.setup({
            capabilities = capabilities,
        })
    else
        -- use vetur (vuels) for vue 2
        lspconfig.vuels.setup({
            capabilities = capabilities,
            filetypes = { "vue" },
            root_dir = lspconfig.util.root_pattern("package.json", ".git"),
        })
    end
end,
PixsaOJ commented 6 days ago

Volar is not able to run and have all capabilities no matter what. Use "typescript-tools" and @vue/typescript-plugin might take up resources, but its working.