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.

  • @[email protected]
    link
    fedilink
    English
    84 days ago

    Given the prevalence of NodeJS and its compatible tools and platforms, I can’t see it as a mistake.

    Through compatibility, Deno established an upgrade path.

    However since 2022, Deno is trying to imitate Node more and more, and this is destroying Deno’s ecosystem.

    My impression was that Deno specifically does not try to nor want to imitate Node. They specifically announce and document their intended tooling and ecosystem which is different from the NodeJS and NPM ecosystem.

    Their reasons for NodeJS support is for compatibility and enabling users of those platforms to use Deno.

    Without it, I don’t see Deno replacing NodeJS in a considerable manner. Now, it’s a possibility. (But the sheer volume and prevalence still makes it seem unlikely.)

    • @[email protected]
      link
      fedilink
      53 days ago

      People may show excitement over the hot new thing, but nobody is going to migrate their entire architecture/platform over unless it’s incredibly convenient or they’re rebuilding from scratch. Backward compatibility makes it less of a barrier of entry to migrate.

      That’s good for adoption.

      But also a foot gun, since the roadmap of Deno just starts to look like Node.

    • @akash_rawalOP
      link
      44 days ago

      Through compatibility, Deno established an upgrade path.

      Sure, but Node compatibility needs to work, and it needs to work reliably. Which means every last detail of Node needs to be supported.

      This is what I am trying to convey… the engineering effort to make an objectively better JS runtime while being Node compatible is likely too much effort. Many popular Node projects are already having issues with Deno. Now imagine how the compatibility scene will look like with every single proprietary Node project out there.

      So instead of trying to replace NodeJS or offering an upgrade path for existing Node projects, incentivize formation of ecosystem around Deno.

      • @[email protected]
        link
        fedilink
        English
        23 days ago

        Maybe automated conversion as an upgrade path would be a lower effort with not the same, but similar usefulness.

      • @[email protected]
        link
        fedilink
        2
        edit-2
        3 days ago

        You’re ignoring the fact that for many projects it does work.

        It only needs to be perfect if you want to run 100% Node.js software unaltered. While that may be a lofty goal, it’s also an infeasible one.

        That doesn’t mean imperfect support is futile though. By your logic, Bun has no right to exist because it only supports Node.js APIs and doesn’t have noteworthy APIs of its own, and they’re not perfect either. Yet they seem to be at least as successful as Deno is.

        Or for an example in a different domain: Your argument would state that a project like WINE shouldn’t exist because it doesn’t have perfect compatibility with Windows, and it disincentivizes development of Linux games. Yet it is largely thanks to WINE that Valve has been able to make the Steam Deck and that Linux gaming is finally taking off.

        I think what your argument fails to take into account is that you need a significant amount of users to make any impact on the market. And many users have legacy requirements that they can’t throw out overnight, so you have to support those legacy environments. And even with imperfect legacy support you can support your users, especially if the users are willing to make a few changes here or there. But if you have no legacy support, you also get no users except those that have niche greenfield requirements.

        So instead of trying to replace NodeJS or offering an upgrade path for existing Node projects, incentivize formation of ecosystem around Deno

        They are incentivizing their own ecosystem. That’s what Jsr.io is all about. But the world isn’t black and white. They can do more than one thing.

        • @akash_rawalOP
          link
          33 days ago

          There is no way legacy projects are going to switch to Deno. Even when Deno is 100% compatible, the only advantage Deno provides is slightly higher performance. Node’s complexity problem? All those configs needs to be supported for compatibility anyway. Typescript? The project already has tsconfig.json set up, so they might as well continue to use tsx. Security? I bet users will just get tired and use -A all the time.

          To benefit from Deno, Node’s legacy needs to be shed.

          Wine is a different case. The reason Wine makes sense is because Windows is so much worse than Linux that even with scrappy game compatibility, Linux offers a better experience. For Linux users, the alternative to Wine is not switching to Windows, it is not being able to play games. On the other hand, legacy Node projects have a very easy alternative… just continue to use Node.

          And btw Bun is making the same mistake.

        • KubeRoot
          link
          fedilink
          English
          13 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.

          • @[email protected]
            link
            fedilink
            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
              link
              fedilink
              English
              13 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.