2026-04-02

Side Quest: Server Fetch

I mentioned in a recent post that I embarked on a lengthy side-quest while configuring a JavaScript environment in Emacs for a hobby project. It might be time to explain what that was about.

Getting the quest

I picked up the quest when I went looking for a JavaScript LSP, and found that almost all the options require installation via npm. I do have a couple of npm based things installed, but I've been feeling sour about it after some recent supply chain attacks against the packaging system and have tried to work around needing it. I hasten to say that my worries weren't focused around a notion of npm as more of a security risk than other supply chains I use, but around the desultory and inexpert way I interact with it. In the case of my other supply chains, I update regularly and follow sources of on-line news that are relevant to the ecosystems in play. Not so with npm. I worried that I would be late to the party on knowing that I had a problem and taking steps to fix it.

The task at hand

I wanted to install a JavaScript LSP without using npm.

To start with, it's not in the least surprising that most JavaScript language servers are distributed via npm. I mean the protocol specifies JSON, so there is every reason to write them (in whole or in part) in JavaScript, and in that case npm is the default distribution mechanism. But, as I indicated above, I was hoping to avoid adding that window of vulnerability to my systems.

If at first you don't succeed...

So, LSP being a microsoft controlled protocol, one of the few central locations that which a list of available servers is maintained by microsoft, but there are others. In any case, I found only a few currently maintained options:

  • typescript-language-server
  • flow
  • quick-lint-js
  • biome-lsp (a part of the greater biome project)
The installation instructions for the first two both start npm install. The third is available from my distribution's package repository and works, but there is a lot that it doesn't implement: it really is a linter than knows the language server protocol (and I don't want to diss that—being a server gives it flexibility in interaction modes—but it isn't all that I hoped for). That leaves biome, and actually, it's installation instructions also start by calling npm, but further down the README.md it says "Biome doesn't require Node.js to function.", and you can find build-from-source instructions on the project homepage. Frankly, they're not very good as they seem to assume that if you're asking that question you can guess your way through it, but I got it done.

Being my own worst enemy

The last hurdle on my quest was largely of my own making. You see, to run biome as a server you have to pass it the lsp-proxy command, which is emphatically not the spelling I would have chosen for that option if I'd been writing the tool. And for some reason, when I was configuring Emacs, I kept spelling it differently. I spent an increasingly frustrating half and hour making variations on the same mistake before noticing what I had been doing all along. Use the right spelling and it just works.