当我们在做Node服务端开发的时候通常都会监听一个启动的端口来进行通信,当服务的内容发生改变的时候总是需要重新启动服务来保证服务内容可以被页面或接口正确获取,当重启的次数变的多了以后往往就会考虑到自动重启来解决这种重复的劳动,如:nodemon。那么我们就来探索一下要实现一个类似nodemon的功能。
前提概要:
1. 涉及知识点:
- fs.watch,fs.watchFile,chokidar;
- child_process,spawn
2. 任务拆解:
- 监听文件的改变;
- 自动重启服务。
监听文件的改变:
在node的fs包下提供watch和watchFile两个API可以来实现文件和内容变化的监听,但是在nodemon的依赖配置中有这么一个依赖chokidar,通过查看chokidar的说明文档得知
如下信息: Node.js fs.watch:
- 在 MacOS 上不报告文件名。
- 在 MacOS 上使用 Sublime 等编辑器时根本不报告事件。
- 重复报告事件。
- 将大多数更改作为rename。
- 不提供递归监听文件树的简单方法。
- 不支持在 Linux 上递归监听。
Node.js fs.watchFile:
- 在事件处理方面不完美。
- 不提供任何递归监听。
- 导致 CPU 使用率高。
我们可以通过chokidar提供的第一个代码片段来实现今天的功能:
const chokidar = require('chokidar'); // One-liner for current directory chokidar.watch('.').on('all', (event, path) => { console.log(event, path); }); 复制代码
自动重启服务:
我们的node服务通常都是通过命令来执行入口文件,所以我们这里就需要使用node中child_process包下的spawn来操作我们的命令,spawn的参数分别是:1.执行的命令,2.命令附带的参数,3.将子进程io对接到父进行进行输出:
function startServer() { let childProcess = spawn("node", ["index.js"], { stdio: [process.stdin, process.stdout, process.stderr], }); console.log("[ starting ] >", `${childProcess}node .index.js`); } 复制代码
完整的代码实现:
// watch.js const chokidar = require("chokidar"); const { spawn } = require("child_process"); let childProcess; const debounceStartServer = debounce(startServer, 1000); chokidar.watch(["./index.js"]).on("all", (event, path) => { childProcess && childProcess.kill(); debounceStartServer(); }); function startServer() { console.log("[ starting ] >", "node .index.js"); childProcess = spawn("node", ["index.js"], { stdio: [process.stdin, process.stdout, process.stderr], }); } function debounce(fun, wait = 200) { let timer; return function () { const context = this; const args = arguments; if (timer) clearTimeout(timer); timer = setTimeout(() => { fun.apply(context, args); }, wait); }; } // index.js const Koa = require("koa"); const app = new Koa(); app.use((ctx) => { ctx.body = "hi Koa"; }); app.listen(3000);