博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
.26-浅析webpack源码之事件流make(1)
阅读量:5105 次
发布时间:2019-06-13

本文共 6597 字,大约阅读时间需要 21 分钟。

  compilation事件流中,依然只是针对细节步骤做事件流注入,代码流程如图:

// apply => this-compilation// apply => compilation // return compialtionconst compilation = this.newCompilation(params);this.applyPluginsParallel("make", compilation, err => {    // callback...});

  触发完compilation事件流后,会直接返回一个compilation对象,然后触发下一个事件流make。

  make的来源在EntryOptionPlugin插件中,无论entry参数是单入口字符串、单入口数组、多入口对象还是动态函数,都会在引入对应的入口插件后,注入一个make事件。

  这里先以最简单的单入口字符串为例,开始跑make事件流:

// SingleEntryPlugincompiler.plugin("make", (compilation, callback) => {    // 生成一个类型为single entry的依赖类    // dep.loc = name    const dep = SingleEntryPlugin.createDependency(this.entry, this.name);    compilation.addEntry(this.context, dep, this.name, callback);});

 

Compilation.addEntry

  这里回到了compilation类中,调用原型函数addEntry。

class Compilation extends Tapable {    // ...    // context => 默认为process.cwd()    // entry => dep => SingleEntryDependency    // name => 单入口默认为main    // callback => 后面的流程    addEntry(context, entry, name, callback) {        const slot = {            name: name,            module: null        };        // 初始为[]        this.preparedChunks.push(slot);        this._addModuleChain(context, entry, (module) => { /**/ }, (err, module) => { /**/ });    }}

 

Compilation._addModuleChain

  没什么好讲的,直接进入_addModuleChain函数:

class Compilation extends Tapable {    // ...    _addModuleChain(context, dependency, onModule, callback) {        // profile => options.profile         // 不传则start为undefined        const start = this.profile && Date.now();        // bail => options.bail        const errorAndCallback = this.bail ? (err) => {            callback(err);        } : (err) => {            err.dependencies = [dependency];            this.errors.push(err);            callback();        };        if (typeof dependency !== "object" || dependency === null || !dependency.constructor) {            throw new Error("Parameter 'dependency' must be a Dependency");        }        // dependencyFactories包含了所有的依赖集合        const moduleFactory = this.dependencyFactories.get(dependency.constructor);        if (!moduleFactory) {            throw new Error(`No dependency factory available for this dependency type: ${dependency.constructor.name}`);        }        this.semaphore.acquire(() => { /**/ });    }}

  profile和bail参数大概不会有人传吧,所有直接忽视。

  接下来就是尝试从dependencyFactories中获取依赖类对应的值,这个Map对象所有值的设置都在compilation事件流中,详情可见24节中的流程图,传送门:http://www.cnblogs.com/QH-Jimmy/p/8183840.html

  在这里,依赖类来源于SingleEntryDependency,键值对设置地点同样来源于SingleEntryPlugin:

// SingleEntryPlugincompiler.plugin("compilation", (compilation, params) => {    const normalModuleFactory = params.normalModuleFactory;    // 这里    compilation.dependencyFactories.set(SingleEntryDependency, normalModuleFactory);});

  所以很简单,这里调用get后取出来的是normalModuleFactory。

  而这个normalModuleFactory,在18节中有简单介绍并分析了其中RuleSet对module.rules的处理,传送门:http://www.cnblogs.com/QH-Jimmy/p/8109903.html

  

semaphore

  获取对应的moduleFactory后,调用的this.semaphore其中是生成一个新类:

this.semaphore = new Semaphore(options.parallelism || 100);

  (类的名字英文翻译是信号机)

  内容比较简单,过一下源码:

class Semaphore {    // 一个数字 默认为100    constructor(available) {        this.available = available;        this.waiters = [];    };    // 当available大于0时执行callback并减1    // 否则将callback弹入waiters    acquire(callback) {        if (this.available > 0) {            this.available--;            callback();        } else {            this.waiters.push(callback);        }    };    // 尝试取出最近弹入的callback并在事件流末尾执行    release() {        if (this.waiters.length > 0) {            const callback = this.waiters.pop();            process.nextTick(callback);        } else {            this.available++;        }    }}

  设计看起来确实像个信号机,构造函数中有一个初始的使用次数以及一个待执行callback数组。

  每次调用acquire时会传入一个callback,如果次数为正就执行callback并将使用次数减1,如果次数用完了,就把这个callback弹入waiters数组中。

  每次调用release时,为尝试取出最新的callback并尽快执行,如果不存在待执行的callback,就将使用次数加1。

 

NormalModuleFactory.create

  也就是说,以下代码可以理解成简单的函数调用:

this.semaphore.acquire(() => {    moduleFactory.create({        contextInfo: {            issuer: "",            compiler: this.compiler.name        },        context: context,        dependencies: [dependency]    }, (err, module) => { /* fn... */ });});

  这样,流程跑到了normalModuleFactory的原型方法create上。

class NormalModuleFactory extends Tapable {    /*        data =>         {            contextInfo:{                issuer: '',                compiler: this.compiler.name // undefined            },            context: context, // process.cwd()            dependencies: [SingleEntryDependency]        }    */    create(data, callback) {        const dependencies = data.dependencies;        // 尝试取缓存        const cacheEntry = dependencies[0].__NormalModuleFactoryCache;        if (cacheEntry) return callback(null, cacheEntry);        // 上下文 => process.cwd()        const context = data.context || this.context;        // 入口文件字符串 => ./input.js        const request = dependencies[0].request;        const contextInfo = data.contextInfo || {};        this.applyPluginsAsyncWaterfall("before-resolve", {            contextInfo,            context,            request,            dependencies        }, (err, result) => { /**/ });    }}

  这里将上下文、入口文件、入口模块依赖类整合,然后开始触发normalModuleFactory类上的事件流。

  关于normalModuleFactory的事件流注入,全部都在24节中有介绍,再来一个传送门:http://www.cnblogs.com/QH-Jimmy/p/8183840.html

  这里的事件流before-resolve是没有的,所以按照Tapable的中applyPluginsAsyncWaterfall的执行方式:

Tapable.prototype.applyPluginsAsyncWaterfall = function applyPluginsAsyncWaterfall(name, init, callback) {    if (!this._plugins[name] || this._plugins[name].length === 0) return callback(null, init);    // more...}

  这里会直接调用callback,分别传入null与第二个参数,如下所示:

this.applyPluginsAsyncWaterfall("before-resolve", {        contextInfo,        context,        request,        dependencies    },    // err => null    // result => 上面的对象     (err, result) => {        if (err) return callback(err);        if (!result) return callback();        // 触发factory事件流        const factory = this.applyPluginsWaterfall0("factory", null);        // Ignored        if (!factory) return callback();        factory(result, (err, module) => { /**/ });    });

  这里会接着触发factory事件流,这个是在构造函数中直接plugin的。

class NormalModuleFactory extends Tapable {    constructor(context, resolvers, options) {        super();        // ...other property        this.plugin("factory", () => (result, callback) => {            let resolver = this.applyPluginsWaterfall0("resolver", null);            if (!resolver) return callback();            resolver(result, (err, data) => { /**/ });        });    }}

  这里又触发了resolver事件流,同样是构造函数中另外一个plugin的事件。

 

  这节先到这里。

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

你可能感兴趣的文章
解释性语言和编译性语言的区别
查看>>
Swift3.0服务端开发(三) Mustache页面模板与日志记录
查看>>
Java读取.properties配置文件的几种方法
查看>>
【转】 FPGA设计的四种常用思想与技巧
查看>>
移动端页面头部定义
查看>>
职责链模式(Chain of Responsibility)
查看>>
C++:同名隐藏和赋值兼容规则
查看>>
EntityFrameWork 实现实体类和DBContext分离在不同类库
查看>>
Microsoft .NET 远程处理:技术概述(代理模式)
查看>>
新手算法学习之路----二叉树(在一个二叉查找树中插入一个节点)
查看>>
autopep8
查看>>
GIT在Linux上的安装和使用简介
查看>>
java 类型转型
查看>>
基于C#编程语言的Mysql常用操作
查看>>
【转】Java反射 之 反射基础
查看>>
mysql数据库备份和还原的常用命令
查看>>
s3c2440实验---定时器
查看>>
HBase配置性能调优(转)
查看>>
MyEclipse10安装SVN插件
查看>>
[转]: 视图和表的区别和联系
查看>>