Set Node.js Version for Neovim and Language Servers

Here's a method for pegging a stable node.js version for nvim and language servers.

What's a language server

Neovim has language server protocol (LSP) support built in. But it doesn't have the language servers themselves. And language servers are installed in all sorts of sundry ways.

Some language servers require Node.js tooling. An example is the typescript-language-server.

Mason.nvim is a package manager for language servers. Mason provides a UI to install new language servers. You can run :MasonInstall to install all those in your config.

Node not found error

When I went to install using mason.nvim, I was getting an error that indicated that the node binary was unfound:

No version is set for command node
Consider adding one of the following versions in your config file at
nodejs 16.15.0
nodejs 16.17.1
spawn: npm failed with exit code 126 and signal 0.

After much searching, I still don't know exactly what is generating this message. But I have fixed it by finding node and making it available to nvim more explicitly.

Insufficient: Node host program

I attempted setting this global option:

vim.g.node_host_prog = '~/.nvm/versions/node/v16.17.1/bin/node'

This didn't affect anything that I could detect. From the output of :h node_host_prog, I just don't think I understand quite yet what uses this and how.

Works: Append $PATH

What did work was appending the path environment variable. I'm doing this inside of my nvim config files:

local is_mac = vim.fn.has "macunix" == 1
local home_dir = "/home/jaketrent"
if is_mac then
  home_dir = "/Users/jaketrent"
end
-- pin nvim to a specific node version, regardless of the project
-- prereq - need to install: nvm i 16.17.1
local node_bin =  "/.nvm/versions/node/v16.17.1/bin"
vim.g.node_host_prog = home_dir .. node_bin .. "/node"

-- for mason.nvim
-- prereq - install lsp server in that node/bin npm i -g typescript-language-server 
-- (handled by :Mason currently)
vim.cmd("let $PATH = '" .. home_dir .. node_bin .. ":' . $PATH")

Note that the full file path (not using ~/) is required.

You can see that I set vim.g.node_host_prog anyway. Maybe it'll be useful for something else that relies on it.

It seems good to have nvim set the $PATH instead .zshenv because I want to run the version of node that I need for a project based on its own virtual env, not the editor.

It's great to pin this node version to the editor so that I can install dependencies like language servers in a node/bin that I have clearly located and will not change between projects.

What are the other ways to do this that you've discovered?