Webpack 概念
概念
webpack 是一個現代的 JavaScript 應用程式的模組打包器(module bundler)。當 webpack 處理應用程式時,它會遞迴地構建一個依賴關係圖表(dependency graph),其中包含應用程式需要的每個模組,然後將所有這些模組打包成少量的 bundle - 通常只有一個,由瀏覽器載入。
學習 webpack,需要先了解幾個核心概念,下面會一一道來。
模組化(module)
在模組化程式設計中,開發者將程式分解相對獨立的程式碼塊,並稱之為模組。
每個模組具有比完整程式更小的接觸面,使得校驗、除錯、測試輕而易舉。 精心編寫的模組提供了可靠的抽象和封裝界限,使得應用程式中每個模組都具有條理清楚的設計和明確的目的。
Node.js 從最一開始就支援模組化程式設計。然而,在 web,模組化的支援正緩慢到來。在 web 存在多種支援 JavaScript 模組化的工具,這些工具各有優勢和限制。webpack 基於從這些系統獲得的經驗教訓,並將模組的概念應用於專案中的任何檔案。
什麼是 webpack 模組
對比 Node.js 模組,webpack 模組能夠以各種方式表達它們的依賴關係,幾個例子如下:
- ES2015
import
語句 - CommonJS
require()
語句 - AMD
define
和require
語句 - css/sass/less 檔案中的
@import
語句。 - 樣式(
url(...)
)或 HTML 檔案(``)中的圖片連結(image url)
webpack 1 需要特定的 loader 來轉換 ES 2015
import
,然而 webpack 2 天然支援。
支援的模組型別
webpack 通過 loader 可以支援各種語言和前處理器編寫模組。loader 描述了 webpack 如何處理 非 JavaScript(non-JavaScript) 模組,並且在bundle中引入這些依賴。 webpack 社群已經為各種流行語言和語言處理器構建了 loader,包括:
總的來說,webpack 提供了可定製的、強大和豐富的 API,允許任何技術棧使用 webpack,保持了在你的開發、測試和生成流程中無侵入性(non-opinionated)。
配置檔案 - webpack.config.js
webpack 是高度可配置的,如何模組化打包、載入都可以基於配置檔案定製。
webpack 的預設配置檔案是
webpack.config.js
。
因為 webpack 配置是標準的 Node.js CommonJS 模組,你可以使用如下特性:
- 通過
require(...)
匯入其他檔案 - 通過
require(...)
使用 npm 的工具函式 - 使用 JavaScript 控制流表示式,例如
?:
操作符 - 對常用值使用常量或變數
- 編寫並執行函式來生成部分配置
依賴圖表(Dependency Graph)
任何時候,一個檔案依賴於另一個檔案,webpack 就把此視為檔案之間有依賴關係。這使得 webpack 可以接收非程式碼資源(non-code asset)(例如影象或 web 字型),並且可以把它們作為依賴提供給你的應用程式。
webpack 從命令列或配置檔案中定義的一個模組列表開始,處理你的應用程式。 從這些入口起點開始,webpack 遞迴地構建一個依賴圖表,這個依賴圖表包含著應用程式所需的每個模組,然後將所有這些模組打包為少量的 bundle- 通常只有一個 - 可由瀏覽器載入。
對於 HTTP/1.1 客戶端,由 webpack 打包你的應用程式會尤其強大,因為在瀏覽器發起一個新請求時,它能夠減少應用程式必須等待的時間。對於 HTTP/2,你還可以使用程式碼拆分(Code Splitting)以及通過 webpack 打包來實現最佳優化。
入口(entry)
webpack 將建立所有應用程式的依賴關係圖表(dependency graph)。圖表的起點被稱之為入口起點(entry point)。入口起點告訴 webpack 從哪裡開始,並遵循著依賴關係圖表知道要打包什麼。可以將您應用程式的入口起點認為是根上下文(contextual root)或 app 第一個啟動檔案。
在 webpack 中,我們使用 webpack 配置物件(webpack configuration object) 中的 entry
屬性來定義入口。
例:
module.exports = {
entry: './path/to/my/entry/file.js'
};
輸出(output)
將所有的資源(assets)歸攏在一起後,還需要告訴 webpack 在哪裡打包應用程式。webpack 的 output
屬性描述了如何處理歸攏在一起的程式碼(bundled
code)。
例:
const path = require('path');
module.exports = {
entry: './path/to/my/entry/file.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js'
}
};
載入(loader)
webpack 的目標是,讓 webpack 聚焦於專案中的所有資源(asset),而瀏覽器不需要關注考慮這些(這並不意味著資源(asset)都必須打包在一起)。webpack 把每個檔案(.css, .html, .scss, .jpg, etc.) 都作為模組處理。然而 webpack 只理解 JavaScript。
webpack loader 會將這些檔案轉換為模組,而轉換後的檔案會被新增到依賴圖表中。
在更高層面,webpack 的配置有兩個目標。
-
識別出(identify)應該被對應的 loader 進行轉換(transform)的那些檔案
-
由於進行過檔案轉換,所以能夠將被轉換的檔案新增到依賴圖表(並且最終新增到 bundle 中)(
use
屬性)
例:
const path = require('path');
const config = {
entry: './path/to/my/entry/file.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js'
},
module: {
rules: [
{test: /\.(js|jsx)$/, use: 'babel-loader'}
]
}
};
module.exports = config;
外掛(plugins)
由於 loader 僅在每個檔案的基礎上執行轉換,而 外掛(plugins)
最常用於(但不限於)在打包模組的“compilation”和“chunk”生命週期執行操作和自定義功能(檢視更多)。webpack
的外掛系統極其強大和可定製化。
想要使用一個外掛,你只需要 require()
它,然後把它新增到 plugins
陣列中。多數外掛可以通過選項(option)自定義。你也可以在一個配置檔案中因為不同目的而多次使用同一個外掛,你需要使用 new
建立例項來呼叫它。
例:
const HtmlWebpackPlugin = require('html-webpack-plugin'); //installed via npm
const webpack = require('webpack'); //to access built-in plugins
const path = require('path');
const config = {
entry: './path/to/my/entry/file.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js'
},
module: {
rules: [
{test: /\.(js|jsx)$/, use: 'babel-loader'}
]
},
plugins: [
new webpack.optimize.UglifyJsPlugin(),
new HtmlWebpackPlugin({template: './src/index.html'})
]
};
module.exports = config;
熱替換(Hot Module Replacement)
模組熱替換功能會在應用程式執行過程中替換、新增或刪除模組,而無需重新載入頁面。這使得你可以在獨立模組變更後,無需重新整理整個頁面,就可以更新這些模組,極大地加速了開發時間。
這一切是如何執行的?
站在 App 的角度
- app 程式碼要求 HMR runtime 檢查更新。
- HMR runtime (非同步)下載更新,然後通知 app 程式碼更新可用。
- app 程式碼要求 HMR runtime 應用更新。
- HMR runtime (非同步)應用更新。
你可以設定 HMR,使此程式自動觸發更新,或者你可以選擇要求在使用者互動後進行更新。
站在編譯器(webpack) 的角度
除了普通資源,編譯器(compiler)需要發出 "update",以允許更新之前的版本到新的版本。"update" 由兩部分組成:
- 待更新 manifest (JSON)
- 一個或多個待更新 chunk (JavaScript)
manifest 包括新的編譯 hash 和所有的待更新 chunk 目錄。
每個待更新 chunk 包括用於與所有被更新模組相對應 chunk 的程式碼(或一個 flag 用於表明模組要被移除)。
編譯器確保模組 ID 和 chunk ID 在這些構建之間保持一致。通常將這些 ID 儲存在記憶體中(例如,當使用 webpack-dev-server 時),但是也可能將它們儲存在一個 JSON 檔案中。
站在模組的角度
HMR 是可選功能,只會影響包含 HMR 程式碼的模組。舉個例子,通過 style-loader
為
style 樣式追加補丁。 為了執行追加補丁,style-loader
實現了
HMR 介面;當它通過 HMR 接收到更新,它會使用新的樣式替換舊的樣式。
類似的,當在一個模組中實現了 HMR 介面,你可以描述出當模組被更新後發生了什麼。然而在多數情況下,不需要強制在每個模組中寫入 HMR 程式碼。如果一個模組沒有 HMR 處理函式,更新就會冒泡。這意味著一個簡單的處理函式能夠對整個模組樹(complete module tree)進行處理。如果在這個模組樹中,一個單獨的模組被更新,那麼整個模組樹都會被重新載入(只會重新載入,不會遷移)。
站在 HMR Runtime 的角度 (Technical)
對於模組系統的 runtime,附加的程式碼被髮送到 parents
和 children
跟蹤模組。
在管理方面,runtime 支援兩個方法 check
和 apply
。
check
傳送
HTTP 請求來更新 manifest。如果請求失敗,說明沒有可用更新。如果請求成功,待更新 chunk 會和當前載入過的 chunk 進行比較。對每個載入過的 chunk,會下載相對應的待更新 chunk。當所有待更新 chunk 完成下載,就會準備切換到 ready
狀態。
apply
方法將所有被更新模組標記為無效。對於每個無效模組,都需要在模組中有一個更新處理函式,或者在它的父級模組們中有更新處理函式。否則,無效標記冒泡,並將父級也標記為無效。每個冒泡繼續直到到達應用程式入口起點,或者到達帶有更新處理函式的模組(以最先到達為準)。如果它從入口起點開始冒泡,則此過程失敗。
之後,所有無效模組都被(通過 dispose 處理函式)處理和解除載入。然後更新當前 hash,並且呼叫所有 "accept" 處理函式。runtime 切換回閒置
狀態,一切照常繼續。
產生的檔案 (Technical)
左側表示初始編譯器通過。右側表示更新了模組 4 和 9 。
它能夠用於?
你可以在開發過程中將 HMR 作為 LiveReload 的替代。webpack-dev-server 支援熱模式,在試圖重新載入整個頁面之前,熱模式會嘗試使用 HMR 來更新。檢視如何實現在 React 專案中使用 HMR 為例。
一些 loader 已經生成可熱更新的模組。例如,style-loader
能夠置換出頁面的樣式表。對於這樣的模組,你不需要做任何特殊處理。
webpack 的強大之處在於它的可定製化,取決於特定專案需求,這裡有許多配置 HMR 的方式。
Webpack 系列教程
歡迎閱讀其它內容:
作者:靜默虛空
歡迎任何形式的轉載,但請務必註明出處。限於本人水平,如果文章和程式碼有表述不當之處,還請不吝賜教。
轉載來自:http://www.cnblogs.com/jingmoxukong/p/6994563.html
相關文章
- webpack概念Web
- webpack(2)webpack核心概念Web
- Webpack核心概念解析Web
- 玩轉webpack系列之webpack核心概念(一)Web
- webpack (1)——核心概念的理解Web
- webpack4.X 實戰(一):全面認識webpack、核心概念Web
- webpack 學習筆記:核心概念(下)Web筆記
- webpack 學習筆記:核心概念(上)Web筆記
- web前端高階webpack - 初識webpack 的安裝執行及核心概念Web前端
- webpack3-loader和plugin的概念理解WebPlugin
- 學習 webpack 前,你需要了解的那些概念Web
- webpack學習(一) -- 基礎概念及安裝執行Web
- [Webpack] 核心概念、基礎配置、常用loader和常用外掛Web
- webpack 3.1 升級webpack 4.0Web
- webpackWeb
- 必會webpack(一)--- 初識webpackWeb
- webpack系列--淺析webpack的原理Web
- webpack(6)webpack處理圖片Web
- webpack 基礎入門 - 瞭解webpackWeb
- webpack(5)webpack處理css檔案WebCSS
- webpack指南-webpack介紹-程式碼分割Web
- webpack 起步Web
- What is WebpackWeb
- webpack原理Web
- webpack配置Web
- webpack uglifyWeb
- Hello, Webpack!Web
- webpack整理Web
- webpack命令Web
- 加速 WebpackWeb
- webpack(一)Web
- React with webpackReactWeb
- 概念
- webpack 快速入門 系列 —— 初步認識 webpackWeb
- webpack4系列教程(一):初識webpackWeb
- 深入解析webpack 外掛html-webpack-pluginWebHTMLPlugin
- Webpack學習 – Webpack安裝及安裝Web
- webpack學習(一)專案中安裝webpackWeb