首页 > 其他分享 >文件指纹是什么?怎么用?

文件指纹是什么?怎么用?

时间:2023-11-17 17:33:05浏览次数:26  
标签:怎么 文件 hash chunk 指纹 js webpack chunkhash

Webpack 中的静态资源文件指纹

在 webpack 中如何给静态资源加 hash 值:每次构建过程都会生成一个新的 hash,所以一般用于做版本控制;chunkhash 是基于内容生成的,但是 webpack 把所有类型的文件都以 js 为汇聚点打成一个 bundle,改了 css 也会导致整个 js 的 hash 发生改变,所以最好通过 ExtractTextWebpackPlugin 把 css 独立抽取出来;chunkhash 只能用于动态导入的 chunk,这样每次 build,入口静态导入的文件还是会生成新的 hash,所以还需要 webpack-md5-hash 插件来完善该功能。

1.如何添加文件名添加指纹

文件的 hash 指纹是前端静态资源实现增量更新最常用的方案。

在 Webpack 编译输出文件名(output.filename)的配置中,对于单个入口起点,filename 会是一个静态名称。

当通过多个入口起点(entry point)、代码拆分(code splitting)或各种插件(plugin)创建多个 bundle,提供了多种模板字符串替换方式,来赋予每个 bundle 一个唯一的名称。

如果需要为文件加入 hash 指纹,Webpack 提供了两个模板字符串可供使用:hash 和 chunkhash。

代码示例如下:

// 使用每次构建过程中,唯一的 hash 生成
filename: "[name].[hash].bundle.js";
// 使用基于每个 chunk 内容的 hash:
filename: "[chunkhash].bundle.js";

2. hash 和 chunkhash

hash

在文档中找到了几个处关于 hash 的定义:

  • Using the unique hash generated for every build;
  • [hash] in this parameter will be replaced with an hash of the compilation
  • The hash of the module identifier

翻译过来就是每个构建过程生成的唯一 hash。

chunkhash

chunkhash 的解释是:Using hashes based on each chunks' content; 翻译过来就是基于每个 chunk 的内容而生成的 hash。

3. chunk

chunk 在 Webpack 中的含义,简单讲就是模块。

  • chunk 的解释还是在[1.0 的文档]chunk中能更深刻的理解。
  • output.chunkFilename决定了非入口(non-entry) chunk 文件的名称。 从这句话中也可以看出来 chunk 就是模块;只不过模块又分入口 chunk 文件和按需动态加载的 chunk。

4.compilation 和 compiler

Webpack 官方文档中How to write a plugin章节有对 compilation 的详解。

compilation 对象代表某个版本的资源对应的编译进程。当使用 Webpack 的 development 中间件时,每次检测到项目文件有改动就会创建一个 compilation,进而能够针对改动生产全新的编译文件。compilation 对象包含当前模块资源、待编译文件、有改动的文件和监听依赖的所有信息。

与 compilation 对应的有个 compiler 对象,通过对比,可以帮助对 compilation 有更深入的理解。

compiler 对象代表的是配置完备的 Webpack 环境。 compiler 对象只在 Webpack 启动时构建一次,由 Webpack 组合所有的配置项构建生成。

简单的讲,compiler 对象代表的是不变的 webpack 环境,是针对 webpack 的;而 compilation 对象针对的是随时可变的项目文件,只要文件有改动,compilation 就会被重新创建。

5. hash 的问题

理解了 compilation 之后,再回头看 hash 的定义:

[hash] is replaced by the hash of the compilation.

compilation 在项目中任何一个文件改动后就会被重新创建,然后 webpack 计算新的 compilation 的 hash 值,这个 hash 值便是 hash。

entry: {
  index: './src/index.js',
  print: './src/print.js'
},
output: {
  path: path.resolve(__dirname, 'dist'),
  filename: '[name].[hash].js',
  publicPath: '/'
},

第一次 build 的结果:

所有的文件名都会使用相同的 hash 指纹

第二次 build 的结果

2 个 js 文件任何一个改动都会影响另外 1 个文件的最终文件名。上线后,另外 1 个文件的浏览器缓存也全部失效。这肯定不是想要的结果。

那么如何避免这个问题呢?答案就是 chunkhash!

6. chunkhash 怎么使用

output.filename不会影响那些「按需加载 chunk」的输出文件。对于这些文件,需要使用 output.chunkFilename选项来控制输出。

根据 chunkhash 的定义知道,chunkhash 是根据具体模块文件的内容计算所得的 hash 值,所以某个文件的改动只会影响它本身的 hash 指纹,不会影响其他文件。

配置 webpack 的 output 如下:

// webpack.config.js配置
output: {
  path: path.resolve(__dirname, 'dist'),
  filename: '[name][hash].js',
  chunkFilename: '[name][chunkhash].js',
  publicPath: '/'
}
// index.js动态引入chunk
import(/* webpackChunkName: "lodash" */ "lodash")
  .then(function (_) {
    console.log(_);
  })
  .catch();

build 的结果:

每个文件的 hash 指纹都不相同,上线后无改动的文件不会失去缓存。

7.hash 应用场景

接上文所述,webpack 的 hash 字段是根据每次编译 compilation 的内容计算所得,也可以理解为项目总体文件的 hash 值,而不是针对每个具体文件的。

webpack 针对 compilation 提供了两个 hash 相关的生命周期钩子:before-hash 和 after-hash。源码如下:

this.applyPlugins("before-hash");
this.createHash();
this.applyPlugins("after-hash");

hash 可以作为版本控制的一环,将其作为编译输出文件夹的名称统一管理,如下:

output: {
  filename: "/dest/[hash]/[name].js";
}

8.chunkhash 的问题

webpack 的理念是一切都是模块:把所有类型的文件都以 js 为汇聚点,不支持 js 文件以外的文件为编译入口。所以如果要编译 style 文件,唯一的办法是在 js 文件中引入 style 文件。如下

import "./style.css";

webpack 默认将 js、image、css 文件统统编译到一个 js 文件中,

这样的模式下有个很严重的问题,当希望将 css 单独编译输出并且打上 hash 指纹,按照前文所述的使用 chunkhash 配置输出文件名时,编译的结果是 js 和 css 文件的 hash 指纹完全相同。

可以借助extract-text-webpack-plugin将 style 文件单独编译输出。从这点可以看出,webpack 将 css 文件视为 js 的一部分。

new ExtractTextPlugin("[name].[chunkhash].css");

但是不论是单独修改了 js 代码还是 css 代码,编译输出的 js/css 文件都会打上全新的相同的 hash 指纹。这种状况下无法有效的进行版本管理和部署上线。

好在 extract-text-webpack-plugin 提供了另外一种 hash 值:contenthash。顾名思义,contenthash 代表的是文本文件内容的 hash 值,也就是只有 style 文件的 hash 值。这个 hash 值就是解决上述问题的银弹。修改配置如下:

new ExtractTextPlugin("[name].[contenthash].css");

编译输出的 js 和 css 文件将会有其独立的 hash 指纹。

再考虑一下这个问题:如果只修改了 style 文件,未修改 index.js 文件,那么编译输出的 js 文件的 hash 指纹会改变吗?

答案是肯定的。

修改了 style 编译输出的 css 文件 hash 指纹理所当然要更新,但是并未修改 index.js,可是 js 文件的 hash 指纹也更新了。这是因为上文提到的:

webpack 计算 chunkhash 时,以 index.js 文件为编译入口,整个 chunk 的内容会将 style.css 的内容也计算在内。

9.chunk-hash

webpack 计算 chunkhash 时,以 index.js 文件为编译入口,整个 chunk 的内容会将 style.css 的内容也计算在内:

body{ color: #000; } alert('I am main.js');

chunk-hash 并不是 webpack 中另一种 hash 值,而是 compilation 执行生命周期中的一个钩子。

chunk-hash 钩子代表的是哪个阶段呢?请看 webpack 的 Compilation.js源码中以下部分: 代码

for (let i = 0; i < chunks.length; i++) {
  const chunk = chunks[i];
  const chunkHash = crypto.createHash(hashFunction);
  if (outputOptions.hashSalt) chunkHash.update(outputOptions.hashSalt);
  chunk.updateHash(chunkHash);
  if (chunk.hasRuntime()) {
    this.mainTemplate.updateHashForChunk(chunkHash, chunk);
  } else {
    this.chunkTemplate.updateHashForChunk(chunkHash, chunk);
  }
  this.applyPlugins2("chunk-hash", chunk, chunkHash);
  chunk.hash = chunkHash.digest(hashDigest);
  hash.update(chunk.hash);
  chunk.renderedHash = chunk.hash.substr(0, hashDigestLength);
}
this.fullHash = hash.digest(hashDigest);
this.hash = this.fullHash.substr(0, hashDigestLength);

webpack 使用 NodeJS 内置的 crypto 模块计算 chunkhash,具体使用哪种算法与讨论的内容无关,只需要关注上述代码中 this.applyPlugins("chunk-hash", chunk, chunkHash);的执行时机。

chunk-hash 是在 chunhash 计算完毕之后执行的,这就意味着如果在 chunk-hash 钩子中可以用新的 chunkhash 替换已存在的值。如下伪代码:

compilation.plugin("chunk-hash", function (chunk, chunkHash) {
  var new_hash = md5(chunk);
  chunkHash.digest = function () {
    return new_hash;
  };
});

webpack 之所以如果流行的原因之一就是拥有庞大的社区和不计其数的开发者们,实际上,遇到的问题已经有先驱者帮解决了。插件webpack-md5-hash便是上述伪代码的具体实现,需要做的只是将这个插件加入到 webpack 的配置中:

// webpack.config.js

var WebpackMd5Hash = require("webpack-md5-hash");

module.exports = {
  // ...
  output: {
    //...
    chunkFilename: "[chunkhash].[id].chunk.js",
  },
  plugins: [new WebpackMd5Hash()],
};

标签:怎么,文件,hash,chunk,指纹,js,webpack,chunkhash
From: https://www.cnblogs.com/wp-leonard/p/17839308.html

相关文章

  • PageOfficeV6.0在线打开excel文件给单元格填充数据
    转载:单元格填充数据单元格填充数据注意本文中展示的代码均为关键代码,复制粘贴到您的项目中,按照实际的情况,例如文档路径,用户名等做适当修改即可使用。PageOffice提供了Workbook对象来实现对Excel文件的数据填充功能,如果只是简单的填充一下数据,那么通过调用Sheet对象的openCell......
  • 记一个漏洞处理,SSH框架上传限制文件类型,以及关于文件上传安全问题的讨论
    -----------------------------------------------------------------------------------------------------------------------------------与同事讨论的文件上传安全问题:1.老项目采用的上传至项目下某个目录的做法是很不安全的,容易被访问到上传文件,应当制定到项目之外的目......
  • chrome老更新的话 driver怎么才能保持更新呢?
    大家好,我是皮皮。一、前言前几天在Python最强王者交流群【鶏啊鶏。】问了一个selenium驱动器的问题,一起来看看吧。问题描述:有没有selenium用的比较多的大佬 想问问一些selenium的定时任务 关于chrome老更新的话 driver怎么才能保持更新呢二、实现过程后来【瑜亮老师】给......
  • Log4j配置文件(四步轻松拿捏Log4j使用-入门必看!!)
    Hii,mJinXiang⭐前言 ⭐本篇文章主要介绍Log4j入门使用以及部分理论知识本篇又称(Log4的使用四步轻松拿捏)......
  • 大文件断点续传
    spark-md5spark-md5.js号称是最适合前端最快的算法,能快速计算文件的md5。spark-md5提供了两个计算md5的方法。一种是用SparkMD5.hashBinary()直接将整个文件的二进制码传入,直接返回文件的md5。这种方法对于小文件会比较有优势——简单而且速度超快。另一种方法是利用js......
  • 实现多个大文件拖拽上传+大文件分片上传+断点续传+文件预览
    技术关键词前端:@vue/cli-service+element-ui+axios后端:node.js+koa思路分析拖拽上传拖拽上传是利用HTML5新特性实现拖拽上传,详细用法可阅读MDN-drag利用dragover事件(当某物被拖动的对象在另一对象容器范围内拖动时触发此事件)和drop事件(在一个拖动过程中,释放鼠标键时......
  • JAVA解析Excel文件 + 多线程 + 事务回滚
    1.项目背景:客户插入Excel文件,Ececel文件中包含大量的数据行和数据列,单线程按行读取,耗时大约半小时,体验感不好。思路:先将excel文件按行读取,存入List,然后按照100均分,n=list.szie()/100+1;n就是要开启的线程总数。(实际使用的时候,数据库连接池的数量有限制,n的大小要结合数据库连......
  • 使用Linux命令sort及uniq对文件或屏幕输出进行分组统计
    sortdemo.txt|uniq-c|sort-rn|head-3在日常Linux操作常常需要对一些文件或屏幕数次中重复的字段进行分组统计。实现的方法非常简单,核心命令为:sort|uniq--c|sort-rn。sort:对指定列进行排序,使该列相同的字段排练到一起uniq-c:uniq命令用于检查及删除文本文件......
  • 单文件WebUploader做大文件的分块和断点续传
    前言:WebUploader是由BaiduWebFE(FEX)团队开发的一个简单的以HTML5为主,FLASH为辅的现代文件上传组件。在现代的浏览器里面能充分发挥HTML5的优势,同时又不摒弃主流IE浏览器,沿用原来的FLASH运行时,兼容IE6+,iOS6+,android4+。两套运行时,同样的调用方式,可供用户任意选用。 上面......
  • 安装 IIS 访问临时文件夹 C:\WINDOWS\TEMP\3C 读取/写入权限 错误: 0x80070005
    在windows中使用命令行方式安装IIS(Web服务器)WindowsServer2022安装IIS报错访问临时文件夹C:\WINDOWS\TEMP\3C读取/写入权限错误:0x80070005,可以使用命令行方式来安装和配置Web服务(IIS)。以下是使用DeploymentImageServicingandManagement(DISM)工具的步骤:1.打......