本文介紹了一些 webpack 的核心概念以及一些概念術語,並對核心配置做了一些簡單的用法講解。建議剛剛接觸 Webpack 的朋友可以先了解一下。想了解更多 Webpack 使用以及配置的話可以參考我的下一篇文章: 從零開始搭建一個 Webpack 開發環境配置(附 Demo)
為什麼需要使用 webpack
-
模組化開發的趨勢 我們在開發的過程中,之前都是使用引入 script 的方式進行各種工具和外掛的引入,但是這樣會造成很大程度上的全域性汙染,所以引入了 模組化 的概念,但是不管是 commomJs 還是 CMD,AMD 的方式,瀏覽器都無法識別,而使用 webpack 就可以自動的將檔案編譯成瀏覽器可以識別的程式碼
-
less、sass 以及 ES6 語法的使用 同樣的,直接使用 less、sass 和 ES6 語法,直接使用,瀏覽器甚至 node 環境也無法正常識別,所以這時候 loader 就派上用場了,可以使用 less-loader、sass-loader 以及 babel-lodaer 對對應的檔案進行轉換之後,就可以正常的編譯了
-
監聽檔案的變化並自動重新整理網頁,做到實時預覽
-
提供 HTTP 服務而不是使用本地檔案預覽
-
對於打包後的檔案進行壓縮,模組拆分,減小打包後的檔案體積
-
等等還有很多別的優勢,這裡我就不一一列舉了
webpack 安裝
-
全域性安裝:
npm install --global webpack 複製程式碼
-
本地安裝:
npm install --save-dev webpack npm install --save-dev webpack-cli 複製程式碼
Webpack 概念
webpack 是一個可高度配置的現代 JavaScript 應用程式模組打包器。當 webpack 處理應用程式時,它會遞迴地構建一個依賴關係圖,其中包含應用程式需要的每個模組,然後將所有這些模組打包成一個或多個 bundle。
Webpack 核心概念
入口
入口點可以告訴 webpack 從哪裡啟動以及遵循依賴關係圖,以此知道要打包什麼東西。你可以考慮將待打包檔案的根目錄作為你應用程式的入口點。
個人理解:入口就是 webpack 在處理應用程式時,需要知道從哪個檔案開始執行,這個檔案就是整個程式的入口檔案。
用法:entry: string|Array|Object
基本用法
webpack.config.js
const config = {
entry: './src/index.js'
};
module.exports = config;
複製程式碼
陣列語法
一般適用於多頁面應用,多個入口的場景。
webpack.config.js
const config = {
entry: ['./src/entry1', './src/entry2']
};
module.exports = config;
複製程式碼
物件語法
一般適用於分離 應用程式(app) 和 第三方庫(vendor) 入口。
webpack.config.js
const config = {
entry: {
app: './src/app.js',
vendors: './src/vendors.js'
}
};
module.exports = config;
複製程式碼
配置動態入口
假如專案裡有多個頁面需要為每個頁面的入口配置一個 Entry ,但這些頁面的數量可能會不斷增長,則這時 Entry 的配置會受到到其他因素的影響導致不能寫成靜態的值。
webpack.config.js
// 同步函式
entry: () => {
return {
a:'./pages/a',
b:'./pages/b',
}
};
// 非同步函式
entry: () => {
return new Promise((resolve)=>{
resolve({
a:'./pages/a',
b:'./pages/b',
});
});
};
複製程式碼
輸出
上面既然已經有入口檔案了,那麼 webpack 執行了一系列操作之後,生成的新的打包後的檔案應該放到哪兒呢,所以我們需要指定一下。
在 webpack 中配置 output 屬性的最低要求是,將它的值設定為一個物件,包括以下兩點:
- filename 用於輸出檔案的檔名
- 目標輸出目錄 path 的絕對路徑
基本用法
webpack.config.js
const path = require('path');
const config = {
entry: './src/index.js',
output: {
// 最基本的兩個配置要求
filename: 'bundle.js', // 輸出檔案的檔名
path: path.resolve(__dirname, 'dist') // 目標輸出目錄 path 的絕對路徑,這裡必須是絕對路徑
}
};
module.exports = config;
複製程式碼
多個入口起點
如果配置建立了多個單獨的 "chunk",則應該使用佔位符(參考*內建的佔位符變數*)來確保每個檔案具有唯一的名稱。
webpack.config.js
const path = require('path');
const config = {
output: {
// 最基本的兩個配置要求
filename: '[name]-bundle.js', // 輸出檔案的檔名
path: path.resolve(__dirname, 'dist') // 目標輸出目錄 path 的絕對路徑
}
};
module.exports = config;
複製程式碼
內建的佔位符變數
變數名 | 含義 |
---|---|
id | Chunk 的唯一標識,從0開始 |
name | Chunk 的名稱 |
hash | Chunk 的唯一標識的 Hash 值 |
chunkhash | Chunk 內容的 Hash 值 |
loader
loader 用於對模組的原始碼進行轉換。loader 可以使你在 import
、require()
或"載入"模組時預處理檔案。
loader 可以將檔案從不同的語言(如 TypeScript)轉換為 JavaScript,或將內聯影像轉換為 data URL。loader 甚至允許你直接在 JavaScript 模組中 import CSS檔案!
基本使用
例如:載入 css 模組:
-
安裝對應的 loader
npm install --save-dev style-loader css-loader 複製程式碼
-
然後指示 webpack 對每個 .css 使用 css-loader 和 style-loader
webpack.config.js
``` js
module.exports = {
module: {
rules: [
{ test: /\.css$/, use: ['style-loader', 'css-loader' }
]
}
};
```
複製程式碼
配置 loader
rules 配置模組的讀取和解析規則,通常用來配置 Loader。其型別是一個陣列,陣列裡每一項都描述瞭如何去處理部分檔案。 配置一項 rules 時大致通過以下方式:
-
條件匹配:通過 test 、 include 、 exclude 三個配置項來命中 Loader 要應用規則的檔案
-
應用規則:對選中後的檔案通過 use 配置項來應用 Loader,可以只應用一個 Loader 或者按照從後往前的順序應用一組 Loader,同時還可以分別給 Loader 傳入引數
-
重置順序:一組 Loader 的執行順序預設是從右到左(從下到上、從後到前)執行,通過 enforce 選項可以讓其中一個 Loader 的執行順序放到最前或者最後
-
在 Loader 需要傳入很多引數時,你還可以通過一個 Object 來描述
-
test include exclude 這三個命中檔案的配置項可以傳入一個字串或正則,其實它們還都支援陣列型別
具體使用:
module.exports = {
module: {
rules: [
{
// 命中 JavaScript 檔案
test: [
/\.js?$/,
/\.jsx?$/
],
// 用 babel-loader 轉換 JavaScript 檔案
// ?cacheDirectory 表示傳給 babel-loader 的引數,用於快取 babel 編譯結果加快重新編譯速度
use: [
{
loader:'babel-loader',
options:{
cacheDirectory:true,
},
// enforce:'post' 的含義是把該 Loader 的執行順序放到最後
// enforce 的值還可以是 pre,代表把 Loader 的執行順序放到最前面
enforce:'post'
}
],
// 只命中src目錄裡的js檔案,加快 Webpack 搜尋速度
include: path.resolve(__dirname, 'src')
},
{
// 命中 SCSS 檔案
test: /\.scss$/,
// 使用一組 Loader 去處理 SCSS 檔案。
// 處理順序為從後到前,即先交給 sass-loader 處理,再把結果交給 css-loader 最後再給 style-loader。
use: ['style-loader', 'css-loader', 'sass-loader'],
// 排除 node_modules 目錄下的檔案
exclude: path.resolve(__dirname, 'node_modules')
}
]
}
};
複製程式碼
plugins
Plugin 是用來擴充套件 Webpack 功能的,通過在構建流程裡注入鉤子實現,它給 Webpack 帶來了很大的靈活性。
基本使用
比如每次打包檔案到 dist 資料夾下,就可能導致資料夾下面的檔案過多,內容過大,那麼此時我們可能需要在打包之前先將 dist 檔案下的檔案都刪除掉,但是每次都手動刪除豈不是太麻煩,此時我們就可以使用 clean-webpack-plugin 外掛來幫助我們清理 dist 資料夾
外掛安裝
npm install clean-webpack-plugin --save-dev
複製程式碼
webpack.config.js
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
plugins: [
new CleanWebpackPlugin(['dist'])
]
}
複製程式碼
其他概念術語
資源(Asset)
這是一個普遍的術語,用於圖片、字型、媒體,還有一些其他型別的檔案,常用在網站和其他應用程式。這些檔案通常最終在輸出(output ) 中成為單個檔案,但也可以通過一些東西內聯,像 style-loader 或者 url-loader 。
Bundle
由多個不同的模組生成,bundles 包含了早已經過載入和編譯的最終原始檔版本。
Chunk
這是 webpack 特定的術語被用在內部來管理 building 過程。bundle 由 chunk 組成,其中有幾種型別(例如,入口 chunk(entry chunk) 和子 chunk(child chunk))。通常 chunk 會直接對應所輸出的 bundle,但是有一些配置並不會產生一對一的關係。
依賴關係圖(Dependency Graph)
有時候一個檔案依賴於其他檔案,webpack 將其視為依賴關係(dependency)。從一個或多個入口點開始,webpack 遞迴構建一個依賴關係圖,裡面包含了你的應用程式需要的所有模組/資源(mudule/asset)。
模組(Module)
提供比完整程式接觸面(surface area)更小的離散功能塊。精心編寫的模組提供了可靠的抽象和封裝界限,使得應用程式中每個模組都具有條理清楚的設計和明確的目的。
- 模組解析(Module Resolution):一個模組可以作為另一個模組的依賴模組,resolver 是一個庫( library )用於幫助找到模組的絕對路徑... 模組將在 resolve.modules 中指定的所有目錄內搜尋。
Tree Shaking
移除未使用/多餘的程式碼,或者更準確地說,只匯入引用的程式碼。編譯器(compiler)(例如 webpack)將通過分析各種 import 語句和引入程式碼的使用情況,來確定哪些部分的依賴關係被實際使用,刪除不是“樹”的部分,以實現此功能
第三方庫入口點(Vendor Entry Point)
從 app.js 和 vendors.js 開始建立依賴圖(dependency graph)。這些依賴圖是彼此完全分離、互相獨立的,允許你使用 CommonsChunkPlugin 從「應用程式 bundle」中提取 vendor 引用(vendor reference) 到 vendor bundle。可以幫助你在 webpack 中實現被稱為長效快取的通用模式。
優化
-
Bundle 分離(Bundle Splitting) 這個流程提供一個優化 build 的方法,允許 webpack 為應用程式生成多個 bundle。最終效果是,當其他某些 bundle 的改動時,彼此獨立的另一些 bundle 都可以不受到影響,減少需要重新發布的程式碼量,因此由客戶端重新下載並利用瀏覽器快取。
-
程式碼分離(Code Splitting) 指將程式碼分離到每個 bundles/chunks 裡面,你可以按需載入,而不是載入一個包含全部的 bundle。
總結
本文簡單介紹了一下 Webpack 的作用以及 Webpack 核心概念的用法。想了解更多的朋友可以參考我的下一篇文章:從零開始搭建一個 Webpack 開發環境配置(附 Demo)