实现一个简单的Nodemon

效果展示

Nodemon 源码分析(核心部分)

第一步

  • 描述:使用 chokidar 进行文件监听,当文件更改后会触发filterAndRestart函数。
  • 文件路径:lib/monitor/watch.js

第二步

  • 描述:filterAndRestart函数,会通过事件总线来发送重启Node.js进程的指令。
  • 文件路径:lib/monitor/watch.js

第三步

  • 描述:事件总线接收到重启指令后,会触发run.kill,终止子进程。
  • 文件路径:lib/monitor/run.js

第四步

  • 描述:子进程退出时,会触发重启函数,从而实现热更新。
  • 文件路径:lib/monitor/run.js

第五步

  • 描述:最后看看nodemon一般会通过spawn运行子进程,与主进程进行管道连接。
  • 文件路径:lib/monitor/run.js

实现思路

  • 使用chokidar来监听JS文件的修改。
  • 通过event模块来实现事件总线,用来跨模块通信。
  • 文件修改后,终止当前子进程,然后重新创建一个子进程,与主进程进行管道连接,最终达到热更新效果。

代码实现

第一步

  • 先搞一个事件总线,用来提供通信。
  • 文件路径:lib/myNodemon/bus.js
js 复制代码
const EventEmitter = require('events')

class Bus extends EventEmitter {}

const bus = new Bus();

module.exports = {
  bus
}

第二步

  • 实现监听函数。
  • 文件路径:lib/myNodemon/watch.js
js 复制代码
const chokidar = require("chokidar");
const path = require("path");
const { bus } = require("./bus.js");

function watch() {
  console.log("开始监听");
  const dirs = path.resolve(__dirname, "../../src");
  chokidar.watch(dirs).on('add', (path) => {
    bus.emit('restart')
  })
  chokidar.watch(dirs).on("change", (path) => {
    bus.emit('restart')
  });
}

module.exports = {
  watch,
};

第三步

  • 在入口文件执行监听、绑定重启函数。
  • 文件路径:lib/myNodemon/main.js
js 复制代码
const { spawn, exec } = require("child_process");
const { bus } = require("./bus.js");
const { watch } = require("./watch.js");

watch();

let child = undefined;

bus.on("restart", restartChild);

function restartChild() {
  console.clear();
  console.log(`[${new Date().toLocaleString()}] 已清理命令行内容:`)
  if (child) {
    child.kill("SIGINT");
    if (process.stdin && child.stdin) {
      process.stdin.unpipe(child.stdin);
    }
    if (process.stdout && child.stdout) {
      process.stdout.unpipe(child.stdout);
    }
  }
  const binPath = process.cwd() + "/node_modules/.bin" + "/node";
  child = spawn("sh", [binPath, process.argv.at(-1)], { stdio: "inherit" });
  if (process.stdin && child.stdin) {
    process.stdin.pipe(child.stdin);
  }
  if (process.stdout && child.stdout) {
    process.stdout.pipe(child.stdout);
  }
}

第四步

  • 最后,在package.json中配置脚本
json 复制代码
{
  "scripts": {
    "dev": "node lib/myNodemon/main.js src/main.js"
  }
}

结语

本文记录了作者对nodemon工作原理的学习和了解,文中若有不足的部分欢迎各位大佬进行指导。

😝 打个广告:如果您目前有合并表格的行/列需求,可以尝试一下 @jinming6/merge-helper 插件。

相关推荐
沙蒿同学16 小时前
我用 Go 搭了一条 AI Agent 流水线:从 1 张商品图到一整套淘宝详情页
前端·javascript·后端
paopaokaka_luck17 小时前
智慧社区综合服务小程序(人脸识别、AI问答、Echarts图形化分析)
前端·javascript·spring boot·spring·数据分析·echarts
Hilaku18 小时前
为什么死磕 1px 的团队,用户体验反而更差?
前端·javascript·程序员
陈拉斯18 小时前
给公司年会写了个大屏抽奖系统:动画在前端跑,凭什么说结果没被改?
javascript
yzy8519 小时前
Vue中下载或打开文件的JavaScript方法
前端·javascript·vue
用户2986985301419 小时前
在 React 中用 JavaScript 将 Word 转换为文本
前端·javascript·react.js
李少兄21 小时前
深入解析 JavaScript 中的 `document` 对象
javascript
paopaokaka_luck21 小时前
考研政治刷题小程序(AI推荐题目、ECharts数据分析、章节练习与专项训练、模拟考试、错题本与收藏夹、学习打卡与目标管理、题库和组卷维护)
前端·javascript·spring boot·spring·数据分析·echarts
刃神太酷啦21 小时前
前端入门第一课:HTML 基础语法 + 常用标签 + 实战全解
服务器·c语言·前端·javascript·css·c++·html
mldong21 小时前
给流程设计器加国际化,我没引 vue-i18n
前端·javascript·vue.js