大家好!我是蘿蔔,這一章跟大家介紹 webpack 4 常見的配置。
webpack.config.js配置文件
webpack 是可配置的模塊打包工具,可以通過修改 webpack.config.js 的配置文件對 webpack 進行配置,webpack 的配置文件遵循 Nodejs 的 CommonJS 模塊規範,可通過 require() 語法導入其他文件或者使用 Nodejs 內置的模塊,其實 webpack.config.js 是一個 Nodejs 的模塊。
一個簡單的 webpack.config.js 例子
const path = require('path');
module.exports = {
mode: 'development',
entry: './entry.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'entry.bundle.js'
}
};
上面例子中使用CommonJS的 require 引入 Nodejs 內置的 path 模塊,然後通過 module.exports 將 webpack 的配置導出。
Tips: webpack 的配置是一個 Nodejs 模塊,並不是 JSON 對象。
webpack 配置支持多種語言
webpack 不僅僅支持 js 配置,還支持 TypeScript 、CoffeeScript 甚至 JSX 語法的配置,但是不論使用什麼語言,核心配置項是相同的,只不過是語法不同。除了配置文件的語法多樣之外,對於配置的類型也是多樣的,最常見的是作爲一個對象來使用,除了對象,webpack 還支持函數、Promise 和多配置數組。
如何使用 webpack.config.js 配置文件
默認情況下,webpack 會查找執行目錄下的 webpack.config.js 作爲配置,如果需要指定某個配置文件,可以使用命令:
npx webpack --config webpack.config.js
或者在項目目錄下運行
node ./node_modules/webpack/bin/webpack --config webpack.config.js
webpack 的核心概念
雖然 webpack 的功能強大且配置項多,但是隻要理解了以下的幾個核心概念,就能隨心應手的使用它,webpack 有以下幾個核心概念:
- entry: 項目入口,webpack 執行構建的第一步將從 entry 開始,可抽象成輸入。
- module: 模塊,在 webpack中一切皆模塊,一個模塊對應一個文件,模塊不侷限於js,也可以是 css、圖片等。webpack 會從配置文件的 entry開始遞歸找出所有依賴的模塊。
- chunk: 代碼塊,一個 chunk 可以由多個模塊組合而成,用於代碼合併與分割。
- loader: 模塊轉換器,用於將模塊的原內容按照需求轉換成新內容。
- plugin: 擴展插件,在 webpack 構建流程中的特定時機注入擴展邏輯,可以完成 loader 完不成的任務。
- output: 輸出結果,在 webpack 經過一系列處理並得出最終想要的代碼後輸出結果。
webpack 的入口(entry)和輸出(output)
webpack 是一個模塊打包工具,能夠從一個需要處理的 javascript 文件開始,構建一個依賴關係圖(dependency graph),該圖映射到了項目中每個模塊,然後將這個依賴關係圖輸出到一個或者多個 bundle 中。
webpack 是從指定的入口文件(entry)開始,經過加工處理,最終按照 output 輸出固定內容的 bundle。而這個加工處理的過程,就用到了 loader 和 plugin 兩個工具,loader 是源代碼的處理器,plugin 解決的是 loader 處理不了的事情。
entry 入口
webpack 的 entry 支持多種類型,包括字符串、對象、數組。從作用上說,包括單文件入口和多文件入口兩種方式。
單文件入口
module.exports = {
entry: 'path/index.js'
}
// 使用對象的方式
module.exports = {
entry: {
main: 'path/index.js'
}
}
單文件入口可以快速創建一個只有單一文件入口的情況,但是相對簡單,在擴展配置時靈活性較低。
module.exports = {
mode: 'development',
entry: ['./src/index1.js', './src/index2.js']
}
無論是字符串還是字符串數組的 entry ,實際上都是隻有一個入口,但是在打包產出上會有差異:
如果直接是 string 的形式,那麼 webpack 就是直接把該 string 指定的模塊作爲入口模塊。
如果是數組的形式,那麼 webpack 會自動生成另一個入口模塊,並將數組中的每個元素指定的模塊加載進來,並將最後一個模塊的 module.exports 作爲入口模塊的 module.exports 導出。
多文件入口
多文件入口是使用對象語法來通過支持多個 entry ,多文件入口的對象語法相對於單文件入口,具有更高的靈活性,例如多頁應用、頁面模塊化分離優化。
module.exports = {
entry: {
home: 'path/home.js',
search: 'path/search.js',
list: 'path/list.js'
}
}
上面的語法將 entry 分成了 3 個獨立的入口文件,這樣會打包出來三個對應的 bundle。
Tips: 對於一個 html 頁面,我推薦只用一個 entry ,通過統一入口,解析出來的依賴關係更方便管理和維護。
output 輸出
webpack 的 output 是指定了 entry 對應文件編譯打包後的輸出 bundle 。output 的常用屬性是:
- path: 規定了打包後輸出的 bundle 的存放路徑。
- filename: 這個是 bundle 的名稱。
- publicPath: 指定了一個在瀏覽器中被引用的 URL 地址。
Tips: 當不指定 output 的時候,默認輸出到 dist/main.js,即 output.path 是
dist,output.filename 是 main。
一個 webpack 的配置,可以包含多個 entry ,但是只能有一個 output 。對於不同的 entry 可以通過 output.filename 佔位符來區分。
module.exports = {
entry: {
home: 'path/home.js',
search: 'path/search.js',
list: 'path/list.js'
},
output: {
filename: '[name].js',
path: __dirname + '/dist'
}
}
其中 [name] 就是佔位符,它對應的是 entry 的 key (home、search、list)。
目前 webpack 支持的佔位符有:
- [hash] 模塊標識符的 hash
- [chunkhash] chunk 內容的 hash
- [name] 模塊名稱
- [id] 模塊標識符
- [query] 模塊的 query,例如,文件名 ? 後面的字符串
- [function] 一個 return 出一個 string 作爲 filename 的函數
[hash] 和 [chunkhash] 的長度可以使用[hash:16] (默認爲 20) 來指定,或者通過指定output.hashDigestLength 在全局配置長度,那麼他們之間的區別是什麼?
- [hash]:是整個項目的 hash 值,其根據每次編譯內容計算得到,每次編譯之後都會生成新的 hash,即修改任何文件都會導致所有文件的 hash 發生改變;在一個項目中雖然入口不同,但是 hash 是相同的;hash 無法實現前端靜態資源在瀏覽器上長緩存,這時候應該使用 chunkhash;
- [chunkhash] :根據不同的入口文件(entry)進行依賴文件解析,構建對應的 chunk,生成相應的 hash;只要組成
entry 的模塊文件沒有變化,則對應的 hash
也是不變的,所以一般項目優化時,會將公共庫代碼拆分到一起,因爲公共庫代碼變動較少的,使用 chunkhash 可以發揮最長緩存的作用; - [contenthash]:使用 chunkhash 存在一個問題,當在一個 JS 文件中引入了 CSS 文件,編譯後它們的 hash
是相同的。而且,只要 JS 文件內容發生改變,與其關聯的 CSS 文件 hash 也會改變,針對這種情況,可以把 CSS 從 JS 中使用
mini-css-extract-plugin 或 extract-text-webpack-plugin 抽離出來並使用
contenthash。
[hash]、[chunkhash] 和 [contenthash] 都支持 [xxx:length] 語法。
Tips: 佔位符是可以組合使用的,例如 [name]-[hash:8]
output.publicPath
我們構建出的靜態資源文件都是通過 <script> 或者 <link> 標籤進行加載的,而且這些靜態資源文件都是需要部署在靜態資源服務器或者 CDN 上,那麼如何將這些靜態資源文件放在不同的域名或者 CDN 上面呢?這時就要用到 output.publicPath 來進行配置:
module.exports = {
output: {
filename: '[name]_[chunkhash:8].js',
publicPath: 'https://cdn.ezample.com/assets/'
}
}
則輸出:
<script src="https://cdn.ezample.com/assets/a_456456456.js"></script>
output.library 與 output.libraryTarget
我們在實際開發中總是需要去打包一些供團隊其他小夥伴使用的庫,這時就需要用到 output.library 與 output.libraryTarget,output.library 用來指定庫的名稱,output.libraryTarget 用來指定打包出來的規範,比如:commonjs2、amd、umd2等。
小結
這一章我們從 webpack 的配置文件 webpack.config.js 基本語法入手,講解了配置的基本用法以及 mode、context、entry、output基礎概念,希望能給大家帶來一些幫助,如果想了解更多,請持續關注我的文章。