webpack的配置
帶你深度解鎖Webpack系列(基礎篇)
三篇長文帶你解鎖Webpack
,希望讀完這三篇文章,你能夠對webpack
的各項配置有一個更為清晰的認識。
1.webpack 是什麼?
webpack
是一個現代JavaScript
應用程式的靜態模組打包器,當webpack
處理應用程式時,會遞迴構建一個依賴關係圖,其中包含應用程式需要的每個模組,然後將這些模組打包成一個或多個bundle
。
2.webpack 的核心概念
- entry: 入口
- output: 輸出
- loader: 模組轉換器,用於把模組原內容按照需求轉換成新內容
- 外掛(plugins): 擴充套件外掛,在webpack構建流程中的特定時機注入擴充套件邏輯來改變構建結果或做你想要做的事情
3.初始化專案
新建一個資料夾,如:webpack-first
(當然,你可以使用任意一個你喜歡的專案名)。推薦大家參考本文一步一步進行配置,不要總是在網上找什麼最佳配置,你掌握了webpack
之後,根據自己的需求配置出來的,就是最佳配置。
本篇文章對應的專案地址(編寫本文時使用):github.com/YvetteLau/w…
使用npm init -y
進行初始化(也可以使用yarn
)。
要使用webpack
,那麼必然需要安裝webpack
、webpack-cli
:
npm install webpack webpack-cli -D
複製程式碼
鑑於前端技術變更迅速,祭出本篇文章基於webpack
├── [email protected]
└── [email protected]
複製程式碼
從wepack V4.0.0
開始,webpack
是開箱即用的,在不引入任何配置檔案的情況下就可以使用。
新建src/index.js
檔案,我們在檔案中隨便寫點什麼:
//index.js
class Animal {
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
}
const dog = new Animal('dog');
複製程式碼
使用npx webpack --mode=development
進行構建,預設是production
模式,我們為了更清楚得檢視打包後的程式碼,使用development
模式。
可以看到專案下多了個dist
目錄,裡面有一個打包出來的檔案main.js
。
webpack
有預設的配置,如預設的入口檔案是./src
,預設打包到dist/main.js
。更多的預設配置可以檢視:node_modules/webpack/lib/WebpackOptionsDefaulter.js
。
檢視dist/main.js
檔案,可以看到,src/index.js
並沒有被轉義為低版本的程式碼,這顯然不是我們想要的。
{
"./src/index.js":
(function (module, exports) {
eval("class Animal {\n constructor(name) {\n this.name = name;\n }\n getName() {\n return this.name;\n }\n}\n\nconst dog = new Animal('dog');\n\n//# sourceURL=webpack:///./src/index.js?");
})
}
複製程式碼
4.將JS轉義為低版本
前面我們說了webpack
的四個核心概念,其中之一就是loader
,loader
用於對原始碼進行轉換,這正是我們現在所需要的。
將JS程式碼向低版本轉換,我們需要使用babel-loader
。
babel-loader
首先安裝一下babel-loader
npm install babel-loader -D
複製程式碼
此外,我們還需要配置babel
,為此我們安裝一下以下依賴:
npm install @babel/core @babel/preset-env @babel/plugin-transform-runtime -D
npm install @babel/runtime @babel/runtime-corejs3
複製程式碼
對babel7配置不熟悉的小夥伴,可以閱讀一下這篇文章:不可錯過的 Babel7 知識
新建webpack.config.js
,如下:
//webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.jsx?$/,
use: ['babel-loader'],
exclude: /node_modules/ //排除 node_modules 目錄
}
]
}
}
複製程式碼
建議給loader
指定include
或是exclude
,指定其中一個即可,因為node_modules
目錄通常不需要我們去編譯,排除後,有效提升編譯效率。
這裡,我們可以在.babelrc
中編寫babel
的配置,也可以在webpack.config.js
中進行配置。
建立一個 .babelrc
配置如下:
{
"presets": ["@babel/preset-env"],
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"corejs": 3
}
]
]
}
複製程式碼
現在,我們重新執行npx webpack --mode=development
,檢視dist/main.js
,會發現已經被編譯成了低版本的JS程式碼。
在webpack中配置 babel
//webpack.config.js
module.exports = {
// mode: 'development',
module: {
rules: [
{
test: /\.jsx?$/,
use: {
loader: 'babel-loader',
options: {
presets: ["@babel/preset-env"],
plugins: [
[
"@babel/plugin-transform-runtime",
{
"corejs": 3
}
]
]
}
},
exclude: /node_modules/
}
]
}
}
複製程式碼
這裡有幾點需要說明:
loader
需要配置在module.rules
中,rules
是一個數組。loader
的格式為:
{
test: /\.jsx?$/,//匹配規則
use: 'babel-loader'
}
複製程式碼
或者也可以像下面這樣:
//適用於只有一個 loader 的情況
{
test: /\.jsx?$/,
loader: 'babel-loader',
options: {
//...
}
}
複製程式碼
test
欄位是匹配規則,針對符合規則的檔案進行處理。
use
欄位有幾種寫法
- 可以是一個字串,例如上面的
use: 'babel-loader'
use
欄位可以是一個數組,例如處理CSS檔案是,use: ['style-loader', 'css-loader']
use
陣列的每一項既可以是字串也可以是一個物件,當我們需要在webpack
的配置檔案中對loader
進行配置,就需要將其編寫為一個物件,並且在此物件的options
欄位中進行配置,如:
rules: [
{
test: /\.jsx?$/,
use: {
loader: 'babel-loader',
options: {
presets: ["@babel/preset-env"]
}
},
exclude: /node_modules/
}
]
複製程式碼
上面我們說了如何將JS的程式碼編譯成向下相容的程式碼,當然你可以還需要一些其它的babel
的外掛和預設,例如@babel/preset-react
,@babel/plugin-proposal-optional-chaining
等,不過,babel
的配置並非本文的重點,我們繼續往下。
不要說細心的小夥伴了,即使是粗心的小夥伴肯定也發現了,我們在使用webpack
進行打包的時候,一直執行的都是npx webpack --mode=development
是否可以將mode
配置在webpack.config.js
中呢?顯然是可以的。
5.mode
將mode
增加到webpack.config.js
中:
module.exports = {
//....
mode: "development",
module: {
//...
}
}
複製程式碼
mode
配置項,告知webpack
使用相應模式的內建優化。
mode
配置項,支援以下兩個配置:
-
development
:將process.env.NODE_ENV
的值設定為development
,啟用NamedChunksPlugin
和NamedModulesPlugin
-
production
:將process.env.NODE_ENV
的值設定為production
,啟用FlagDependencyUsagePlugin
,FlagIncludedChunksPlugin
,ModuleConcatenationPlugin
,NoEmitOnErrorsPlugin
,OccurrenceOrderPlugin
,SideEffectsFlagPlugin
和UglifyJsPlugin
現在,我們直接使用npx webpack
進行編譯即可。
6.在瀏覽器中檢視頁面
搞了這麼久,還不能在瀏覽器中檢視頁面,這顯然不能忍!
檢視頁面,難免就需要html
檔案,有小夥伴可能知道,有時我們會指定打包檔案中帶有hash
,那麼每次生成的js
檔名會有所不同,總不能讓我們每次都人工去修改html
,這樣不是顯得我們很蠢嘛~
我們可以使用html-webpack-plugin
外掛來幫助我們完成這些事情。
首先,安裝一下外掛:
npm install html-webpack-plugin -D
複製程式碼
新建public
目錄,並在其中新建一個index.html
檔案( 檔案內容使用html:5
快捷生成即可)
修改webpack.config.js
檔案。
//首先引入外掛
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
//...
plugins: [
//陣列 放著所有的webpack外掛
new HtmlWebpackPlugin({
template: './public/index.html',
filename: 'index.html', //打包後的檔名
minify: {
removeAttributeQuotes: false, //是否刪除屬性的雙引號
collapseWhitespace: false, //是否摺疊空白
},
// hash: true //是否加上hash,預設是 false
})
]
}
複製程式碼
此時執行npx webpack
,可以看到dist
目錄下新增了index.html
檔案,並且其中自動插入了<script>
指令碼,引入的是我們打包之後的 js 檔案。
這裡要多說一點點東西,HtmlWebpackPlugin
還為我們提供了一個config
的配置,這個配置可以說是非常有用了。
html-webpack-plugin 的 config 的妙用
有時候,我們的腳手架不僅僅給自己使用,也許還提供給其它業務使用,html
檔案的可配置性可能很重要,比如:你公司有專門的部門提供M頁的公共頭部/公共尾部,埋點jssdk以及分享的jssdk等等,但是不是每個業務都需要這些內容。
一個功能可能對應多個js
或者是css
檔案,如果每次都是業務自行修改public/index.html
檔案,也挺麻煩的。首先他們得搞清楚每個功能需要引入的檔案,然後才能對index.html
進行修改。
此時我們可以增加一個配置檔案,業務通過設定true
或false
來選出自己需要的功能,我們再根據配置檔案的內容,為每個業務生成相應的html
檔案,豈不是美美的。
Let's Go!
首先,我們在public
目錄下新增一個config.js
( 檔名你喜歡叫什麼就叫什麼 ),將其內容設定為:
//public/config.js 除了以下的配置之外,這裡面還可以有許多其他配置,例如,pulicPath 的路徑等等
module.exports = {
dev: {
template: {
title: '你好',
header: false,
footer: false
}
},
build: {
template: {
title: '你好才怪',
header: true,
footer: false
}
}
}
複製程式碼
現在,我們修改下我們的webpack.config.js
:
//webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const isDev = process.env.NODE_ENV === 'development';
const config = require('./public/config')[isDev ? 'dev' : 'build'];
modue.exports = {
//...
mode: isDev ? 'development' : 'production'
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
filename: 'index.html', //打包後的檔名
config: config.template
})
]
}
複製程式碼
相應的,我們需要修改下我們的public/index.html
檔案(嵌入的js和css並不存在,僅作為示意):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<% if(htmlWebpackPlugin.options.config.header) { %>
<link rel="stylesheet" type="text/css" href="//common/css/header.css">
<% } %>
<title><%= (htmlWebpackPlugin.options.config.title) %></title>
</head>
<body>
</body>
<% if(htmlWebpackPlugin.options.config.header) { %>
<script src="//common/header.min.js" type="text/javascript"></script>
<% } %>
</html>
複製程式碼
process.env
中預設並沒有NODE_ENV
,這裡配置下我們的package.json
的scripts
.
為了相容Windows和Mac,我們先安裝一下cross-env
:
npm install cross-env -D
複製程式碼
{
"scripts": {
"dev": "cross-env NODE_ENV=development webpack",
"build": "cross-env NODE_ENV=production webpack"
}
}
複製程式碼
然後我們執行npm run dev
和 執行npm run build
,對比下dist/index.html
,可以看到npm run build
,生成的index.html
檔案中引入了對應的css
和js
。並且對應的title
內容也不一樣。
你說這裡是不是非得是用NODE_ENV
去判斷?當然不是咯,你寫aaa=1
,aaa=2
都行(當然啦,webpack.config.js
和scripts
都需要進行相應修改),但是可能會被後面接手的人打死。
如何在瀏覽器中實時展示效果
說了這麼多,到現在還沒能在瀏覽器中實時檢視效果,是不是已經有點捉急了,先看一下如何實時檢視效果吧,不然都不知道自己配得對不對。
話不多說,先裝依賴:
npm install webpack-dev-server -D
複製程式碼
修改下咱們的package.json
檔案的scripts
:
"scripts": {
"dev": "cross-env NODE_ENV=development webpack-dev-server",
"build": "cross-env NODE_ENV=production webpack"
},
複製程式碼
在控制檯執行npm run dev
,啟動正常,頁面上啥也沒有,修改下我們的JS程式碼,往頁面中增加點內容,正常重新整理(也就是說不需要進行任何配置就可以使用了)。
Excuse me。怪我平時不認真咯,每次都乖乖的配個contentBase
,原來根本不需要配,帶著疑問,我又去搜尋了一番。
原來在配置了html-webpack-plugin
的情況下,contentBase
不會起任何作用,也就是說我以前都是白配了,這是一個悲傷的故事。
不過呢,我們還是可以在webpack.config.js
中進行webpack-dev-server
的其它配置,例如指定埠號,設定瀏覽器控制檯訊息,是否壓縮等等:
//webpack.config.js
module.exports = {
//...
devServer: {
port: '3000', //預設是8080
quiet: false, //預設不啟用
inline: true, //預設開啟 inline 模式,如果設定為false,開啟 iframe 模式
stats: "errors-only", //終端僅列印 error
overlay: false, //預設不啟用
clientLogLevel: "silent", //日誌等級
compress: true //是否啟用 gzip 壓縮
}
}
複製程式碼
- 啟用
quiet
後,除了初始啟動資訊之外的任何內容都不會被列印到控制檯。這也意味著來自webpack
的錯誤或警告在控制檯不可見 ———— 我是不會開啟這個的,看不到錯誤日誌,還搞個錘子 stats
: "errors-only" , 終端中僅打印出error
,注意當啟用了quiet
或者是noInfo
時,此屬性不起作用。 ————— 這個屬性個人覺得很有用,尤其是我們啟用了eslint
或者使用TS
進行開發的時候,太多的編譯資訊在終端中,會干擾到我們。- 啟用
overlay
後,當編譯出錯時,會在瀏覽器視窗全屏輸出錯誤,預設是關閉的。
clientLogLevel
: 當使用內聯模式時,在瀏覽器的控制檯將顯示訊息,如:在重新載入之前,在一個錯誤之前,或者模組熱替換啟用時。如果你不喜歡看這些資訊,可以將其設定為silent
(none
即將被移除)。
本篇文章不是為了細說webpack-dev-server
的配置,所以這裡就不多說了。關於webpack-dev-server
更多的配置可以點選檢視。
細心的小夥伴可能發現了一個小問題,我們在src/index.js
中增加一句console.log('aaa')
:
class Animal {
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
}
const dog = new Animal('dog');
console.log('aaa');
複製程式碼
然後通過npm run dev
檢視效果,會發現:
這顯然不是我們原始碼中對應的行號,點進去的話,會發現程式碼是被編譯後的,我當前的程式碼非常簡單,還能看出來,專案程式碼複雜後,“親媽”看編譯後都費勁,這不利於我們開發除錯,不是我們想要的,我們肯定還是希望能夠直接對應到原始碼的。
7.devtool
devtool
中的一些設定,可以幫助我們將編譯後的程式碼映射回原始原始碼。不同的值會明顯影響到構建和重新構建的速度。
對我而言,能夠定位到原始碼的行即可,因此,綜合構建速度,在開發模式下,我設定的devtool
的值是cheap-module-eval-source-map
。
//webpack.config.js
module.exports = {
devtool: 'cheap-module-eval-source-map' //開發環境下使用
}
複製程式碼
生產環境可以使用none
或者是source-map
,使用source-map
最終會單獨打包出一個.map
檔案,我們可以根據報錯資訊和此map
檔案,進行錯誤解析,定位到原始碼。
source-map
和hidden-source-map
都會打包生成單獨的.map
檔案,區別在於,source-map
會在打包出的js檔案中增加一個引用註釋,以便開發工具知道在哪裡可以找到它。hidden-source-map
則不會在打包的js中增加引用註釋。
但是我們一般不會直接將.map
檔案部署到CDN,因為會直接對映到原始碼,更希望將.map
檔案傳到錯誤解析系統,然後根據上報的錯誤資訊,直接解析到出錯的原始碼位置。
還可以設定其他的devtool值,你可以使用不同的值,構建對比差異。
現在我們已經說了html
、js
了,並且也可以在瀏覽器中實時看到效果了,現在就不得不說頁面開發三巨頭之一的css
。
8.如何處理樣式檔案呢
webpack
不能直接處理css
,需要藉助loader
。如果是.css
,我們需要的loader
通常有:style-loader
、css-loader
,考慮到相容性問題,還需要postcss-loader
,而如果是less
或者是sass
的話,還需要less-loader
和sass-loader
,這裡配置一下less
和css
檔案(sass
的話,使用sass-loader
即可):
先安裝一下需要使用的依賴:
npm install style-loader less-loader css-loader postcss-loader autoprefixer less -D
複製程式碼
//webpack.config.js
module.exports = {
//...
module: {
rules: [
{
test: /\.(le|c)ss$/,
use: ['style-loader', 'css-loader', {
loader: 'postcss-loader',
options: {
plugins: function () {
return [
require('autoprefixer')({
"overrideBrowserslist": [
">0.25%",
"not dead"
]
})
]
}
}
}, 'less-loader'],
exclude: /node_modules/
}
]
}
}
複製程式碼
測試一下,新建一個less
檔案,src/index.less
:
//src/index.less
@color: red;
body{
background: @color;
transition: all 2s;
}
複製程式碼
再在入口檔案中引入此less
:
//src/index.js
import './index.less';
複製程式碼
我們修改了配置檔案,重新啟動一下服務:npm run dev
。可以看到頁面的背景色變成了紅色。
OK,我們簡單說一下上面的配置:
style-loader
動態建立style
標籤,將css
插入到head
中.css-loader
負責處理@import
等語句。postcss-loader
和autoprefixer
,自動生成瀏覽器相容性字首 —— 2020了,應該沒人去自己徒手去寫瀏覽器字首了吧less-loader
負責處理編譯.less
檔案,將其轉為css
這裡,我們之間在webpack.config.js
寫了autoprefixer
需要相容的瀏覽器,僅是為了方便展示。推薦大家在根目錄下建立.browserslistrc
,將對應的規則寫在此檔案中,除了autoprefixer
使用外,@babel/preset-env
、stylelint
、eslint-plugin-conmpat
等都可以共用。
注意:
loader
的執行順序是從右向左執行的,也就是後面的loader
先執行,上面loader
的執行順序為:less-loader
--->postcss-loader
--->css-loader
--->style-loader
當然,loader
其實還有一個引數,可以修改優先順序,enforce
引數,其值可以為:pre
(優先執行) 或post
(滯後執行)。
現在,我們已經可以處理.less
檔案啦,.css
檔案只需要修改匹配規則,刪除less-loader
即可。
現在的一切看起來都很完美,但是假設我們的檔案中使用了本地的圖片,例如:
body{
background: url('../images/thor.png');
}
複製程式碼
你就會發現,報錯啦啦啦,那麼我們要怎麼處理圖片或是本地的一些其它資原始檔呢。不用想,肯定又需要loader
出馬了。
9.圖片/字型檔案處理
我們可以使用url-loader
或者file-loader
來處理本地的資原始檔。url-loader
和file-loader
的功能類似,但是url-loader
可以指定在檔案大小小於指定的限制時,返回DataURL
,因此,個人會優先選擇使用url-loader
。
首先安裝依賴:
npm install url-loader -D
複製程式碼
安裝url-loader
的時候,控制檯會提示你,還需要安裝下file-loader
,聽人家的話安裝下就行(新版npm
不會自動安裝peerDependencies
):
npm install file-loader -D
複製程式碼
在webpack.config.js
中進行配置:
//webpack.config.js
module.exports = {
//...
modules: {
rules: [
{
test: /\.(png|jpg|gif|jpeg|webp|svg|eot|ttf|woff|woff2)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 10240, //10K
esModule: false
}
}
],
exclude: /node_modules/
}
]
}
}
複製程式碼
此處設定limit
的值大小為 10240,即資源大小小於10K
時,將資源轉換為base64
,超過 10K,將圖片拷貝到dist
目錄。esModule
設定為false
,否則,<img src={require('XXX.jpg')} />
會出現<img src=[Module Object] />
將資源轉換為base64
可以減少網路請求次數,但是base64
資料較大,如果太多的資源是base64
,會導致載入變慢,因此設定limit
值時,需要二者兼顧。
預設情況下,生成的檔案的檔名就是檔案內容的MD5
雜湊值並會保留所引用資源的原始副檔名,例如我上面的圖片(thor.jpeg)對應的檔名如下:
當然,你也可以通過options
引數進行修改。
//....
use: [
{
loader: 'url-loader',
options: {
limit: 10240, //10K
esModule: false,
name: '[name]_[hash:6].[ext]'
}
}
]
複製程式碼
重新編譯,在瀏覽器中審查元素,可以看到圖片名變成了:thor_a5f7c0.jpeg
。
當本地資源較多時,我們有時會希望它們能打包在一個資料夾下,這也很簡單,我們只需要在url-loader
的options
中指定outpath
,如:outputPath: 'assets'
,構建出的目錄如下:
更多的url-loader
配置可以檢視
到了這裡,有點歲月靜好的感覺了。
不過還沒完,如果你在public/index.html
檔案中,使用本地的圖片,例如,我們修改一下public/index.html
:
<img src="./a.jpg" />
複製程式碼
重啟本地服務,雖然,控制檯不會報錯,但是你會發現,瀏覽器中根本載入不出這張圖片,Why?因為構建之後,通過相對路徑壓根找不著這張圖片呀。
How?怎麼解決呢?
10.處理 html 中的本地圖片
安裝html-withimg-loader
來解決咯。
npm install html-withimg-loader -D
複製程式碼
修改webpack.config.js
:
module.exports = {
//...
module: {
rules: [
{
test: /.html$/,
use: 'html-withimg-loader'
}
]
}
}
複製程式碼
然後在我們的html
中引入一張檔案測試一下(圖片地址自己寫咯,這裡只是示意):
<!-- index.html -->
<img src="./thor.jpeg" />
複製程式碼
重啟本地服務,圖片並沒能載入,審查元素的話,會發現圖片的地址顯示的是{"default":"assets/thor_a5f7c0.jpeg"}
。
我當前file-loader
的版本是 5.0.2,5版本之後,需要增加esModule
屬性:
//webpack.config.js
module.exports = {
//...
modules: {
rules: [
{
test: /\.(png|jpg|gif|jpeg|webp|svg|eot|ttf|woff|woff2)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 10240, //10K
esModule: false
}
}
]
}
]
}
}
複製程式碼
再重啟本地服務,就搞定啦。
話說使用html-withimg-loader
處理圖片之後,html
中就不能使用vm
,ejs
的模板了,如果想繼續在html
中使用<% if(htmlWebpackPlugin.options.config.header) { %>
這樣的語法,但是呢,又希望能使用本地圖片,可不可以?魚和熊掌都想要,雖然很多時候,能吃個魚就不錯了,但是這裡是可以的哦,像下面這樣編寫圖片的地址,並且刪除html-withimg-loader
的配置即可。
<!-- index.html -->
<img src="<%= require('./thor.jpeg') %>" />
複製程式碼
圖片載入OK啦,並且<% %>
語法也可以正常使用,吼吼吼~~~
雖然,webpack
的預設配置很好用,但是有的時候,我們會有一些其它需要啦,例如,我們不止一個入口檔案,這時候,該怎麼辦呢?
11.入口配置
入口的欄位為:entry
//webpack.config.js
module.exports = {
entry: './src/index.js' //webpack的預設配置
}
複製程式碼
entry
的值可以是一個字串,一個數組或是一個物件。
字串的情況無需多說,就是以對應的檔案為入口。
為陣列時,表示有“多個主入口”,想要多個依賴檔案一起注入時,會這樣配置。例如:
entry: [
'./src/polyfills.js',
'./src/index.js'
]
複製程式碼
polyfills.js
檔案中可能只是簡單的引入了一些polyfill
,例如babel-polyfill
,whatwg-fetch
等,需要在最前面被引入(我在 webpack2 時這樣配置過)。
那什麼時候是物件呢?不要捉急,後面將多頁配置的時候,會說到。
12.出口配置
配置output
選項可以控制webpack
如何輸出編譯檔案。
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'), //必須是絕對路徑
filename: 'bundle.js',
publicPath: '/' //通常是CDN地址
}
}
複製程式碼
例如,你最終編譯出來的程式碼部署在 CDN 上,資源的地址為: 'https://AAA/BBB/YourProject/XXX',那麼可以將生產的publicPath
配置為://AAA/BBB/
。
編譯時,可以不配置,或者配置為/
。可以在我們之前提及的config.js
中指定publicPath
(config.js
中區分了dev
和public
), 當然還可以區分不同的環境指定配置檔案來設定,或者是根據isDev
欄位來設定。
除此之外呢,考慮到CDN快取的問題,我們一般會給檔名加上hash
.
//webpack.config.js
module.exports = {
output: {
path: path.resolve(__dirname, 'dist'), //必須是絕對路徑
filename: 'bundle.[hash].js',
publicPath: '/' //通常是CDN地址
}
}
複製程式碼
如果你覺得hash
串太長的話,還可以指定長度,例如bundle.[hash:6].js
。使用npm run build
打包看看吧。
問題出現啦,每次檔案修改後,重新打包,導致dist
目錄下的檔案越來越多。要是每次打包前,都先清空一下目錄就好啦。可不可以做到呢?必須可以!
13.每次打包前清空dist目錄
反正我是懶得手動去清理的,只要你足夠懶,你總是會找到好辦法的,懶人推動科技進步。這裡,我們需要外掛:clean-webpack-plugin
安裝依賴:
npm install clean-webpack-plugin -D
複製程式碼
以前,clean-webpack-plugin
是預設匯出的,現在不是,所以引用的時候,需要注意一下。另外,現在建構函式接受的引數是一個物件,可預設。
//webpack.config.js
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
//...
plugins: [
//不需要傳引數喔,它可以找到 outputPath
new CleanWebpackPlugin()
]
}
複製程式碼
現在你再修改檔案,重現構建,生成的hash值和之前dist中的不一樣,但是因為每次clean-webpack-plugin
都會幫我們先清空一波dist
目錄,所以不會出現太多檔案,傻傻分不清楚究竟哪個是新生成檔案的情況。
希望dist目錄下某個資料夾不被清空
不過呢,有些時候,我們並不希望整個dist
目錄都被清空,比如,我們不希望,每次打包的時候,都刪除dll
目錄,以及dll
目錄下的檔案或子目錄,該怎麼辦呢?
clean-webpack-plugin
為我們提供了引數cleanOnceBeforeBuildPatterns
。
//webpack.config.js
module.exports = {
//...
plugins: [
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns:['**/*', '!dll', '!dll/**'] //不刪除dll目錄下的檔案
})
]
}
複製程式碼
此外,clean-webpack-plugin
還有一些其它的配置,不過我使用的不多,大家可以檢視clean-webpack-plugin
至此,我們算是完成了一個基礎配置。但是這不夠完美,或者說有些時候,我們還會有一些其它的需求。下一篇關於webpack
配置的文章會介紹一些其它的情況。