资讯专栏INFORMATION COLUMN

浅析webpack源码之Compiler.js模块(八)

PumpkinDylan / 660人阅读

摘要:小尾巴最终返回了属性挂载把引入的函数模块全部暴露出来下面暴露了一些插件再通俗一点的解释比如当你你能调用文件下的方法这个和上面的不同在于上面的是挂在函数对象上的正题要想理解必须要理解再写一遍地址我们先简单的理解它为一个通过注册插件是插件的事

webpack.js小尾巴
const webpack = (options, callback) => {
    //... 
    if (callback) {
        if (typeof callback !== "function") {
            throw new Error("Invalid argument: callback");
        }
        if (
            options.watch === true ||
            (Array.isArray(options) && options.some(o => o.watch))
        ) {
            const watchOptions = Array.isArray(options)
                ? options.map(o => o.watchOptions || {})
                : options.watchOptions || {};
            return compiler.watch(watchOptions, callback);
        }
        compiler.run(callback);
    }
    return compiler;
}

最终返回了compiler

  
exports.version = version;

// ...属性挂载,把引入的函数模块全部暴露出来
webpack.WebpackOptionsDefaulter = WebpackOptionsDefaulter;
webpack.WebpackOptionsApply = WebpackOptionsApply;
webpack.Compiler = Compiler;
webpack.MultiCompiler = MultiCompiler;
webpack.NodeEnvironmentPlugin = NodeEnvironmentPlugin;
// @ts-ignore Global @this directive is not supported
webpack.validate = validateSchema.bind(this, webpackOptionsSchema);
webpack.validateSchema = validateSchema;
webpack.WebpackOptionsValidationError = WebpackOptionsValidationError;

下面暴露了一些插件

const exportPlugins = (obj, mappings) => {
    for (const name of Object.keys(mappings)) {
        Object.defineProperty(obj, name, {
            configurable: false,
            enumerable: true,
            get: mappings[name]
        });
    }
};

exportPlugins(exports, {
    AutomaticPrefetchPlugin: () => require("./AutomaticPrefetchPlugin"),
    BannerPlugin: () => require("./BannerPlugin"),
    CachePlugin: () => require("./CachePlugin")}
)

再通俗一点的解释:

比如当你api.AutomaticPrefetchPlugin你能
调用AutomaticPrefetchPlugin文件下的方法

这个和上面的不同在于上面的是挂在webpack函数对象上的

Compiler.js正题

要想理解Compiler.js
必须要理解tapable
再写一遍 git地址

我们先简单的理解它为一个通过tap 注册插件
call是run插件的事件流,里面还有一些异步的操作

Compiler整理如下

class Compiler extends Tapable {
    constructor(context) {
        super();
        this.hooks = {
            //罗列一些出现频率比较高的
            shouldEmit: new SyncBailHook(["compilation"]),
            done: new AsyncSeriesHook(["stats"]),
            beforeRun: new AsyncSeriesHook(["compiler"]),
            run: new AsyncSeriesHook(["compiler"]),
            emit: new AsyncSeriesHook(["compilation"]),
            afterEmit: new AsyncSeriesHook(["compilation"]),
            thisCompilation: new SyncHook(["compilation", "params"]),
            compilation: new SyncHook(["compilation", "params"]),
            beforeCompile: new AsyncSeriesHook(["params"]),
            compile: new SyncHook(["params"]),
            make: new AsyncParallelHook(["compilation"]),
            afterCompile: new AsyncSeriesHook(["compilation"]),
            watchRun: new AsyncSeriesHook(["compiler"]),
            //...
            
        }
        // 添加事件流
        this._pluginCompat.tap("Compiler", options => {
            switch (options.name) {
                case "additional-pass":
                case "before-run":
                case "run":
                case "emit":
                case "after-emit":
                case "before-compile":
                case "make":
                case "after-compile":
                case "watch-run":
                    options.async = true;
                    break;
            }
        });
        
    }
    watch(){
           //...
    }
    
    run(callback) {
        //... 
    }
    // 清除输入文件系统
    purgeInputFileSystem() {
        if (this.inputFileSystem && this.inputFileSystem.purge) {
            this.inputFileSystem.purge();
        }
    }
    emitAssets(compilation, callback) {
        //...
    }
    createChildCompiler(
        compilation,
        compilerName,
        compilerIndex,
        outputOptions,
        plugins
    ) {
        //...
    
        
    }
    //...
    compile(callback){
        //...
    }    
}

和tapable用法一个模子里刻出来的,我们仔细的研究run函数

compiler.js是webpack 的核心

run(callback) {
   //如果正在running,返回报错处理
    if (this.running) return callback(new ConcurrentCompilationError());
    
    //running调用finalCallback 
    const finalCallback = (err, stats) => {
        this.running = false;

        if (callback !== undefined) return callback(err, stats);
    };
    //记录初始化running时间
    const startTime = Date.now();
    //设置running标志,防止多次running
    this.running = true;
    
    //正在编译
    const onCompiled = (err, compilation) => {
        //如果报错,编译结束
        if (err) return finalCallback(err);

        //如果没有编译完成
        if (this.hooks.shouldEmit.call(compilation) === false) {
             // Stats模块有1400行,
             // compiler.js是webpack 的核心,new Stats(compilation)是compiler.js的核心
            const stats = new Stats(compilation);
             //    stats对象挂载startTime,endTime 
            stats.startTime = startTime;
            stats.endTime = Date.now();
            // 异步调用完成事件流,running结束
            this.hooks.done.callAsync(stats, err => {
                if (err) return finalCallback(err);
                return finalCallback(null, stats);
            });
            return;
        }
        // 调用emitAsset方法,emitAsset主要负责写入文件输出文件,不影响我们先看编译
        this.emitAssets(compilation, err => {
            // 类似同上, 如果报错,编译结束
            if (err) return finalCallback(err);
            // 如果需要额外的编译,上次的没编译完成吗           
               
                                           
                       
                 

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/101228.html

相关文章

  • 浅析webpack源码Tapable粗解(五)

    摘要:打开是个构造函数,定义了一些静态属性和方法我们先看在插件下地址上面写的解释就跟没写一样在文件下我们看到输出的一些对象方法每一个对应一个模块而在下引入的下面,我们先研究引入的对象的英文单词解释,除了最常用的点击手势之外,还有一个意思是水龙头进 打开compile class Compiler extends Tapable { constructor(context) { ...

    Arno 评论0 收藏0
  • FE.SRC-webpack原理梳理

    摘要:执行完成后会返回如下图的结果,根据返回数据把源码和存储在的属性上的回调函数中调用类生成,并根据生成依赖后回调方法返回类。 webpack设计模式 一切资源皆Module Module(模块)是webpack的中的关键实体。Webpack 会从配置的 Entry 开始递归找出所有依赖的模块. 通过Loaders(模块转换器),用于把模块原内容按照需求转换成新模块内容. 事件驱动架构 we...

    cfanr 评论0 收藏0
  • 浅析webpack源码convert-argv模块(二)

    摘要:接下来我看看一下函数我们先按照分支走为读取是里的对象,饶了这大的一个圈子,那么接下来一起来看一看对你的输入配置做了怎么样的处理吧 打开webpeck-cli下的convert-argv.js文件 // 定义options为空数组 const options = []; // webpack -d 检查 -d指令 if (argv.d) { //... } ...

    lemon 评论0 收藏0
  • 浅析webpack源码processOptions处理Options以及入口函数(三)

    摘要:我们打开根据上次所返回的这个因为有了上次的基础,比较容易读了大体逻辑是这样的先定义一个空对象同上次的一个逻辑,还是一个目前的方式只有一个满足如果满足的会执行一系列函数这个函数直接结果是的影响是打比如如果满足的话当你的时候就会在页面上出 我们打开bin/cli.js根据上次所返回的Options processOptions(options)这个因为有了上次的基础,比较容易读了,大体逻辑...

    doodlewind 评论0 收藏0
  • 浅析webpack源码WebpackOptionsApply 模块(七)

    摘要:还做了处理,是之所以能根据变化自己更新的核心,好凌乱,我们先从那个坑跳出来进入这个大坑进入这个页面看到前面一大堆的模块引入,已经给跪了,但是马马虎虎的完成也比放弃好前面一大堆的引入,主要是下和文件夹下的模块父类就只是定义了接口主要核心在方法 NodeEnvironmentPlugin还做了watch处理,NodeWatchFileSystem是webpack之所以能根据变化自己更新的核...

    AaronYuan 评论0 收藏0

发表评论

0条评论

PumpkinDylan

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<