第 06 章:模块系统
第 06 章:模块系统
6.1 Deno 模块系统概述
Deno 基于 ECMAScript Modules (ESM) 标准构建模块系统,与 Node.js 的 CommonJS 有本质区别:
| 特性 | Deno (ESM) | Node.js (CJS) |
|---|---|---|
| 模块语法 | import / export | require() / 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
| 特性 | JSR | npm |
|---|---|---|
| TypeScript 原生 | ✅ | ❌(需预编译) |
| 文档生成 | ✅ 自动生成 | ❌ 需要工具 |
| 多运行时 | Deno / Node / Bun / 浏览器 | 主要 Node |
| 包格式 | ESM | CJS + 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 官方标准库的各个模块。