隨著現(xiàn)代前端開發(fā)的規(guī)模日益龐大包竹,幾乎已經(jīng)不能拋開諸如 React 或 Vue 等前端開發(fā)框架來獨(dú)立開發(fā)了脐恩,這些框架很大程度上的提高了我們的開發(fā)效率,但是框架中所使用特殊文件疆瑰,比如
jsx
是辕、vue
囤热、scss
或less
等猎提,瀏覽器是無法直接識(shí)別的获三,必須經(jīng)過編譯后才能在瀏覽器中使用。于是在眾多的前端工程化工具中锨苏,Webpack 脫穎而出成為了當(dāng)今最流行的前端構(gòu)建工具疙教。 [1]
Webpack 配置模板:
// webpack.config.js
const path = require("path");
module.exports = {
entry: "./app/entry", // string | object | array
// Webpack打包的入口
output: {
// 定義webpack如何輸出的選項(xiàng)
path: path.resolve(__dirname, "dist"), // string
// 所有輸出文件的目標(biāo)路徑
filename: "[chunkhash].js", // string
// 「入口(entry chunk)」文件命名模版
publicPath: "/assets/", // string
// 構(gòu)建文件的輸出目錄
/* 其它高級(jí)配置 */
},
module: {
// 模塊相關(guān)配置
rules: [
// 配置模塊loaders,解析規(guī)則
{
test: /\.jsx?$/, // RegExp | string
include: [
// 和test一樣伞租,必須匹配選項(xiàng)
path.resolve(__dirname, "app"),
],
exclude: [
// 必不匹配選項(xiàng)(優(yōu)先級(jí)高于test和include)
path.resolve(__dirname, "app/demo-files"),
],
loader: "babel-loader", // 模塊上下文解析
options: {
// loader的可選項(xiàng)
presets: ["es2015"],
},
},
],
},
resolve: {
// 解析模塊的可選項(xiàng)
modules: [
// 模塊的查找目錄
"node_modules",
path.resolve(__dirname, "app"),
],
extensions: [".js", ".json", ".jsx", ".css"], // 用到的文件的擴(kuò)展
alias: {
// 模塊別名列表
module: "new-module",
},
},
devtool: "source-map", // enum
// 為瀏覽器開發(fā)者工具添加元數(shù)據(jù)增強(qiáng)調(diào)試
plugins: [
// 附加插件列表
// ...
],
};
Webpack 的運(yùn)行流程是怎樣的贞谓?
Webpack 的運(yùn)行流程是一個(gè)串行的過程,從啟動(dòng)到結(jié)束會(huì)依次執(zhí)行以下流程:[2]
-
初始化參數(shù):從配置文件
webpack.config.js
和命令行中讀取與合并參數(shù)葵诈,初始化本次構(gòu)建的配置參數(shù)裸弦,得出最終的參數(shù); -
開始編譯:用上一步得到的參數(shù)初始化
Compiler
對(duì)象作喘,加載配置文件的所有plugin
理疙,執(zhí)行對(duì)象的 run 方法開始執(zhí)行編譯; -
確定入口:根據(jù)配置中的
entry
找出所有的入口文件泞坦,遞歸遍歷所有的入口文件窖贤; -
編譯模塊:從入口文件出發(fā),調(diào)用所有配置的
loader
對(duì)模塊進(jìn)行編譯,再找出該模塊依賴的模塊赃梧,再遞歸本步驟直到所有入口依賴的文件都經(jīng)過了本步驟的處理滤蝠。 -
輸出資源:所有文件的編譯及轉(zhuǎn)化都已經(jīng)完成,也就是最終輸出的資源授嘀,其中包括即將輸出的資源物咳、代碼塊
Chunk
等等信息。
運(yùn)行流程圖:[3]
Webpack 的 Loader 是什么蹄皱?
Webpack
只能理解 JavaScript
和 JSON
文件所森,這是 Webpack
開箱可用的自帶能力。loader
可以讓 Webpack
能夠去處理其他類型的文件夯接,比如 .scss
和 .ts
焕济,并將它們轉(zhuǎn)換為有效的功能離散的 chunk
文件以供應(yīng)用程序使用,以及被添加到依賴圖中盔几,也可將內(nèi)聯(lián)圖像轉(zhuǎn)換為 data URL
晴弃。簡單來說,loader
可以將一段代碼轉(zhuǎn)換成另一端代碼逊拍,通常用來將一段特殊代碼轉(zhuǎn)換成一段瀏覽器可識(shí)別的代碼上鞠。
loader
從下到上地取值(evaluate)/執(zhí)行(execute),也就是是從后往前執(zhí)行芯丧。在下面的示例中芍阎,從 ts-loader
開始執(zhí)行,然后繼續(xù)執(zhí)行 css-loader
缨恒,最后以 raw-loader
為結(jié)束谴咸。loader
有兩個(gè)屬性:test
,正則表達(dá)式骗露,用于識(shí)別出哪些文件會(huì)被轉(zhuǎn)換岭佳,use
定義在進(jìn)行轉(zhuǎn)換時(shí)應(yīng)該使用哪個(gè) loader
,可以是字符串萧锉、數(shù)組和對(duì)象珊随。[4]
// webpack.config.js
module.exports = {
output: {
filename: "my-first-webpack.bundle.js",
},
module: {
rules: [
{ test: /\.txt$/, use: "raw-loader" }, // 通過 npm 安裝
{
test: /\\.css$/,
use: [
{
loader: "css-loader", // 通過 npm 安裝
options: { modules: true },
},
],
},
{ test: /\\.ts$/, use: "ts-loader" }, // 通過 npm 安裝
],
},
};
有哪些常見的 Loader ??? Loaders
-
raw-loader
:加載文件原始內(nèi)容(utf-8) -
file-loader
:把文件輸出到一個(gè)文件夾中柿隙,在代碼中通過相對(duì) URL 去引用輸出的文件 (處理圖片和字體) -
url-loader
:與 file-loader 類似叶洞,區(qū)別是用戶可以設(shè)置一個(gè)閾值,大于閾值會(huì)交給 file-loader 處理禀崖,小于閾值時(shí)返回文件 base64 形式編碼 (處理圖片和字體) -
source-map-loader
:加載額外的 Source Map 文件衩辟,以方便斷點(diǎn)調(diào)試 -
svg-inline-loader
:將壓縮后的 SVG 內(nèi)容注入代碼中 -
image-loader
:加載并且壓縮圖片文件 -
json-loader
加載 JSON 文件(默認(rèn)包含) -
handlebars-loader
: 將 Handlebars 模版編譯成函數(shù)并返回 -
babel-loader
:把 ES6 轉(zhuǎn)換成 ES5 -
ts-loader
: 將 TypeScript 轉(zhuǎn)換成 JavaScript -
awesome-typescript-loader
:將 TypeScript 轉(zhuǎn)換成 JavaScript,性能優(yōu)于 ts-loader -
sass-loader
:將SCSS/SASS代碼轉(zhuǎn)換成CSS -
css-loader
:加載 CSS帆焕,支持模塊化惭婿、壓縮不恭、文件導(dǎo)入等特性 -
style-loader
:把 CSS 代碼注入到 JavaScript 中,通過 DOM 操作去加載 CSS -
postcss-loader
:擴(kuò)展 CSS 語法财饥,使用下一代 CSS换吧,可以配合 autoprefixer 插件自動(dòng)補(bǔ)齊 CSS3 前綴 -
eslint-loader
:通過 ESLint 檢查 JavaScript 代碼 -
tslint-loader
:通過 TSLint檢查 TypeScript 代碼 -
mocha-loader
:加載 Mocha 測(cè)試用例的代碼 -
coverjs-loader
:計(jì)算測(cè)試的覆蓋率 -
vue-loader
:加載 Vue.js 單文件組件 -
i18n-loader
: 國際化 -
cache-loader
: 可以在一些性能開銷較大的 Loader 之前添加,目的是將結(jié)果緩存到磁盤里
Webpack 的 Plugin 是什么钥星?
loader
用于轉(zhuǎn)換某些類型的模塊沾瓦,而 plugin
(插件)則可以用于執(zhí)行范圍更廣的任務(wù)。包括:打包優(yōu)化谦炒,資源管理贯莺,注入環(huán)境變量。想要使用一個(gè) plugin
宁改,你只需要 require()
它缕探,然后把它添加到 plugins
數(shù)組中。多數(shù)插件可以通過 option
自定義还蹲,也可以在一個(gè)配置文件中因?yàn)椴煌康亩啻问褂猛粋€(gè)插件爹耗,這時(shí)需要通過使用 new
操作符來創(chuàng)建一個(gè)插件實(shí)例。[5]
// webpack.config.js
const webpack = require('webpack'); // 用于訪問內(nèi)置插件
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通過 npm 安裝
module.exports = {
module: {
rules: [
{ test: /\.txt$/, use: 'raw-loader' }
]
},
plugins: [
new HtmlWebpackPlugin({template: './src/index.html'})
]
};
有哪些常見的 Plugin 谜喊?Plugins
-
define-plugin
:定義環(huán)境變量 (Webpack4 之后指定 mode 會(huì)自動(dòng)配置) -
ignore-plugin
:忽略部分文件 -
html-webpack-plugin
:簡化 HTML 文件創(chuàng)建 (依賴于 html-loader) -
web-webpack-plugin
:可方便地為單頁應(yīng)用輸出 HTML潭兽,比 html-webpack-plugin 好用 -
uglifyjs-webpack-plugin
:不支持 ES6 壓縮 (Webpack4 以前) -
terser-webpack-plugin
: 支持壓縮 ES6 (Webpack4) -
webpack-parallel-uglify-plugin
: 多進(jìn)程執(zhí)行代碼壓縮,提升構(gòu)建速度 -
mini-css-extract-plugin
: 分離樣式文件斗遏,CSS 提取為獨(dú)立文件山卦,支持按需加載 (替代extract-text-webpack-plugin) -
serviceworker-webpack-plugin
:為網(wǎng)頁應(yīng)用增加離線緩存功能 -
clean-webpack-plugin
: 目錄清理 -
ModuleConcatenationPlugin:
開啟 Scope Hoisting -
speed-measure-webpack-plugin
: 可以看到每個(gè) Loader 和 Plugin 執(zhí)行耗時(shí) (整個(gè)打包耗時(shí)、每個(gè) Plugin 和 Loader 耗時(shí)) -
webpack-bundle-analyzer
: 可視化 Webpack 輸出文件的體積 (業(yè)務(wù)組件诵次、依賴第三方模塊)
Webpack 的熱更新原理是怎樣的账蓉?
Webpack
的熱更新又稱熱替換(Hot Module Replacement
),縮寫為 HMR
藻懒。 這個(gè)機(jī)制可以做到不用刷新瀏覽器而將新變更的模塊替換掉舊的模塊剔猿。
-
Webpack
通過Watch
模式可以偵聽文件的變化,當(dāng)文件發(fā)生改變時(shí)嬉荆,會(huì)根據(jù)配置進(jìn)行重新編譯(Compile
),并將編譯后的代碼保存在內(nèi)存中酷含。 -
webpack-dev-server
也會(huì)對(duì)文件變化進(jìn)行監(jiān)控(需要配置devServer.watchContentBase = true
)鄙早,但不會(huì)進(jìn)行重新編譯,而是監(jiān)聽這些配置文件中靜態(tài)文件的變化椅亚,變化后會(huì)通知瀏覽器進(jìn)行直接刷新限番,而不是HMR
。 - 在瀏覽器和服務(wù)端之間有一個(gè)通過
SocketJs
建立的websocket
長連接呀舔。webpack-dev-server
會(huì)將Webpack
編譯打包時(shí)的各個(gè)階段的狀態(tài)信息和 hash 值一并告知webpack-dev-server/client
(位于瀏覽器端)弥虐。 - 但是
webpack-dev-server/client
并不能夠請(qǐng)求更新的代碼扩灯,而是把這些工作交給了webpack/hot/dev-server
,webpack/hot/dev-server
的工作就是根據(jù)webpack-dev-server/client
傳來的信息以及dev-server
的配置決定是刷新瀏覽器還是HMR
霜瘪。 -
HotModuleReplacement.runtime
是客戶端HMR
的中樞珠插,它接收到webpack/hot/dev-server
傳遞的新模塊的 hash 值,通過JsonpMainTemplate.runtime
向webpack-dev-server
發(fā)送Ajax
請(qǐng)求獲取到返回的Json
颖对,該Json
包含了所有要更新的模塊的 hash 值捻撑,之后通過Jsonp
請(qǐng)求,獲取到最新的模塊代碼缤底。 - 接下來顾患,HotModulePlugin 將會(huì)對(duì)新舊模塊進(jìn)行對(duì)比,決定是否更新模塊个唧,在決定更新模塊后江解,檢查模塊之間的依賴關(guān)系,更新模塊的同時(shí)更新模塊間的依賴引用徙歼。
- 如果
HMR
失敗膘流,則通過刷新瀏覽器來獲取最新打包代碼。