课程总纲 / 阶段 0 · 地基
L01

够用的 Node.js 与工具链

不追求精通 Node,但让项目里每条命令、每种写法你都能看懂。

预计阅读 20 分钟难度 ★☆☆☆☆动手:3 个小练习

一、三个角色:JavaScript、Node、浏览器The Cast

JavaScript(JS)是语言本身,像一份菜谱;照着做菜的程序叫运行时(runtime)。浏览器是最常见的一种;2009 年 JS 引擎被搬出浏览器做成独立程序,就是 Node.js

浏览器里的 JS

  • 能操作网页(按钮、动画)
  • 不能读文件、跑命令行
  • 安全沙箱罩着,干不了"系统级"的事

Node.js 里的 JS

  • 读写文件(node:fs)、跑子进程(node:child_process
  • 能开网络服务器
  • 拥有整台机器的能力——智能体框架必须基于它
定位:dsh 整个跑在 Node.js 上——读写文件、跑命令、调模型 API 全靠 Node。版本要求 ^22.19 || >=24

二、包与包管理器:npm 与 pnpmPackages

包(package)是发布出来复用的代码,相当于手机 App;全发布在 npm registry(应用商店)。包管理器负责下载安装:老牌叫 npm,本项目用升级版 pnpm(更快、更省磁盘)。

任何包(含仓库本身和每个子包)根目录都有 package.json

{
  "name": "@deepseek-ai/dsh-tools",   // @组织/包名 叫"scope"(命名空间)
  "version": "0.1.0",                // 语义化版本
  "type": "module",                 // ESM 模块标准(下一节讲)
  "dependencies": {                  // 运行时依赖:装我必须先装它们
    "@deepseek-ai/cordis": "workspace:*"
  }
}

本仓库一个真实包的 package.json(节选)

pnpm install 把所有依赖递归下载到 node_modules/相当于食材一次买齐。

三、Monorepo:一个仓库,几十个包Monorepo

monorepo:许多包放同一仓库统一管理,像写字楼租户——共用电梯物业,各自独立经营。

包名门道:自有包全是 @deepseek-ai/dsh-*(dsh = DeepSeek Harness 缩写);唯一例外 cordis——底层插件框架(阶段 1 专讲)。

四、ESM 模块:import 与 exportESM

模块就是一个 JS/TS 文件,官方标准 ESM 用两个关键字连接:

// math.ts —— 导出
export function add(a: number, b: number) { return a + b }
export const PI = 3.14

// main.ts —— 导入
import { add, PI } from './math.ts'
console.log(add(1, 2))  // 3

像快递柜:export 放东西进柜子,import 凭取件码去拿。老标准 CommonJS(require)本仓库不用,看到 require 要警惕。

铁律:dsh 源码启动走 tsx 的 ESM 专用通道,触及的模块必须保持 ESM。写插件用 import/export 天然满足。

五、TypeScript:带类型的 JavaScriptTypeScript

TypeScript(TS)= JS + 类型标注,后缀 .ts,先编译成 .js 才能跑。相当于合同:类型写死,违反了开工前报错,不是跑到一半崩。

function greet(name: string): string {
  return 'Hello, ' + name
}
greet('Ada')   // ✔ 合同允许
greet(42)      // ✘ 编译期就报错

本项目中反复见到的类型写法(速查)

写法含义通俗解释
string / number / boolean基础类型文本 / 数字 / 真假
interface Foo { ... }对象结构合同必须长这样
name?: string可选字段有最好,没有也行
'a' | 'b'联合类型只准是这几个值之一(单选题)
Promise<T>异步结果"过会儿给你的 T"(外卖单)
async / await异步语法等外卖到了再干下一步
(input: string) => void函数类型收 string、不返回的函数
Context本框架核心类型"总插座板",L05 讲
编译:pnpm run buildsrc/*.ts 编译到 lib/;开发时 tsx 可直跑源码。改源码 → 重新 build → 产物在 lib/

六、终端与 pnpm runScripts

package.json 的 scripts 给常用命令起短名字:

"scripts": {
  "build": "pnpm run -r build",   // 递归让每个子包各自 build
  "test": "vitest run"            // 用 vitest 跑测试
}

pnpm run build = 执行引号里的原始命令,相当于通讯录昵称。完整清单见 命令速查表

运行时 runtime
能执行某语言的程序。Node 是 JS 的运行时。
包 package
发布出来复用的代码单元,有 package.json 身份证。
monorepo
一个仓库管理多个包,本仓库的 packages/ 就是。
ESM
import/export 官方模块标准,本仓库强制使用。
TypeScript
带类型合同的 JS,编译成 js 才能跑。
scope 作用域包名
@组织/包名 形式,如 @deepseek-ai/dsh-tools。
✏️ 动手练习
  1. 输入 node -v 查版本,低于 22.19 去 nodejs.org 装 LTS。
  2. 输入 pnpm -v,不存在则 npm install -g pnpm(npm 随 Node 自带)。
  3. 打开仓库根 package.json,数 scripts 段有几个"昵称",对照 命令速查表
预期结果:三条完成,对"命令 = 脚本昵称"有手感。
📝 自测(点击展开答案)
1. Node 和浏览器 JS 的最大区别?
能力范围:浏览器 JS 被沙箱限制碰不了文件系统;Node 拥有整台机器能力,智能体框架必须基于它。
2. pnpm install 做了什么?
读 package.json(含子包)的依赖清单,从 npm registry 下载到 node_modules/。
3. @deepseek-ai 这段包名前缀叫什么?
scope(命名空间),DeepSeek AI 组织的包。自有包都是 dsh-*;cordis 是唯一例外。
4. 为什么改了源码要重新 build?
源码是 .ts,运行的是 lib/ 里的 .js 产物;不重新 build 跑的还是旧的。
5. import/export 和 require 什么关系?
前者是 ESM(本仓库强制),后者是 CommonJS(老标准)。
权威出处:docs/development.md · packages/README.md · AGENTS.md(Conventions 节)