Deno

Deno的开发环境和Deno本身都很粗糙, 不应将其用于生产环境.
从Deno的开发时间来考虑的话, Deno团队的表现不佳,
以至于Node.js已经逐渐赶上Deno的特性, 还出现了Bun这样相同生态位的竞争对手.
很难对Deno的未来有信心.
  • 用Rust开发.
  • API尽可能与Web环境兼容.
  • 具有主见的 deno fmt, deno lint, deno test, deno bench.
  • 默认安全, 具有细粒度的权限系统, 支持动态请求权限.
    目前, 由于Deno有很多内部使用的字段, 细粒度权限用起来可能很不方便, 最后还是会被逼去使用粗粒度权限.
  • 原生支持TypeScript, 这点正变得越来越重要, 因为JavaScript社区在向TypeScript转变.
  • Node.js兼容性.
Deno的内置功能普遍缺乏严谨的测试, 依赖社区反馈错误.
尽管LTS在各种项目里都有越来越短的迹象, 但Deno 2在发布时将6个月声明为LTS仍然令人忍俊不禁.
Deno Land Inc.热衷于开发其他生态环境产品的克隆/替代品.
这些产品明显缺乏深思熟虑, 可维护性存疑.
这种倾向也影响了Deno本身, 例如Node.js兼容性就是一个营销炒作凌驾于实际交付的典型例子:
https://docs.deno.com/runtime/reference/node_apis/#fully-supported-modules
稍有规模的Deno项目就会导致LSP的响应速度变慢, 很容易劝退想要使用Deno的开发人员.
相比之下, 基于Node.js和TypeScript的项目则完全没有类似的问题.
Deno的LSP默认配置相当保守, 例如, documentPreloadLimit 的默认值为1000, 实际开发中很容易超出.
WHATWG流模型的设计相当简陋, 远远比不上Node.js的流.
举例来说, 使用者甚至无法知道一个流是否关闭, 或是什么时候关闭的.
模块会根据被导入的情况, 决定其协议.
当模块作为本地模块被导入时, 模块的 import.meta.url 为file协议.
当模块作为远程模块在被导入时, 其 import.meta.url 为http/https协议.
问题在于相当多的API只支持一种协议, 例如 Deno.readFile 仅支持file协议, 不支持http/https协议.
这种情况导致开发者在使用 import.meta.url 时有更多的心智负担.
根本问题出在Deno不暴露导入模块(缓存)的本地路径, 而这本身是一个在设计层面就可以解决的问题.
https://github.com/denoland/deno/issues/5987
相当可悲的, Deno通过让fetch函数支持file协议来解决读取文件相关的问题.
https://github.com/denoland/deno/issues/3196
TypeScript不支持将 .ts 扩展名的模块路径编译为 .js 扩展名,
而Deno的模块路径一定是 .ts 扩展名.
因此, 为Node.js模块设计的TypeScript项目的代码将无法在Deno里运行.
TypeScript 5开始支持allowImportingTsExtensions配置项, 这允许在项目里使用 .ts 扩展名,
但该配置项被限制为只能在配置为noEmit或emitDeclarationOnly的情况下使用,
这意味着使用 .ts 扩展名的同时不能生成可用于Node.js的代码.
Deno官方推进的JavaScript包注册表.
尽管JSR在宣传上标榜自己是一个现代JavaScript的包注册表, 但它仍然只是Deno版本的npm.
JSR不是npm的超集, 就像TypeScript不是JavaScript的超集一样.
该注册表很大程度上是为了解决Deno存在的依赖管理问题(Ryan Dahl在2018年掷出的回旋镖终于打中了自己):
不同的模块会导入来自不同注册表的依赖项, 或是因为缺乏SemVer导致导入同一注册表依赖项的不同子版本.
这导致项目的体积膨胀(会增加LSP负担), 导入的依赖项之间缺乏引用相等性.
Deno官方声称原来的包注册表deno.land/x仍可继续使用,
但考虑到官方的标准库std在deno.land/x上已经停更, 预期继续在deno.land/x发布包是没有意义的.
现在可以(像Deno 1.28添加的对npm模块的支持那样)使用专用前缀 jsr:, 简化了URL.
https://github.com/oakserver/oak
https://fresh.deno.dev/
Deno官方于2022年推出的全栈Web框架, 对标Next.js.
不建议使用它, 因为:
  • 几乎没有React库为Deno支持做测试.
  • 内部使用的是React的轻量变体Preact, 这是一个没有前途的技术路线.
Deno可以通过CDN导入JSDOM.
import { JSDOM } from 'https://esm.sh/jsdom@22.1.0'
https://github.com/b-fuze/deno-dom
该项目是Rust的html5ever包的绑定.
使用Deno FFI的SQLite.
优点:
  • 接口与better-sqlite3基本相同.
  • 高性能.
编译为WASM的SQLite.
优点:
  • 最小权限.
  • 跨平台.
缺点:
  • 受到Deno文件系统API的限制.
  • 默认启用的编译选项非常少, 很可能需要自己编译.
自Deno 1.21开始, 标准库提供了相当多的测试功能,
这使得在大多数情况下不需要使用第三方库就可以完成测试.
Deno的这种技术选择有效避免了Node.js测试的供应商绑定问题.
当前标准库已经支持BDD风格, mock/stub, 快照匹配, 计时器模拟:
https://deno.land/std@0.181.0/testing
https://github.com/denoland/deno_std/issues/1779
Deno提供一个内置的命令 deno bundle 用于将项目打包成一个脚本文件.
Ryan Dahl曾提议删除此命令, 但这个想法后来被撤回.
然而, 在v1.31里, 该命令仍在没有经过社区讨论的情况下被列为弃用, 官方手册建议改用esbuild.
在v2.4, deno bundle莫名其妙回归, 其底层使用esbuild.
在v2.5, 支持以HTML文件作为打包的入口点.
用 deno run 命令运行脚本时, 会加载TypeScript类型检查器, 这会导致deno进程使用更多的内存.
如果先通过 deno compile 编译后再运行, 脚本的内存用量会有明显改善.