Deno 2 代表了 JavaScript 和 TypeScript 运行时领域的重大进化。凭借完全的 Node.js 兼容性、原生 npm 包支持和精炼的开发体验,Deno 2 弥合了现代运行时愿景和现有 Node.js 生态系统实际需求之间的差距。
Deno 2 的新特性
Deno 2 引入了多项突破性变化,使其成为生产应用的实际选择。最重大的变化是与 Node.js 和 npm 的向后兼容性。
完全的 Node.js 兼容性
Deno 2 包含 Node.js 兼容层,支持绝大多数 Node.js 内置模块,包括 fs、path、http、crypto、stream 和 child_process。
// Using Node.js built-in modules in Deno 2
import { readFileSync } from "node:fs";
import { join } from "node:path";
import { createHash } from "node:crypto";
import { EventEmitter } from "node:events";
const content = readFileSync(join(".", "config.json"), "utf-8");
const hash = createHash("sha256").update(content).digest("hex");
console.log("Config hash:", hash);
// Node.js streams work too
import { Readable, Transform } from "node:stream";
const readable = Readable.from(["hello", "world"]);原生 npm 支持
Deno 2 可以使用 npm: 说明符直接导入 npm 包。默认不创建 node_modules 目录,包被全局缓存。
// Import npm packages directly
import express from "npm:express@4";
import { z } from "npm:zod";
import chalk from "npm:chalk@5";
import _ from "npm:lodash";
// Or use an import map in deno.json
// deno.json:
// {
// "imports": {
// "express": "npm:express@4",
// "zod": "npm:zod",
// "chalk": "npm:chalk@5"
// }
// }
// Then import normally:
// import express from "express";精细化权限系统
Deno 保留了安全优先的权限系统,但现在支持更细粒度的控制。可以允许特定的文件路径、网络主机和环境变量。
# Granular permissions
deno run --allow-read=./data --allow-write=./output server.ts
deno run --allow-net=api.example.com:443 fetch.ts
deno run --allow-env=DATABASE_URL,API_KEY app.ts
# Allow all permissions (development only)
deno run --allow-all server.ts
# Or use the shorthand
deno run -A server.ts
# Run with no permissions (most secure)
deno run sandboxed.ts标准库更新
Deno 标准库已经稳定化并提供清晰的版本控制。关键模块包括文件操作、HTTP 服务器、测试工具和异步辅助函数。
// Deno standard library (jsr:@std/)
import { ensureDir, copy } from "jsr:@std/fs";
import { parse } from "jsr:@std/flags";
import { assertEquals } from "jsr:@std/assert";
import { delay } from "jsr:@std/async";
await ensureDir("./output");
await copy("./src", "./output/src", { overwrite: true });
const args = parse(Deno.args, {
string: ["port"],
default: { port: "3000" },
});Deno 2 入门
安装和运行 Deno 2 非常简单。Deno 作为单个二进制文件分发,没有外部依赖。
# Install Deno
curl -fsSL https://deno.land/install.sh | sh # macOS/Linux
irm https://deno.land/install.ps1 | iex # Windows
# Verify installation
deno --version
# deno 2.x.x
# v8 12.x.x
# typescript 5.x.x
# Create a new project
deno init my-project
cd my-project
# Run a TypeScript file directly
deno run main.ts
# Run with watch mode
deno run --watch main.ts
# Format, lint, and test
deno fmt
deno lint
deno test使用 deno.json 配置
Deno 2 使用 deno.json(或 deno.jsonc)进行项目配置。此文件替代了 tsconfig.json 和 package.json。
// deno.json
{
"tasks": {
"dev": "deno run --watch --allow-all main.ts",
"start": "deno run --allow-net --allow-read main.ts",
"test": "deno test --allow-all",
"build": "deno compile --output=app main.ts"
},
"imports": {
"@std/http": "jsr:@std/http@^1.0.0",
"@std/assert": "jsr:@std/assert@^1.0.0",
"express": "npm:express@4",
"zod": "npm:zod@^3.22"
},
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "react"
},
"fmt": {
"semiColons": true,
"singleQuote": true,
"lineWidth": 100
},
"lint": {
"rules": {
"tags": ["recommended"]
}
}
}从 Node.js 迁移
将现有 Node.js 项目迁移到 Deno 2 比以往任何时候都更加实际。以下是分步方法。
步骤 1:添加 deno.json
在项目根目录创建 deno.json 文件。过渡期间可以保留现有的 package.json。
步骤 2:更新导入
将 Node.js 内置导入转换为使用 node: 前缀。将 npm 包导入更新为使用 npm: 说明符。
// Before (Node.js)
const fs = require("fs");
const path = require("path");
const express = require("express");
// After (Deno 2)
import fs from "node:fs";
import path from "node:path";
import express from "npm:express@4";
// Or use Deno-native APIs
const content = await Deno.readTextFile("./config.json");
const joined = new URL("./data/file.txt", import.meta.url);步骤 3:处理 CommonJS
Deno 2 通过 node: 兼容层支持 CommonJS 模块。对于你自己的代码,将 require() 转换为 ESM import。
步骤 4:更新脚本
用 deno.json 中的 Deno 任务替换 npm 脚本。Deno 任务支持类 shell 语法。
// package.json scripts:
// "scripts": {
// "dev": "nodemon server.ts",
// "test": "jest",
// "build": "tsc && node dist/index.js"
// }
// deno.json tasks:
// "tasks": {
// "dev": "deno run --watch --allow-all server.ts",
// "test": "deno test --allow-all",
// "build": "deno compile --output=app server.ts"
// }Deno 2 中的 Web 框架
Deno 2 支持多种方式构建 Web 应用,从内置的 Deno.serve() 到流行的框架。
Deno.serve() (Built-in)
// Simple HTTP server with Deno.serve()
Deno.serve({ port: 3000 }, async (req: Request) => {
const url = new URL(req.url);
if (url.pathname === "/api/hello") {
return Response.json({ message: "Hello from Deno 2!" });
}
if (url.pathname === "/api/data" && req.method === "POST") {
const body = await req.json();
return Response.json({ received: body }, { status: 201 });
}
return new Response("Not Found", { status: 404 });
});
console.log("Server running on http://localhost:3000");Express.js 兼容性
得益于 npm 兼容性,你可以在 Deno 2 中直接运行 Express.js 应用,只需最小的更改。
// Express.js running in Deno 2
import express from "npm:express@4";
import cors from "npm:cors";
const app = express();
app.use(cors());
app.use(express.json());
app.get("/api/users", (_req, res) => {
res.json([
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" },
]);
});
app.listen(3000, () => {
console.log("Express on Deno 2: http://localhost:3000");
});Deno 2 中的测试
Deno 包含内置的测试运行器,支持断言、模拟、基准测试和代码覆盖率。无需额外的测试框架。
// math.test.ts
import { assertEquals, assertThrows } from "jsr:@std/assert";
function add(a: number, b: number): number {
return a + b;
}
Deno.test("add function", () => {
assertEquals(add(2, 3), 5);
assertEquals(add(-1, 1), 0);
assertEquals(add(0, 0), 0);
});
Deno.test("async test", async () => {
const response = await fetch("https://api.example.com/data");
assertEquals(response.status, 200);
});
Deno.test({
name: "test with permissions",
permissions: { read: true, net: false },
fn() {
const data = Deno.readTextFileSync("./test-data.txt");
assertEquals(data.length > 0, true);
},
});
// Run: deno test
// Run with coverage: deno test --coverage=./cov部署选项
Deno 2 应用可以部署到各种平台,包括 Deno Deploy、Docker 容器和传统 VPS。
Deno Deploy
Deno Deploy 是专为 Deno 设计的全球分布式边缘托管平台,提供零配置部署和自动 HTTPS。
# Install deployctl
deno install -A jsr:@deno/deployctl
# Deploy to Deno Deploy
deployctl deploy --project=my-app main.ts
# Or link to GitHub for automatic deploymentsDocker 部署
Deno 在 Docker 容器中运行良好。官方 Deno Docker 镜像轻量且适合生产使用。
# Dockerfile for Deno 2
FROM denoland/deno:2.0.0
WORKDIR /app
# Cache dependencies
COPY deno.json deno.lock ./
RUN deno install
# Copy source
COPY . .
# Cache the main module
RUN deno cache main.ts
EXPOSE 3000
CMD ["deno", "run", "--allow-net", "--allow-read", "--allow-env", "main.ts"]常见问题
可以在 Deno 2 中使用现有的 npm 包吗?
可以。Deno 2 使用 npm: 说明符原生支持 npm 包。绝大多数 npm 包无需修改即可工作。
Deno 2 已经准备好用于生产了吗?
是的。Deno 2 为生产使用而设计。Slack、Netlify 和 Supabase 等公司在生产中使用 Deno。
应该从 Node.js 迁移到 Deno 2 吗?
对于新项目,Deno 2 是出色的选择。对于现有项目,迁移是可行的但可选的。
Deno 2 与 Bun 相比如何?
两者都是现代 JavaScript 运行时。Bun 专注于原始速度,Deno 专注于安全性和 Web 标准合规性。
Deno 2 开箱即用支持 TypeScript 吗?
是的。Deno 原生支持 TypeScript,无需任何配置。可以直接运行 .ts 和 .tsx 文件。