1. 源码简介

update-notifier 作用:Update notifications for your CLI app (检测 npm 包是否有更新)。
本质就是开了 child_process 运行在后台,如果检查到有可用更新版,会将结果保存在 .update 属性中。

简单例子:

  1. const updateNotifier = require('update-notifier');
  2. updateNotifier({
  3. pkg: {
  4. name: 'public-ip',
  5. version: '0.9.2'
  6. },
  7. updateCheckInterval: 24 * 60 * 60
  8. }).notify();

学习目标:
1)学习 update-notifier 源码,输出记录文档。

源码地址:
https://github.com/yeoman/update-notifier

2. update-notifier 源码

源码其实就一个 200 行不到的 index.js 文件,乍一看用到了很多包,但核心是 UpdateNotifier 构造函数。它接收一个 options 对象,输出一个 UpdateNotifier 实例。这个实例有一个属性 update,是用来标记是否有可用更新版,如果有,就输出更新信息,运行上面简单例子结果如下(存在可用更新版):
image.png
UpdateNotifier 构造函数有三个函数:check() 检查,fetchInfo() 拉取信息,notify() 通知。

以上面的简单例子结合源码为例:

  1. // 初始化 UpdateNotifier 实例
  2. const updateNotifier = require('update-notifier');
  3. // 对应源码中 UpdateNotifier constructor 部分的代码 + check函数
  4. constructor(options = {}) {
  5. this.options = options;
  6. // ... 省略了部分源码,主要是容错处理和字段检测
  7. }
  8. check() {
  9. // 当存在以下情况时停止检查
  10. if (!this.config || this.config.get('optOut') || this.disabled) {
  11. return;
  12. }
  13. // 获取相关包的更新信息 第一次检查时是 undefined
  14. this.update = this.config.get('update');
  15. if (this.update) {
  16. // 如果有更新,赋值
  17. this.update.current = this.packageVersion;
  18. // 删除缓存的数据
  19. this.config.delete('update');
  20. }
  21. if (Date.now() - this.config.get('lastUpdateCheck') < this.updateCheckInterval) {
  22. return;
  23. }
  24. // 子进程
  25. spawn(process.execPath, [path.join(__dirname, 'check.js'), JSON.stringify(this.options)], {
  26. detached: true,
  27. stdio: 'ignore'
  28. }).unref();
  29. }
  30. // 调用实例的 notify 函数
  31. updateNotifier({
  32. pkg: {
  33. name: 'public-ip',
  34. version: '0.9.2'
  35. },
  36. updateCheckInterval: 24 * 60 * 60
  37. }).notify();
  38. // 对应源码中的 notify 函数
  39. notify(options) {
  40. // 满足以下情况时不需要通知(比如没有更新的时候不需要通知)
  41. const suppressForNpm = !this.shouldNotifyInNpmScript && isNpm().isNpmOrYarn;
  42. if (!process.stdout.isTTY || suppressForNpm || !this.update || !semver().gt(this.update.latest, this.update.current)) {
  43. return this;
  44. }
  45. // 需要通知的情况,控制台输出更新信息
  46. // 省略部分描写UI的源码...
  47. // 此处return的this,option配置已改变
  48. return this;
  49. }

3. 总结

总体流程引用【凌晨三点半】的笔记:

  • const updateNotifier = new UpdateNotifier({})
    • 初始化 constuctor
    • updateNotifier.check()
  • 判断是否执行 check.js,如果执行:
    • updateNotifier.fetchInfo()
    • set(‘lastUpdateCheck’)
    • set(‘update’)
  • notify()

【凌晨三点半】的笔记很详细,细节满满的,感谢~