Node.js 工程化开发流程 — 知识点总结

Node.js 工程化开发流程 --- 知识点总结


一、Node.js 项目初始化

1.1 npm init --- 创建项目

bash 复制代码
npm init -y    # -y 跳过交互式问答,直接生成 package.json

package.json 是 Node.js 项目的身份证,记录:

  • 项目名称、版本、描述
  • 依赖列表(dependencies / devDependencies
  • 脚本命令(scripts
  • 模块类型("type": "module" 或默认 CommonJS)

1.2 安装依赖

bash 复制代码
npm install openai /dotenv    # 等价于 npm i openai/ dotenv

安装的包会:

  • 下载到 node_modules/ 目录
  • 记录到 package.jsondependencies
  • 生成 package-lock.json(锁定精确版本)

二、npm 和 pnpm 是什么

2.1 包管理器的作用

npm (Node Package Manager)和 pnpm (Performant npm)都是 Node.js 的包管理器

它们做的事:

  1. 下载 --- 从 npm registry 拉取第三方包
  2. 安装 --- 把包放到 node_modules/,解析依赖树
  3. 管理版本 --- 记录、锁定、升级依赖版本
  4. 运行脚本 --- npm run dev / pnpm run dev

npm 是 Node.js 自带的(装 Node 就自带 npm),pnpm 需要额外安装。

2.2 核心区别:磁盘管理方式

这是两者最本质的区别:

npm --- 每个项目各自存一份完整的依赖副本:

bash 复制代码
project-a/node_modules/express/   (真实的 express 文件)
project-b/node_modules/express/   (又一份完整的 express 文件)
project-c/node_modules/express/   (第三份)

pnpm --- 全局只存一份,项目里放硬链接(指针):

bash 复制代码
磁盘
├── ~/.pnpm-store/               ← 全局缓存,每份包只存一次
│   └── express@4.21.0/           (唯一的真实文件)
│
├── project-a/node_modules/express → 硬链接(指针)
├── project-b/node_modules/express → 硬链接(指针)
└── project-c/node_modules/express → 硬链接(指针)

效果:同样的依赖装 10 个项目,npm 占 10 份磁盘空间,pnpm 只占 1 份。

2.3 全方位对比

维度 npm pnpm
安装速度 🟡 基准线 🟢 快得多(并行下载 + 硬链接)
磁盘占用 🔴 每个项目各自存 🟢 全局去重
node_modules 结构 扁平化(依赖全铺平) 严格树状(只暴露你声明的)
幽灵依赖 ❌ 允许(你没声明也能 import) ✅ 禁止(必须显式声明)
Monorepo 支持 一般 🟢 原生 workspace
命令兼容性 --- 🟢 和 npm 基本一致

幽灵依赖 :你 import express 但没在 package.json 里安装它,npm 下"碰巧能用"(因为被别的包间接依赖了)。pnpm 不允许,强制你显式声明。

2.4 使用

bash 复制代码
# 安装 pnpm(只需一次)
npm install -g pnpm

# 之后日常使用,命令和 npm 一样
pnpm init -y
pnpm add openai /dotenv         # 等同于 npm install
pnpm add -D nodemon            # -D 装为开发依赖
pnpm run dev                   # 运行 scripts

2.5 pnpm add 和 pnpm install 的区别

pnpm addpnpm install 不是一回事 ,虽然 npm 里 install 可以当 add 用。

pnpm 的区分:

命令 作用
pnpm add openai 添加 一个新依赖(写入 package.json + 下载安装)
pnpm install 安装 package.json 里已有的全部依赖(不带包名)
bash 复制代码
pnpm add openai          # ✅ 新增 openai 依赖
pnpm install             # ✅ 安装已有全部依赖(clone 项目后首次执行)
pnpm install openai      # ⚠️ pnpm 不推荐,但部分版本会当作 add 处理

npm 的混淆来源:

npm 的设计导致了这个困惑------同一个命令干了两种事:

bash 复制代码
npm install              # 安装全部依赖(读取 package.json)
npm install openai       # 添加 openai 依赖(写入 package.json + 安装)

npm 早期没有 add 子命令(新版加了但少有人用),所以 install 承载了两层含义。

pnpm 的设计更清晰:

go 复制代码
pnpm add <包名>     → 往项目里加一个新依赖(修改 package.json)
pnpm install        → 把已有依赖全部装好(不修改 package.json)

对照表:

场景 npm pnpm
装全部依赖 npm install pnpm install
新增一个包 npm install xxx pnpm add xxx
新增开发依赖 npm install -D xxx pnpm add -D xxx
简写 npm i xxx pnpm add xxx

总结 :pnpm 里装全部依赖用 install,新增依赖用 add,分工明确。"已有依赖"指的是已经写在 package.jsondependencies 里的包。pnpm install 就是照着那张清单把所有包下载回来。


三、nodemon --- 文件监听自动重启

3.1 它是什么

nodemon 是一个开发工具,监听文件变化,自动重启 Node.js 进程

没有它的时候,你每改一行代码都要手动:

bash 复制代码
# 改代码 → Ctrl+C 停掉 → 重新 node index.mjs → 测试 → 再改 → 再重启...
node index.mjs

有了它:

bash 复制代码
nodemon index.mjs
# 改代码 → 保存 → nodemon 自动检测 → 自动重启 → 直接看效果 ✅

3.2 安装和使用

bash 复制代码
# 装为开发依赖(只在开发时用,上线不需要)
npm add -D nodemon
# 或 pnpm add -D nodemon

# 使用
npx nodemon index.mjs

3.3 原理

nodemon 用 fs.watch() 监控项目目录的文件变化 → 检测到变更 → 杀死旧进程 → 启动新进程。

通常在 package.json 里配一个脚本:

json 复制代码
{
  "scripts": {
    "dev": "nodemon index.mjs"
  }
}

之后 npm run dev 就能启动带热重载的开发模式。


四、API Key 隐藏工作流

4.1 问题

API 密钥(sk-xxx...)不能硬编码在代码里,更不能提交到 git。

4.2 解决方案:.env + .gitignore

bash 复制代码
项目根目录
├── .env           ← 存真实密钥,.gitignore 忽略
├── .env.example   ← 存变量名模板(值留空),提交到 git
└── .gitignore     ← 加上 .env

4.3 .env 文件格式

env 复制代码
# .env
# 格式:KEY=VALUE(大写键名,等号连接,一行一对)
DEEPSEEK_API_KEY=sk-xxxxxxxxxxxxx
DEEPSEEK_BASE_URL=https://api.deepseek.com

注意= 两边不要加空格,值不需要加引号。

4.4 完整流程

arduino 复制代码
1. 在 .gitignore 中加上 .env
       ↓
2. 创建 .env,写入真实密钥
       ↓
3. 创建 .env.example,只写变量名(值留空当模板),提交到 git
       ↓
4. 代码中 import 'dotenv/config'
       ↓
5. 用 process.env.KEY 读取

这样密钥只在本地,永远不会泄露到 git 仓库。


五、ES Module 模块系统

js 复制代码
import dotenv from 'dotenv';
import OpenAI from 'openai';

5.1 .mjs 后缀

  • .mjs = Module JavaScript,明确告诉 Node.js 这个文件使用 ES Module 语法
  • .cjs = CommonJS(require / module.exports
  • .js = 由 package.json"type" 字段决定:"module" 走 ESM,不配就走 CJS

5.2 ESM vs CommonJS

ES Module (ES6) CommonJS (Node 传统)
导入 import xxx from 'yyy' const xxx = require('yyy')
导出 export default / export const module.exports =
加载时机 静态分析,编译时确定 运行时动态加载
Tree-shaking ✅ 支持 ❌ 不支持
异步 天然异步 同步加载

六、dotenv 环境变量加载

js 复制代码
import dotenv from 'dotenv';
dotenv.config();
// 之后 process.env.KEY 就可用了

也可以一行搞定:

js 复制代码
import 'dotenv/config';    // 等价于上面两行

dotenv 做的事(原理):

  1. 读取项目根目录的 .env 文件
  2. 按行解析 KEY=VALUE
  3. 注入到 process.env(Node.js 进程的环境变量对象)
  4. 已存在的同名环境变量默认不覆盖(系统级优先)

七、process 进程对象

7.1 进程是什么

css 复制代码
操作系统分配资源(内存、CPU、I/O)的最小单位 = 进程
node index.mjs → 操作系统启动一个 Node.js 进程 → 执行你的代码

7.2 process 全局对象

process 是 Node.js 的全局对象(不用 import,任何文件直接用),封装了当前进程的全部信息和控制能力。

属性/方法 用途 示例
process.env 运行时环境变量 process.env.PORT
process.argv 命令行参数 node app.js --port 3000
process.cwd() 当前工作目录 /home/user/project
process.exit() 退出进程 process.exit(0)
process.pid 进程 ID 12345
process.version Node.js 版本 v20.11.0
process.memoryUsage() 内存使用情况 调试内存泄漏

八、OpenAI SDK 调用 AI 模型

js 复制代码
// 1. 实例化客户端
const client = new OpenAI({
    apiKey: process.env.DEEPSEEK_API_KEY,    // 从环境变量取密钥
    baseURL: process.env.DEEPSEEK_BASE_URL   // 兼容任意厂商的 API 地址
});

// 2. 调用 Chat Completion API
const result = await client.chat.completions.create({
    model: 'deepseek-v4-flash',
    messages: [
        { role: 'user', content: 'hello world' }
    ],
});

// 3. 提取回复
console.log(result.choices[0].message.content);

关键认知:

  • OpenAI SDK 是通用客户端 ,改 baseURL 就能对接 DeepSeek、通义千问、智谱等任何兼容 OpenAI 接口的服务
  • messages 数组支持多轮对话,角色有三种:
    • system --- 设定 AI 的行为/人设
    • user --- 用户说的话
    • assistant --- AI 之前的回复
  • 同步调用 vs 异步调用 :API 请求是异步的(需要等网络返回),必须用 await 等结果,否则拿到的是 Promise 对象而不是实际数据

九、async/await 异步编程

9.1 核心认知

JS 代码的编写顺序执行顺序有时候不同。

同步代码:写完一行执行一行,顺序一致。 异步代码:发起请求后不等着,继续往下执行,结果回来后再回调。

js 复制代码
// 同步 --- 顺序一致
console.log(1);
console.log(2);
// 输出:1  2

// 异步 --- 顺序不同
console.log(1);
setTimeout(() => console.log(2), 1000);
console.log(3);
// 输出:1  3  (1秒后) 2

9.2 async/await 的作用

控制异步代码的执行顺序,让异步代码按同步的方式写。

js 复制代码
const main = async () => {           // async 声明异步函数
    console.log('程序开始运行');
    const result = await client.chat... // await 等结果回来再继续
    console.log(result);                 // 拿到结果后才执行
    console.log('程序结束');
};
main();
关键字 作用
async 修饰函数,让它变成异步函数(自动返回 Promise)
await 暂停执行,等 Promise 完成拿到结果后再往下走

9.3 常用于异步的场景

  • API 调用(网络请求,耗时不确定)
  • 文件读写(磁盘 I/O)
  • 定时器(setTimeout
  • 数据库查询

9.4 单点入口模式

js 复制代码
// main.mjs --- 单点入口文件
const main = async () => {   // main --- 单点入口函数
    // 所有逻辑从这里开始
};
main();

这是 Node.js 工程化的一个约定:一个入口文件 + 一个入口函数,结构清晰。


十、AIGC 工程化开发流程总结

流程图

csharp 复制代码
① npm init -y                      → 初始化项目,生成 package.json
       ↓
② 配置 .gitignore + .env            → 密钥安全
       ↓
③ pnpm add openai/ dotenv            → 安装依赖
       ↓
④ 创建 main.mjs(单点入口文件)      → 定义 main() 单点入口函数
       ↓
⑤ import + dotenv.config()          → 加载环境变量
       ↓
⑥ new OpenAI({ apiKey, baseURL })   → 实例化客户端对象
       ↓
⑦ await client.chat.completions...   → 调用 Chat Completion API
       ↓
⑧ async/await 控制异步执行顺序       → 同步按顺序执行(快)/ 异步需等待(慢)
       ↓
⑨ nodemon 监听文件变化自动重启       → 开发效率

关键认知

  • AI 项目 / Agent 项目几乎都是后端项目(Node.js 或 Python)
  • 为什么?因为 API 密钥不能暴露在前端,模型调用必须在服务端
  • 工程化不只是写代码,还包括:初始化 → 配置管理 → 依赖管理 → 开发工具 → 代码组织
相关推荐
ZengLiangYi1 小时前
sql.js WASM 深度解析
javascript·数据库·后端
JustHappy2 小时前
古法编程秘籍(三):为什么需要函数?因为程序员讨厌重复劳动
前端·javascript·后端
想要狠赚笔的小燕2 小时前
vue项目的入口文件是什么 main.js还是index.html,他俩有啥区别
前端·javascript
之歆2 小时前
Day02_ES6+ 核心特性深度解析:现代 JavaScript 开发的基石
前端·javascript·es6
小KK_3 小时前
新手必看篇——JS类型判断
前端·javascript
小妖6663 小时前
console.log 显示内容不全怎么办
javascript·js·console.log
AI科技星3 小时前
万有引力G与真空介电常数ε0全维度完整关系式汇编(基于v=c螺旋时空理论)
c语言·开发语言·前端·javascript·网络·汇编·electron
didadida2623 小时前
第二回: Session Assistant 工具链的三节点设计
javascript·agent
云间寄信3 小时前
异步编程与事件循环
javascript