WebpackOptionsDefaulter模块

 

  通过参数检查评定后,会根据单/多配置举办拍卖,本文基于单配置,所以会伸开到如下代码:

if (Array.isArray(options)) {
    compiler = new MultiCompiler(options.map(options => webpack(options)));
} else if (typeof options === "object") {
    // TODO webpack 4: process returns options
    // 这里的处理有部分是为了webpack4.0做准备
    new WebpackOptionsDefaulter().process(options);
    // ...
}

  模块的成效是进行暗中同意值的设置,流程图如下:

  永利开户送38元体验金 1

  进入该模块:

"use strict";

const OptionsDefaulter = require("./OptionsDefaulter");
const Template = require("./Template");

class WebpackOptionsDefaulter extends OptionsDefaulter {
    constructor() {
        super();
        this.set("devtool", false);
        // 大量的this.set...
    }
}
module.exports = WebpackOptionsDefaulter;

  能够见到,这么些模块的源委是用ES陆的新语法写的,很好明白,因为这么些模块是只是指向webpack的暗中同意设置,所以最主要效率内容应当都在原型上边,直接进入OptionsDefaulter模块:

"use strict";

function getProperty(obj, name) { /**/ }

function setProperty(obj, name, value) { /**/ }

class OptionsDefaulter {
    constructor() {
        this.defaults = {};
        this.config = {};
    }

    process(options) {
        // TODO: change this for webpack 4: options = Object.assign({}, options);
        for (let name in this.defaults) {
            switch (this.config[name]) {
                // case...
            }
        }
    }

    set(name, config, def) {
        if (arguments.length === 3) {
            this.defaults[name] = def;
            this.config[name] = config;
        } else {
            this.defaults[name] = config;
            delete this.config[name];
        }
    }
}
module.exports = OptionsDefaulter;

  那么些模块也是用ES6写的,内容相比轻松,首要内容如下:

一、构造函数定义七个目的defaults,config

2、四个原型方法process,set

3、五个工具方法getProperty,setProperty

  构造函数创建了多个目的,defaults对象保存了参数的私下认可值,而config对象保存了少数参数的极其规处理情势。

  由于原型方法重视于工具方法,所以从工具方法早先上课:

getProperty

// obj就是options
function getProperty(obj, name) {
    // 切割name
    name = name.split(".");
    // 注意这里是length-1
    for (let i = 0; i < name.length - 1; i++) {
        // 层层赋值
        obj = obj[name[i]];
        // 若obj非对象返回直接返回undefined
        if (typeof obj !== "object" || !obj) return;
    }
    // 返回最后一层的值
    return obj[name.pop()];
}

  那些函数有趣,直接占星比懵逼,必要来个案例:

// obj => {entry:'./inpuit.js',output:{filename:'output.js'}}
// name => output.filename
function getProperty(obj, name) {
    // 切割后得到[output,filename]
    name = name.split(".");
    // 第二次跳出循环
    for (let i = 0; i < name.length - 1; i++) {
        // obj => {filename:'output.js'}
        obj = obj[name[i]];
        // 返回了对象这里就不返回了
        if (typeof obj !== "object" || !obj) return;
    }
    // 注意这里obj是options.output
    // 所以返回的是options.output.filename
    return obj[name.pop()];
}

  可以看来,那些函数是尝尝获得对象的某部键,键的推动用点来连接,如若获得退步重返undefined。

  精妙的函数!制止了累累判定 obj[key] 是或不是为undefined,直接用字符串的主意消除了此难题。

setProperty

function setProperty(obj, name, value) {
    name = name.split(".");
    for (let i = 0; i < name.length - 1; i++) {
        // 非对象直接返回undefined
        if (typeof obj[name[i]] !== "object" && typeof obj[name[i]] !== "undefined") return;
        // 设置为对象
        if (!obj[name[i]]) obj[name[i]] = {};
        obj = obj[name[i]];
    }
    // 设置对应的值
    obj[name.pop()] = value;
}

  有了前方的getProperty,那一个就相比较好懂了。

 

  上边正是原型方法:

永利开户送38元体验金,set

    set(name, config, def) {
        if (arguments.length === 3) {
            this.defaults[name] = def;
            this.config[name] = config;
        }else {
            this.defaults[name] = config;
            delete this.config[name];
        }
    }

  没什么好讲的,依照传参数量对构造函数生成的对象开始展览复制。

  至于process方法会在后面调用,所以这边临时不讲,回到WebpackOptionsDefaulter中的多量set,抽出八个情景的张开解说:

this.set("output.chunkFilename", "make", (options) => {
    const filename = options.output.filename;
    return filename.indexOf("[name]") >= 0 ? filename.replace("[name]", "[id]") : "[id]." + filename;
});
this.set("resolve.extensions", [".js", ".json"]);

  调用那多个格局后,defaults与config对象如下:

defaults = {
    "resolve.extensions": [".js", ".json"],
    "output.chunkFilename": (options) => {
        const filename = options.output.filename;
        return filename.indexOf("[name]") >= 0 ? filename.replace("[name]", "[id]") : "[id]." + filename;
    })
}
config = {
    "output.chunkFilename": "make"
}

  函数中,由于output.filename是必传参数,所以能取到值。

  chunkFilename的函数会对字符串中的 [name] 置换成 [id] ,假若未有就增进 [id.] 前缀。

  譬如多输出中不经常会取 [name].js 作为出口文件名,在此地chunkFilename的暗许值就是 [id].js 。

 

  多量恢宏的set后,能够来探视process函数了,为便于呈现,写成function形式:

// 传进来的options
function process(options) {
    // 遍历defaults对象
    for (let name in this.defaults) {
        // 匹配config参数
        switch (this.config[name]) {
            // 默认情况直接进行赋值
            case undefined:
                if (getProperty(options, name) === undefined)
                    setProperty(options, name, this.defaults[name]);
                break;
                // 用来保证根键为对象
            case "call":
                setProperty(options, name, this.defaults[name].call(this, getProperty(options, name), options), options);
                break;
                // 默认值通过调用函数注入
                // 传入一个options参数
            case "make":
                if (getProperty(options, name) === undefined)
                    setProperty(options, name, this.defaults[name].call(this, options), options);
                break;
                // 将默认值添加进已有的数组中
            case "append":
                {
                    let oldValue = getProperty(options, name);
                    if (!Array.isArray(oldValue)) oldValue = [];
                    oldValue.push.apply(oldValue, this.defaults[name]);
                    setProperty(options, name, oldValue);
                    break;
                }
            default:
                throw new Error("OptionsDefaulter cannot process " + this.config[name]);
        }
    }
}

  依照config的情况有四种默许值注入格局,其中等学校函授数调用情势得以更进一步灵活的进展安顿。

 

  为求完整,在有个别set中有调用 Template.toIdentifier 方法,看1眼其里面贯彻:

// 匹配所有非大小写字母$_
const IDENTIFIER_NAME_REPLACE_REGEX = /^[^a-zA-Z$_]/;
// 匹配所有非大小写字母数字$_
const IDENTIFIER_ALPHA_NUMERIC_NAME_REPLACE_REGEX = /[^a-zA-Z0-9$_]/g;
module.exports = class Template extends Tapable {
    constructor(outputOptions) { /**/ }

    //静态方法 直接调用
    static toIdentifier(str) {
        if (typeof str !== "string") return "";
        // 特殊符号全部置换为_
        return str.replace(IDENTIFIER_NAME_REPLACE_REGEX, "_").replace(IDENTIFIER_ALPHA_NUMERIC_NAME_REPLACE_REGEX, "_");
    }

    // 其余方法...
}

  只是2个清淡无奇的字符替换函数而已。

  一句话计算:WebpackOptionsDefaulter模块对options配置对象增加了大气的暗许参数。

 

完事~

相关文章