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.

  • KubeRoot@discuss.tchncs.de
    link
    fedilink
    English
    arrow-up
    1
    ·
    3 days ago

    By your logic, Bun has no right to exist because it only supports Node.js APIs and doesn’t have its own APIs

    I don’t know much on the topic, but I know I used Bun a bit for some scripts, and it most certainly does have its own APIs, so that’s incorrect.

    • arendjr
      link
      fedilink
      arrow-up
      2
      ·
      edit-2
      3 days ago

      Yes, it has a few APIs of its own. I merely think they are negligible in this discussion because they only provide a minimal superset over Node.js’s own APIs and are also very minimal compared to what Deno provides.

      I’ve updated my post to mention “noteworthy” APIs.

      • KubeRoot@discuss.tchncs.de
        link
        fedilink
        English
        arrow-up
        1
        ·
        3 days ago

        I don’t think I’d agree about it being negligible, but I think that’s ultimately subjective, so fair enough. I get the impression a lot of Bun’s own library are nicer to use equivalents of libraries present in Node, but I think even that is significant for anybody looking to write new code.