webpack 是一個模塊打包機,將根據文件間的依賴關係對其進行靜態分析,而後將這些模塊按指定規則生成靜態資源webpack
當 webpack 處理程序時,它會遞歸地構建一個依賴關係圖(dependency graph),其中包含應用程序須要的每一個模塊,而後將全部這些模塊打包成一個或多個 bundleweb
主要承擔以下功能:npm
打包:將多個文件 打包成 一個文件,減小服務器壓力和下載帶寬編程
轉換:將預編譯語言 轉換成 瀏覽器識別的語言瀏覽器
優化:性能優化緩存
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
複製代碼
在使用 webpack 構建的典型應用程序或站點中,有三種主要的代碼類型:
你或你的團隊編寫的源碼。
你的源碼會依賴的任何第三方的 library 或 "vendor" 代碼。
webpack 的 runtime 和 manifest,管理全部模塊的交互
下面 闡述 runtime
runtime 包含:在模塊交互時,鏈接模塊所需的加載和解析邏輯;包括瀏覽器中的已加載模塊的鏈接,以及懶加載模塊的執行邏輯
下面 闡述 manifest
當編譯器(compiler)開始執行、解析、映射應用程序時,它會保留全部模塊的詳細要點,這個數據集合稱爲 "Manifest"
當完成打包併發送到瀏覽器時,會在運行時經過 manifest 來解析、加載模塊
runtime 和 manifest 管理模塊的交互
在瀏覽器運行時,runtime 和 manifest 用來鏈接模塊化的應用程序的全部代碼
不管你選擇哪一種模塊語法,那些 import 或 require 語句如今都已經轉換爲
__webpack_require__
方法,此方法指向模塊標識符(module identifier)
經過使用 manifest 中的數據(每一個模塊的詳細要點:映射、依賴等),runtime 將可以查詢模塊標識符,檢索出背後對應的模塊
做用
告訴 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'
}
};
複製代碼
做用
告訴 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 讓 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 使用
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 構建過程開始!");
});
}
}
複製代碼
做用
告訴 webpack 使用相應模式的內置優化
使用
// webpack 配置
module.exports = {
mode: 'production'
};
複製代碼
// CLI 參數中
webpack --mode=production
複製代碼
兩種模式的區別
選項 | 描述 |
---|---|
development |
會將 process.env.NODE_ENV 的值設爲 development啓用 NamedChunksPlugin 和 NamedModulesPlugin |
production |
會將 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
}
複製代碼
webpack 可以爲 多種環境 或 target 構建編譯(編譯後代碼 的運行環境)
默認值:
web
常見值 見 API
不一樣的 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 是最好的選擇