处理部署后有css缓存问题
在部署上线后经常出现js、css缓存问题 导致样式等
区分不同的缓存
hash
hash是跟整个webpack构建项目相关的,每次项目构建hash对应的值都是不同的,即使项目文件没有做“任何修改”。
其实是有修改的,因为每次webpack打包编译都会注入webpack的运行时代码,导致整个项目有变化,所以每次hash值都会变化的。
chunkhash
chunkhash,从字面上就能猜出它是跟webpack打包的chunk相关的。具体来说webpack是根据入口entry配置文件来分析其依赖项并由此来构建该entry的chunk,并生成对应的hash值。不同的chunk会有不同的hash值。一般在项目中把公共的依赖库和程序入口文件隔离并进行单独打包构建,用chunkhash来生成hash值,只要依赖公共库不变,那么其对应的chunkhash就不会变,从而达到缓存的目的。
一般在项目中对webpack的entry使用chunkhash,具体表现在output配置项上:
moudule.exports = {
entry: { app: './src/main.js', vendor: ['react', 'redux', 'react-dom', 'react-redux', 'react-router-redux'] }, output: { path:path.join(__dirname, '/dist/js'),
filename: '[name].[chunkhash].js' } ...
}
contenthash
contenthash表示由文件内容产生的hash值,内容不同产生的contenthash值也不一样。在项目中,通常做法是把项目中css都抽离出对应的css文件来加以引用。比方在webpack配置这样来用:
module.exports = { ... plugins: [
new ExtractTextPlugin({ filename: 'static/[name]_[chunkhash:7].css',
disable: false,
allChunks: true
})
... ]
}
上面配置有一个问题,因为使用了chunkhash,它与依赖它的chunk共用chunkhash。
比方在上面app chunk例子中依赖一个index.css文件,index.css的hash是跟着app的chunkhash走的,只要app文件变更的话,那么即使index.css文件没有变化,它的hash值也是会跟着变化的,导致缓存失效。
那么这时我们可以使用extra-text-webpack-plugin里的contenthash
值,保证即使css文件所处的模块里就算其他文件内容改变,只要css文件内容不变,它的hash值就不会变。
实现js缓存
webpack插件CommonsChunkPlugin
的主要作用是抽取webpack项目入口chunk的公共部分,具体的用法就不做过多介绍,不太了解可以参考webpack官网介绍;
该插件是webpack项目常用的一个优化功能,几乎在每个webpack项目中都会用到。使用该插件带来的好处:
-
提升webpack打包速度和项目体积:将webpack入口的chunk文件中所有公共的代码提取出来,减少代码体积;同时提升webpack打包速度。
-
利用缓存机制:依赖的公共模块文件一般很少更改或者不会更改,这样独立模块文件提取出可以长期缓存。
但是在项目中,若插件打开方式不正确的话,上面的第二点其实是无法实现,因为这种情况下:
没有被修改过的公有代码或库代码打包出的Entry Chunk,会随着其他业务代码的变化而变化,导致页面上的长缓存机制失效。
那么,下面就来开启CommonsChunkPlugin
正确的打开方式。
CommonsChunkPlugin不正确用法
假如将我们项目的公共库如react、react-dom、react-router与业务代码隔离,将其提取为vendor chunk,webpack配置如下:
const webpack = require("webpack"); const path = require('path'); module.exports = { entry: { app: "./src/main.js", vendor: ["react","react-dom", "redux", "react-redux", "react-router-redux"] }, output: { path: path.resolve(__dirname, 'output'), filename: "[name].[chunkhash].js" }, plugins: [ new webpack.optimize.CommonsChunkPlugin({names: ["vendor"]}) ] };
引起问题的原因
引起webpack每次打包编译时vendor跟着变化的原因:
webpack每次build的时候都会生成一些运行时代码。当只有一个文件时,运行时代码直接塞到这个文件中。当有多个文件时,运行时代码会被提取到公共文件中,也就是上面CommonsChunkPlugin配置的vendor chunk中。
webpack每次编译时产生的运行时代码,包括全局webpackJsonp方法的定义和维护模块依赖关系,具体可以参考这里>>。
所以,上面webpack的CommonsChunkPlugin配置中,每次编译时这些代码都会打包到vendor中,导致每次vendor的chunkhash每次都会变化。
在webpack中配置CommonsChunkPlugin时需要注意几点:
1、 配置webpack的output项时,其
filename
和chunkFilename
必须使用chunkhash。不要使用hash,否则即使按照上面的配置也不能达到预期的效果。至于hash与chunkhash的区别
2、对于图片、字体等静态资源抽离使用的
file-loader
,其配置的hash表示的是静态文件的内容hash值,不是webpack每次打包编译生成的hash值, 切记!!!
3、对于抽取的css样式文件,需要使用
contenthash
, 与file-loader
中的hash意义相同。此处不能为chunkhash,否则其与抽取该样式文件的entry chunk的chunkhash保持一致,打不到缓存的目的。
实现图片/字体的缓存
对于图片、字体等静态资源,在使用webpack构建提取时,其实是使用了file-loader
来完成的,生成对应的文件hash值也就是由对应的file-loader
来计算的。那么这些静态文件的hash值使用的是什么hash值呢,其实就是hash
属性值。如下面代码所示:
module.exports = { ... rules: [ ... { test: /\.(gif|png|jpe?g)(\?\S*)?$/, loader: require.resolve('url-loader'), options: { limit: 10000, name: path.posix.join('static', '[name]_[hash:7].[ext]') } }, font: { test: /\.otf|ttf|woff2?|eot(\?\S*)?$/, loader: require.resolve('url-loader'), options: { limit: 10000, name: path.posix.join('static', '[name]_[hash:7].[ext]') } } ] }
可以看到上面使用的是hash属性值,此hash非webpack每次项目构建的hash,它是由file-loader根据文件内容计算出来的,不要误认为是webpack构建的hash。
解决的方案有三种:
1、用户自行清理浏览器缓存。
2、使用禁用缓存标签,实现禁用浏览器缓存。
3、为js和css文件添加版本号。
1.一般没这么干的
2.
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Cache" content="no-cache">
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
3.使用webpack构建的时候css、js添加hash进行改变