BetaSu / fe-hunter

每天一道题,3个月后,你就是面试小能手,答题还能赚钱哦
1.67k stars 116 forks source link

Webpack中几种hash的区别是? #43

Closed BetaSu closed 2 years ago

BetaSu commented 2 years ago

发生问题的场景

小明初次接触webpack,了解到hash这一概念,但不清楚他的应用场景及分类。

需要解决的问题

你能以如下顺序帮小明解惑么:

  1. 为什么有hash,他的应用场景是什么?
  2. webpack中有几种hash,他们的分类依据是?
  3. 对不同类型的hash什么时候使用,你能给出一些最佳实践么?

最佳答案评选标准

  1. 答案遵循以上顺序作答
  2. 有条理,全面的回答

最佳答案

shenzhim的回答

答题同学须知

围观同学须知

shenzhim commented 2 years ago

为什么有hash,他的应用场景是什么

hash 是webpack在生成文件时,根据文件内容进行hash运算,得到的一个hash值。导致打包时,只要文件发生变更,则会生成一个新的hash值用来跟之前的打包文件做区分,避免存在由于浏览器的缓存问题导致无法获取新的打包文件

在webpack中有几种hash,他们的分类依据是?

webpack中存在三种hash:hash,chunkhash,contenthash 分类依据还是要从他们生成的方式不同说起:

对不同类型的hash什么时候使用,你能给出一些最佳实践么?

JingweiXiong commented 2 years ago

为什么有hash,他的应用场景是什么?

先说一下背景:通过 Web 缓存可以减少等待时间和网络流量,因此减少了显示资源表示形式所需的时间。关于缓存的mdn链接

而有了web缓存,webpack作为构建工具在需要部署新版本时必须要更新发生变化的资源的文件名,确保浏览器会去请求新的资源,否则浏览器会根据缓存策略去判断可能还是复用着旧的资源。

在webpack中有几种hash,他们的分类依据是?

使用方式:在配置文件名的地方使用对应的 webpack 内置变量,webpack在生成文件的时候会把内置变量替换成计算好的 hash,比如 module.exports = { entry: './src/index.js', output: { // 这的[contenthash]就是内置的关于hash的变量,可以指定长度,比如[contenthash:8]就是8位,默认20位 filename: '[name].[contenthash].js', path: path.resolve(__dirname, 'dist'), }, }; 产物里对应资源的文件名就带上了一段哈希值,比如 mail-web.61e2ba31c173a3d30cf2.js,vuecommon-web.19c44d4d7e0db584cb98.js

前置概念:webpack新手可能会对 module、chunk、bundle 的概念不理解,给个简单总结,还不理解可以谷歌一下

image

分类: 1、hash hash 计算是跟整个项目的构建相关,比如下面的例子里生成文件的 hash 和项目的构建 hash 都是一模一样的 image

2、chunkhash 因为 hash 是项目构建的哈希值,项目中如果有些变动,hash 一定会变,比如说我改动了 utils.js 的代码,index.js 里的代码虽然没有改变,但是大家都是用的同一份 hash。hash 一变,缓存一定失效了,所以不符合预期。

chunkhash 就是解决这个问题的,它根据不同的入口文件(Entry)进行依赖文件解析、构建对应的 chunk,生成对应的哈希值。

效果:不同 chunk 之间不会相互影响

3、contenthash contenthash是处理属于同一个 chunk 的情况,比如 a.js 和 b.js 都属于同一个 chunk,如果希望 a.js 变化,b.js不变化时,打包之后b.js的缓存未失效,就使用 contenthash。

效果:contenthash 将根据资源内容创建出唯一 hash,也就是说文件内容不变,hash 就不变。

3、对不同类型的hash什么时候使用,你能给出一些最佳实践么? 上一段分类的描述里已经描述了效果对比,根据你的需要选用即可。 留个小作业:楼主可以去看看某些好的开源项目主要用的是哪种hash。

总结 篇幅有限,时间有限,总结得不好,没有举出很多具体的demo来说明,望见谅。 我的经验是,webpack可以抽个周末,自己从简单到复杂去自己写 demo,看效果,遇到不懂的就查官方文档或谷歌,循序渐进就好。

aztack commented 2 years ago

FYI:

createHash.js

module.exports = algorithm => {
    if (typeof algorithm === "function") {
        return new BulkUpdateDecorator(() => new algorithm());
    }
    switch (algorithm) {
        // TODO add non-cryptographic algorithm here
        case "debug":
        return new DebugHash();
        case "xxhash64":
        if (createXXHash64 === undefined) {
            createXXHash64 = require("./hash/xxhash64");
            if (BatchedHash === undefined) {
                BatchedHash = require("./hash/BatchedHash");
            }
        }
        return new BatchedHash(createXXHash64());
        case "md4":
        if (createMd4 === undefined) {
            createMd4 = require("./hash/md4");
            if (BatchedHash === undefined) {
                BatchedHash = require("./hash/BatchedHash");
            }
        }
        return new BatchedHash(createMd4());
        case "native-md4":
        if (crypto === undefined) crypto = require("crypto");
        return new BulkUpdateDecorator(() => crypto.createHash("md4"), "md4");
        default:
        if (crypto === undefined) crypto = require("crypto");
        return new BulkUpdateDecorator(
            () => crypto.createHash(algorithm),
            algorithm
            );
    }
};

All occurrences of createHash in Webpack source code

schemes/HttpUriPlugin.js
80:  const hash = createHash("sha512");
392:  const hash = createHash(hashFunction);

optimize/ConcatenatedModule.js
1041:  const hash = createHash(hashFunction);

optimize/RealContentHashPlugin.js
345:  const hash = createHash(this._hashFunction);

cache/getLazyHashedEtag.js
34:  const hash = createHash(this._hashFunction);

asset/AssetGenerator.js
280:  const hash = createHash(runtimeTemplate.outputOptions.hashFunction);

css/CssModulesPlugin.js
199:  const hash = createHash(hashFunction);

ChunkGraph.js
1557:  const hash = createHash(this._hashFunction);
1648:  const hash = createHash(this._hashFunction);

CodeGenerationResults.js
132:  const hash = createHash(this._hashFunction);

serialization/ObjectMiddleware.js
86:  const hash = createHash(hashFunction);

serialization/FileMiddleware.js
52:  const hash = createHash(hashFunction);

dependencies/WorkerPlugin.js
279:  const hash = createHash(compilation.outputOptions.hashFunction);

ModuleFilenameHelpers.js
64:  const hash = createHash(hashFunction);

FileSystemInfo.js
2893:  const hash = createHash(this._hashFunction);
3095:  const hash = createHash(this._hashFunction);
3168:  const hash = createHash(this._hashFunction);
3218:  const hash = createHash(this._hashFunction);
3272:  const hash = createHash(this._hashFunction);
3350:  const tsHash = createHash(this._hashFunction);
3351:  const hash = createHash(this._hashFunction);
3434:  const hash = createHash(this._hashFunction);
3435:  const tsHash = createHash(this._hashFunction);

ids/HashedModuleIdsPlugin.js
61:  const hash = createHash(options.hashFunction);

ids/IdHelpers.js
25:  const hash = createHash(hashFunction);

NormalModule.js
918:  const hash = createHash(compilation.outputOptions.hashFunction);

DefinePlugin.js
289:  const mainHash = createHash(compilation.outputOptions.hashFunction);

Compilation.js
3949:  const moduleHash = createHash(hashFunction);
3977:  const hash = createHash(hashFunction);
4152:  const chunkHash = createHash(hashFunction);
4201:  const moduleHash = createHash(hashFunction);
4219:  const chunkHash = createHash(hashFunction);

javascript/JavascriptModulesPlugin.js
359:  const hash = createHash(hashFunction);

DependencyTemplates.js
50:  const hash = createHash(this._hashFunction);