前面的文章介紹了 Webpack撵割、HMR独柑、React、Redux缝其、ESLint挎塌、Prettier 等內(nèi)容。
但其實(shí) Webpack 4 部分內(nèi)容是沒有比較詳細(xì)的講述的内边,那這篇文章就來介紹它吧榴都。
編寫本文的時(shí)候,最新版本是 webpack 5.1.3
漠其。而本文要介紹的時(shí)候 webpack 4.x
相關(guān)接口嘴高。
提供兩個(gè)鏈接:
請注意本文所指 Webpack 中文文檔由印記中文翻譯。
一和屎、前言
在此前的系列文章拴驮,多多少少都涉及到 webpack 的相關(guān)配置,主要有這幾項(xiàng)柴信。
今天就每一個(gè)知識點(diǎn)套啤,盡可能地都詳細(xì)介紹一下。
webpack 支持所有符合 ES5 標(biāo)準(zhǔn) 的瀏覽器(不支持 IE8 及以下版本)随常。webpack 的
import()
和require.ensure()
需要Promise
潜沦。如果你想要支持舊版本瀏覽器,在使用這些表達(dá)式之前绪氛,還需要提前加載 polyfill唆鸡。
{
mode, // 模式
entry, // 入口
deServer, // 開發(fā)
optimization, // 優(yōu)化
plugins, // 插件
resolve, // 解析
module // 模塊
}
即使有些內(nèi)容前面已經(jīng)介紹過,這里還是再啰嗦簡單介紹一下枣察。
安裝依賴包
不推薦全局安裝 webpack争占。這會將你項(xiàng)目中的 webpack 鎖定到指定版本,并且在使用不同的 webpack 版本的項(xiàng)目中序目,可能會導(dǎo)致構(gòu)建失敗臂痕。
$ yarn add --dev webpack@4.41.2
$ yarn add --dev webpack-cli@3.3.10
webpack 配置文件
webpack 開箱即用,可以無需使用任何配置文件宛琅。然而刻蟹,默認(rèn)情況下 webpack 會假定項(xiàng)目的入口起點(diǎn)為 src/index
逗旁,然后會在 dist/main.js
輸出結(jié)果嘿辟,并且在生產(chǎn)環(huán)境開啟壓縮和優(yōu)化舆瘪。
通常,我們的項(xiàng)目還需要繼續(xù)擴(kuò)展此能力红伦,為此我們可以在項(xiàng)目根目錄下創(chuàng)建一個(gè) webpack.config.js
文件英古,webpack 會自動使用它。
Webpack 配置文件是標(biāo)準(zhǔn)的 Node.js CommonJS 模塊(所以不能使用 ESM 標(biāo)準(zhǔn)導(dǎo)出)昙读,可以導(dǎo)出為 object召调、function 或 Promise,本項(xiàng)目將使用導(dǎo)出 object 的形式蛮浑。雖然可行唠叛,但不建議通過 CLI 形式指定過多參數(shù),會導(dǎo)致編寫很長的腳本命令沮稚,推薦使用配置文件的形式艺沼。
使用自定義配置文件,則可通過 Webpack CLI 命令
--config
來指定蕴掏。
// package.json
// 假定項(xiàng)目根目錄下有兩個(gè)配置文件 dev.config.js 和 prod.config.js障般,分別對應(yīng)開發(fā)模式和生產(chǎn)模式的兩種不同配置,這樣我們就可以通過 --config 來指定了盛杰。
{
"script": {
"webpack:dev": "webpack --config dev.config.js --mode development",
"webpack:build": "webpack --config prod.config.js"
}
}
*附上一個(gè) Webpack 配置文件選項(xiàng)詳解挽荡。
*附上一個(gè)前端構(gòu)建配置生成器 Create App。
常用 Webpack CLI 接口參數(shù)
需要注意的是即供,命令行接口參數(shù)的優(yōu)先級是高于配置文件參數(shù)的定拟。
參數(shù) | 說明 | 默認(rèn)值 |
---|---|---|
--config |
配置文件的路徑 | webpack.config.js 或者 webpackfile.js |
--mode |
用到的模式,development 或 production | |
--hot |
開啟模塊熱替換 | |
--progress |
打印出編譯進(jìn)度的百分比值 | false |
--debug |
將 loader 設(shè)置為 debug 模式 | false |
--color , --colors
|
強(qiáng)制在控制臺開啟顏色 | |
--watch , -w
|
觀察文件系統(tǒng)的變化 | |
--env |
配置文件導(dǎo)出一個(gè)函數(shù)時(shí)逗嫡,會將此環(huán)境變量傳給該函數(shù) |
二办素、Webpack API
1. 入口(entry)
項(xiàng)目的入口文件,從這個(gè)入口文件開始祸穷,應(yīng)用程序啟動執(zhí)行性穿。如果傳遞一個(gè)數(shù)組,那么數(shù)組的每一項(xiàng)都會執(zhí)行雷滚。
不配置入口文件的情況下需曾,Webpack 會默認(rèn)取 src/index.js
作為啟動文件。若不存在祈远,則打包失敗并報(bào)錯(cuò):
ERROR in Entry module not found: Error: Can't resolve './src' in 'xxx'
// 僅舉例說明呆万,實(shí)際情況取其一,下同
module.exports = {
// 支持 string | array | object | function 形式车份,常用的是數(shù)組和對象的形式
// 字符串形式谋减,chunk 被命名為 'main'
entry: 'string',
// 字符串?dāng)?shù)組形式,chunk 被命名為 'main'
entry: ['string'],
// 對象形式扫沼,每個(gè) key 作為 chunk 名稱
entry: {
main: 'string or array',
vendor: 'string or array'
},
// 動態(tài)入口(dynamic entry)可使用函數(shù)形式出爹,比如從服務(wù)器獲取等庄吼,我暫時(shí)未用過
entry: () => {
// 還可以返回 Promise。
return 'string | [string]'
}
}
2. 輸出(output)
它包括了一組選項(xiàng)严就,指示 Webpack 如何去輸出总寻,以及在哪里輸出你的 bundle、asset 和其他你所打包或者使用 Webpack 載入的任何內(nèi)容梢为。
注意整個(gè)配置中我們使用 Node 內(nèi)置的 path 模塊渐行,并在它前面加上 __dirname 這個(gè)全局變量≈可以防止不同操作系統(tǒng)之間的文件路徑問題祟印,并且可以使相對路徑按照預(yù)期工作。我們在很多地方將會使用到它粟害。
__dirname
指當(dāng)前文件所在的目錄
__filename
表示正在執(zhí)行腳本的文件名需要注意的是旁理,它是兩個(gè)下劃線,兩者均返回一個(gè)絕對路徑我磁。
它的選項(xiàng)很多孽文,主要介紹常用的幾個(gè):
- path
所有輸出文件的目標(biāo)路徑。它是一個(gè)絕對路徑夺艰,默認(rèn)是項(xiàng)目根目錄下的 dist
路徑芋哭。
例如,打包后的 JS 文件郁副、url-loader
解析的圖片减牺,html-webpack-plugin
生成的 HTML 文件等都會存放到該路徑下(或相對于該路徑的子目錄)
若非絕對路徑,它將會構(gòu)建失敗并報(bào)錯(cuò):configuration.output.path: The provided value "xxx" is not an absolute path!
- publicPath
publicPath 并不會對生成文件的路徑造成影響存谎,主要是對你的頁面里面引入的資源的路徑做對應(yīng)的補(bǔ)全拔疚,常見的就是 CSS 文件里面引入的圖片。
其中某些 loader(例如 file-loader
) 的 publicPath
選項(xiàng)會覆蓋掉 output.publicPath
的既荚。
關(guān)于
path
和publicPath
很多人容易混淆稚失,官方的描述我看起來是模糊的,所以下面我通俗地描述一下恰聘。通俗地講句各,
path
就是打包文件存放在硬盤上的路徑,它不會因?yàn)?publicPath
的設(shè)置而改變晴叨。而
publicPath
會影響項(xiàng)目中引用的資源路徑并重寫凿宾。它只會修改項(xiàng)目中的相對路徑和絕對路徑,而完整的絕對路徑將不受影響(例如 https://cdn.example.com/assets/ 這種形式不會被修改)兼蕊。最常見的就是圖片資源初厚、打包產(chǎn)出的 JavaScript 文件在 HTML 中的引用路徑等。這些文件的路徑目錄將被 publicPath 替換重寫(除了文件名不變孙技,其他被替換)产禾。常被用來指定上線后的 cdn 域名排作。
- filename
此選項(xiàng)決定了每個(gè)(入口 chunk 文件)輸出 bundle 的名稱。這些 bundle 將寫入到 output.path
選項(xiàng)指定的目錄下下愈。
注意纽绍,此選項(xiàng)不會影響那些「按需加載 chunk」的輸出文件蕾久。對于這些文件势似,請使用
output.chunkFilename
選項(xiàng)來控制輸出。通過 loader 創(chuàng)建的文件也不受影響僧著。在這種情況下履因,你必須嘗試 loader 特定的可用選項(xiàng)。
可以使用以下替換模板字符串:
模板 | 描述 |
---|---|
[hash] |
模塊標(biāo)識符(module identifier)的 hash
|
[chunkhash] |
chunk 內(nèi)容的 hash
|
[name] |
模塊名稱(即入口文件名稱)盹愚,默認(rèn)為 main
|
[id] |
模塊標(biāo)識符(module identifier) |
[query] |
模塊的 query 栅迄,例如文件名 ? 后面的字符串 |
[function] |
The function, which can return filename [string] |
*[hash]
和 [chunkhash]
的長度可以使用 [hash:16]
(默認(rèn)為 20)來指定。
*如果將這個(gè)選項(xiàng)設(shè)為一個(gè)函數(shù)皆怕,函數(shù)將返回一個(gè)包含上面表格中替換信息的對象毅舆。
*注意此選項(xiàng)被稱為文件名,但是你還是可以使用像 js/[name]/bundle.js
這樣的文件夾結(jié)構(gòu)愈腾。
關(guān)于 Webpack 的
hash
憋活、chunkhash
、contenthash
的區(qū)別虱黄,可以看下這篇文章悦即。
- chunkFilename
此選項(xiàng)決定了非入口(non-entry)chunk 文件的名稱。
注意橱乱,這些文件名需要在 runtime 根據(jù) chunk 發(fā)送的請求去生成辜梳。因此,需要在 webpack runtime 輸出 bundle 值時(shí)泳叠,將 chunk id 的值對應(yīng)映射到占位符(如 [name]
和 [chunkhash]
)作瞄。這會增加文件大小,并且在任何 chunk 的占位符值修改后危纫,都會使 bundle 失效粉洼。
默認(rèn)使用 [id].js
或從 output.filename
中推斷出的值([name]
會被預(yù)先替換為 [id]
或 [id].
),所以它的可讀性很差叶摄。
默認(rèn) [id]
和 [name]
是一樣的属韧。
chunkFileName
不能靈活自定義,這誰能忍蛤吓,于是便有了webpackChunkName
宵喂,可以看下這篇文章。
const path = require('path')
module.exports = {
output: {
// 指定打包輸出路徑為 dist会傲,
// 它必須絕對路徑锅棕,為了避免不同操作系統(tǒng)之間文件路徑問題拙泽,這里借助 Node.js 內(nèi)置的 path 模塊以及 __dirname 全局變量
// __dirname 是兩個(gè)下劃線
path: path.resolve(__dirname, 'dist'),
// 它通常是以 '/' 結(jié)束,避免出現(xiàn)訪問不到生成之后的靜態(tài)資源的問題
// 實(shí)際場景裸燎,根據(jù)項(xiàng)目本身設(shè)置
publicPath: '',
// publicPath: 'https://cdn.example.com/assets/', // CDN(總是 HTTPS 協(xié)議)
// publicPath: '//cdn.example.com/assets/', // CDN(協(xié)議相同)
// publicPath: '/assets/', // 相對于服務(wù)(server-relative)
// publicPath: 'assets/', // 相對于 HTML 頁面
// publicPath: '../assets/', // 相對于 HTML 頁面
// publicPath: '', // 相對于 HTML 頁面(目錄相同)顾瞻,默認(rèn)
// 入口文件輸出 bundle 的名稱
filename: 'bundle.js', // 靜態(tài)名稱
// filename: '[name].bundle.js', // 使用入口名稱
// filename: 'js/[name].bundle.js', // 支持文件夾結(jié)構(gòu)
// filename: '[id].bundle.js', // 使用內(nèi)部 chunk id
// filename: '[name].[hash].bundle.js', // 使用每次構(gòu)建過程中,唯一的 hash 生成
// filename: '[chunkhash].bundle.js', // 使用基于每個(gè) chunk 內(nèi)容的 hash
// filename: '[contenthash].bundle.css', // Using hashes generated for extracted content
// filename: (chunkData) => { // Using function to return the filename
// // 如果將這個(gè)選項(xiàng)設(shè)為一個(gè)函數(shù)德绿,函數(shù)將返回一個(gè)包含上面表格中替換信息的對象荷荤。
// return chunkData.chunk.name === 'main' ? '[name].js' : '[name]/[name].js'
// },
// 非入口文件,但參與構(gòu)建的 bundle
chunkFilename: '[chunkhash].bundle.js' // 可取的值與 filename 一致
}
}
一句話總結(jié):
filename
指列在entry
中移稳,打包后輸出的文件的名稱蕴纳。
chunkFilename
指未列在entry
中,卻又需要被打包出來的文件的名稱个粱。
3. 模塊(module)
這些選項(xiàng)決定了如何處理項(xiàng)目中的不同類型的模塊古毛。
- noParse
它的作用是防止 webpack 解析那些任意與給定正則表達(dá)式項(xiàng)匹配的文件。因?yàn)樗鼈儽缓雎粤硕夹恚圆粫?Babel 等做語法轉(zhuǎn)換以兼容低版本的瀏覽器稻薇,故它們不應(yīng)該含有 import、require胶征、define 的調(diào)用塞椎。
module.exports = {
module: {
// 支持 RegExp、[RegExp]弧烤、function(resource)忱屑、string、[string] 的形式
noParse: /jquery|loadsh/
// noParse: content => /jquery|lodash/.test(content)
}
}
- rules(重要)
創(chuàng)建模塊時(shí)暇昂,匹配請求的規(guī)則數(shù)組莺戒。這些規(guī)則能夠修改模塊的創(chuàng)建方式报嵌。這些規(guī)則能夠?qū)δK(module)應(yīng)用 loader判沟,或者修改解析器(parser)摘仅。
module.rules
是數(shù)組形式荣倾,支持一個(gè)或多個(gè)規(guī)則,而每個(gè)規(guī)則(Rule
)可以分為三部分:條件(condition)蝌以、結(jié)果(result)躏惋、嵌套規(guī)則(nested rule)发框。
Rule 條件
條件有兩種輸入值:
1. resource:請求文件的絕對路徑泣懊。(它已經(jīng)根據(jù) resolve 規(guī)則解析)
2. issuer:被請求資源的模塊文件的絕對路徑伸辟,它是導(dǎo)入時(shí)的路徑。如果看起來有點(diǎn)懵馍刮,沒關(guān)系信夫,下面舉例說明。
在規(guī)則中,resource 由屬規(guī)則屬性
test
静稻、include
警没、exclude
、resource
對其進(jìn)行匹配振湾。而 issuer 則由規(guī)則屬性issuer
對其進(jìn)行匹配杀迹。
// 假如我們在入口文件 index.js 導(dǎo)入 app.css
import './styles/app.css?inline'
// webpack 匹配
module.exports = {
module: {
rules: [
{
test: /\.css$/,
exclude: /node_modules/,
use: info => {
// info 是正在加載模塊的一些參數(shù)
// 包括 resource、issuer押搪、realResource树酪、compiler
console.log(info)
return ['style-loader', 'css-loader']
}
}
]
}
}
// info 打印結(jié)果如下:
{
resource: '/Users/frankie/Desktop/Web/Temp/temp_webpack/src/styles/app.css',
realResource: '/Users/frankie/Desktop/Web/Temp/temp_webpack/src/styles/app.css',
resourceQuery: '?inline',
issuer: '/Users/frankie/Desktop/Web/Temp/temp_webpack/src/index.js',
compiler: undefined
}
結(jié)合概念和例子,其實(shí)已經(jīng)很清楚了嵌言。app.css
是我們的目標(biāo)文件嗅回,而 index.js
則是導(dǎo)入目標(biāo)文件的位置及穗。因此摧茴,resource 就是目標(biāo)文件的絕對路徑,而 issuer 則是 index.js
的絕對路徑埂陆。
Rule 結(jié)果
規(guī)則結(jié)果只有在規(guī)則條件匹配時(shí)使用苛白。
規(guī)則有兩種輸入值:
1. 應(yīng)用的 loader:應(yīng)用在 resource 上的 loader 數(shù)組。
2. Parser 選項(xiàng):用于為模塊創(chuàng)建擠下去的選項(xiàng)對象焚虱。這些規(guī)則屬性
loader
购裙、options
、use
會影響 loader鹃栽。(query
躏率、loaders
也會影響,但它們也被廢棄)
enforce
屬性會影響 loader 種類民鼓。
parser
屬性會影響 parser 選項(xiàng)薇芝。
不知道你們第一次看到上面這些概率描述夯到,會不會有點(diǎn)發(fā)懵,反正我開始看的時(shí)候是會的饮亏。
接下來耍贾,介紹規(guī)則(Rule)的屬性,先看下有哪些:
module.exports = {
module: {
rules: [
// Rule
{
resource: {
test,
include,
exclude
},
use: [
{
loader,
options
}
],
loaders, // 此選項(xiàng)已廢棄路幸,請使用 Rule.use
query, // 此選項(xiàng)已廢棄荐开,請使用 Rule.use.options
issuer,
enforce,
oneOf,
parser,
resourceQuery,
rules,
type,
sideEffects
},
{
// 可能你們看到更多是長這樣的,但其實(shí)它們只是簡寫罷了简肴。
// 后面添加配置晃听,我可能使用簡寫多一些。
test, // Rule.resource.test 的簡寫
include, // Rule.resource.include 的簡寫
exclude, // Rule.resource.exclude 的簡寫
loader, // Rule.use: [ { loader } ] 的簡寫
options // Rule.use: [ { options } ] 的簡寫
}
]
}
}
(1) Rule.test、Rule.include杂伟、Rule.exclude
它們分別是 Rule.resource: { test, inclued, exclued }
的縮寫移层。實(shí)際中,很多開發(fā)的朋友都說采用縮寫的寫法赫粥。
條件可以是這些之一:
- 字符串:匹配輸入必須以提供的字符串開始观话。是的。目錄絕對路徑或文件絕對路徑越平。
- 正則表達(dá)式:test 輸入值频蛔。
- 函數(shù):調(diào)用輸入的函數(shù),必須返回一個(gè)真值(truthy value)以匹配秦叛。
- 條件數(shù)組:至少一個(gè)匹配條件晦溪。
- 對象:匹配所有屬性。每個(gè)屬性都有一個(gè)定義行為挣跋。
test
:匹配特定條件三圆。一般是提供一個(gè)正則表達(dá)式或正則表達(dá)式的數(shù)組,但這不是強(qiáng)制的避咆。
include
:匹配特定條件舟肉。一般是提供一個(gè)字符串或者字符串?dāng)?shù)組,但這不是強(qiáng)制的查库。
exclude
:排除特定條件路媚。一般是提供一個(gè)字符串或字符串?dāng)?shù)組,但這不是
強(qiáng)制的樊销。
匹配條件每個(gè)選項(xiàng)都接收一個(gè)正則表達(dá)式或字符串整慎。
test
和include
具有相同的作用,都是必須匹配選項(xiàng)围苫。exclude
是必不匹配選項(xiàng)(優(yōu)先于test
和include
)最佳實(shí)踐:
- 只在
test
和文件名匹配
中使用正則表達(dá)式裤园。- 在
include
和exclude
中使用絕對路徑數(shù)組。- 盡量避免
exclude
够吩,更傾向于使用include
比然。
(2) Rule.use
支持 UseEntries 和 function(info) 兩種方式。
其中 UseEntry 是一個(gè)對象周循,要求必須有一個(gè) loader 屬性是字符串强法。
也可以有一個(gè) options 屬性為字符串或?qū)ο螅渲悼梢詡鬟f到 loader 中湾笛,將其理解為 loader 選項(xiàng)饮怯。
由于兼容性原因,也有可能有 query 屬性嚎研,它是 options 屬性的別名蓖墅。請使用 options 屬性替代库倘。
傳遞字符串(如:use: [ 'style-loader' ]
)是 loader 屬性的簡寫方式(如:use: [ { loader: 'style-loader' } ]
)
它還可以傳遞多個(gè) loader,但要注意 loader 的加載順序是從右往左(從下往上)论矾。
Rule.use 也可以是一個(gè)函數(shù)教翩,該函數(shù)接收描述正在加載的模塊的 object 參數(shù),并且必須返回 UseEntry 項(xiàng)的數(shù)組贪壳。
該函數(shù) function(info)
的參數(shù) info
包含以下幾個(gè)字段 { compiler, issuer, realResource, resource }
饱亿。
那這幾個(gè)字段究竟是什么呢,其實(shí)上面講述 Rule 條件的時(shí)候闰靴,就有打印出來彪笼,可以往上翻翻,或者看下官網(wǎng)的介紹蚂且。
關(guān)于此我不展開贅述配猫,因?yàn)橐膊恢酪盟鉀Q什么實(shí)際的場景問題,所以其實(shí)沒用過杏死。那說明我目前是不需要它的泵肄,使用 UseEntry 即可滿足我的需求。
我在寫 Redux 篇的時(shí)候识埋,引用過一句話凡伊,用著這里也是同理的零渐。
如果你不知道是否需要 Redux窒舟,那就是不需要它。
module.exports = {
module: {
rules: [
{
// ...
// 單個(gè) loader诵盼,可以使用簡寫形式
loader: 'file-loader',
options: {
name: '[name].[ext]'
}
},
{
// ...
// 多個(gè) loader惠豺,不含 options 簡寫形式
use: ['style-loader', 'css-loader'],
},
{
// ...
// 多個(gè) loader,且含 options 簡寫形式
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1
}
},
{
loader: 'less-loader',
options: {
noIeCompat: true
}
}
]
}
]
}
}
(3) Rule.enforce
該屬性指定 loader 種類风宁,其值可以是 pre
或者 post
(字符串)洁墙,沒有值表示普通 loader。
所有一個(gè)接一個(gè)地進(jìn)入的 loader戒财,都有兩個(gè)階段:
1. Pitching 階段:loader 上的 pitch 方法热监,按照 后置(post)
、行內(nèi)(inline)
饮寞、普通(normal)
孝扛、前置(pre)
的順序調(diào)用。更多詳細(xì)信息幽崩,請查看 pitching loader苦始。
2. Normal 階段:loader 上的常規(guī)方法,按照 前置(pre)
慌申、普通(normal)
陌选、行內(nèi)(inline)
、后置(post)
的順序調(diào)用。模塊源碼的轉(zhuǎn)換咨油,發(fā)生在這個(gè)階段您炉。
所有普通 loader 可以通過在請求中加上 !
前綴來忽略(覆蓋)。
所有普通和前置 loader 可以通過在請求中加上 -!
前綴來忽略(覆蓋)役电。
所有普通邻吭,后置和前置 loader 可以通過在請求中加上 !!
前綴來忽略(覆蓋)。
不應(yīng)該使用
行內(nèi) loader
和!
前綴宴霸,因?yàn)樗鼈兪欠菢?biāo)準(zhǔn)的囱晴。PS:我沒使用過行內(nèi) loader 的方式,也不太了解它這樣做的目的是什么瓢谢。設(shè)置成前置 loader 倒是用過畸写,前面文章講解
eslint-loader
與babel-loader
順序先后問題用過。
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: path.resolve(__dirname, 'node_modules'),
loader: 'babel-loader'
},
// 由于 eslint-loader 要于 babel-loader 之前執(zhí)行氓扛,且 loader 執(zhí)行順序是從下往上執(zhí)行的枯芬,所以 eslint-loader 要寫在下面
// 但出于安全謹(jǐn)慎考慮,添加 enforce: 'pre' 屬性采郎,使其無論寫在 babel-loader 前后都能優(yōu)先執(zhí)行千所。
{
test: /\.js$/,
enforce: 'pre',
exclude: path.resolve(__dirname, 'node_modules'),
loader: 'eslint-loader',
options: {
fix: true
cache: true
}
}
]
}
}
(4) 其他屬性
- 請注意 Rule.loaders、Rule.query 屬性已廢棄蒜埋,請分別使用 Rule.use淫痰、Rule.options 替代。
- 以下屬性一般較少使用整份,這里不展開細(xì)說待错,可點(diǎn)擊進(jìn)一步了解。 Rule.issuer烈评、Rule.oneOf火俄、Rule.parser、Rule.resourceQuery讲冠、Rule.type瓜客、Rule.sideEffects。
4. 解析(resolve)
該選項(xiàng)用于配置模塊如何解析竿开。例如谱仪,當(dāng)在 ES6 中調(diào)用 import 'lodash'
,resolve
選項(xiàng)能夠?qū)?webpack 查找 lodash
的方式去做修改德迹。
這一塊內(nèi)容已在另外一篇文章詳細(xì)介紹了芽卿,請移步至文章 Webpack 如何解析模塊路徑。
5. 模式(mode)
提供 mode
配置選項(xiàng)胳搞,告知 webpack 使用響應(yīng)環(huán)境的內(nèi)置優(yōu)化卸例〕蒲睿可選值有:none
、development
或 production
筷转。
如果沒有設(shè)置姑原,mode
默認(rèn)設(shè)置為 production
∥厥妫可通過以下方式設(shè)定:
// webpack.config.js
module.exports = {
mode: 'production'
}
或者從 CLI 傳遞參數(shù):
// package.json
{
"scripts": {
"build": "webpack --mode production"
}
}
development
它會將DefinePlugin
中的process.env.NODE_ENV
的值設(shè)置為development
锭汛。啟用NamedChunksPlugin
和NamedModulesPlugin
。production
它會將DefinePlugin
中的process.env.NODE_ENV
的值設(shè)置為production
袭蝗。啟用FlagDependencyUsagePlugin
唤殴、FlagIncludedChunksPlugin
、ModuleConcatenationPlugin
到腥、NoEmitOnErrorsPlugin
朵逝、OccurrenceOrderPlugin
、SideEffectsFlagPlugin
乡范、TerserPlugin
配名。none
它會退出任何默認(rèn)優(yōu)化選項(xiàng)。注意晋辆,設(shè)置了
NODE_ENV
并不會自動地設(shè)置mode
渠脉。
6. devtool
此選項(xiàng)控制是否生成,以及如何生成 Source Map瓶佳。不同的值會明顯影響到構(gòu)建(build)和重新構(gòu)建(rebuild)的速度芋膘。
建議:開發(fā)環(huán)境使用
eval-cheap-module-source-map
,而生產(chǎn)環(huán)境多數(shù)只需要知道報(bào)錯(cuò)的模塊和行號就可以了涩哟,所以使用的是nosources-source-map
索赏。
你可以直接使用 SourceMapDevToolPlugin
/EvalSourceMapDevToolPlugin
來替代使用 devtool
選項(xiàng),因?yàn)樗懈嗟倪x項(xiàng)贴彼。切勿同時(shí)使用 devtool
選項(xiàng)和 SourceMapDevToolPlugin
/EvalSourceMapDevToolPlugin
插件。devtool
選項(xiàng)在內(nèi)部添加過這些插件埃儿,所以你最終將應(yīng)用兩次插件器仗。
- Devtool 可選值有很多,看這里:Webpack Devtool童番。
- 了解 Source Map 請看這篇文章:一文徹底搞懂 Webpack Devtool精钮。
7. 插件(plugins)
該選項(xiàng)用于已各種方式自定義 webpack 構(gòu)建過程。webpack 附帶了各種內(nèi)置的插件剃斧,可以通過 webpack.[plugin-name]
訪問這些插件轨香。
可以查看插件頁面獲取插件列表和對應(yīng)的文檔,這只是其中一部分幼东,社區(qū)中還有很多插件臂容。
每個(gè)插件都是一個(gè)構(gòu)造函數(shù)科雳,使用它的時(shí)候需要用 new
實(shí)例化。
以下是此前系列文章使用過的插件脓杉,后續(xù)文章還將會用到其他插件糟秘,比如 copy-webpack-plugin
、happypack
等球散,用到再介紹尿赚。
// webpack.config.js
const webpack = require('webpack')
// 導(dǎo)入非 webpack 自帶默認(rèn)插件
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
module.exports = {
// ...
plugins: [
// 創(chuàng)建 HTML 文件
new HtmlWebpackPlugin({
title: 'webpack demo',
template: './src/index.html',
filename: 'index.html',
inject: 'body',
hash: true,
favicon: './src/favicon.ico'
}),
// 新版無需再指定刪除目錄,默認(rèn)刪除 output 的目錄
new CleanWebpackPlugin(),
// 通過它啟用 HMR 之后蕉堰,它的接口將被暴露在 module.hot 屬性下面
new webpack.HotModuleReplacementPlugin(),
// 允許在編譯時(shí)(compile time)配置的全局常量
new webpack.DefinePlugin({
// 注意凌净,因?yàn)檫@個(gè)插件直接執(zhí)行文本替換,給定的值必須包含字符串本身內(nèi)的實(shí)際引號屋讶。通常泻蚊,有兩種方式來達(dá)到這個(gè)效果,使用 '"production"', 或者使用 JSON.stringify('production')丑婿。
'process.env.NODE_ENV': JSON.stringify('development')
})
]
}
8. 開發(fā)環(huán)境
關(guān)于 watch mode
性雄、webpack-dev-server
、webpack-dev-middleware
的選擇羹奉,寫在這篇 Webpack 開發(fā)環(huán)境選擇文章了秒旋。
文章中提到了 webpack-dev-server 生成的包并沒有存儲在你的硬盤中,而是放到了內(nèi)存里诀拭。
接下來介紹的是 webpack-dev-server 選項(xiàng)迁筛。
*若想通過 Node.js API 來使用它,此處有一個(gè)簡單示例耕挨。
webpack-dev-server 支持兩種模式來刷新頁面:
- iframe:頁面放在
<iframe>
標(biāo)簽中细卧,當(dāng)文件發(fā)生更改會重新刷新頁面,設(shè)置方式有兩種筒占,如下:
module.exports = {
devServer: {
inline: false, // 啟用 iframe 模式
open: true // 在 server 啟動后打開瀏覽器
}
}
或者通過 CLI 方式:
{
"scripts": {
"dev": "webpack-dev-server --inline=false"
}
}
啟動之后贪庙,打開的 URL 格式如下:
http://?host?:?port?/webpack-dev-server/?path?
# 比如
http://localhost:8080/webpack-dev-server/
*我看過的項(xiàng)目好像還沒有人用這種方式的,我也沒用過翰苫,不展開說了止邮。(PS:我嘗試過這種方式好像只能 Live Reload,不能 HMR奏窑。我不知道是我配置問題导披,還是其他原因?后面有時(shí)間再研究一下埃唯,研究明白了再回來更新這塊內(nèi)容)
- inline:默認(rèn)是
inline mode
撩匕。
配置方式有三種,看這篇別人踩坑的文章墨叛。我怕我說越多越亂止毕,記住它是默認(rèn)的模式就好了模蜡。
注意接著,往下的內(nèi)容將基于 inline 模式介紹滓技。
告訴服務(wù)器從哪個(gè)目錄中提供內(nèi)容哩牍。只有在你需要提供靜態(tài)文件(如圖片,數(shù)據(jù)等一些不受 webpack 控制的資源文件)時(shí)才需要令漂。devServer.publicPath
將用于確定應(yīng)該從哪里提供 bundle膝昆,并且此選項(xiàng)優(yōu)先。
推薦使用一個(gè)絕對路徑叠必。
默認(rèn)情況下荚孵,將使用當(dāng)前工作目錄作為提供內(nèi)容的目錄,將其設(shè)置為 false
以禁用 contentBase
纬朝。
// webpack.config.js
const path = require('path')
module.exports = {
devServer: {
// 單個(gè)目錄
contentBase: path.join(__dirname, 'public'),
// 多個(gè)目錄
contentBase: [
path.join(__dirname, 'public'),
path.join(__dirname, 'assets')
]
}
}
*CLI 用法不介紹了收叶,下同。
此路徑下的打包文件可在瀏覽器中訪問共苛。devServer.publicPath
默認(rèn)值是 /
判没。
假設(shè)服務(wù)器運(yùn)行在 http://localhost:8080
并且 output.filename
被設(shè)置為 bundle.js
。devServer.publicPath
默認(rèn)值是 /
隅茎,所以你的包(bundle)可以通過 http://localhost:8080/bundle.js
訪問澄峰。
module.exports = {
//...
devServer: {
publicPath: '/assets/'
}
}
修改配置,將 bundle 放置指定的目錄下”傧現(xiàn)在通過 http://localhost:8080/assets/bundle.js
訪問到 bundle俏竞。
未完待續(xù)...