在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
引言静态资源缓存是前端性能优化的一个点,所以在前端开发过程中,一般会最大限度的利用缓存(这里主要是强缓存)。回到本文主题,在使用webpack构建的项目中,稍有不慎的话,即使服务器设置了缓存策略,可能构建的项目无法实现静态资源缓存。那么webpack怎样才能达到使用缓存的效果呢,下面就来谈谈这个问题。 区分一下几种不同的hash我们都知道,webpack有各种hash值,包括每次项目构建 hashhash是跟整个webpack构建项目相关的,每次项目构建hash对应的值都是不同的,即使项目文件没有做“任何修改”。 其实是有修改的,因为每次webpack打包编译都会注入webpack的运行时代码,导致整个项目有变化,所以每次hash值都会变化的。 以本人项目代码为例,代码两次构建前后没有做任何修改的对比图 可以看出,前后两次对应项目构建hash改变了。由此推断使用该方式是无法达到缓存的,因为每次hash都会变化。 chunkhashchunkhash,从字面上就能猜出它是跟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' } ... } 最后app和vendor的chunkhash编译结果如下图 contenthashcontenthash表示由文件内容产生的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里的 实现js缓存webpack插件 该插件是webpack项目常用的一个优化功能,几乎在每个webpack项目中都会用到。使用该插件带来的好处:
但是在项目中,若插件打开方式不正确的话,上面的第二点其实是无法实现,因为这种情况下: 没有被修改过的公有代码或库代码打包出的Entry Chunk,会随着其他业务代码的变化而变化,导致页面上的长缓存机制失效。 那么,下面就来开启 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"]}) ] }; 上面将项目一些基础库打包成一个名为vendor的chunk中,并将业务相关的代码打包到一个名为app的chunk中; webpack打包编译后的结果如下: 我们对其中的业务代码app.js进行修改后,重新编译结果如下: 可以发现,在CommonsChunkPlugin这种配置下,当业务代码app发生变化,而库代码也跟着变化,vender的chunkhash也跟着变化,这样vendor的引用的名称跟着变化,导致浏览器端的长缓存机制失效。 引起问题的原因引起webpack每次打包编译时vendor跟着变化的原因: webpack每次build的时候都会生成一些运行时代码。当只有一个文件时,运行时代码直接塞到这个文件中。当有多个文件时,运行时代码会被提取到公共文件中,也就是上面CommonsChunkPlugin配置的vendor chunk中。 webpack每次编译时产生的运行时代码,包括全局webpackJsonp方法的定义和维护模块依赖关系,具体可以参考这里>>。 所以,上面webpack的CommonsChunkPlugin配置中,每次编译时这些代码都会打包到vendor中,导致每次vendor的chunkhash每次都会变化。 那么,我们可以在对vendor chunk进行配置,抽取其中的公共代码,即webpack运行时代码,这样就可以将项目依赖的基础库模块与业务模块隔离开来,因为不会对这些文件进行修改,所以这些文件可达到长缓存的作用。具体配置如下: module.exports = { entry: { app: "./app.js", vendor: ["react","react-dom", "redux", "react-redux", "react-router-redux"] }, .... plugins: [ new webpack.optimize.CommonsChunkPlugin({names: ["vendor"]}), new webpack.optimize.CommonsChunkPlugin({ name: 'manifest', chunks: ['vendor'] }) ] }; 这样,即使修改业务app代码,项目依赖的基础库vendor chunk也不会发生变化;只是抽取的manifest chunk每次还会变化,但是这个文件体积非常小,相比vendor来说这种方式的收益更大。如下图: 修改app代码后的打包编译结果如下,可以看到vendor的chunkhash没有变化 在webpack中配置CommonsChunkPlugin时需要注意几点: 1、 配置webpack的output项时,其 2、对于图片、字体等静态资源抽离使用的 3、对于抽取的css样式文件,需要使用 实现css的缓存webpack实现css的缓存,就是使用上面介绍过的contenthash,该hash属性值其实是 module.exports = { ... plugins: [ new ExtractTextPlugin({ filename: 'static/[name]_[contenthash:7].css', disable: false, allChunks: true }) ... ] 实现图片/字体的缓存对于图片、字体等静态资源,在使用webpack构建提取时,其实是使用了 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、webpack之CommonsChunkPlugin正确打开方式 到此这篇关于webpack实现静态资源缓存的方法的文章就介绍到这了,更多相关webpack 静态资源缓存内容请搜索极客世界以前的文章或继续浏览下面的相关文章希望大家以后多多支持极客世界! |
请发表评论