在只要這幾步,webpack速成不是事兒一文中, 筆者簡單介紹了webpack的常見用法。能滿足最基本的開發需求。在這篇文章中,再來談談一些較高階的應用。
1. 配置不同環境的構建指令碼
之前構建都是通過 npx webpack ...
這樣的方式執行構建命令。可能你會覺得這樣的方式不夠高效。甚至在某些特定的情況下還需要設定 Node 的環境變數。根據環境變數值的不同,設定構建 --mode 的不同。
scripts 配置的入口在 package.json
中,另外再介紹下。通過執行 npm i
預設安裝package.json中全部依賴。
"scripts": {
"build": "webpack",
"dev": "webpack-dev-server"
},
複製程式碼
cross-env 設定node環境變數的外掛 npm i cross-env -D
- 開發環境構建:
npm run dev
通過圖中可以看到,npm run dev
相當於 npx webpack-dev-server
- 生產環境構建:
npm run build
1.1 設定node環境變數
"scripts": {
"dev": "cross-env NODE_ENV=development webpack-dev-server",
"build": "cross-env NODE_ENV=production webpack"
},
複製程式碼
先安裝外掛cross-env
npm i cross-env -D
執行 npm run dev
, 先設定環境變數 NODE_ENV=devlelopment, 然後執行 webpack 命令。
為什麼要設定環境變數呢? 設定環境變數後,可以在打包構建時執行相應環境變數下的指令碼。
在webpack.config.js中process.env.NODE_ENV
拿到環境變數值。做你想做的事情。哈哈哈~
- 通過 webpack 自帶的外掛定義全域性變數
_DEV_
,類似於全域性變數 window
//應用: 在專案 src/index.js 檔案中程式碼裡區分開發或者是生產環境
if(__DEV__){
alert('開發環境')
}else{
alert('生產環境')
}
複製程式碼
- 根據環境不同,來設定某些外掛是否可用
在webpack.config.js檔案中,設定變數 let isDev = process.env.NODE_ENV === 'development',然後定義外掛的disable屬性的值
plugins: [
new ExtractTextWebpackPlugin({
filename: 'css/index.css',
disable: isDev
}),
],
複製程式碼
1.2 構建 DLL 動態連結庫
.dll 為字尾的檔案稱為動態連結庫,在一個動態連結庫中可以包含給其他模組呼叫的函式和資料
- 把 基礎模組獨立出來打包到單獨的動態連線庫裡
- 當需要匯入的模組在動態連線庫裡的時候,模組不能再次被打包,而是去動態連線庫裡獲取 dll-plugin
- 提高構建效率
react, react-dom 為例
- 建立 webpack.config.react.js
let path = require('path');
let webpack = require('webpack');
module.exports = {
entry: {
vendor: ['react', 'react-dom']
},
output: {
filename: '[name].js',
path: path.join(__dirname, 'dist'),
libraryTarget: "var", //構建後輸出js檔案所屬規範, 如果 設定為 commonjs, 則輸出檔案符合 commonjs規範
library: '_dll_[name]', //構建後輸出js庫的名字
},
mode: 'development',
plugins: [
new webpack.DllPlugin({
name: '_dll_[name]',
path: path.join(__dirname, 'dist', '[name].manifest.json')
})
],
};
複製程式碼
- 設定構建命令
"scripts": {
"build": "webpack",
"dev": "webpack-dev-server",
"react": "wepack --config webpack.config.react.js"
},
複製程式碼
- 執行 npm run react
- 輸出的 vendor.js
1.3 使用動態連結庫
在webpack.config.js中配置外掛
plugins: [
new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, 'dist', 'vendor.manifest.json')
})
]
複製程式碼
- react編譯需要安裝如下loader
npm i babel-core babel-loader babel-preset-env babel-preset-react babel-preset-stage-0 -D
- 配置相關rules
module: {
rules: [
{
test: /\.jsx?/,
use: 'babel-loader',
exclude:/node_modules/,
include:/src/
},
]
},
複製程式碼
- 在專案根目錄下建立 .babelrc檔案
{
"presets": [
"env",
"stage-0",
"react"
]
}
複製程式碼
- 執行構建命令
npm run build
, 控制檯列印:
[./node_modules/react-dom/index.js] delegated ./node_modules/react-dom/index.js from dll-reference _dll_vendor 42 bytes {index} [built]
[./node_modules/react/index.js] delegated ./node_modules/react/index.js from dll-reference _dll_vendor 42 bytes {index} [built]
複製程式碼
由此可以看出專案構建時是使用的預先構建好的react庫檔案,從控制檯列印的構建耗時也明顯不同。
2. 抽離公共程式碼(庫檔案或元件)
- 建立src/a.js, src/x.js 檔案
- 在src/index.js 和 src/x.js檔案中都import a.js檔案
- 在src/index.js 和 src/x.js檔案中都引入 react庫檔案
index.js
import './index.css';
// if(module.hot){
// console.log('熱更新');
// }
import React, { Component } from 'react'
import { render } from 'react-dom'
import a from './a.js'
render(<h1>hello zfpx</h1>, window.app)
複製程式碼
x.js
import React, { Component } from 'react'
import { render } from 'react-dom'
import a from './a.js'
複製程式碼
a.js
module.exports = {
a: 'a.js'
}
複製程式碼
在webpack.config.js中配置:
optimization: {
splitChunks: {
cacheGroups: {
commons: { //提供公共元件, 只要超出0位元組就生產新的包
chunks: 'initial',
//miniChunks: 2,
//maxInitalRequest: 5,
name: 'commons',
minSize: 0
},
vendor: {// 抽離第三外掛
test: /node_modules/,
chunks: 'initial',
name: 'vender',
priority: 10,
enforce: true
}
}
}
},
複製程式碼
執行構建指令碼 npm run build
, 控制檯列印:
如果註釋相關構建資訊:
從二者控制檯資訊中可以看出,構建後的index.js 和 x.js檔案體積大小和 dist目錄中輸出的檔案數量是不一樣的。3. 設定全域性變數
在index.js中引入 jquery.js後,在a.js檔案中想不引入jquery.js直接使用jquery物件
webpack.config.js中配置
module: {
rules: [
{
test: /jquery/,
use:[{
loader:'expose-loader',
options:'$'
}]
},
]
}
複製程式碼
或者使用webpack提供的內建外掛
// 提供全域性變數外掛
new webpack.ProvidePlugin({
$:'jquery'
}),
複製程式碼
二者的區別是神馬呢
- 使用外掛時:
1. $不會定義到window上
2. 只要是用到jquery(或者 $)的地方,當前bundle.js都會把jquery打包進去
複製程式碼
webpack.config.js 相關配置為:
entry: {
index: './src/index.js',
x: './src/x.js'
},
output: {
filename: '[name].[hash].bundle.js',
path: path.resolve(__dirname, 'dist'),
library: '_dll_[name]'
},
...
pugins: [
new HtmlWebpackPlugin({
template: 'src/index.html',
hash: true
}),
]
複製程式碼
index.js
console.log($)
複製程式碼
x.js
console.log($);
複製程式碼
從構建的日誌中可以看出,index.js構建後的檔案大小和x.js構建的檔案大小一致
- 使用 expose-loader
1.匯入一次,就會暴露出來
2.$會定義到在window上
複製程式碼
index.js
import $ from 'jquery'
console.log('index.js');
console.log($);
複製程式碼
x.js
console.log('x.js');
console.log($);
console.log(window.$);
複製程式碼
構建日誌:
瀏覽器列印日誌:
從構建的日誌中可以看出,index.js構建後的檔案大小和x.js構建的檔案大小不一致 從瀏覽器列印日誌可以看出,x.js在沒有直接import jquery時,也可以拿到jquery物件
4. 小結
webpack還有很多其他適用的功能,比如在使用vue時,常常會根據路由載入相應的元件js也就是我們所說的 按需載入。可以用到webpack程式碼分離中的 動態匯入和懶載入(dynamic imports),優化程式碼載入,提升效能。