I think Deno made a huge mistake.
Deno intended to be the redo of ‘Javascript outside the browser’, making it simpler while getting rid of the legacy.
When Deno was announced in 2020, Deno was its own thing. Deno bet hard on ESM,
re-used web APIs and metas wherever possible, pushed for URL imports instead
of node_modules
, supported executing typescript files without tsx
or tsconfig.json
and so on.
However since 2022, Deno is trying to imitate Node more and more, and this is destroying Deno’s ecosystem.
Users’ Perspective
“If Deno implemented Node APIs and tried to imitate Node and NPM ways of doing things, existing libraries and frameworks written using Node will automatically work in Deno and thus adopting Deno will be easier.” I don’t know who said this, someone must have said this.
What has happened instead, is that Deno trying to imitate Node has disincentivized formation of any practical ecosystem for Deno, while the existing libraries and frameworks are unreliable when used with Deno.
I tried using Next.js via Deno some time back, and Next.js dev server crashed when Turbopack is enabled. There is a workaround, so for the time being that issue is solved. But today there is another issue, type checking (and LSP) for JSX is broken.
This is my experience with using Node libraries with Deno. Every hour of work is accompanied with another hour (sometimes more) of troubleshooting the libraries themselves.
I think this is the consequence of trying to imitate something you are not. Deno is trying to be compatible with Node. but there are gaps in the said compatibility. I think achieving compatibility with Node is hard, and the gaps in compatibility will stay for a long time.
For example, at the time of writing, FileHandle.readLines is not implemented in Deno.
import fs from 'node:fs/promises';
const hd = await fs.open(Deno.args[0]);
for await (const line of hd.readLines()) {
console.log("Line: ", line);
}
The above script crashes despite having no issues with Typescript.
$ deno check test.ts
Check file://path/to/test.ts
$ deno run -R test.ts input.txt
error: Uncaught (in promise) TypeError: hd.readLines(...) is not a function or its return value is not async iterable
for await (const line of hd.readLines()) {
^
at file://path/to/test.ts:4:29
$
Using NPM libraries is also typically accompanied with a complete disregard
for Deno’s security features. You just end up running deno with -A
all the
time.
Library devs’ Perspective
Deno 1.0 is released, and library devs are excited to join the ecosystem. Projects like drollup, denodb, drizzle-deno are started,
But then Deno announces Node and NPM compatibility and all that momentum is gone.
Now, it seems like Deno’s practical ecosystem is limited to first party libraries like @std and Fresh, libraries on JSR, and a small subset of libaries on NPM that works on Deno.
If you look at the situation from library or framework dev’s perspective, it all seems reasonable. Most of them are not new to Javascript; they are much more familiar with Node than with Deno.
When Deno is announced, some of them might want to contribute to Deno’s ecosystem. But then Deno announces Node and NPM compatibility, and now there is not enough incentive to develop software for Deno. It doesn’t matter that Node compatibility is spotty, because they’d rather just go back to using Node like they’re used to. Supporting multiple runtimes is painful. If you want to understand the pain, ask anyone who tried to ship any cross platform application written in C or C++.
Deno should have promoted its own API
If the competition is trying to be more like Node, Node is the winner.
There is a lesson to be learned here. If you are trying to replace a legacy system, don’t re-implement the same legacy system. Instead, put the burden of backwards-compatibility on the legacy system.
Deno aimed to uncomplicate Javascript. (Deno’s homepage literally says that.) By trying to mimic Node, Deno has unintentionally put Node’s complexity problem at the center of the stage. And now, it cannot be removed. Instead of being a brand new thing, Deno ended up being a less reliable variant of Node.
Deno should have supported its own API on top of Node instead. Since Deno controls its API, supporting its own API on Node would be simpler than supporting Node APIs. For library and framework developers, libraries made for Deno would work on Node and there would be no need to support multiple runtimes.
This would have resulted in a much larger ecosystem of software made for Deno which is more reliable and free of Node’s legacy.
Deno intended to be the redo of 'Javascript
That’s their first mistake.
Statistically speaking, you are right.