摘要:配置無入口的在輸出時(shí)的文件名稱。配置發(fā)布到線上資源的前綴,為類型。則是用于配置這個(gè)異步插入的標(biāo)簽的值。配置以何種方式導(dǎo)出庫。是字符串的枚舉類型,支持以下配置。在為時(shí),配置將沒有意義。是可選配置項(xiàng),類型需要是其中一個(gè)。
webpack配置
查看所有文檔頁面:全棧開發(fā),獲取更多信息。原文鏈接:第2章 配置,原文廣告模態(tài)框遮擋,閱讀體驗(yàn)不好,所以整理成本文,方便查找。
配置 Webpack 的方式有兩種:
通過一個(gè) JavaScript 文件描述配置,例如使用 webpack.config.js 文件里的配置;
執(zhí)行 Webpack 可執(zhí)行文件時(shí)通過命令行參數(shù)傳入,例如 webpack --devtool source-map。
這兩種方式可以相互搭配,例如執(zhí)行 Webpack 時(shí)通過命令 webpack --config webpack-dev.config.js 指定配置文件,再去 webpack-dev.config.js 文件里描述部分配置。
按照配置所影響的功能來劃分,可分為:
Entry 配置模塊的入口;
Output 配置如何輸出最終想要的代碼;
Module 配置處理模塊的規(guī)則;
Resolve 配置尋找模塊的規(guī)則;
Plugins 配置擴(kuò)展插件;
DevServer 配置 DevServer;
其它配置項(xiàng) 其它零散的配置項(xiàng);
整體配置結(jié)構(gòu) 整體地描述各配置項(xiàng)的結(jié)構(gòu);
多種配置類型 配置文件不止可以返回一個(gè) Object,還有其他返回形式;
配置總結(jié) 尋找配置 Webpack 的規(guī)律,減少思維負(fù)擔(dān)。
EntryWebpack 在尋找相對(duì)路徑的文件時(shí)會(huì)以 context 為根目錄,context 默認(rèn)為執(zhí)行啟動(dòng) Webpack 時(shí)所在的當(dāng)前工作目錄。
如果想改變 context 的默認(rèn)配置,可以在配置文件里設(shè)置:
module.exports = { context: path.resolve(__dirname, "app") }
注意, context 必須是一個(gè)絕對(duì)路徑的字符串。 除此之外,還可以通過在啟動(dòng) Webpack 時(shí)帶上參數(shù) webpack --context 來設(shè)置 context。
Chunk 名稱Webpack 會(huì)為每個(gè)生成的 Chunk 取一個(gè)名稱,Chunk 的名稱和 Entry 的配置有關(guān):
如果 entry 是一個(gè) string 或 array,就只會(huì)生成一個(gè) Chunk,這時(shí) Chunk 的名稱是 main;
如果 entry 是一個(gè) object,就可能會(huì)出現(xiàn)多個(gè) Chunk,這時(shí) Chunk 的名稱是 object 鍵值對(duì)里鍵的名稱。
配置動(dòng)態(tài) Entry假如項(xiàng)目里有多個(gè)頁面需要為每個(gè)頁面的入口配置一個(gè) Entry ,但這些頁面的數(shù)量可能會(huì)不斷增長,則這時(shí) Entry 的配置會(huì)受到到其他因素的影響導(dǎo)致不能寫成靜態(tài)的值。其解決方法是把 Entry 設(shè)置成一個(gè)函數(shù)去動(dòng)態(tài)返回上面所說的配置,代碼如下:
// 同步函數(shù) entry: () => { return { a:"./pages/a", b:"./pages/b", } }; // 異步函數(shù) entry: () => { return new Promise((resolve)=>{ resolve({ a:"./pages/a", b:"./pages/b", }); }); };Output
output 配置如何輸出最終想要的代碼。output 是一個(gè) object,里面包含一系列配置項(xiàng):
filenameoutput.filename 配置輸出文件的名稱,為 string 類型。 如果只有一個(gè)輸出文件,則可以把它寫成靜態(tài)不變的:
filename: "bundle.js"
但是在有多個(gè) Chunk 要輸出時(shí),就需要借助模版和變量了。前面說到 Webpack 會(huì)為每個(gè) Chunk取一個(gè)名稱,可以根據(jù) Chunk 的名稱來區(qū)分輸出的文件名:
filename: "[name].js"
代碼里的 [name] 代表用內(nèi)置的 name 變量去替換[name],這時(shí)你可以把它看作一個(gè)字符串模塊函數(shù), 每個(gè)要輸出的 Chunk 都會(huì)通過這個(gè)函數(shù)去拼接出輸出的文件名稱。
變量名 | 含義 |
---|---|
id | Chunk 的唯一標(biāo)識(shí),從0開始 |
name | Chunk 的名稱 |
hash | Chunk 的唯一標(biāo)識(shí)的 Hash 值 |
chunkhash | Chunk 內(nèi)容的 Hash 值 |
其中 hash 和 chunkhash 的長度是可指定的,[hash:8] 代表取8位 Hash 值,默認(rèn)是20位。
注意 ExtractTextWebpackPlugin 插件是使用 contenthash 來代表哈希值而不是 chunkhash, 原因在于 ExtractTextWebpackPlugin 提取出來的內(nèi)容是代碼內(nèi)容本身而不是由一組模塊組成的 Chunk。chunkFilename
output.chunkFilename 配置無入口的 Chunk 在輸出時(shí)的文件名稱。 chunkFilename 和上面的 filename 非常類似,但 chunkFilename 只用于指定在運(yùn)行過程中生成的 Chunk 在輸出時(shí)的文件名稱。 常見的會(huì)在運(yùn)行時(shí)生成 Chunk 場(chǎng)景有在使用 CommonChunkPlugin、使用 import("path/to/module") 動(dòng)態(tài)加載等時(shí)。 chunkFilename 支持和 filename 一致的內(nèi)置變量。
path
output.path 配置輸出文件存放在本地的目錄,必須是 string 類型的絕對(duì)路徑。通常通過 Node.js 的 path 模塊去獲取絕對(duì)路徑:
path: path.resolve(__dirname, "dist_[hash]")publicPath
在復(fù)雜的項(xiàng)目里可能會(huì)有一些構(gòu)建出的資源需要異步加載,加載這些異步資源需要對(duì)應(yīng)的 URL 地址。
output.publicPath 配置發(fā)布到線上資源的 URL 前綴,為string 類型。 默認(rèn)值是空字符串 "",即使用相對(duì)路徑。
把構(gòu)建出的資源文件上傳到 CDN 服務(wù)上,以利于加快頁面的打開速度。配置代碼如下:
filename:"[name]_[chunkhash:8].js" publicPath: "https://cdn.example.com/assets/"
這時(shí)發(fā)布到線上的 HTML 在引入 JavaScript 文件時(shí)就需要:
使用該配置項(xiàng)時(shí)要小心,稍有不慎將導(dǎo)致資源加載404錯(cuò)誤。
output.path 和 output.publicPath 都支持字符串模版,內(nèi)置變量只有一個(gè):hash 代表一次編譯操作的 Hash 值。
crossOriginLoadingWebpack 輸出的部分代碼塊可能需要異步加載,而異步加載是通過 JSONP 方式實(shí)現(xiàn)的。 JSONP 的原理是動(dòng)態(tài)地向 HTML 中插入一個(gè) 標(biāo)簽去加載異步資源。
output.crossOriginLoading 則是用于配置這個(gè)異步插入的標(biāo)簽的 crossorigin 值。
script 標(biāo)簽的 crossorigin 屬性可以取以下值:
false(默認(rèn)) 在加載此腳本資源時(shí)不會(huì)帶上用戶的 Cookies;
use-credentials 在加載此腳本資源時(shí)會(huì)帶上用戶的 Cookies。
通常用設(shè)置 crossorigin 來獲取異步加載的腳本執(zhí)行時(shí)的詳細(xì)錯(cuò)誤信息。
libraryTarget 和 library當(dāng)用 Webpack 去構(gòu)建一個(gè)可以被其他模塊導(dǎo)入使用的庫時(shí)需要用到它們。
output.libraryTarget 配置以何種方式導(dǎo)出庫。
output.library 配置導(dǎo)出庫的名稱。
假如配置了 output.library="LibraryName",則輸出和使用的代碼如下:
// Webpack 輸出的代碼 var LibraryName = lib_code; // 使用庫的方法 LibraryName.doSomething();
假如 output.library 為空,則將直接輸出:lib_code
其中 lib_code 代指導(dǎo)出庫的代碼內(nèi)容,是有返回值的一個(gè)自執(zhí)行函數(shù)。
它們通常搭配在一起使用。
output.libraryTarget 是字符串的枚舉類型,支持以下配置。
var (默認(rèn))編寫的庫將通過 var 被賦值給通過 library 指定名稱的變量。
commonjs編寫的庫將通過 CommonJS2 規(guī)范導(dǎo)出,輸出和使用的代碼如下:
// Webpack 輸出的代碼 module.exports = lib_code; // 使用庫的方法 require("library-name-in-npm").doSomething();
CommonJS2 和 CommonJS 規(guī)范很相似,差別在于 CommonJS 只能用 exports 導(dǎo)出,而 CommonJS2 在 CommonJS 的基礎(chǔ)上增加了 module.exports 的導(dǎo)出方式。
在 output.libraryTarget 為 commonjs2 時(shí),配置 output.library 將沒有意義。
this編寫的庫將通過 this 被賦值給通過 library 指定的名稱,輸出和使用的代碼如下:
// Webpack 輸出的代碼
this["LibraryName"] = lib_code;
// 使用庫的方法
this.LibraryName.doSomething();
編寫的庫將通過 window 被賦值給通過 library 指定的名稱,即把庫掛載到 window 上,輸出和使用的代碼如下:
// Webpack 輸出的代碼 window["LibraryName"] = lib_code; // 使用庫的方法 window.LibraryName.doSomething();global
編寫的庫將通過 global 被賦值給通過 library 指定的名稱,即把庫掛載到 global 上,輸出和使用的代碼如下:
// Webpack 輸出的代碼 global["LibraryName"] = lib_code; // 使用庫的方法 global.LibraryName.doSomething();libraryExport
output.libraryExport 配置要導(dǎo)出的模塊中哪些子模塊需要被導(dǎo)出。 它只有在 output.libraryTarget 被設(shè)置成 commonjs 或者 commonjs2 時(shí)使用才有意義。
假如要導(dǎo)出的模塊源代碼是:
export const a=1; export default b=2;
現(xiàn)在想讓構(gòu)建輸出的代碼只導(dǎo)出其中的 a,可以把 output.libraryExport 設(shè)置成 a,那么構(gòu)建輸出的代碼和使用方法將變成如下:
// Webpack 輸出的代碼 module.exports = lib_code["a"]; // 使用庫的方法 require("library-name-in-npm")===1;Module 配置 Loader
rules 配置模塊的讀取和解析規(guī)則,通常用來配置 Loader。其類型是一個(gè)數(shù)組,數(shù)組里每一項(xiàng)都描述了如何去處理部分文件。 配置一項(xiàng) rules 時(shí)大致通過以下方式:
條件匹配:通過 test 、 include 、 exclude 三個(gè)配置項(xiàng)來命中 Loader 要應(yīng)用規(guī)則的文件。
應(yīng)用規(guī)則:對(duì)選中后的文件通過 use 配置項(xiàng)來應(yīng)用 Loader,可以只應(yīng)用一個(gè) Loader 或者按照從后往前的順序應(yīng)用一組 Loader,同時(shí)還可以分別給 Loader 傳入?yún)?shù)。
重置順序:一組 Loader 的執(zhí)行順序默認(rèn)是從右到左執(zhí)行,通過 enforce 選項(xiàng)可以讓其中一個(gè) Loader 的執(zhí)行順序放到最前或者最后。
module: { rules: [ { // 命中 JavaScript 文件 test: /.js$/, // 用 babel-loader 轉(zhuǎn)換 JavaScript 文件 // ?cacheDirectory 表示傳給 babel-loader 的參數(shù),用于緩存 babel 編譯結(jié)果加快重新編譯速度 use: ["babel-loader?cacheDirectory"], // 只命中src目錄里的js文件,加快 Webpack 搜索速度 include: path.resolve(__dirname, "src") }, { // 命中 SCSS 文件 test: /.scss$/, // 使用一組 Loader 去處理 SCSS 文件。 // 處理順序?yàn)閺暮蟮角?,即先交給 sass-loader 處理,再把結(jié)果交給 css-loader 最后再給 style-loader。 use: ["style-loader", "css-loader", "sass-loader"], // 排除 node_modules 目錄下的文件 exclude: path.resolve(__dirname, "node_modules"), }, { // 對(duì)非文本文件采用 file-loader 加載 test: /.(gif|png|jpe?g|eot|woff|ttf|svg|pdf)$/, use: ["file-loader"], }, ] }
在 Loader 需要傳入很多參數(shù)時(shí),你還可以通過一個(gè) Object 來描述,例如在上面的 babel-loader 配置中有如下代碼:
use: [ { loader:"babel-loader", options:{ cacheDirectory:true, }, // enforce:"post" 的含義是把該 Loader 的執(zhí)行順序放到最后 // enforce 的值還可以是 pre,代表把 Loader 的執(zhí)行順序放到最前面 enforce:"post" }, // 省略其它 Loader ]
上面的例子中 test include exclude 這三個(gè)命中文件的配置項(xiàng)只傳入了一個(gè)字符串或正則,其實(shí)它們還都支持?jǐn)?shù)組類型,使用如下:
{ test:[ /.jsx?$/, /.tsx?$/ ], include:[ path.resolve(__dirname, "src"), path.resolve(__dirname, "tests"), ], exclude:[ path.resolve(__dirname, "node_modules"), path.resolve(__dirname, "bower_modules"), ] }
數(shù)組里的每項(xiàng)之間是或的關(guān)系,即文件路徑符合數(shù)組中的任何一個(gè)條件就會(huì)被命中。
noParsenoParse 配置項(xiàng)可以讓 Webpack 忽略對(duì)部分沒采用模塊化的文件的遞歸解析和處理,這樣做的好處是能提高構(gòu)建性能。 原因是一些庫例如 jQuery 、ChartJS 它們龐大又沒有采用模塊化標(biāo)準(zhǔn),讓 Webpack 去解析這些文件耗時(shí)又沒有意義。
noParse 是可選配置項(xiàng),類型需要是 RegExp、[RegExp]、function 其中一個(gè)。
例如想要忽略掉 jQuery 、ChartJS,可以使用如下代碼:
// 使用正則表達(dá)式 noParse: /jquery|chartjs/ // 使用函數(shù),從 Webpack 3.0.0 開始支持 noParse: (content)=> { // content 代表一個(gè)模塊的文件路徑 // 返回 true or false return /jquery|chartjs/.test(content); }
注意被忽略掉的文件里不應(yīng)該包含 import 、 require 、 define 等模塊化語句,不然會(huì)導(dǎo)致構(gòu)建出的代碼中包含無法在瀏覽器環(huán)境下執(zhí)行的模塊化語句。parser
因?yàn)?Webpack 是以模塊化的 JavaScript 文件為入口,所以內(nèi)置了對(duì)模塊化 JavaScript 的解析功能,支持 AMD、CommonJS、SystemJS、ES6。
parser 屬性可以更細(xì)粒度的配置哪些模塊語法要解析哪些不解析,和 noParse 配置項(xiàng)的區(qū)別在于 parser 可以精確到語法層面, 而 noParse 只能控制哪些文件不被解析。 parser 使用如下:
module: { rules: [ { test: /.js$/, use: ["babel-loader"], parser: { amd: false, // 禁用 AMD commonjs: false, // 禁用 CommonJS system: false, // 禁用 SystemJS harmony: false, // 禁用 ES6 import/export requireInclude: false, // 禁用 require.include requireEnsure: false, // 禁用 require.ensure requireContext: false, // 禁用 require.context browserify: false, // 禁用 browserify requireJs: false, // 禁用 requirejs } }, ] }Resolve
Webpack 在啟動(dòng)后會(huì)從配置的入口模塊出發(fā)找出所有依賴的模塊,Resolve 配置 Webpack 如何尋找模塊所對(duì)應(yīng)的文件。 Webpack 內(nèi)置 JavaScript 模塊化語法解析功能,默認(rèn)會(huì)采用模塊化標(biāo)準(zhǔn)里約定好的規(guī)則去尋找,但你也可以根據(jù)自己的需要修改默認(rèn)的規(guī)則。
aliasresolve.alias 配置項(xiàng)通過別名來把原導(dǎo)入路徑映射成一個(gè)新的導(dǎo)入路徑。例如使用以下配置:
// Webpack alias 配置 resolve:{ alias:{ components: "./src/components/" } }
當(dāng)你通過 import Button from "components/button" 導(dǎo)入時(shí),實(shí)際上被 alias 等價(jià)替換成了 import Button from "./src/components/button"。
以上 alias 配置的含義是把導(dǎo)入語句里的 components 關(guān)鍵字替換成 ./src/components/。
這樣做可能會(huì)命中太多的導(dǎo)入語句,alias 還支持 $ 符號(hào)來縮小范圍到只命中以關(guān)鍵字結(jié)尾的導(dǎo)入語句:
resolve:{ alias:{ "react$": "/path/to/react.min.js" } }
react$ 只會(huì)命中以 react 結(jié)尾的導(dǎo)入語句,即只會(huì)把 import "react" 關(guān)鍵字替換成 import "/path/to/react.min.js"。
mainFields有一些第三方模塊會(huì)針對(duì)不同環(huán)境提供幾分代碼。 例如分別提供采用 ES5 和 ES6 的2份代碼,這2份代碼的位置寫在 package.json 文件里,如下:
{ "jsnext:main": "es/index.js",// 采用 ES6 語法的代碼入口文件 "main": "lib/index.js" // 采用 ES5 語法的代碼入口文件 }
Webpack 會(huì)根據(jù) mainFields 的配置去決定優(yōu)先采用哪份代碼,mainFields 默認(rèn)如下:
mainFields: ["browser", "main"]
Webpack 會(huì)按照數(shù)組里的順序去 package.json 文件里尋找,只會(huì)使用找到的第一個(gè)。
假如你想優(yōu)先采用 ES6 的那份代碼,可以這樣配置:
mainFields: ["jsnext:main", "browser", "main"]extensions
在導(dǎo)入語句沒帶文件后綴時(shí),Webpack 會(huì)自動(dòng)帶上后綴后去嘗試訪問文件是否存在。 resolve.extensions 用于配置在嘗試過程中用到的后綴列表,默認(rèn)是:
extensions: [".js", ".json"]modules
resolve.modules 配置 Webpack 去哪些目錄下尋找第三方模塊,默認(rèn)是只會(huì)去 node_modules 目錄下尋找。
有時(shí)你的項(xiàng)目里會(huì)有一些模塊會(huì)大量被其它模塊依賴和導(dǎo)入,由于其它模塊的位置分布不定,針對(duì)不同的文件都要去計(jì)算被導(dǎo)入模塊文件的相對(duì)路徑, 這個(gè)路徑有時(shí)候會(huì)很長,就像這樣 import "../../../components/button" 這時(shí)你可以利用 modules 配置項(xiàng)優(yōu)化,假如那些被大量導(dǎo)入的模塊都在 ./src/components 目錄下,把 modules 配置成:
modules:["./src/components","node_modules"]
后,你可以簡單通過 import "button" 導(dǎo)入。
descriptionFilesresolve.descriptionFiles 配置描述第三方模塊的文件名稱,也就是 package.json 文件。默認(rèn)如下:
descriptionFiles: ["package.json"]enforceExtension
resolve.enforceExtension 如果配置為 true 所有導(dǎo)入語句都必須要帶文件后綴, 例如開啟前 import "./foo" 能正常工作,開啟后就必須寫成 import "./foo.js"。
enforceModuleExtensionenforceModuleExtension 和 enforceExtension 作用類似,但 enforceModuleExtension 只對(duì) node_modules 下的模塊生效。
enforceModuleExtension 通常搭配 enforceExtension 使用,在 enforceExtension:true 時(shí),因?yàn)榘惭b的第三方模塊中大多數(shù)導(dǎo)入語句沒帶文件后綴, 所以這時(shí)通過配置 enforceModuleExtension:false 來兼容第三方模塊。
PluginsPlugin 用于擴(kuò)展 Webpack 功能,各種各樣的 Plugin 幾乎讓 Webpack 可以做任何構(gòu)建相關(guān)的事情。
配置 PluginPlugin 的配置很簡單,plugins 配置項(xiàng)接受一個(gè)數(shù)組,數(shù)組里每一項(xiàng)都是一個(gè)要使用的 Plugin 的實(shí)例,Plugin 需要的參數(shù)通過構(gòu)造函數(shù)傳入。
const CommonsChunkPlugin = require("webpack/lib/optimize/CommonsChunkPlugin"); module.exports = { plugins: [ // 所有頁面都會(huì)用到的公共代碼提取到 common 代碼塊中 new CommonsChunkPlugin({ name: "common", chunks: ["a", "b"] }), ] };
使用 Plugin 的難點(diǎn)在于掌握 Plugin 本身提供的配置項(xiàng),而不是如何在 Webpack 中接入 Plugin。
DevServer要配置 DevServer ,除了在配置文件里通過 devServer 傳入?yún)?shù)外,還可以通過命令行參數(shù)傳入。 注意只有在通過 DevServer 去啟動(dòng) Webpack 時(shí)配置文件里 devServer 才會(huì)生效,因?yàn)檫@些參數(shù)所對(duì)應(yīng)的功能都是 DevServer 提供的,Webpack 本身并不認(rèn)識(shí) devServer 配置項(xiàng)。
hotdevServer.hot 配置是否啟用模塊熱替換功能。
DevServer 默認(rèn)的行為是在發(fā)現(xiàn)源代碼被更新后會(huì)通過自動(dòng)刷新整個(gè)頁面來做到實(shí)時(shí)預(yù)覽,開啟模塊熱替換功能后將在不刷新整個(gè)頁面的情況下通過用新模塊替換老模塊來做到實(shí)時(shí)預(yù)覽。
inlineDevServer 的實(shí)時(shí)預(yù)覽功能依賴一個(gè)注入到頁面里的代理客戶端去接受來自 DevServer 的命令和負(fù)責(zé)刷新網(wǎng)頁的工作。
devServer.inline 用于配置是否自動(dòng)注入這個(gè)代理客戶端到將運(yùn)行在頁面里的 Chunk 里去,默認(rèn)是會(huì)自動(dòng)注入。 DevServer 會(huì)根據(jù)你是否開啟 inline 來調(diào)整它的自動(dòng)刷新策略:
如果開啟 inline,DevServer 會(huì)在構(gòu)建完變化后的代碼時(shí)通過代理客戶端控制網(wǎng)頁刷新。
如果關(guān)閉 inline,DevServer 將無法直接控制要開發(fā)的網(wǎng)頁。這時(shí)它會(huì)通過 iframe 的方式去運(yùn)行要開發(fā)的網(wǎng)頁,當(dāng)構(gòu)建完變化后的代碼時(shí)通過刷新 iframe 來實(shí)現(xiàn)實(shí)時(shí)預(yù)覽。
如果你想使用 DevServer 去自動(dòng)刷新網(wǎng)頁實(shí)現(xiàn)實(shí)時(shí)預(yù)覽,最方便的方法是直接開啟 inline。
historyApiFallbackdevServer.historyApiFallback 用于方便的開發(fā)使用了 HTML5 History API 的單頁應(yīng)用。
這類單頁應(yīng)用要求服務(wù)器在針對(duì)任何命中的路由時(shí)都返回一個(gè)對(duì)應(yīng)的 HTML 文件,例如在訪問 http://localhost/user 和 http://localhost/home 時(shí)都返回 index.html 文件, 瀏覽器端的 JavaScript 代碼會(huì)從 URL 里解析出當(dāng)前頁面的狀態(tài),顯示出對(duì)應(yīng)的界面。
配置 historyApiFallback 最簡單的做法是:
historyApiFallback: true
這會(huì)導(dǎo)致任何請(qǐng)求都會(huì)返回 index.html 文件,這只能用于只有一個(gè) HTML 文件的應(yīng)用。
如果你的應(yīng)用由多個(gè)單頁應(yīng)用組成,這就需要 DevServer 根據(jù)不同的請(qǐng)求來返回不同的 HTML 文件,配置如下:
historyApiFallback: { // 使用正則匹配命中路由 rewrites: [ // /user 開頭的都返回 user.html { from: /^/user/, to: "/user.html" }, { from: /^/game/, to: "/game.html" }, // 其它的都返回 index.html { from: /./, to: "/index.html" }, ] }contentBase
devServer.contentBase 配置 DevServer HTTP 服務(wù)器的文件根目錄。 默認(rèn)情況下為當(dāng)前執(zhí)行目錄,通常是項(xiàng)目根目錄,所有一般情況下你不必設(shè)置它,除非你有額外的文件需要被 DevServer 服務(wù)。 例如你想把項(xiàng)目根目錄下的 public 目錄設(shè)置成 DevServer 服務(wù)器的文件根目錄,你可以這樣配置:
devServer:{ contentBase: path.join(__dirname, "public") }
這里需要指出可能會(huì)讓你疑惑的地方,DevServer 服務(wù)器通過 HTTP 服務(wù)暴露出的文件分為兩類:
暴露本地文件。
暴露 Webpack 構(gòu)建出的結(jié)果,由于構(gòu)建出的結(jié)果交給了 DevServer,所以你在使用了 DevServer 時(shí)在本地找不到構(gòu)建出的文件。
contentBase 只能用來配置暴露本地文件的規(guī)則,你可以通過 contentBase:false 來關(guān)閉暴露本地文件。
headersdevServer.headers 配置項(xiàng)可以在 HTTP 響應(yīng)中注入一些 HTTP 響應(yīng)頭,使用如下:
devServer:{ headers: { "X-foo":"bar" } }host
devServer.host 配置項(xiàng)用于配置 DevServer 服務(wù)監(jiān)聽的地址。
例如你想要局域網(wǎng)中的其它設(shè)備訪問你本地的服務(wù),可以在啟動(dòng) DevServer 時(shí)帶上 --host 0.0.0.0。 host 的默認(rèn)值是 127.0.0.1 即只有本地可以訪問 DevServer 的 HTTP 服務(wù)。
portdevServer.port 配置項(xiàng)用于配置 DevServer 服務(wù)監(jiān)聽的端口,默認(rèn)使用 8080 端口。 如果 8080 端口已經(jīng)被其它程序占有就使用 8081,如果 8081 還是被占用就使用 8082,以此類推。
allowedHostsdevServer.allowedHosts 配置一個(gè)白名單列表,只有 HTTP 請(qǐng)求的 HOST 在列表里才正常返回,使用如下:
allowedHosts: [ // 匹配單個(gè)域名 "host.com", "sub.host.com", // host2.com 和所有的子域名 *.host2.com 都將匹配 ".host2.com" ]disableHostCheck
devServer.disableHostCheck 配置項(xiàng)用于配置是否關(guān)閉用于 DNS 重綁定的 HTTP 請(qǐng)求的 HOST 檢查。
DevServer 默認(rèn)只接受來自本地的請(qǐng)求,關(guān)閉后可以接受來自任何 HOST 的請(qǐng)求。 它通常用于搭配 --host 0.0.0.0 使用,因?yàn)槟阆胍渌O(shè)備訪問你本地的服務(wù),但訪問時(shí)是直接通過 IP 地址訪問而不是 HOST 訪問,所以需要關(guān)閉 HOST 檢查。
httpsDevServer 默認(rèn)使用 HTTP 協(xié)議服務(wù),它也能通過 HTTPS 協(xié)議服務(wù)。 有些情況下你必須使用 HTTPS,例如 HTTP2 和 Service Worker 就必須運(yùn)行在 HTTPS 之上。 要切換成 HTTPS 服務(wù),最簡單的方式是:
devServer:{ https: true }
DevServer 會(huì)自動(dòng)的為你生成一份 HTTPS 證書。
如果你想用自己的證書可以這樣配置:
devServer:{ https: { key: fs.readFileSync("path/to/server.key"), cert: fs.readFileSync("path/to/server.crt"), ca: fs.readFileSync("path/to/ca.pem") } }clientLogLevel
devServer.clientLogLevel 配置在客戶端的日志等級(jí),這會(huì)影響到你在瀏覽器開發(fā)者工具控制臺(tái)里看到的日志內(nèi)容。
clientLogLevel 是枚舉類型,可取如下之一的值 none | error | warning | info。 默認(rèn)為 info 級(jí)別,即輸出所有類型的日志,設(shè)置成 none 可以不輸出任何日志。
compressdevServer.compress 配置是否啟用 gzip 壓縮。boolean 為類型,默認(rèn)為 false。
opendevServer.open 用于在 DevServer 啟動(dòng)且第一次構(gòu)建完時(shí)自動(dòng)用你系統(tǒng)上默認(rèn)的瀏覽器去打開要開發(fā)的網(wǎng)頁。 同時(shí)還提供 devServer.openPage 配置項(xiàng)用于打開指定 URL 的網(wǎng)頁。
其它配置項(xiàng) Targettarget 配置項(xiàng)可以讓 Webpack 構(gòu)建出針對(duì)不同運(yùn)行環(huán)境的代碼。 target 可以是以下之一:
target值 | 描述 |
---|---|
web | 針對(duì)瀏覽器 (默認(rèn)),所有代碼都集中在一個(gè)文件里 |
node | 針對(duì) Node.js,使用 require 語句加載 Chunk 代碼 |
async-node | 針對(duì) Node.js,異步加載 Chunk 代碼 |
webworker | 針對(duì) WebWorker |
electron-main | 針對(duì) Electron 主線程 |
electron-renderer | 針對(duì) Electron 渲染線程 |
例如當(dāng)你設(shè)置 target:"node" 時(shí),源代碼中導(dǎo)入 Node.js 原生模塊的語句 require("fs") 將會(huì)被保留,fs 模塊的內(nèi)容不會(huì)打包進(jìn) Chunk 里。
Devtooldevtool 配置 Webpack 如何生成 Source Map,默認(rèn)值是 false 即不生成 Source Map,想為構(gòu)建出的代碼生成 Source Map 以方便調(diào)試,可以這樣配置:
module.export = { devtool: "source-map" }Watch 和 WatchOptions
前面介紹過 Webpack 的監(jiān)聽模式,它支持監(jiān)聽文件更新,在文件發(fā)生變化時(shí)重新編譯。在使用 Webpack 時(shí)監(jiān)聽模式默認(rèn)是關(guān)閉的,想打開需要如下配置:
module.export = { watch: true }
在使用 DevServer 時(shí),監(jiān)聽模式默認(rèn)是開啟的。
除此之外,Webpack 還提供了 watchOptions 配置項(xiàng)去更靈活的控制監(jiān)聽模式,使用如下:
module.export = { // 只有在開啟監(jiān)聽模式時(shí),watchOptions 才有意義 // 默認(rèn)為 false,也就是不開啟 watch: true, // 監(jiān)聽模式運(yùn)行時(shí)的參數(shù) // 在開啟監(jiān)聽模式時(shí),才有意義 watchOptions: { // 不監(jiān)聽的文件或文件夾,支持正則匹配 // 默認(rèn)為空 ignored: /node_modules/, // 監(jiān)聽到變化發(fā)生后會(huì)等300ms再去執(zhí)行動(dòng)作,防止文件更新太快導(dǎo)致重新編譯頻率太高 // 默認(rèn)為 300ms aggregateTimeout: 300, // 判斷文件是否發(fā)生變化是通過不停的去詢問系統(tǒng)指定文件有沒有變化實(shí)現(xiàn)的 // 默認(rèn)每1000豪秒去問1次 poll: 1000 } }Externals
Externals 用來告訴 Webpack 要構(gòu)建的代碼中使用了哪些不用被打包的模塊,也就是說這些模版是外部環(huán)境提供的,Webpack 在打包時(shí)可以忽略它們。
有些 JavaScript 運(yùn)行環(huán)境可能內(nèi)置了一些全局變量或者模塊,例如在你的 HTML HEAD 標(biāo)簽里通過以下代碼:
引入 jQuery 后,全局變量 jQuery 就會(huì)被注入到網(wǎng)頁的 JavaScript 運(yùn)行環(huán)境里。
如果想在使用模塊化的源代碼里導(dǎo)入和使用 jQuery,可能需要這樣:
import $ from "jquery"; $(".my-element");
構(gòu)建后你會(huì)發(fā)現(xiàn)輸出的 Chunk 里包含的 jQuery 庫的內(nèi)容,這導(dǎo)致 jQuery 庫出現(xiàn)了2次,浪費(fèi)加載流量,最好是 Chunk 里不會(huì)包含 jQuery 庫的內(nèi)容。
Externals 配置項(xiàng)就是為了解決這個(gè)問題。
通過 externals 可以告訴 Webpack JavaScript 運(yùn)行環(huán)境已經(jīng)內(nèi)置了那些全局變量,針對(duì)這些全局變量不用打包進(jìn)代碼中而是直接使用全局變量。 要解決以上問題,可以這樣配置 externals:
module.export = { externals: { // 把導(dǎo)入語句里的 jquery 替換成運(yùn)行環(huán)境里的全局變量 jQuery jquery: "jQuery" } }ResolveLoader
ResolveLoader 用來告訴 Webpack 如何去尋找 Loader,因?yàn)樵谑褂?Loader 時(shí)是通過其包名稱去引用的, Webpack 需要根據(jù)配置的 Loader 包名去找到 Loader 的實(shí)際代碼,以調(diào)用 Loader 去處理源文件。
ResolveLoader 的默認(rèn)配置如下:
module.exports = { resolveLoader:{ // 去哪個(gè)目錄下尋找 Loader modules: ["node_modules"], // 入口文件的后綴 extensions: [".js", ".json"], // 指明入口文件位置的字段 mainFields: ["loader", "main"] } }
該配置項(xiàng)常用于加載本地的 Loader。
整體配置結(jié)構(gòu)之前的章節(jié)分別講述了每個(gè)配置項(xiàng)的具體含義,但沒有描述它們所處的位置和數(shù)據(jù)結(jié)構(gòu),下面通過一份代碼來描述清楚:
const path = require("path"); module.exports = { // entry 表示 入口,Webpack 執(zhí)行構(gòu)建的第一步將從 Entry 開始,可抽象成輸入。 // 類型可以是 string | object | array entry: "./app/entry", // 只有1個(gè)入口,入口只有1個(gè)文件 entry: ["./app/entry1", "./app/entry2"], // 只有1個(gè)入口,入口有2個(gè)文件 entry: { // 有2個(gè)入口 a: "./app/entry-a", b: ["./app/entry-b1", "./app/entry-b2"] }, // 如何輸出結(jié)果:在 Webpack 經(jīng)過一系列處理后,如何輸出最終想要的代碼。 output: { // 輸出文件存放的目錄,必須是 string 類型的絕對(duì)路徑。 path: path.resolve(__dirname, "dist"), // 輸出文件的名稱 filename: "bundle.js", // 完整的名稱 filename: "[name].js", // 當(dāng)配置了多個(gè) entry 時(shí),通過名稱模版為不同的 entry 生成不同的文件名稱 filename: "[chunkhash].js", // 根據(jù)文件內(nèi)容 hash 值生成文件名稱,用于瀏覽器長時(shí)間緩存文件 // 發(fā)布到線上的所有資源的 URL 前綴,string 類型 publicPath: "/assets/", // 放到指定目錄下 publicPath: "", // 放到根目錄下 publicPath: "https://cdn.example.com/", // 放到 CDN 上去 // 導(dǎo)出庫的名稱,string 類型 // 不填它時(shí),默認(rèn)輸出格式是匿名的立即執(zhí)行函數(shù) library: "MyLibrary", // 導(dǎo)出庫的類型,枚舉類型,默認(rèn)是 var // 可以是 umd | umd2 | commonjs2 | commonjs | amd | this | var | assign | window | global | jsonp , libraryTarget: "umd", // 是否包含有用的文件路徑信息到生成的代碼里去,boolean 類型 pathinfo: true, // 附加 Chunk 的文件名稱 chunkFilename: "[id].js", chunkFilename: "[chunkhash].js", // JSONP 異步加載資源時(shí)的回調(diào)函數(shù)名稱,需要和服務(wù)端搭配使用 jsonpFunction: "myWebpackJsonp", // 生成的 Source Map 文件名稱 sourceMapFilename: "[file].map", // 瀏覽器開發(fā)者工具里顯示的源碼模塊名稱 devtoolModuleFilenameTemplate: "webpack:///[resource-path]", // 異步加載跨域的資源時(shí)使用的方式 crossOriginLoading: "use-credentials", crossOriginLoading: "anonymous", crossOriginLoading: false, }, // 配置模塊相關(guān) module: { rules: [ // 配置 Loader { test: /.jsx?$/, // 正則匹配命中要使用 Loader 的文件 include: [ // 只會(huì)命中這里面的文件 path.resolve(__dirname, "app") ], exclude: [ // 忽略這里面的文件 path.resolve(__dirname, "app/demo-files") ], use: [ // 使用那些 Loader,有先后次序,從后往前執(zhí)行 "style-loader", // 直接使用 Loader 的名稱 { loader: "css-loader", options: { // 給 html-loader 傳一些參數(shù) } } ] }, ], noParse: [ // 不用解析和處理的模塊 /special-library.js$/ // 用正則匹配 ], }, // 配置插件 plugins: [], // 配置尋找模塊的規(guī)則 resolve: { modules: [ // 尋找模塊的根目錄,array 類型,默認(rèn)以 node_modules 為根目錄 "node_modules", path.resolve(__dirname, "app") ], extensions: [".js", ".json", ".jsx", ".css"], // 模塊的后綴名 alias: { // 模塊別名配置,用于映射模塊 // 把 "module" 映射 "new-module",同樣的 "module/path/file" 也會(huì)被映射成 "new-module/path/file" "module": "new-module", // 使用結(jié)尾符號(hào) $ 后,把 "only-module" 映射成 "new-module", // 但是不像上面的,"module/path/file" 不會(huì)被映射成 "new-module/path/file" "only-module$": "new-module", }, alias: [ // alias 還支持使用數(shù)組來更詳細(xì)的配置 { name: "module", // 老的模塊 alias: "new-module", // 新的模塊 // 是否是只映射模塊,如果是 true 只有 "module" 會(huì)被映射,如果是 false "module/inner/path" 也會(huì)被映射 onlyModule: true, } ], symlinks: true, // 是否跟隨文件軟鏈接去搜尋模塊的路徑 descriptionFiles: ["package.json"], // 模塊的描述文件 mainFields: ["main"], // 模塊的描述文件里的描述入口的文件的字段名稱 enforceExtension: false, // 是否強(qiáng)制導(dǎo)入語句必須要寫明文件后綴 }, // 輸出文件性能檢查配置 performance: { hints: "warning", // 有性能問題時(shí)輸出警告 hints: "error", // 有性能問題時(shí)輸出錯(cuò)誤 hints: false, // 關(guān)閉性能檢查 maxAssetSize: 200000, // 最大文件大小 (單位 bytes) maxEntrypointSize: 400000, // 最大入口文件大小 (單位 bytes) assetFilter: function (assetFilename) { // 過濾要檢查的文件 return assetFilename.endsWith(".css") || assetFilename.endsWith(".js"); } }, devtool: "source-map", // 配置 source-map 類型 context: __dirname, // Webpack 使用的根目錄,string 類型必須是絕對(duì)路徑 // 配置輸出代碼的運(yùn)行環(huán)境 target: "web", // 瀏覽器,默認(rèn) target: "webworker", // WebWorker target: "node", // Node.js,使用 `require` 語句加載 Chunk 代碼 target: "async-node", // Node.js,異步加載 Chunk 代碼 target: "node-webkit", // nw.js target: "electron-main", // electron, 主線程 target: "electron-renderer", // electron, 渲染線程 externals: { // 使用來自 JavaScript 運(yùn)行環(huán)境提供的全局變量 jquery: "jQuery" }, stats: { // 控制臺(tái)輸出日志控制 assets: true, colors: true, errors: true, errorDetails: true, hash: true, }, devServer: { // DevServer 相關(guān)的配置 proxy: { // 代理到后端服務(wù)接口 "/api": "http://localhost:3000" }, contentBase: path.join(__dirname, "public"), // 配置 DevServer HTTP 服務(wù)器的文件根目錄 compress: true, // 是否開啟 gzip 壓縮 historyApiFallback: true, // 是否開發(fā) HTML5 History API 網(wǎng)頁 hot: true, // 是否開啟模塊熱替換功能 https: false, // 是否開啟 HTTPS 模式 }, profile: true, // 是否捕捉 Webpack 構(gòu)建的性能信息,用于分析什么原因?qū)е聵?gòu)建性能不佳 cache: false, // 是否啟用緩存提升構(gòu)建速度 watch: true, // 是否開始 watchOptions: { // 監(jiān)聽模式選項(xiàng) // 不監(jiān)聽的文件或文件夾,支持正則匹配。默認(rèn)為空 ignored: /node_modules/, // 監(jiān)聽到變化發(fā)生后會(huì)等300ms再去執(zhí)行動(dòng)作,防止文件更新太快導(dǎo)致重新編譯頻率太高 // 默認(rèn)為300ms aggregateTimeout: 300, // 判斷文件是否發(fā)生變化是不停的去詢問系統(tǒng)指定文件有沒有變化,默認(rèn)每秒問 1000 次 poll: 1000 }, };多種配置類型
除了通過導(dǎo)出一個(gè) Object 來描述 Webpack 所需的配置外,還有其它更靈活的方式,以簡化不同場(chǎng)景的配置。
導(dǎo)出一個(gè) Function在大多數(shù)時(shí)候你需要從同一份源代碼中構(gòu)建出多份代碼,例如一份用于開發(fā)時(shí),一份用于發(fā)布到線上。
如果采用導(dǎo)出一個(gè) Object 來描述 Webpack 所需的配置的方法,需要寫兩個(gè)文件。 一個(gè)用于開發(fā)環(huán)境,一個(gè)用于線上環(huán)境。再在啟動(dòng)時(shí)通過 webpack --config webpack.config.js 指定使用哪個(gè)配置文件。
采用導(dǎo)出一個(gè) Function 的方式,能通過 JavaScript 靈活的控制配置,做到只寫一個(gè)配置文件就能完成以上要求。
導(dǎo)出一個(gè) Function 的使用方式如下:
const path = require("path"); const UglifyJsPlugin = require("webpack/lib/optimize/UglifyJsPlugin"); module.exports = function (env = {}, argv) { const plugins = []; const isProduction = env["production"]; // 在生成環(huán)境才壓縮 if (isProduction) { plugins.push( // 壓縮輸出的 JS 代碼 new UglifyJsPlugin() ) } return { plugins: plugins, // 在生成環(huán)境不輸出 Source Map devtool: isProduction ? undefined : "source-map", }; };
在運(yùn)行 Webpack 時(shí),會(huì)給這個(gè)函數(shù)傳入2個(gè)參數(shù),分別是:
env:當(dāng)前運(yùn)行時(shí)的 Webpack 專屬環(huán)境變量,env 是一個(gè) Object。讀取時(shí)直接訪問 Object 的屬性,設(shè)置它需要在啟動(dòng) Webpack 時(shí)帶上參數(shù)。例如啟動(dòng)命令是 webpack --env.production --env.bao=foo 時(shí),則 env 的值是 {"production":"true","bao":"foo"}。
argv:代表在啟動(dòng) Webpack 時(shí)所有通過命令行傳入的參數(shù),例如 --config、--env、--devtool,可以通過 webpack -h 列出所有 Webpack 支持的命令行參數(shù)。
就以上配置文件而言,在開發(fā)時(shí)執(zhí)行命令 webpack 構(gòu)建出方便調(diào)試的代碼,在需要構(gòu)建出發(fā)布到線上的代碼時(shí)執(zhí)行 webpack --env.production 構(gòu)建出壓縮的代碼。
導(dǎo)出一個(gè)返回 Promise 的函數(shù)在有些情況下你不能以同步的方式返回一個(gè)描述配置的 Object,Webpack 還支持導(dǎo)出一個(gè)返回 Promise 的函數(shù),使用如下:
module.exports = function(env = {}, argv) { return new Promise((resolve, reject) => { setTimeout(() => { resolve({ // ... }) }, 5000) }) }導(dǎo)出多份配置
除了只導(dǎo)出一份配置外,Webpack 還支持導(dǎo)出一個(gè)數(shù)組,數(shù)組中可以包含每份配置,并且每份配置都會(huì)執(zhí)行一遍構(gòu)建。
使用如下:
module.exports = [ // 采用 Object 描述的一份配置 { // ... }, // 采用函數(shù)描述的一份配置 function() { return { // ... } }, // 采用異步函數(shù)描述的一份配置 function() { return Promise(); } ]
以上配置會(huì)導(dǎo)致 Webpack 針對(duì)這三份配置執(zhí)行三次不同的構(gòu)建。
這特別適合于用 Webpack 構(gòu)建一個(gè)要上傳到 Npm 倉庫的庫,因?yàn)閹熘锌赡苄枰喾N模塊化格式的代碼,例如 CommonJS、UMD。
配置總結(jié)從前面的配置看來選項(xiàng)很多,Webpack 內(nèi)置了很多功能。
你不必都記住它們,只需要大概明白 Webpack 原理和核心概念去判斷選項(xiàng)大致屬于哪個(gè)大模塊下,再去查詳細(xì)的使用文檔。
通常你可用如下經(jīng)驗(yàn)去判斷如何配置 Webpack:
想讓源文件加入到構(gòu)建流程中去被 Webpack 控制,配置 entry。
想自定義輸出文件的位置和名稱,配置 output。
想自定義尋找依賴模塊時(shí)的策略,配置 resolve。
想自定義解析和轉(zhuǎn)換文件的策略,配置 module,通常是配置 module.rules 里的 Loader。
其它的大部分需求可能要通過 Plugin 去實(shí)現(xiàn),配置 plugin。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/95190.html
摘要:中的配置熱加載插件安裝中的配置優(yōu)化插件為組件分配,通過這個(gè)插件可以分析和優(yōu)先考慮使用最多的模塊,并為它們分配最小的壓縮代碼分離和文件 0 前言 本文是針對(duì)TCM項(xiàng)目所做的WebPack配置文件總結(jié),主要概述了一些常用配置選項(xiàng)和插件使用,對(duì)以后的項(xiàng)目有指導(dǎo)意義。TCM的webpack配置文件包括webapck.config.base.js、webapck.config.dev.js、we...
摘要:中的配置熱加載插件安裝中的配置優(yōu)化插件為組件分配,通過這個(gè)插件可以分析和優(yōu)先考慮使用最多的模塊,并為它們分配最小的壓縮代碼分離和文件 0 前言 本文是針對(duì)TCM項(xiàng)目所做的WebPack配置文件總結(jié),主要概述了一些常用配置選項(xiàng)和插件使用,對(duì)以后的項(xiàng)目有指導(dǎo)意義。TCM的webpack配置文件包括webapck.config.base.js、webapck.config.dev.js、we...
前言 什么是webpack 本質(zhì)上,webpack 是一個(gè)現(xiàn)代 JavaScript 應(yīng)用程序的靜態(tài)模塊打包器(module bundler)。當(dāng) webpack 處理應(yīng)用程序時(shí),它會(huì)遞歸地構(gòu)建一個(gè)依賴關(guān)系圖(dependency graph),其中包含應(yīng)用程序需要的每個(gè)模塊,然后將所有這些模塊打包成一個(gè)或多個(gè) bundle。 webpack 有哪些功能(代碼轉(zhuǎn)換 文件優(yōu)化 代碼分割 模塊合并 ...
前言 什么是webpack 本質(zhì)上,webpack 是一個(gè)現(xiàn)代 JavaScript 應(yīng)用程序的靜態(tài)模塊打包器(module bundler)。當(dāng) webpack 處理應(yīng)用程序時(shí),它會(huì)遞歸地構(gòu)建一個(gè)依賴關(guān)系圖(dependency graph),其中包含應(yīng)用程序需要的每個(gè)模塊,然后將所有這些模塊打包成一個(gè)或多個(gè) bundle。webpack 有哪些功能(代碼轉(zhuǎn)換 文件優(yōu)化 代碼分割 模塊合并 自...
摘要:基于構(gòu)建的工程一篇現(xiàn)在都已經(jīng)出到的版本了,可我對(duì)它的認(rèn)識(shí)還是停留在的版本。然后是寫啟動(dòng)的命令行,也就是上面的這樣寫的意思是,當(dāng)你輸入你的命令名字就會(huì)讓執(zhí)行你對(duì)應(yīng)命令的語句。我們首先把基本的配置引進(jìn)來。 基于webpack構(gòu)建的angular 1.x 工程(一)webpack篇 ??現(xiàn)在AngularJS都已經(jīng)出到4.x的版本了,可我對(duì)它的認(rèn)識(shí)還是停留在1.x的版本。 ??之前用它是為...
閱讀 3074·2021-11-18 10:07
閱讀 3849·2021-11-17 17:00
閱讀 2161·2021-11-15 18:01
閱讀 984·2021-10-11 10:58
閱讀 3499·2021-09-10 10:50
閱讀 3665·2021-08-13 15:05
閱讀 1274·2019-08-30 15:53
閱讀 2707·2019-08-29 13:01