强曰为道

与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

第 06 章:模块系统

第 06 章:模块系统

6.1 Deno 模块系统概述

Deno 基于 ECMAScript Modules (ESM) 标准构建模块系统,与 Node.js 的 CommonJS 有本质区别:

特性Deno (ESM)Node.js (CJS)
模块语法import / exportrequire() / module.exports
加载方式静态分析,异步加载动态加载,同步执行
文件扩展名必须带扩展名可省略
模块来源URL、npm、JSR、本地文件npm / 本地文件
顶层 await✅ 支持⚠️ 仅 ESM 支持
Tree Shaking✅ 原生支持❌ 需要工具
// Deno 标准的模块导入方式
import { serve } from "https://deno.land/[email protected]/http/server.ts";
import { Router } from "jsr:@oak/oak@^16";
import express from "npm:[email protected]";
import { helper } from "./utils.ts";

6.2 URL 导入

Deno 最初的设计理念之一——依赖通过 URL 显式声明

远程 URL 导入

// 导入 Deno 标准库
import { serve } from "https://deno.land/[email protected]/http/server.ts";

// 导入第三方模块
import { bold, green } from "https://deno.land/[email protected]/fmt/colors.ts";

// 导入其他 CDN 托管的模块
import lodash from "https://esm.sh/[email protected]";

URL 导入的优势

优势说明
无需包管理器不需要 npm/yarn/pnpm
版本显式URL 中直接包含版本号
去中心化可以从任意 HTTP 服务器导入
缓存下载后缓存到本地,离线可用

URL 导入的缓存机制

首次运行:下载模块 → 存入 ~/.cache/deno/deps/
后续运行:检查缓存 → 直接使用缓存版本
deno cache --reload:强制重新下载
# 手动缓存依赖
deno cache main.ts

# 重新加载特定模块
deno cache --reload=https://deno.land/[email protected]/ main.ts

# 重新加载所有依赖
deno cache --reload main.ts

deno.land 命名规范

https://deno.land/std@版本/模块路径       # 标准库
https://deno.land/x/包名@版本/模块路径    # 第三方模块
// 标准库
import { join } from "https://deno.land/[email protected]/path/join.ts";

// 第三方模块
import { oak } from "https://deno.land/x/[email protected]/mod.ts";

6.3 JSR(JavaScript Registry)

JSR 是 Deno 团队推出的现代化包注册中心,原生支持 TypeScript。

从 JSR 导入

// 使用 jsr: 协议
import { encodeBase64 } from "jsr:@std/[email protected]/base64";

// 使用版本范围
import { serve } from "jsr:@std/http@^0.224";

// 在导入映射中配置
import { oak } from "oak";  // 需要在 deno.json 中配置

JSR vs npm

特性JSRnpm
TypeScript 原生❌(需预编译)
文档生成✅ 自动生成❌ 需要工具
多运行时Deno / Node / Bun / 浏览器主要 Node
包格式ESMCJS + ESM
注册方式Git 仓库npm publish
类型声明自动生成.d.ts 文件

发布到 JSR

// deno.json
{
  "name": "@username/my-package",
  "version": "1.0.0",
  "exports": "./mod.ts"
}
# 首次发布
deno publish

# 更新版本后发布
deno publish

JSR 的包发现

# 搜索包
deno search http server

# 查看包信息
deno info jsr:@std/http

6.4 npm 兼容(Deno 2.0+)

Deno 2.0 大幅增强了 npm 兼容性,可以直接使用绝大多数 npm 包。

npm: 协议导入

// 直接导入 npm 包
import express from "npm:[email protected]";

// 使用 npm 包的子模块
import { zip } from "npm:[email protected]";

// 使用 @types(自动获取类型)
import chalk from "npm:chalk@5";

npm 包版本范围

// 精确版本
import _ from "npm:[email protected]";

// 版本范围
import _ from "npm:lodash@^4.17";    // >=4.17.0 <5.0.0
import _ from "npm:lodash@~4.17.21";  // >=4.17.21 <4.18.0

// 最新版本(不推荐)
import _ from "npm:lodash";

npm 包缓存

# npm 包缓存位置
deno info
# npm modules cache: /home/user/.cache/deno/npm

# 清理 npm 缓存
deno clean

使用 package.json(可选)

// package.json
{
  "dependencies": {
    "express": "^4.18",
    "lodash-es": "^4.17"
  },
  "devDependencies": {
    "@types/express": "^4.17"
  }
}
// 仍然使用 npm: 协议,但版本从 package.json 读取
import express from "npm:express";
import _ from "npm:lodash-es";

6.5 导入映射(Import Map)

导入映射是管理依赖别名的强大工具,相当于项目的"依赖字典"。

在 deno.json 中配置

{
  "imports": {
    "std/": "https://deno.land/[email protected]/",
    "oak": "jsr:@oak/oak@^16.0",
    "drizzle-orm": "npm:drizzle-orm@^0.29",
    "react": "npm:react@^18.0",
    "react-dom": "npm:react-dom@^18.0",
    "react-dom/": "npm:react-dom@^18.0/",
    "@utils/": "./src/utils/",
    "@models/": "./src/models/",
    "@config": "./src/config.ts"
  }
}

使用导入映射

// 不再使用长 URL,使用简洁别名
import { serve } from "std/http/server.ts";
import { Router } from "oak";
import { drizzle } from "drizzle-orm";
import React from "react";
import { formatDate } from "@utils/date.ts";
import { User } from "@models/user.ts";
import config from "@config";

导入映射的范围

{
  "imports": {
    "lodash/": "npm:[email protected]/"
  }
}
// 支持路径映射
import { map } from "lodash/map.js";
import { filter } from "lodash/filter.js";

导入映射的注意事项

⚠️ 注意

  • 映射键如果以 / 结尾,值也必须以 / 结尾
  • 精确匹配优先于前缀匹配
  • 映射不支持通配符

6.6 工作空间(Workspace)

Deno 2.0 支持工作空间管理多个关联包。

项目结构

my-monorepo/
├── deno.json           # 根配置
├── packages/
│   ├── core/
│   │   ├── deno.json
│   │   └── mod.ts
│   ├── api/
│   │   ├── deno.json
│   │   └── main.ts
│   └── web/
│       ├── deno.json
│       └── main.tsx

根配置

// my-monorepo/deno.json
{
  "workspace": [
    "./packages/core",
    "./packages/api",
    "./packages/web"
  ],
  "imports": {
    "@my/core": "./packages/core/mod.ts"
  }
}

子包配置

// packages/api/deno.json
{
  "name": "@my/api",
  "version": "1.0.0",
  "exports": "./main.ts",
  "imports": {
    "@my/core": "jsr:@my/core@^1.0",
    "oak": "jsr:@oak/oak@^16"
  }
}

工作空间命令

# 在工作空间根目录运行
deno task dev         # 运行任务
deno test             # 测试所有包
deno lint             # 检查所有包
deno fmt              # 格式化所有包

# 运行特定包的任务
deno task --filter @my/api dev

6.7 模块导出模式

默认导出

// mod.ts
export default class App {
  start() {
    console.log("App started");
  }
}

// 使用
import App from "./mod.ts";

命名导出

// utils.ts
export function formatDate(date: Date): string {
  return date.toISOString().split("T")[0];
}

export function parseJSON<T>(text: string): T {
  return JSON.parse(text);
}

// 使用
import { formatDate, parseJSON } from "./utils.ts";

重导出(Re-export)

// mod.ts — 作为包的入口文件
export { serve } from "./server.ts";
export { Router } from "./router.ts";
export type { Request, Response } from "./types.ts";

条件导出

// deno.json 中的 exports 字段
{
  "exports": {
    ".": "./mod.ts",
    "./utils": "./src/utils.ts",
    "./types": "./src/types.ts"
  }
}

6.8 动态导入

// 动态导入模块
const modulePath = "./feature.ts";
const { default: feature } = await import(modulePath);

// 动态导入 npm 包
const lodash = await import("npm:[email protected]");

// 条件导入
if (Deno.env.get("NODE_ENV") === "production") {
  const { prodLogger } = await import("./logger.prod.ts");
  prodLogger.init();
} else {
  const { devLogger } = await import("./logger.dev.ts");
  devLogger.init();
}

6.9 本章小结

要点说明
ESM 标准Deno 完全基于 ES Modules
URL 导入依赖通过 URL 显式声明
JSR现代化的 TypeScript 优先包注册中心
npm 兼容npm: 协议直接使用 npm 包
导入映射deno.json 中管理依赖别名
工作空间workspace 字段管理 monorepo
扩展名导入本地文件必须带 .ts 扩展名

导入方式速查

// 1. 远程 URL
import { x } from "https://deno.land/[email protected]/mod.ts";

// 2. JSR 包
import { x } from "jsr:@std/http@^0.224";

// 3. npm 包
import x from "npm:[email protected]";

// 4. 本地文件
import { x } from "./utils.ts";

// 5. 导入映射
import { x } from "std/http/server.ts";

📖 扩展阅读


下一章第 07 章:标准库 → 了解 Deno 官方标准库的各个模块。