介紹webpack
webpack誕生之初主要想解決程式碼拆分問題,是現代JS應用程式的靜態模組打包器。
4個核心概念:
-
入口(entry)
指示 webpack 應該使用哪個模組,來作為構建其內部依賴圖的開始複製程式碼
-
輸出(output)
webpack 在哪裡輸出它所建立的 bundles,以及如何命名這些檔案複製程式碼
-
loader
由於webpack只能處理javascript,所以我們需要對一些非js檔案 處理成webpack能夠處理的模組,比如sass檔案複製程式碼
-
外掛(plugins)
Loaders將各型別的檔案處理成webpack能夠處理的模組,plugins 有著很強的能力。外掛的範圍包括,從打包優化和壓縮,一直到重新定 義環境中的變數。複製程式碼
安裝
$> npm i webpack webpack-cli -D
$> npm i webpack-cli -D
* Tips: webpack4 中 cli 工具分離成了 webpack 核心庫 與 webpack-cli 命令列工具兩個模組,需要
使用 CLI,必安裝 webpack-cli 至專案中
複製程式碼
零配置
webpack4 設定了預設值,以便無配置啟動專案
- entry 預設值是 ./src/
- output.path 預設值是 ./dist
- mode 預設值是 production
複製程式碼
模式
mode: development / production / none
開發模式 development
- 瀏覽器除錯工具
- 註釋、開發階段的詳細錯誤日誌和提示
- 快速和優化的增量構建機制
- 開啟 output.pathinfo 在 bundle 中顯示模組資訊
- 開啟 NamedModulesPlugin
- 開啟 NoEmitOnErrorsPlugin
生產模式 production
- 啟用所有優化程式碼的功能
- 更小的bundle大小
- 去除只在開發階段執行的程式碼
- 關閉記憶體快取
- Scope hoisting 和 Tree-shaking
- 開啟 NoEmitOnErrorsPlugin
- 開啟 ModuleConcatenationPlugin
- 開啟 optimization.minimize
none 會禁用所有的預設設定,可以使用 optimization.* 的方式去設定更詳細的配置(搭建你的自定義模式)複製程式碼
webpack 更新日誌
配置更新:
* NoEmitOnErrorsPlugin
-> optimization.noEmitOnErrors(production 模式預設開啟)
* ModuleConcatenationPlugin
-> optimization.concatenateModules(production 模式預設開啟)
* NameModulesPlugin
-> optimization.nameModules(development 模式預設開啟)
* CommonsChunkPlugin已經被移除
-> optimization.splitChunks,optimization.runtimeChunk
* ExtractTextWebpackPlugin調整
-> 建議選用新的CSS檔案提取外掛mini-css-extract-plugin
複製程式碼
JSON:
* webpack現在能處理原生的json
1.當你需要通過loader去把json轉換成js的時候,你可能需要新增
type:"javascript/auto"
2.不使用loader也可以直接使用JSON
* 允許通過ESM語法匯入JSON
1.JSON模組的未使用的匯出部分會被消除
複製程式碼
其他相關細節-> webpack更新日誌
基本配置 webpack.base.conf.js
1.主入口檔案 entry:
entry: {
//入口檔案,如果是多頁專案,可配置多個
app: '.src/main.js'
}
複製程式碼
2.輸出檔案 output:
output: {
// 匯出目錄的絕對路徑,通過HtmlWebpackPlugin外掛生成的html檔案
存放在這個目錄下面
path: path.resolve(__dirname, '../dist/' + outputDir),
// 生產模式或者開發模式下的html,js等檔案內部引用的公共路徑
publicPath: '/',
//匯出檔案的檔名,編譯生成的js檔案存放到根目錄下面的js目錄下面,
如果js目錄不存在則自動建立
filename: 'js/[name]' + chunkhash + '.js’,
/*
* chunkFilename用來打包require.ensure方法中引入的模組,如果該
方法中沒有引入任何模組則不會生成任何chunk塊檔案
* 比如在main.js檔案中,require.ensure([],function(require)
{alert(11);}),這樣不會打包塊檔案
* 只有這樣才會打包生成塊檔案require.ensure([],function(require)
{alert(11);require('./greeter')})
* 或者這樣require.ensure(['./greeter'],function(require)
{alert(11);})
* chunk的hash值只有在require.ensure中引入的模組發生變化,hash
值才會改變
* 注意:對於不是在ensure方法中引入的模組,此屬性不會生效,只能用
CommonsChunkPlugin外掛來提取(webpack 4中用splitChunks&runtimeChunk)
*
*/
chunkFilename: 'js/[name]' + chunkhash + '.js'
},
複製程式碼
3.檔案解析
resolve: {
//自動解析確定的副檔名,使倒入模組時不帶副檔名
extensions: ['.js', '.vue', '.json'],
// 定義引用路徑別名 配置別名可以加快webpack查詢模組的速度
alias: {
'vue$': 'vue/dist/vue.esm.js’,
'@': path.resolve(__dirname, '../src’),
'src': path.resolve(__dirname, '../src')
}
}
複製程式碼
4.模組解析module
{
test: /\.vue$/, //規則對vue字尾
loader: 'vue-loader’, //使用vue-loader進行處理
query:{ //query是對loader做的額外配置
limit: 10000
}
include: /src/, //必須包含src資料夾
}
複製程式碼
loader 的用法準則:
1.單一職責,一個loader只做一件事情,這樣設計的原因是因為,職責越單一,組合性就強,
可配置性就好。
2.從右到左,鏈式執行,上一個loader的處理結果傳給下一個loader接著處理
3.模組化,一個loader就是一個模組,單獨存在不依賴其他的任何模組
4.無狀態,就類似於純函式。
5.loader有實用工具loader-utils解析loader引數的和schema-utils校驗格式的
6.loader的依賴
複製程式碼
Vue-cli 升級 Q&A
1.webpack4推薦使用了最新版本的vue-loader("vue-loader": "^15.0.10"),
但是最新的vue-loader需要在webapck config檔案中設定VueLoaderPlugin外掛,
否則會報以下錯誤:
vue-loader was used without the corresponding plugin.
Make sure to include VueLoaderPlugin in your webpack config.
解決:
const { VueLoaderPlugin } = require('vue-loader');
module.exports = {
...
plugins: [
// 新增VueLoaderPlugin,以響應vue-loader
new VueLoaderPlugin()
],
...
}
複製程式碼
2.Error: No PostCSS Config found in…
解決:在專案根目錄新建postcss.config.js檔案,並對postcss進行配置:
module.exports = {
plugins: [
require('autoprefixer')()
...
]
}
複製程式碼
3.關於CSS Modules相關
現在 Vue Loader v15 使用了一個不一樣的策略來推導語言塊使用的 loader。
拿`< style lang="less" >` 舉例:在 v14 或更低版本中,它會嘗試使用
less-loader 載入這個塊,並在其後面隱式地鏈上 css-loader
和 vue-style-loader,這一切都使用內聯的 loader 字串。
在 v15 中,`< style lang="less" >` 會完成把它當作一個真實的 *.less 檔案
來載入。因此,為了這樣處理它,你需要在你的主 webpack 配置中顯式地提供一條規則:
{
module: {
rules: [
// ... 其它規則
{
test: /\.less$/,
use: [
'vue-style-loader',
'css-loader',
'less-loader'
]
}
]
}
}
在 v15 中你再也不用在 Vue Loader 自己的 loaders 選項中將它重複一遍~
* 關於 CSS modules: https://juejin.im/post/5b2f6f42e51d4558da1adba7
複製程式碼
4.提取 js 中的 css 部分到單獨的檔案
* 新的替代外掛 mini-css-extract-plugin
loader 部分:
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader"
]
}
]
plugins 部分(區分環境決定hash值):
plugins: [
new MiniCssExtractPlugin({
filename: 'css/[name]' + hash + '.css',
chunkFilename: 'css/[name]' + hash + '.css'
})
],
複製程式碼
5.影響也最大的就是webpack4使用optimization.splitChunks替代了
CommonsChunkPlugin.以前的CommonsChunkPlugin主要用來抽取程式碼中的共用部分,
webpack runtime之類的程式碼,結合chunkhash,實現最好的快取策略。
而optimization.splitChunks則實現了相同的功能,並且配置更加靈活,具體解釋如下:
optimization: {
//! 替代 CommonsChunkPlugin 提取公共程式碼
splitChunks: {
// chunks: "async",
// minSize: 30000, //!塊生成最小大小。
// minChunks: 1, //!最小數量的塊分裂之前,必須共享一個模組。
// maxAsyncRequests: 5, //!按需載入時並行請求的最大數量。
// maxInitialRequests: 3, //!最大數量的並行請求一個入口點。
// name: true, //!分割塊的名稱。提供true將根據塊和快取組金鑰自動生成名稱
//!快取組會從splitChunks.*中繼承相應的選項值,
test、priority和reuseExistingChunk則只能在快取組層次上配置。
cacheGroups: {
// default: {
// minChunks: 2,
// priority: -20,
// reuseExistingChunk: true
// },
//!"initial"、"async"和"all"。分別用於選擇初始塊、按需載入的塊和所有塊。
vendors: {
test: /[\\/]node_modules[\\/]/, //! 不繼承
priority: -10, //!不繼承,該配置項是設定處理的優先順序,數值越大越優先處理
chunks: 'initial',
reuseExistingChunk: true, //!不繼承 ,沒有預設值,選項用於配置在模組完全
匹配時重用已有的塊,而不是建立新塊
name: 'vendors',
},
'async-vendors': {
test: /[\\/]node_modules[\\/]/,
minChunks: 2,
chunks: 'async',
reuseExistingChunk: true,
name: 'async-vendors'
},
//!多個css chunk合併成一個css檔案
styles: {
name: 'styles',
test: /\.(scss|sass|less|css)$/,
chunks: 'all',
minChunks: 1,
reuseExistingChunk: true
}
}
},
// !分離出webpack編譯執行時的程式碼
runtimeChunk: { name: 'manifest' }
},
* webpack.optimize.UglifyJsPlugin現在也不需要了,只需要使用
optimization.minimize為true就行,
production mode下面自動為true,當然如果想使用第三方的壓縮外掛也可以
在optimization.minimizer的陣列列表中進行配置
/** like this code **/
optimization:{
minimizer: [
new UglifyJsPlugin({
exclude: /\.min\.js$/,
cache: false, //! 檔案快取
parallel: true, //! 利用多程式並行執行提高構建速度
sourceMap: false,
extractComments: false, //! 移除註釋
//! uglifyES
uglifyOptions: {
compress: {
warnings: false, //! 在UglifyJs刪除沒有用到的程式碼時不輸出警告
drop_console: true, //! 刪除所有的 `console` 語句,可以相容ie瀏覽器
collapse_vars: true, //! 內嵌定義了但是隻用到一次的變數
reduce_vars: true //! 提取出出現多次但是沒有定義成變數去引用的靜態值
},
output: {
beautify: false, //!不需要格式化
comments: false //!不保留註釋
}
}
})
]
}
複製程式碼
效能優化
* 使用happypack
HappyPack就能讓Webpack把任務分解給多個子程式去併發的執行,子程式處理完後再把結果傳送給主程式
* babel-loader設定快取
cacheDirectory: 指定的目錄將用來快取 loader 的執行結果。之後的 webpack 構建,將會嘗試讀取快取,來避免在每次執行時,可能產生的、高效能消耗的 Babel 重新編譯過程
複製程式碼
Tips
1.建議在 webpack 構建流程中使用到的 loaders 及 plugins 都升級到最新版本,
如果 pakage.json 中有相應的模組配置,可刪除之後重新安裝
複製程式碼
Webpack5展望:
* ESM 模組匯出支援
* 持久快取
* WebAssembly 支援從 experimental 升級為 stable 穩定版。並增加 * tree-shaking 和未使用程式碼去除!
* Presets —— 基於零配置設計,任何東西都能支援零配置
* CSS 模組型別——支援 CSS 作為入口檔案(再見吧 ExtractTextWebpackPlugin)
* HTML 模組型別——支援 HTML 作為入口檔案
* URL/檔案 模組型別
* 自定義模組型別
* 多執行緒
* 重新定義我們的組織章程和計劃任務
* Google Summer of Code (之後單獨寫問說明!!!)
複製程式碼
參考閱讀:
webpack 更新日誌-English
webpack4.0 升級日誌-中文版
webpack-module官網
webpack 4 釋出English
webpack 4 釋出