三 、hash - qianlongdoit/webpack GitHub Wiki


hash的流程

  1. createHash
  2. updateHash

createHash类,后续的updateHash操作,最终都会指向这里

// lib/util/createHash.js
// 具类,上面主要有下面两个常用方法
// 新hash.buffer,及时清零
update(data){
    this.buffer += data;
}
// 成摘要
digest(encoding) {
    return hash.digest(encoding);
}

createHash 初始化hash fullhash renderHash

这个方法会在 seal(封存) 阶段调用,Compilation.seal

// /lib/Compilation.js
// 这个方法会在seal阶段调用
createHash() {
    const outputOptions = this.outputOptions;
    const hashFunction = outputOptions.hashFunction;
    const hashDigest = outputOptions.hashDigest;
    const hashDigestLength = outputOptions.hashDigestLength;
    const hash = createHash(hashFunction);
    if (outputOptions.hashSalt) {
        hash.update(outputOptions.hashSalt);
    }
    // hash.buff += 'maintemplate3'
    this.mainTemplate.updateHash(hash);
    // hash.buff += 'ChunkTemplate2'
    this.chunkTemplate.updateHash(hash);
    for (const key of Object.keys(this.moduleTemplates).sort()) {
        this.moduleTemplates[key].updateHash(hash);
    	// hash.buff += '1'
    }
    for (const child of this.children) {
        hash.update(child.hash);
    }
    for (const warning of this.warnings) {
        hash.update(`${warning.message}`);
    }
    for (const error of this.errors) {
        hash.update(`${error.message}`);
    }
    const modules = this.modules;
    for (let i = 0; i < modules.length; i++) {
        const module = modules[i];
        const moduleHash = createHash(hashFunction);	//生成一个hash实例, hashFunction: md4
        module.updateHash(moduleHash);	//moduleHash.buffer += module.id + 'true';
        module.hash = /** @type {string} */ (moduleHash.digest(hashDigest));	//生成hash摘要
        module.renderedHash = module.hash.substr(0, hashDigestLength);
    }
    // clone needed as sort below is inplace mutation
    const chunks = this.chunks.slice();
    /**
     * sort here will bring all "falsy" values to the beginning
     * this is needed as the "hasRuntime()" chunks are dependent on the
     * hashes of the non-runtime chunks.
     */
    chunks.sort((a, b) => {
        const aEntry = a.hasRuntime();
        const bEntry = b.hasRuntime();
        if (aEntry && !bEntry) return 1;
        if (!aEntry && bEntry) return -1;
        return byId(a, b);
    });
    for (let i = 0; i < chunks.length; i++) {
        const chunk = chunks[i];
        const chunkHash = createHash(hashFunction);
        try {
            if (outputOptions.hashSalt) {
                chunkHash.update(outputOptions.hashSalt);
            }
            chunk.updateHash(chunkHash);
            const template = chunk.hasRuntime()
                ? this.mainTemplate
                : this.chunkTemplate;
            template.updateHashForChunk(
                chunkHash,
                chunk,
                this.moduleTemplates.javascript,
                this.dependencyTemplates
            );
            this.hooks.chunkHash.call(chunk, chunkHash);
            // 这里生成了初始hash
            // 此时的chunkHash.buffer = 固定内容 + '入口文件'
            // eg: `// Load entry module and return exports
			// return __webpack_require__(__webpack_require__.s = "./node_modules/html-webpack-plugin/lib/loader.js!./src/index.html");`
            chunk.hash = /** @type {string} */ (chunkHash.digest(hashDigest));
            // 这里把所有的chunk.hash累加到最开始的hash里面,也就是项目的hash里面
            hash.update(chunk.hash);
            chunk.renderedHash = chunk.hash.substr(0, hashDigestLength);
            // contentHash的钩子函数触发
            this.hooks.contentHash.call(chunk);
        } catch (err) {
            this.errors.push(new ChunkRenderError(chunk, "", err));
        }
    }
    // 生成全部的fullHash、以及项目的hash摘要
    this.fullHash = /** @type {string} */ (hash.digest(hashDigest));
    this.hash = this.fullHash.substr(0, hashDigestLength);
}