Configuring eslint to work with Neovim LSP - Phelipe Teles

Configuring eslint to work with Neovim LSP

2 min.
View source code

The way we’ll get this to work is by using a generic Language Server called efm-langserver, which is written in Go.

These Language Servers are generic in that they were made to be powered by command-line tools and for any programming language.

Making eslint faster with eslint_d

To reduce latency when invoking eslint, I’m gonna use eslint_d, which runs eslint as a daemon process.

Configuring eslint_d in efm-langserver

It’s possible to configure it with a YAML file, by following their README. I did this initially I found that it’s more powerful to configure it with Lua.

Here’s the configuration, which more explanation below.

lua
local lspconfig = require"lspconfig" local eslint = {  lintCommand = "eslint_d -f unix --stdin --stdin-filename ${INPUT}",  lintStdin = true,  lintFormats = {"%f:%l:%c: %m"},  lintIgnoreExitCode = true,  formatCommand = "eslint_d --fix-to-stdout --stdin --stdin-filename=${INPUT}",  formatStdin = true} lspconfig.tsserver.setup {  on_attach = function(client)    if client.config.flags then      client.config.flags.allow_incremental_sync = true    end    client.resolved_capabilities.document_formatting = false    set_lsp_config(client)  end} lspconfig.efm.setup {  on_attach = function(client)    client.resolved_capabilities.document_formatting = true    client.resolved_capabilities.goto_definition = false    set_lsp_config(client)  end,  root_dir = function()    if not eslint_config_exists() then      return nil    end    return vim.fn.getcwd()  end,  settings = {    languages = {      javascript = {eslint},      javascriptreact = {eslint},      ["javascript.jsx"] = {eslint},      typescript = {eslint},      ["typescript.tsx"] = {eslint},      typescriptreact = {eslint}    }  },  filetypes = {    "javascript",    "javascriptreact",    "javascript.jsx",    "typescript",    "typescript.tsx",    "typescriptreact"  },}

I defined a table to configure efm-langserver with eslint_d by giving the necessary commands for linting and formatting.

I customize the on_attach function of both efm and tsserver so that only one has documentFormatting capability, otherwise they would conflict with each other.

The root_dir function was also customized so that eslint_d is spawned just for the current working directory and not for every directory it encounters a .eslintrc (or similar).

But I also want this to happen only if the directory has some sort of eslint configuration. So I created a function to do this:

lua
local function eslint_config_exists()  local eslintrc = vim.fn.glob(".eslintrc*", 0, 1)   if not vim.tbl_isempty(eslintrc) then    return true  end   if vim.fn.filereadable("package.json") then    if vim.fn.json_decode(vim.fn.readfile("package.json"))["eslintConfig"] then      return true    end  end   return falseend

Conclusion

This is kind like a poor replacement for the VS Code eslint extension, which does a similar thing as eslint_d. And it works ok, it’s pretty fast, much faster than typescript-language-server, so it’s definitely an improvement.

It would be nice if there was a way to shut down the server if eslint is broken for example, but I didn’t manage to do it just yet.