剩下一个watch模块,这个模块比较深,先大概过一下整体涉及内容再分部讲解。

  流程图如下:

NodeWatchFileSystem

const Watchpack = require("watchpack");class NodeWatchFileSystem {constructor(inputFileSystem) {this.inputFileSystem = inputFileSystem;this.watcherOptions = {aggregateTimeout: 0};this.watcher = new Watchpack(this.watcherOptions);}watch(files, /*Array*/dirs, /*Array*/missing, /*Array*/startTime, /*number*/options, /*object*/callback, /*function*/callbackUndelayed /*function*/) {// params validate...const oldWatcher = this.watcher;// 生成Watchpack对象this.watcher = new Watchpack(options);if (callbackUndelayed)this.watcher.once("change", callbackUndelayed);this.watcher.once("aggregated", (changes, removals) => { /**/ });// 调用watch方法this.watcher.watch(files.concat(missing), dirs.concat(missing), startTime);if (oldWatcher) {oldWatcher.close();}return {close: () => { /**/ },pause: () => { /**/ }};}
}module.exports = NodeWatchFileSystem;

  除去细节代码,该模块大体如下;

1、引入Watchpack模块

2、接受一个inputFileSystem作为构造函数的参数

3、根据配置选项实例化一个Watchpack类

4、核心watch方法为调用实例类的watch方法,传入给定参数,绑定两个一次性事件绑定并返回了一个对象

  模块核心的方法调用的是Watchpack实体类上的,所以需要进一步探究该类。

  该模块涉及到了nodejs的event模块,内容非常简单,这里就不做介绍了,详情可查看官网API:https://nodejs.org/dist/latest-v8.x/docs/api/events.html

Watchpack

var watcherManager = require("./watcherManager");
var EventEmitter = require("events").EventEmitter;
Watchpack.prototype = Object.create(EventEmitter.prototype);class Watchpack {constructor(options) {EventEmitter.call(this);if (!options) options = {};if (!options.aggregateTimeout) options.aggregateTimeout = 200;this.options = options;this.watcherOptions = {ignored: options.ignored,poll: options.poll};this.fileWatchers = [];this.dirWatchers = [];this.mtimes = Object.create(null);this.paused = false;this.aggregatedChanges = [];this.aggregatedRemovals = [];this.aggregateTimeout = 0;this._onTimeout = this._onTimeout.bind(this);}watch(files, directories, startTime) {this.paused = false;var oldFileWatchers = this.fileWatchers;var oldDirWatchers = this.dirWatchers;this.fileWatchers = files.map(function(file) {return this._fileWatcher(file, watcherManager.watchFile(file, this.watcherOptions, startTime));}, this);this.dirWatchers = directories.map(function(dir) {return this._dirWatcher(dir, watcherManager.watchDirectory(dir, this.watcherOptions, startTime));}, this);oldFileWatchers.forEach(function(w) {w.close();}, this);oldDirWatchers.forEach(function(w) {w.close();}, this);};pause() { /**/ };getTimes() { /**/ };_fileWatcher(file, watcher) { /**/ };_dirWatcher(item, watcher) { /**/ };_onChange(item, mtime, file) { /**/ };_onRemove(item, file) { /**/ };_onTimeout() { /**/ };close() { /**/ };
}module.exports = Watchpack;function addWatchersToArray(watchers, array) { /**/ }

  本模块引入了并继承了nodejs的EventEmitter,并引入了新模块watcherManager,主要内容罗列如下:

1、构造函数接受一个对象,键包括aggregateTimeout、ignored、poll,本例只传入第一个并设置为0

2、核心方法为watch,依赖于引入的watchManager模块

3、其余方法均为工具方法

WatcherManager

var path = require("path");class WatcherManager {constructor() {this.directoryWatchers = {};};// 工厂函数
    getDirectoryWatcher(directory, options) {// 引入模块var DirectoryWatcher = require("./DirectoryWatcher");options = options || {};var key = directory + " " + JSON.stringify(options);if (!this.directoryWatchers[key]) {this.directoryWatchers[key] = new DirectoryWatcher(directory, options);// 文件监视结束则从容器删除this.directoryWatchers[key].on("closed", function() {delete this.directoryWatchers[key];}.bind(this));}return this.directoryWatchers[key];};// 监视文件
    watchFile(p, options, startTime) {var directory = path.dirname(p);return this.getDirectoryWatcher(directory, options).watch(p, startTime);};// 监视目录
    watchDirectory(directory, options, startTime) {return this.getDirectoryWatcher(directory, options).watch(directory, startTime);};
}
module.exports = new WatcherManager();

  可以看出这是一个中间处理函数,其中构造函数生成了一个容器,容器的键为目录+参数生成的一个字符串,当监视关闭后会并立即删除。

  这个模块类似于tapable,是一个监视对象管理器。

  然后是监视核心实现模块,模块内容比较多,这里只简单看一下构造函数以及watch方法:

var EventEmitter = require("events").EventEmitter;
var async = require("async");
var chokidar = require("chokidar");
var fs = require("graceful-fs");class Watcher {constructor(directoryWatcher, filePath, startTime) {EventEmitter.call(this);this.directoryWatcher = directoryWatcher;this.path = filePath;this.startTime = startTime && +startTime;this.data = 0;};checkStartTime(mtime, initial) { /**/ };close() { /**/ };
}function DirectoryWatcher(directoryPath, options) {EventEmitter.call(this);this.options = options;this.path = directoryPath;this.files = Object.create(null);this.directories = Object.create(null);this.watcher = chokidar.watch(directoryPath, {ignoreInitial: true,persistent: true,followSymlinks: false,depth: 0,atomic: false,alwaysStat: true,ignorePermissionErrors: true,ignored: options.ignored,usePolling: options.poll ? true : undefined,interval: typeof options.poll === "number" ? options.poll : undefined,disableGlobbing: true});this.watcher.on("add", this.onFileAdded.bind(this));this.watcher.on("addDir", this.onDirectoryAdded.bind(this));this.watcher.on("change", this.onChange.bind(this));this.watcher.on("unlink", this.onFileUnlinked.bind(this));this.watcher.on("unlinkDir", this.onDirectoryUnlinked.bind(this));this.watcher.on("error", this.onWatcherError.bind(this));// ...
}DirectoryWatcher.prototype.watch = function watch(filePath, startTime) {this.watchers[withoutCase(filePath)] = this.watchers[withoutCase(filePath)] || [];this.refs++;var watcher = new Watcher(this, filePath, startTime);watcher.on("closed", function() { /**/ }.bind(this));// ...return watcher;
};// ...

module.exports = DirectoryWatcher;

  从构造函数和模块引入可以得到很多信息,如下:

1、引入了graceful-js模块,可以看出底层还是利用nodejs的fs模块来进行监视

2、所有的监视事件都是基于nodejs的EventEmitter模块来进行操作

3、内部还有一个辅助类Watcher

4、根据构造函数的代码,监视的操作包含(可能不限于)新增文件、新增文件夹、改变内容、删除文件、删除文件夹等

  async模块是一个类似于tapable的辅助工具,用于异步处理批量方法,详细内容可自行去网上查阅。

  构造函数中,该模块又再次引用了chokidar模块,并调用其watch方法进行初始化,看似调用方法,源码简化后如下:

class FSWatcher {// ...
}
exports.FSWatcher = FSWatcher;
exports.watch = function(paths, options) {return new FSWatcher(options).add(paths);
};

  假的,这还是个new操作,只是为了方便把两步合成到了一个方法中。

  所有的模块整理如上,下面几节再来剖析每一块内容。

转载于:https://www.cnblogs.com/QH-Jimmy/p/8059129.html

.12-浅析webpack源码之NodeWatchFileSystem模块总览相关推荐

  1. .9-浅析webpack源码之NodeEnvironmentPlugin模块总览

    介绍Compiler的构造比较无趣,不如先过后面的,在用到compiler的时候再做讲解. 这一节主要讲这行代码: // 不管这里 compiler = new Compiler(); compile ...

  2. webpack 源码分析(四)——complier模块

    webpack 源码分析(四)--complier模块 上一篇我们看到,webpack-cli 通过 yargs 对命令行传入的参数和配置文件里的配置项做了转换包装,然后传递给 webpack 的 c ...

  3. webpack源码阅读——npm脚本运行webpack与命令行输入webpack的区别

    原文地址:webpack源码阅读--npm脚本执行webpack与命令行输入webpack执行的区别 如有错误,欢迎指正! webpack是目前被大家广为使用的模块打包器.从命令行输入webpack或 ...

  4. nginx源码分析之模块初始化

    在nginx启动过程中,模块的初始化是整个启动过程中的重要部分,而且了解了模块初始化的过程对应后面具体分析各个模块会有事半功倍的效果.在我看来,分析源码来了解模块的初始化是最直接不过的了,所以下面主要 ...

  5. webpack 源码泄露

    0x01 漏洞简介 webpack是一个JavaScript应用程序的静态资源打包器(module bundler).它会递归构建一个依赖关系图(dependency graph),其中包含应用程序需 ...

  6. webpack 源码分析系列 ——loader

    想要更好的格式阅读体验,请查看原文:webpack 源码分析系列 --loader 为什么需要 loader webpack是一个用于现代 JavaScript 应用程序的静态模块打包工具.内部通过构 ...

  7. .17-浅析webpack源码之compile流程-入口函数run

    本节流程如图: 现在正式进入打包流程,起步方法为run: Compiler.prototype.run = (callback) => {const startTime = Date.now() ...

  8. Tengine怎么去安装第三方模块、以及安装源码中的模块

    Tengine怎么去安装第三方模块 检查配置文件nginx.conf的内容编辑后是否有错误 nginx -t 有以下错误,需要下载第三方模块 nginx: [emerg] unknown direct ...

  9. thttpd源码解析 定时器模块

    thttpd源码解析 定时器模块 thttpd是非常轻量级的http服务器,可执行文件仅50kB.名称中的第一个t表示tiny, turbo, 或throttling 与lighttpd.memcac ...

最新文章

  1. cocos2d-x 3.1.1 学习笔记[15] Shader 著色器
  2. 使用NMAKE管理工程
  3. 选什么地方,进多少商品,想开超市,这些必须了解
  4. journal of systems science and complexity
  5. 张向东:就以当年期望别人对我们那样的方式
  6. 重温Elasticsearch
  7. aws python lambda_python – AWS Lambda发送HTTP请求
  8. 安卓模拟器安装过程记录 20200926
  9. python小测试1答案_测试1:Python 基本语法(选择题
  10. 嵌入式linux设备驱动程序是,嵌入式Linux设备驱动开发之:按键驱动程序实例-嵌入式系统-与非网...
  11. 爬取网易某只股票2017-01到2018-01的数据
  12. Cetnos环境下inotify+rsync实时同步
  13. SQL 2005 Reporting Services:物理分页和逻辑分页 SSRS 2008 report export to PDF - Cannot get size to work...
  14. 移动计算机笔试题,广东移动笔试题目
  15. 数字图像处理编程入门笔记
  16. 三星手机微信下载的文件路径
  17. STM32——EMWIN 字体(二十)
  18. springboot基于安卓的移动数字图书馆的设计与实现毕业设计源码030911
  19. 斐讯(Phicomm)空气检测仪(悟空 M1)通过 EasyLink
  20. Unity图集优化原理

热门文章

  1. 【HDU - 1559】最大子矩阵 (二维前缀和裸题)
  2. 1.UNIX网络编程卷1:源码配置
  3. 消息测试服务器,测试统一消息服务器功能
  4. Redis 缓存 Key
  5. servlet基础总结
  6. 《Head First设计模式》读书笔记_第一章
  7. Xcode的Architectures和Valid Architectures的区别
  8. php 单选框选中事件,html中的checkbox和radio事件选择用法详解
  9. C++primer 第 3 章 字符串、向量和数组 3 . 4 迭代器介绍
  10. C++11学习 新特性之 “=default” 、“=delete”