1. 簡介
loader 被用于轉(zhuǎn)換某些類型的模塊,而插件則可以用于執(zhí)行范圍更廣的任務(wù)。插件的范圍包括,從打包優(yōu)化和壓縮,一直到重新定義環(huán)境中的變量。簡言之,我們利用 loader 來處理非 js 類型的模塊,用 plugin 來簡化我們的打包工作。
2. htmlWebpackPlugin
前面,我們將 index.html 放在 src 和 build 目錄之外,就是因為考慮到index.html的復(fù)用性,不用每次生成 build 文件夾,都要專門手動 copy 一份 index.html 到build。但是事實上,index.html 和index.js一樣都屬于源文件,應(yīng)該放在src之下,而輸出目錄也應(yīng)該包含 index.html。那么,有沒有辦法能自動幫我們生成index.html到build目錄,幫助我們簡化打包流程呢?答案是有的,就是htmlWebpackPlugin插件。
插件也是npm包,使用前需要安裝。
cnpm install --save-dev html-webpack-plugin
這個插件會我們自動生成 html 文件到指定目錄,并且會自動引入打包好的js腳本和 css 文件。
只需進行如下配置:
var HtmlWebpackPlugin = require('html-webpack-plugin');
var path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'build'),
publicPath: 'build/'
},
plugins: [new HtmlWebpackPlugin()],
module: {...} // 這里忽略module詳細內(nèi)容,大家可以參考前面章節(jié)補全
};
然后我們開始打包,發(fā)現(xiàn) build 目錄下,確實多出了index.html.

并且自動引入了打包好的bundle.js。但是我們打開 index.html。發(fā)現(xiàn)頁面什么也沒有,看一下src 目錄的index.html:

發(fā)現(xiàn)區(qū)別在于 build 目錄下的 index.html 少了 id="root"的div。其實,src 下面即使沒有index.html文件,打包后同樣會生成上述index.html文件。也就是生成的index.html和源文件的html并無關(guān)系,這顯然不是我們想要的效果。那么有沒有辦法讓生成的 index.html 是根據(jù) src 下的 index.html 內(nèi)容來決定的呢。答案是有的。
如下,我們在src下面建立一個最簡單的html文件,注意我們并不需要顯示引入最后的打包js文件,這為我們創(chuàng)造了極大的便利:
<!--index.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>esmodule-oop</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
然后在配置文件增加如下配置:
plugins: [new HtmlWebpackPlugin({
template: './src/index.html'
})],
再次打包。如下:

竟然還是什么也沒有。問題很明顯,src引用路徑報錯了。原因在于3-2 使用loader打包靜態(tài)資源(圖片)
中,為了保證圖片的引用地址正確,我們加了publicPath這一配置。當(dāng)時一筆帶過,現(xiàn)在為大家詳細講述一下這個配置的用途。
3. publicPath
為什么有了path的情況下還需要一個publicPath呢。我們先來解釋一下什么是path就是輸出文件的目標(biāo)路徑,也就是打包好的代碼我們能在哪里找到。如果打包好的html文件和其他靜態(tài)資源都放在一起,在生成資源引用路徑時只要按照他們處在同格目錄下即可。不管丟到哪里都能正常運行。但事實上,我們生成的html文件,往往和其他資源并不放在一處,另外,它們也并不都是處在同級目錄,我們很可能為這些資源文件單獨生成一個父目錄,然后丟在其他地方。如果這些資源換了位置,那么之前的引用路徑就會出錯。
publicPath 就是針對這種情況,用來指明資源文件最終的引用地址。它并不影響我們打包文件的輸出地址,只是會影響打包后生成文件內(nèi)的引用路徑。如果我們更換了發(fā)布時的靜態(tài)資源服務(wù)器地址,只需在打包前修改publicPath即可。
這里,由于html和其他靜態(tài)資源在一起,我們可以不配置publickPath,也可以如下配置:
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'build'),
publicPath: '/webpack-study/build/'
}
這里之所以這么配置,是因為webstorm點開html時,根目錄對應(yīng)整個項目文件的父目錄。
當(dāng)然,更復(fù)雜的情況是,我的js文件,css文件,圖片文件,并不想放在一起。這種情況是很常見的,就比如我們的圖片經(jīng)常放在cdn。這時,我們就需要區(qū)分不同的資源文件,配置不同的publicPath了,如下:
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'build')
},
plugins: [new HtmlWebpackPlugin({
template: './src/index.html'
})],
module: {
rules: [
{
test: /\.(jpg|jpeg|png|gif)$/,
use: {
loader: 'url-loader',
options: {
name: '[name].[ext]',
limit: 2048,
publicPath: '/images/'
}
}
},
...
]
}
};


js資源和圖片資源的引用目錄就不一樣了。
4. clean-webpack-plugin
這里,再為大家介紹一個簡單常用的插件。試想這種情況,我們修改了輸出文件的名稱,重新打包:

可以看到生成了新的dist.js,但是老的bundle.js也還存在。如果存在多個文件的變動,導(dǎo)致舊的生成文件不需要時,webpack并不能為我們智能的刪除。這就會造成無用文件遺留,打包文件增大。最好是,每次生成新的打包文件時,能夠先清理一下打包目錄。這個時候就可以借助clean-webpack-plugin。
先安裝:
cnpm i clean-webpack-plugin -D
用法和html-webpack-plugin類似。
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'dist.js',
path: path.resolve(__dirname, 'build')
},
plugins: [new HtmlWebpackPlugin({
template: './src/index.html'
}), new CleanWebpackPlugin(['build'])],
...
打包,發(fā)現(xiàn)報錯了。

翻開https://www.npmjs.com/package/clean-webpack-plugin,我們發(fā)現(xiàn)原來clean-webpack-plugin插件導(dǎo)出和導(dǎo)入方法已發(fā)生變化,改成如下即可:
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
打包后bundle.js不見了。

5 plugins
可以看到,其實plugins就是允許我們在打包的不同階段,插入一些指定的操作。
參考
https://www.webpackjs.com/concepts/#%E6%8F%92%E4%BB%B6-plugins-
https://www.webpackjs.com/api/plugins/
https://www.webpackjs.com/plugins/
https://www.webpackjs.com/plugins/html-webpack-plugin/
https://www.webpackjs.com/configuration/
https://www.webpackjs.com/guides/output-management/