node.js开发
node.js开发
最近, 学院打算部署一个DeepSeek用于2025级招生问答工作, 苏喵觉得学院方案并不可行, 所以, 我编写了一个基于DeepSeek API和本地数据库的程序Kirafint.
该程序使用nodejs编写, 过程中咱也学到了很多东西, 这里一一分享一下.
1. node文件结构
一个node程序结构如下:
<Project Name>
├── node_modules/
├── src
│ ├── index.js
│ ├── cli
│ │ └── cli.js
│ └── other
│ ├── file1.js
│ └── file2.json
├── .gitignore
├── package.json
├── package-lock.json
├── pnpm-lock.yaml
└── README.md上述file-tree中, 有些文件由包管理器直接生成, 其他文件为自己编写, 下面一一讲解.
1.1 必须文件
1.1.1 src/文件夹
src/文件夹是整个项目的程序文件, 该文件夹所有完全由开发者编写.
src/index.js是整个程序都入口文件, 运行该模块时, 实际上就行以运行该文件的方式运行.
src/文件夹其他文件多以文件夹包裹, 为其他逻辑, 接口等功能文件.
src/文件夹中也有一些约定俗成的文件(夹), 如src/utils/文件夹, 用于存储插件(如自己编写的日志工具)等.
1.1.2 package.json文件
package.json是项目的清单, 是整个工具的配置中心.
专业详细的讲解详见node官方文档 入门教程/package.json指南
package.json文件如下内容如下:
{
"name": "project_name",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {},
"keywords": [],
"author": "",
"license": "MIT",
"packageManager": "[email protected]",
"dependencies": {}
}其中:
name,version,description: 项目名, 版本号, 描述main: 程序主入口scripts: 定义了一组可以运行的脚本license: (开源)协议packageManager: 包管理器, 示例使用的是pnpmdependencies: 项目依赖, 当项目使用某外部库时, 需要在此处写明(一般IDE会自动添加), 之后包管理器会自动下载相应包.
当我们使用包管理器初始化一个node项目时, package.json文件会自动生成.
1.2 包文件
1.2.1 package-lock.json文件
package.json文件中, 对依赖的版本并不明确. 例如对于某依赖的0.13.0版本, 若写入~0.13.0, 则意味着0.13.*版本均可用; 若写入^0.13.0, 则意味着0.13.0+(包括0.14.*等更高版本)均可用; 只有写入0.13.0时, 才会固定0.13.0版本.
当文件发送给他人, 使用pnpm install时, 包管理器会下载许可的最新依赖. 也就是除了写死0.13.0版本外, 会自动下载~0.13.0中的0.13.<max>和^0.13.0的最新版本.
所以使用package-lock.json文件, 固定了现在包的版本. 当使用pnpm install安装/更新时, 该文件不会变化; 只有明确使用pnpm install更新时, 该文件才会发生变化.
1.2.2 pnpm-lock.yaml文件
别问, 窝也不知道...
1.2.3 node_modules/文件夹

如图所示.
node_mudules文件夹是自动生成的依赖文件夹. 但是前端社区经常各种互相依赖, 所以可能所需几个依赖, 但最终下载了一大堆东西.
不过该文件夹并不需要开发者管理, 包管理器会自动填满它.
1.3 自定义文件
README.md没啥可说的.
.gitignore一定要写上node_modules/!!
2. 常用库
不定期更新
2.1 commander
commander库是用于命令行程序入口的库, 在index.js中引用commander, 可快速制作一个cli入口.
const {Command} = require("commander");
const program = new Command();之后可以如下定义程序的name, description和其他操作.
Kirafint的定义如下所示:
program
.name("Kirafint")
.description("基于Deepseek API和本地模型的AI Demo")
.option("-c, --cli", "命令行模式")
.option("-s, --server", "服务器模式")
program.parse(process.argv);定义好name, description后, 直接运行该文件, commander会自动生成入口说明. 例如提示词和使用方法等.
此外, .option()中规定的参数操作, commander也就自动根据提示生成-h, --help帮助提示.
直接运行该文件效果如下:
Usage: Kirafint [options]
基于Deepseek API和本地模型的AI Demo
Options:
-c, --cli 命令行模式
-s, --server 服务器模式
-h, --help display help for command在.option()中规定的参数(flag)会被处理成对象的属性, 可用如下代码检测读取到的参数:
const options = program.opts();
if (options.cli) {
// cli 部分代码
} else if (options.server) {
// server 部分代码
} else if (Object.keys(options).length === 0) {
program.help();
}当输入node src/index -c时, options.cli为true, 执行对应代码.
此外, .option()中还可以自定义参数, 例如:
program.option("-f, --float <number>", "float argument", parseFloat);这样会对opts新建一个float属性, 类型为float(因为结尾的parsefloat).
我们可以使用如下代码检查用户是否输入该命令或输入了什么参数:
const options = program.opts();
if (options.float !== undefined) {
// 我是代码
}代码和示例摘自Commander中文网开发文档/选项/自定义选项处理
2.2 chalk
chalk提供了一系列终端字符串样式, 可以轻松的调整输出的颜色, 字体等.
该库使用十分简单, 直接展示代码:
const chalk = require("chalk");
console.log(chalk.blue("Hello world!"))
console.log(chalk.blue.bgRed.bold("Hello chalk~"));
console.log(chalk.blud("Hello", "World!", "Foo"));
console.log(chalk.red("Hello", chalk.underline.bgBlue("World") + "!"));
console.log(chalk.rgb(123, 45, 67).underline("Underlined reddish color"));
console.log(chalk.hex('#DEADED').bold('Bold gray!'));上述代码差不多覆盖了chalk的所有应用场景.
Chalk中文网开发文档