三 、hash - qianlongdoit/webpack GitHub Wiki
hash的流程
- createHash
- 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);
}