爲何要使用緩存呢?單就功能來說,不用緩存也能達到一樣的效果,使用緩存最大的目的實際上是爲了 提升性能javascript
爲此咱們必需要確保 webpack 編譯生成的文件能被客戶端緩存,而且當文件發生變化後,客戶端能獲得新的文件html
下面,咱們先來搭建一個小小的項目,一步一步說明如何在 webpack 中配置使用緩存java
建立一個空文件夾 Demo
,做爲項目的根目錄,而後在該目錄中運行如下命令安裝依賴node
> # 建立 package.json 文件 > npm init -y > # 安裝 webpack > npm install --save-dev webpack > npm install --save-dev webpack-cli > # 安裝 lodash 模塊 > npm install --save lodash
在根目錄下建立 dist
和 src
文件夾,分別用於存放資源文件和打包以後的輸出文件webpack
並在 src
文件夾下建立 index.js
文件,該文件的做用是添加一個 div
元素做爲 body
的子節點web
import _ from 'lodash'; function component() { var element = document.createElement('div'); element.innerHTML = _.join(['Hello', 'webpack'], ' '); return element; } let elem = component(); document.body.appendChild(elem);
以後,咱們在根目錄下建立一個 webpack.config.js
文件,用於指定 webpack 的一些配置shell
經過 hash,咱們可使得每次打包生成的文件命名都是惟一的npm
const path = require('path'); module.exports = { entry: './src/index.js', output: { filename: '[name].[chunkhash].js', path: path.resolve(__dirname, 'dist') } };
這裏有一個問題,若是每次打包以後生成的文件命名都不同,那麼咱們要怎麼引用文件呢?json
答案是使用 HtmlWebpackPlugin,這個插件會自動生成一個 HTML5 文件,動態添加每次編譯後引用的資源緩存
首先安裝插件
> npm install --save-dev html-webpack-plugin
而後在 webpack.config.js
文件中進行配置
const path = require('path'); // 引入 HtmlWebpackPlugin 插件 const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './src/index.js', output: { filename: '[name].[chunkhash].js', path: path.resolve(__dirname, 'dist') }, plugins: [ // 使用 HtmlWebpackPlugin 插件 new HtmlWebpackPlugin() ] };
另一個問題,若是通過屢次修改和打包,因爲以前打包生成的文件也會殘留下來,因此文件會越堆越多
要怎麼解決呢?答案是使用 CleanWebpackPlugin,該插件能夠在從新打包的時候,把沒有用的文件自動清除
仍是先安裝插件
> npm install --save-dev clean-webpack-plugin
而後在 webpack.config.js
文件中進行配置
const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); // 引入 CleanWebpackPlugin 插件 const { CleanWebpackPlugin } = require('clean-webpack-plugin'); module.exports = { entry: './src/index.js', output: { filename: '[name].[chunkhash].js', path: path.resolve(__dirname, 'dist') }, plugins: [ new HtmlWebpackPlugin(), // 使用 CleanWebpackPlugin 插件 new CleanWebpackPlugin() ] };
有的時候,將第三方庫提取到獨立的 chunk 文件是比較推薦的作法
由於它們不多被修改,因此利用客戶端的長效緩存機制,能夠最大限度的減小客戶端向服務器請求資源的次數
修改 webpack.config.js
文件以下
const path = require('path'); // 引入 webpack 內置插件 const webpack = require('webpack'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const { CleanWebpackPlugin } = require('clean-webpack-plugin'); module.exports = { entry: { main: './src/index.js', // 新增 vender 入口,指定第三方庫 vender: [ 'lodash' ] }, output: { filename: '[name].[chunkhash].js', path: path.resolve(__dirname, 'dist') }, plugins: [ // 將指定的模塊分離到單獨的文件 new webpack.optimize.CommonsChunkPlugin({ name: 'vendor' }), new HtmlWebpackPlugin(), new CleanWebpackPlugin() ] };
至此,還有最後一個問題,假如咱們在 src
目錄下添加一個文件 hello.js
,文件內容以下
export function SayHello() { console.log('Hello World') }
而後,咱們在 src
目錄下的 index.js
文件中引用新建的文件,修改 index.js
文件以下
import _ from 'lodash'; import { SayHello } from './hello.js'; function component() { SayHello() var element = document.createElement('div'); element.innerHTML = _.join(['Hello', 'webpack'], ' '); return element; } let elem = component(); document.body.appendChild(elem);
可是當咱們從新打包的時候,卻發現以前打包 vender 生成的 bundle 文件的 hash 也發生了改變
這是由於 module.id
會基於默認的解析順序進行增量,因此 vender 生成的 bundle 文件的 hash 也會所以變化
對於這種狀況,webpack 提供兩種解決方法
一是使用 NamedModulesPlugin
(適合開發環境使用),二是使用 HashedModuleIdsPlugin
(適合生產環境使用)
修改 webpack.config.js
文件以下
const path = require('path'); const webpack = require('webpack'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const { CleanWebpackPlugin } = require('clean-webpack-plugin'); module.exports = { entry: { main: './src/index.js', vender: [ 'lodash' ] }, output: { filename: '[name].[chunkhash].js', path: path.resolve(__dirname, 'dist') }, plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: 'vendor' }), // 使用 HashedModuleIdsPlugin 插件 new webpack.HashedModuleIdsPlugin(), new HtmlWebpackPlugin(), new CleanWebpackPlugin() ] };
【 更新:webpack.optimize.CommonsChunkPlugin 已棄用,請使用 config.optimization.splitChunks 】
對於報錯信息,不針對上面的例子,下面是一個比較通用的寫法
const path = require('path'); const webpack = require('webpack'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const { CleanWebpackPlugin } = require('clean-webpack-plugin'); module.exports = { entry: './src/index.js', output: { filename: '[name].[chunkhash].js', path: path.resolve(__dirname, 'dist') }, plugins: [ new webpack.HashedModuleIdsPlugin(), new HtmlWebpackPlugin(), new CleanWebpackPlugin() ], optimization: { splitChunks: { chunks: 'all', // 可選值有三個,initial(入口)、async(異步)和 all minSize: 30000, // 最小尺寸 minChunks: 1, // 最小引用次數 maxAsyncRequests: 5, // 最大請求異步 chunk 的次數 maxInitialRequests: 3, // 最大請求入口 chunk 的次數 cacheGroups: { vendor: { // 提取第三方庫 test: /[\\/]node_modules[\\/]/, // 根據需求修改 name: 'vendor', }, common: { // 提取公共文件 test: /[\\/]src[\\/]js[\\/]/, // 根據需求修改 name: 'common' } } } } };
【 閱讀更多 webpack 系列文章,請看 webpack學習筆記 】