一、什麼是 webpack
webpack 是一個模組打包機,將根據檔案間的依賴關係對其進行靜態分析,然後將這些模組按指定規則生成靜態資源
當 webpack 處理程式時,它會遞迴地構建一個依賴關係圖(dependency graph),其中包含應用程式需要的每個模組,然後將所有這些模組打包成一個或多個 bundle
-
主要承擔如下功能:
-
打包:將多個檔案 打包成 一個檔案,減少伺服器壓力和下載頻寬
-
轉換:將預編譯語言 轉換成 瀏覽器識別的語言
-
優化:效能優化
-
-
webpack 特點:
-
程式碼拆分
webpack 有兩種組織模組的依賴方式,同步、非同步
非同步依賴將作為分割點,形成一個新的塊;在優化了依賴樹之後,每一個非同步區塊都將作為一個檔案被打包
-
智慧解析
webpack 有一個智慧解析器,幾乎可以處理任何第三方庫
無論它們的模組形式是 CommonJS、 AMD 還是普通的 JS 檔案;甚至在載入依賴的時候,允許使用動態表示式 require("./templates/" + name + ".jade")
-
快速執行
webpack 使用非同步 I/O 、多級快取提高執行效率,使得 webpack 以難以令人置信的速度 快速增量編譯
-
二、安裝
-
全域性安裝
sudo npm i webpack -g 複製程式碼
-
區域性安裝
// 在已經 npm 初始化的專案 根目錄執行 npm i webpack -D 複製程式碼
-
提醒:webpack4.x 版本需要額外安裝 webpack-cli
// 以下為區域性安裝方式,全域性安裝同上 npm i webpack-cli -D 複製程式碼
三、模組互動 runtime、manifest
-
在使用 webpack 構建的典型應用程式或站點中,有三種主要的程式碼型別:
-
你或你的團隊編寫的原始碼。
-
你的原始碼會依賴的任何第三方的 library 或 "vendor" 程式碼。
-
webpack 的 runtime 和 manifest,管理所有模組的互動
-
-
下面 闡述 runtime
runtime 包含:在模組互動時,連線模組所需的載入和解析邏輯;包括瀏覽器中的已載入模組的連線,以及懶載入模組的執行邏輯
-
下面 闡述 manifest
當編譯器(compiler)開始執行、解析、對映應用程式時,它會保留所有模組的詳細要點,這個資料集合稱為 "Manifest"
當完成打包併傳送到瀏覽器時,會在執行時通過 manifest 來解析、載入模組
-
runtime 和 manifest 管理模組的互動
在瀏覽器執行時,runtime 和 manifest 用來連線模組化的應用程式的所有程式碼
無論你選擇哪種模組語法,那些 import 或 require 語句現在都已經轉換為
__webpack_require__
方法,此方法指向模組識別符號(module identifier)通過使用 manifest 中的資料(每個模組的詳細要點:對映、依賴等),runtime 將能夠查詢模組識別符號,檢索出背後對應的模組
四、核心概念:入口 entry
-
作用
告訴 webpack 從哪個檔案開始構建,這個檔案將作為 webpack 依賴關係圖的起點
-
配置 單入口
// webpack 配置 module.exports = { entry: './path/to/my/entry/file.js' }; 複製程式碼
// webpack 配置 module.exports = { entry: { main: './src/main.js' } }; 複製程式碼
-
配置 多入口
// 場景一:分離 應用程式(app) 和 第三方庫(vendor) 入口 // webpack 配置 module.exports = { entry: { app: './src/app.js', vendors: './src/vendors.js' } }; 複製程式碼
// 場景二:多頁面應用程式,告訴 webpack 需要 3 個獨立分離的依賴圖 // webpack 配置 module.exports = { entry: { pageOne: './src/pageOne/index.js', pageTwo: './src/pageTwo/index.js', pageThree: './src/pageThree/index.js' } }; 複製程式碼
五、核心概念:出口 output
-
作用
告訴 webpack 在哪裡輸出 構建後的包、包的名稱 等
-
配置 單出口
// webpack 配置 const path = require('path'); module.exports = { entry: main: './src/main.js', output: { filename: 'main.js', path: path.resolve(__dirname, 'dist') } }; 複製程式碼
-
配置 多出口
// webpack 配置 const path = require('path'); module.exports = { entry: { app: './src/app.js', vendors: './src/vendors.js' }, output: { filename: '[name].js', path: path.resolve(__dirname, 'dist') } }; 複製程式碼
-
其他引數配置
六、核心概念:loader
-
作用
loader 讓 webpack 能夠去處理那些非 JavaScript 檔案(webpack 自身只理解 JavaScript)
loader 可以將所有型別的檔案轉換為 webpack 能夠處理的有效模組
-
loader 使用方式:配置(常用)
// 安裝 loader npm install --save-dev css-loader 複製程式碼
// webpack 配置 module.exports = { module: { rules: [{ test: /\.css$/, use: ['style-loader', 'css-loader'] }] } }; // 或 module.exports = { module: { rules: [{ test: /\.css$/, use: ['style-loader', { loader: 'css-loader', options: { modules: true } }] }] } }; 複製程式碼
-
loader 使用方式:內聯 (不常用)
// 在專案檔案中,import 語句時使用 import Styles from 'style-loader!css-loader?modules!./styles.css'; 複製程式碼
-
loader 使用方式:CLI(不常用)
webpack --module-bind jade-loader --module-bind 'css=style-loader!css-loader' // 如上 會對 .jade 檔案使用 jade-loader,對 .css 檔案使用 style-loader 和 css-loader 複製程式碼
-
loader 特性
-
幾乎所有 loader 都 需要安裝, 但 不需要 在 webpack 配置檔案中通過
require
引入 -
逆向編譯,鏈式傳遞
// webpack 配置 module.exports = { module: { rules: [{ test: /\.css$/, use: ['style-loader', 'css-loader', 'postcss-loader'] }] } }; // 如上,css 檔案編譯順序依次為:postcss-loader ---> css-loader ---> style-loader // 編譯過程中,第一個loader的值 傳遞給下一個loader,依次傳遞;最後一個loader編譯完成後,將預期值傳遞給 webpack 複製程式碼
-
七、核心概念:plugin
-
作用
可以處理各種任務,從打包優化和壓縮,一直到重新定義環境中的變數
-
plugin 使用
npm i html-webpack-plugin -D 複製程式碼
// webpack 配置 const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { plugins: [ new HtmlWebpackPlugin({ template: './src/index.html' }) ] }; 複製程式碼
-
plugin 特性
有些外掛需要單獨安裝,有些外掛是webpack內建外掛 不需要單獨安裝
但所有的外掛都 需要 在 webpack 配置檔案中通過
require
引入 -
plugin 剖析:
webpack 外掛是一個具有 apply 屬性的 JavaScript 物件
apply 屬性會被 webpack compiler 呼叫,並且 compiler 物件可在整個編譯生命週期訪問
// ConsoleLogOnBuildWebpackPlugin.js const pluginName = 'ConsoleLogOnBuildWebpackPlugin'; class ConsoleLogOnBuildWebpackPlugin { apply(compiler) { compiler.hooks.run.tap(pluginName, compilation => { console.log("webpack 構建過程開始!"); }); } } 複製程式碼
八、核心概念:模式 mode(webpack 4.x)
-
作用
告訴 webpack 使用相應模式的內建優化
-
使用
// webpack 配置 module.exports = { mode: 'production' }; 複製程式碼
// CLI 引數中 webpack --mode=production 複製程式碼
-
兩種模式的區別
選項 描述 development
會將 process.env.NODE_ENV 的值設為 development啟用
NamedChunksPlugin 和 NamedModulesPluginproduction
會將 process.env.NODE_ENV 的值設為 production。
啟用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin,
ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin,
SideEffectsFlagPlugin 和 UglifyJsPlugin// mode: development module.exports = { + mode: 'development' - plugins: [ - new webpack.NamedModulesPlugin(), - new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("development") }), - ] } 複製程式碼
// mode: production module.exports = { + mode: 'production', - plugins: [ - new UglifyJsPlugin(/* ... */), - new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") }), - new webpack.optimize.ModuleConcatenationPlugin(), - new webpack.NoEmitOnErrorsPlugin() - ] } 複製程式碼
-
在 webpack 中區分兩種 模式
if(process.env.NODE_ENV === 'development'){ //開發環境 do something }else{ //生產環境 do something } 複製程式碼
九、核心概念:target
-
webpack 能夠為 多種環境 或 target 構建編譯(編譯後程式碼 的執行環境)
預設值:
web
常見值 見 API
十、核心概念:source map 定位程式碼中的錯誤
-
不同的 source map(資源對映)
會決定 程式碼中錯誤的顯示方式(打包後程式碼、生成後程式碼、轉換過程式碼、原始碼等 詳細見)
會影響 構建(build)、重新構建(rebuild) 的速度
整個 source map 作為一個單獨的檔案生成。它為 bundle 新增了一個引用註釋,以便開發工具知道在哪裡可以找到它
-
開發環境的幾種常見的 source map
-
以如下程式碼為例,執行
console.log('js'); class A extends test {} 複製程式碼
-
eval-source-map
構建速度:-- 、重新構建速度:+ 、生產環境:no 、顯示原始原始碼
-
cheap-eval-source-map
構建速度:+ 、重新構建速度:++ 、生產環境:no 、轉換過的程式碼(僅限行)
-
cheap-module-eval-source-map
【推薦】構建速度:0 、重新構建速度:++ 、生產環境:no 、原始原始碼(僅限行)
-
-
生產環境中 常見的 source map
-
以如下程式碼為例,執行
console.log('js'); class A extends test {} 複製程式碼
-
none
【推薦】構建速度:+++ 、重新構建速度:+++ 、生產環境:yes 、打包後程式碼
-
總結: 需要注意的是不同的 devtool 的設定,會導致不同的效能差異。
-
"eval" 具有最好的效能,但並不能幫助你轉譯程式碼。
-
如果你能接受稍差一些的 mapping 質量,可以使用 cheap-source-map 選項來提高效能
-
使用 eval-source-map 配置進行增量編譯
-
在大多數情況下,cheap-module-eval-source-map 是最好的選擇
-
-
-
附言
- 小夥伴們,有什麼問題 可以留言,一起交流哈
- 接下來,我還會發布幾篇 webpack4.X 實戰文章,敬請關注
- 我是一名熱衷於程式設計的前端開發,WX:ZXvictory66