I wish Deno would keep doing what it does best
I wish Deno would keep doing what it does best
我希望 Deno 能继续做它最擅长的事
洪 民憙 (Hong Minhee) @hongminhee@hackers.pub 2026年6月8日, 下午 1:30:42
The wall of configuration
配置之墙
For years I worked in Python and dreamed in Haskell on weekends. When I needed a script, Python. When I wanted the type system to hold me accountable, Haskell. Somewhere between the two sat TypeScript, and I knew it. Practical where Haskell is austere, typed where Python isn’t. But I kept my distance. tsconfig.json, .eslintrc, .prettierrc, babel.config.js. Files you have to create before you’ve written a single line of actual code. Every time I thought about trying it, I looked at the list and gave up. The JavaScript ecosystem always felt to me like an amusement park where you have to wait in a long queue just to get inside. Deno dissolved that queue. No configuration files, no node_modules, no agonizing over which package manager to use. Just deno run main.ts. The first time I actually wrote TypeScript properly, I couldn’t understand why I’d put it off so long. What I’d been avoiding wasn’t TypeScript. It was the ritual surrounding TypeScript.
多年来,我一直使用 Python 工作,周末则沉浸在 Haskell 的世界里。需要写脚本时,我用 Python;想要类型系统来约束我时,我用 Haskell。TypeScript 恰好位于两者之间,我对此心知肚明。它既有 Haskell 所缺乏的实用性,又有 Python 所不具备的类型系统。但我一直对它敬而远之。tsconfig.json、.eslintrc、.prettierrc、babel.config.js……这些文件在你写下第一行代码之前就必须创建。每次我打算尝试时,看着这份清单就放弃了。JavaScript 生态系统给我的感觉就像一个游乐园,光是进门就得排长队。Deno 拆除了那道排队的围栏。没有配置文件,没有 node_modules,不用纠结该用哪个包管理器。只需 deno run main.ts。当我第一次真正地写起 TypeScript 时,我不禁纳闷自己为什么拖了这么久。我回避的并不是 TypeScript,而是围绕着 TypeScript 的那些繁文缛节。
What hooked me
是什么吸引了我
At first I couldn’t point to one killer feature. The appeal was that everything seemed to be pulling in the same direction. The fetch() I used in browsers worked the same way on the server. Web Crypto API was just there. MDN effectively became Deno’s documentation. Instead of installing packages, you imported ESM by URL, thinking about dependencies in an entirely different way. Having deno fmt, deno lint, deno test, deno bench, and deno check all in a single binary was part of the same logic. No installing ESLint, no wiring up Prettier, no untangling configuration conflicts between the two. That convenience had an attitude behind it. The pattern was obvious enough: build on web standards, then ship the boring tools yourself.
起初,我无法指出某一个“杀手级”功能。它的魅力在于一切似乎都在朝着同一个方向努力。我在浏览器中使用的 fetch() 在服务器端以同样的方式运行。Web Crypto API 直接可用。MDN 实际上成了 Deno 的文档。你不再需要安装各种包,而是通过 URL 导入 ESM,这彻底改变了对依赖项的思考方式。将 deno fmt、deno lint、deno test、deno bench 和 deno check 集成在同一个二进制文件中,也是出于同样的逻辑。无需安装 ESLint,无需配置 Prettier,也无需解决两者之间错综复杂的配置冲突。这种便利背后体现了一种态度:基于 Web 标准构建,然后自己提供那些枯燥但必要的工具。
Chasing Node.js
追赶 Node.js
Today’s Deno feels like it’s drifting away from that. npm: specifier support, node_modules back in play, node:* module compatibility. Then in Deno 2.8, deno add without a specifier now adds an npm package by default. JSR was introduced as an answer to npm’s stagnation, as the future of JavaScript packaging. These decisions make that announcement look distant. I can understand each one in isolation. Put them together, though, and the shape is hard to ignore: Deno is spending more and more of its energy catching up to Node.js. The OS/2 story comes to mind. IBM expected that building Windows compatibility into OS/2 would pull Windows users across. What actually happened was the opposite: developers realized they could target Windows and have it run on both platforms, so there was no reason to learn the OS/2 API separately. Deno pushing further toward Node.js compatibility has the same dynamic. The more compatible Deno becomes, the less reason library authors have to think about it specifically.
今天的 Deno 似乎正在偏离这一初衷。对 npm: 说明符的支持、node_modules 的回归、node:* 模块兼容性。接着在 Deno 2.8 中,不带说明符的 deno add 现在默认添加 npm 包。JSR 被引入作为对 npm 停滞不前的回应,被视为 JavaScript 包管理的未来。这些决定让最初的愿景显得遥不可及。单独看每一个决定,我都能理解。但把它们放在一起,其趋势就难以忽视了:Deno 正在投入越来越多的精力去追赶 Node.js。我不禁想起了 OS/2 的故事。IBM 曾期望在 OS/2 中构建 Windows 兼容性来吸引 Windows 用户。但实际发生的情况恰恰相反:开发者意识到他们可以直接针对 Windows 开发,并且程序能在两个平台上运行,因此没有理由再去学习 OS/2 的 API。Deno 向 Node.js 兼容性靠拢也存在同样的逻辑。Deno 变得越兼容,库作者就越没有理由专门为它进行适配。
Meanwhile, Node.js has been walking toward Deno. TypeScript runs without flags as of v22. A permission model arrived in v20. fetch() and Web Crypto API are both there now. node:test and node:assert/strict have quietly become the best cross-runtime test harness for projects targeting Deno, Node.js, and Bun alike. The two runtimes are converging, but Deno seems to be doing more of the reaching. Early Deno set the agenda. Web standards, the permission model, URL imports, JSR: Deno put these down and the ecosystem responded. What Deno is doing now runs in the opposite direction, catching up to what the ecosystem already has.
与此同时,Node.js 也在向 Deno 靠拢。从 v22 开始,TypeScript 无需标志即可运行。v20 引入了权限模型。fetch() 和 Web Crypto API 现在也都具备了。node:test 和 node:assert/strict 已悄然成为针对 Deno、Node.js 和 Bun 等跨运行时项目的最佳测试工具。这两个运行时正在趋同,但 Deno 似乎在主动靠拢方面做得更多。早期的 Deno 设定了议程:Web 标准、权限模型、URL 导入、JSR——Deno 提出了这些,生态系统也做出了回应。而 Deno 现在所做的正背道而驰,去追赶生态系统已经拥有的东西。
On the defensive
处于守势
There’s a more specific frustration here. Deno had a fight it could have led rather than chased. What drove me away from the JavaScript ecosystem wasn’t Node.js itself. It was the full combination: Node.js + npm + TypeScript + Vite + ESLint + Prettier + Vitest. That stack was the problem, and Deno was already doing well against it. deno fmt, deno lint, deno test, deno bench, deno check, and in 2.4, deno bundle came back. It had been deprecated once and then restored; that round trip is its own admission that the direction was right. The most visible gap that remains is the dev server: HMR, live reload, an asset pipeline, and the plugin ecosystem that accumulates on top of all that. Fresh 2.0, Deno’s own framework, chose not to fill that gap from within Deno and adopted Vite instead. That disappointed me. Making Vite run well on Deno and making Deno a self-sufficient development environment are two entirely different directions. Once your own framework makes that choice, you can’t expect the wider ecosystem to go the other way.
这里有一个更具体的挫败感。Deno 本可以引领一场变革,而不是去追赶。让我离开 JavaScript 生态系统的不是 Node.js 本身,而是整个组合:Node.js + npm + TypeScript + Vite + ESLint + Prettier + Vitest。这个技术栈才是问题所在,而 Deno 原本在对抗这一问题上做得很好。deno fmt、deno lint、deno test、deno bench、deno check,以及在 2.4 版本中回归的 deno bundle。它曾被弃用又被恢复;这种反复本身就承认了最初的方向是正确的。目前最明显的缺口是开发服务器:HMR、实时重载、资源管道以及堆叠在这一切之上的插件生态系统。Deno 自己的框架 Fresh 2.0 选择不从 Deno 内部填补这一空白,而是采用了 Vite。这让我很失望。让 Vite 在 Deno 上运行良好,与让 Deno 成为一个自给自足的开发环境,是两个完全不同的方向。一旦你自己的框架做出了这种选择,你就不能指望更广泛的生态系统会选择另一条路。
But vertical integration alone might not have been enough. Individual component quality matters too. If deno lint and deno fmt were clearly better than ESLint and Prettier, developers would reach for them even in Node.js projects. That could have been the Trojan horse. Once enough projects are using Deno’s tools without using the Deno runtime, the next question follows naturally. ESLint and Prettier seemed unmovable, and yet Biome and the Ox series (Oxlint, Oxfmt) are finding their footing. The market was always there. Better tools just weren’t. Deno could have gotten there first.
但仅靠垂直整合可能还不够。单个组件的质量也很重要。如果 deno lint 和 deno fmt 明显优于 ESLint 和 Prettier,开发者即使在 Node.js 项目中也会选择使用它们。这本可以成为“特洛伊木马”。一旦足够多的项目在不使用 Deno 运行时的情况下使用 Deno 的工具,接下来的问题就会自然而然地出现。ESLint 和 Prettier 曾被认为不可撼动,但 Biome 和 Ox 系列(Oxlint, Oxfmt)正在站稳脚跟。市场一直都在,只是缺乏更好的工具。Deno 本可以率先做到这一点。
The clock I keep thinking about
我一直在思考的时间钟
Why didn’t Deno hold the course? This is speculation, but here’s my read. The integrated toolchain path required patience. Getting developers to feel the pain of configuration complexity, making Deno the place they move to, waiting for the ecosystem to grow comfortable with Deno’s way of doing things. All of that takes time. Node.js is a community project under the OpenJS Foundation. There’s no investor clock pushing it, and the project doesn’t wobble if the ecosystem moves slowly. Deno Land Inc. is different. A VC-backed company has a clock. How long that clock allows for a patient fight is not the same as what a community project can afford. Expanding Node.js compatibility produces visible results faster than the slow alternative. From the outside, I can’t tell when I’m seeing a product decision and when I’m se…
为什么 Deno 没有坚持下去?这纯属猜测,但这是我的看法。集成工具链的道路需要耐心。让开发者感受到配置复杂性的痛苦,让 Deno 成为他们迁移的目的地,等待生态系统逐渐适应 Deno 的方式——这一切都需要时间。Node.js 是 OpenJS 基金会下的一个社区项目。它没有投资人的时间表在背后催促,即使生态系统发展缓慢,项目也不会动摇。Deno Land Inc. 则不同。一家有风险投资支持的公司有自己的时间表。这个时间表所允许的“耐心抗争”时长,与社区项目所能承受的完全不同。扩大 Node.js 兼容性比那种缓慢的替代方案能更快地产生可见成果。从外部看,我无法分辨我看到的是产品决策,还是……