DevToolBox免费
博客

Deno 2 完全指南:Node.js 兼容性与迁移

14 分钟作者 DevToolBox

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 deployments

Docker 部署

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 文件。

𝕏 Twitterin LinkedIn
这篇文章有帮助吗?

保持更新

获取每周开发技巧和新工具通知。

无垃圾邮件,随时退订。

试试这些相关工具

JSTypeScript to JavaScript{ }JSON Formatter

相关文章

Bun vs Node.js vs Deno 2026:运行时对比

对比 JavaScript 运行时。

TypeScript 5 新特性:装饰器、const 类型参数与 satisfies 运算符

TypeScript 5 新特性完全指南:装饰器、const 类型参数、satisfies 运算符及性能改进。