這篇文件主要介紹以下基本配置:
- 拆分不同環(huán)境的配置文件:
webpack-merge - 自動(dòng)生成模板文件:
html-webpack-plugin - 自動(dòng)刪除以前的打包文件:
clean-webpack-plugin - 定義全局變量:
- 使用
cross-env設(shè)置命令行參數(shù),并在配置文件中獲取process.env.xxx,這個(gè)只能在腳本配置文件中獲取 - 使用
webpack.DefinePlugin設(shè)置模塊中可以使用的全局變量,注意要使用JSON.stringify封裝變量
- 使用
- 開(kāi)發(fā)環(huán)境跨域設(shè)置:
devServer.proxy中設(shè)置代理 - 樣式資源導(dǎo)入處理
- css:
css-loader,style-loader - less:
less-loader - 增加瀏覽器兼容前綴:
postcss-loader和autoprefixer插件結(jié)合使用 - 抽離css文件:
mini-css-extract-plugin的loader和插件
- css:
- 圖片資源導(dǎo)入處理
- file-loader:將資源文件抽離出來(lái),打包到指定位置
- url-loader:同
file-loader,但url-loader增加文件大小閾值,小于閾值使用base64導(dǎo)入
- 將es6轉(zhuǎn)換成es5:
babel-loader
創(chuàng)建demo
- 創(chuàng)建項(xiàng)目
mkdir webpack-demo
cd webpack-demo
npm init -y
npm i webpack webpack-cli -D
可以看到package.json中webpack 和 webpack-cli的版本,現(xiàn)在最新的已經(jīng)是webpack5了
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^5.40.0",
"webpack-cli": "^4.7.2"
}
}
- 創(chuàng)建基本目錄
- src:資源目錄,隨便創(chuàng)建一個(gè)文件
index.js,作為文件入口
// index.js
function hello() {
console.log('hello')
}
hello() // 注意要調(diào)用這個(gè)函數(shù),不然會(huì)被默認(rèn)tree-shaking掉
- dist:創(chuàng)建打包輸出目錄
- webpack.config.js:webpack默認(rèn)的基本配置文件
const path = require('path')
module.exports = {
entry: path.join(__dirname, 'src', 'index.js'), // 單文件入口
output: {
filename: 'bundle.js', // 輸出文件名
path: path.join(__dirname, 'dist') // 輸出目錄
}
}
- 改下
package.json腳本命令
"scripts": {
"build": "webpack"
},
- 啟動(dòng)打包:
npm run build
會(huì)在dist/bundle.js打包出以下結(jié)果,可以看出來(lái)webpack5的tree-shaking已經(jīng)非常強(qiáng)大,無(wú)用的代碼不再被保留
console.log("hello");
區(qū)分 開(kāi)發(fā)環(huán)境dev 和 生產(chǎn)環(huán)境prod
在大項(xiàng)目中,我們往往需要根據(jù)不同的環(huán)境來(lái)進(jìn)行不同的配置,所以需要拆分webpack配置文件
- 創(chuàng)建一個(gè)
config目錄,用來(lái)區(qū)分不同環(huán)境的配置文件:-
webpack.common.js:用來(lái)配置公共的webpack配置 -
webpack.dev.js:用來(lái)配置開(kāi)發(fā)環(huán)境專有的webpack配置 -
webpack.prod.js:用來(lái)配置生產(chǎn)環(huán)境專有的webpack配置
-
- 在不同環(huán)境的配置文件中,使用
webpack-merge中的merge來(lái)合并公共的webpack配置文件(webpack4中是通過(guò)smart來(lái)合并的)
npm i webpack-merge -D
// webpack.common.js 公共的配置
const path = require('path')
const srcPath = path.join(__dirname, '..', 'src')
module.exports = {
entry: path.join(srcPath, 'index')
}
// webpack.dev.js
const path = require('path')
const commonConfig = require('./webpack.common')
const {merge} = require('webpack-merge')
const devConfig = {
mode: 'development', // 開(kāi)發(fā)環(huán)境
output: {
filename: 'bundle.js', // 輸出文件名
path: path.join(__dirname, '..', 'dist') // 輸出目錄
}
}
module.exports = merge(commonConfig, devConfig)
// webpack.prod.js
const path = require('path')
const commonConfig = require('./webpack.common.js')
const {merge} = require('webpack-merge')
const prodConfig = {
mode: 'production', // 生產(chǎn)環(huán)境
output: {
filename: 'bundle.[chunkhash].js', // 輸出文件名,一般要加上hash
path: path.join(__dirname, '..', 'dist') // 輸出目錄
}
}
module.exports = merge(commonConfig, prodConfig)
- 在
package.json腳本中區(qū)分不同環(huán)境的啟動(dòng)命令
先要安裝:npm install webpack-dev-server -D
PS:在webpack4中開(kāi)發(fā)環(huán)境使用的命令是webpack-dev-server --config config/webpack.dev.js,在webpack5后,改成了webpack server
"scripts": {
"build": "webpack --config config/webpack.prod.js",
"dev": "webpack server --config config/webpack.dev.js"
},
- 運(yùn)行
npm run build,打包
// dist/bundle.004799ddc36231aeaad8.js
console.log("hello");
html-webpack-plugin 自動(dòng)創(chuàng)建index.html文件
打包的js文件,需要我們有一個(gè)載體來(lái)查看結(jié)果,也就是我們一般說(shuō)的模板文件index.html
- 手動(dòng)創(chuàng)建一個(gè)
index.html(根目錄)文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="./dist/bundle.004799ddc36231aeaad8.js"></script>
</body>
</html>
使用瀏覽器打開(kāi),可以看到正常輸出的結(jié)果

這個(gè)載體文件,不單單是開(kāi)發(fā)環(huán)境需要,生產(chǎn)環(huán)境也是需要的,但是生產(chǎn)環(huán)境我們往往會(huì)生成不同的hash值來(lái)防止資源緩存,所以每次生成的文件名都是不同的,手動(dòng)引入入口文件往往不太現(xiàn)實(shí),所以需要借助html-webpack-plugin插件來(lái)自動(dòng)生成項(xiàng)目中的html頁(yè)面,并實(shí)現(xiàn)自動(dòng)導(dǎo)入對(duì)應(yīng)腳本
- html-webpack-plugin 自動(dòng)創(chuàng)建
index.html文件
- 安裝:
npm i html-webpack-plugin -D - 在
plugins中使用,因?yàn)槭枪玫?,所以?xiě)在webpack.common.js配置文件中:
// webpack.common.js 公共的配置
const path = require('path')
const srcPath = path.join(__dirname, '..', 'src')
const htmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: path.join(srcPath, 'index'),
plugins: [
new htmlWebpackPlugin({
// 以根目錄中的index.html文件作為模板來(lái)自動(dòng)生成dist/index.html文件
// 注意,這里是相對(duì)根目錄而言的,因?yàn)槟_本的上下文是在根目錄下
template: 'index.html'
// inject: 'head', // 腳本注入的位置,可以是head, body,或者為 false默認(rèn)
// 在這里還可以自定義參數(shù),在模板中,使用ejs方式 <%= htmlWebpackPlugin.options %>獲取自定義屬性
title: 'webpack demo',
// webpack5默認(rèn)開(kāi)啟壓縮屬性,webpack4要手動(dòng)設(shè)置
// minify: {
// removeComments: true, // 刪除注釋
// collapseWhitespace: true // 刪除空格
// }
})
]
}
- 刪除根目錄下
index.html模板中手動(dòng)導(dǎo)入的語(yǔ)句,并接收自在htmlWebpackPlugin設(shè)置的自定義參數(shù)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<!-- 這是注釋 -->
</body>
</html>
- 執(zhí)行打包命令
npm run build,可以看到dist目錄下生成了index.html
a. 自動(dòng)導(dǎo)入了打包后的文件
b. 顯示了自定義參數(shù)的title標(biāo)題
c. 默認(rèn)開(kāi)啟了壓縮,刪除了注釋和空格
<!doctype html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><title>webpack demo</title><script defer="defer" src="bundle.e97c675afbdcfa8f531d.js"></script></head><body></body></html>
clean-html-plugin 刪除之前的打包文件
隨便修改下入口文件,發(fā)現(xiàn)打包新的文件時(shí),之前生成的打包文件每次都會(huì)存在,所以我們往往配合clean-html-plugin,在每次生成新的打包文件之前,會(huì)先刪除之前的打包文件
- 安裝
npm i clean-webpack-plugin -D - 在
webpack.common.js中配置
// webpack.common.js 公共的配置
const path = require('path')
const srcPath = path.join(__dirname, '..', 'src')
const htmlWebpackPlugin = require('html-webpack-plugin')
// webpack5寫(xiě)法
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
module.exports = {
entry: path.join(srcPath, 'index'),
plugins: [
new CleanWebpackPlugin(), // 清除之前的打包文件
new htmlWebpackPlugin({
// 以根目錄中的index.html文件作為模板來(lái)自動(dòng)生成dist/index.html文件
// 注意,這里是相對(duì)根目錄而言的,因?yàn)槟_本的上下文是在根目錄下
template: 'index.html'
})
]
}
PS:webpack4中導(dǎo)入插件的寫(xiě)法為const CleanWebpackPlugin = require('clean-webpack-plugin')
- 再次打包時(shí),就發(fā)現(xiàn)之前的包被清除了
定義全局變量
我們通常會(huì)有個(gè)配置文件,需要根據(jù)環(huán)境的不同,配置不同的接口地址,這時(shí)一般就會(huì)用到全局變量,webpack可以使用DefinePlugin插件來(lái)設(shè)置全局變量
我們一般在package.json文件運(yùn)行腳本中,會(huì)自定義一個(gè)環(huán)境變量NODE_ENV(,這個(gè)變量其實(shí)是自定義的,但前端約定俗成用這個(gè)變量名):
// mac電腦
"scripts": {
"build": "NODE_ENV=prod webpack --config config/webpack.prod.js",
"dev": "NODE_ENV=dev webpack server --config config/webpack.dev.js NODE_ENV=development"
},
// windows電腦
"scripts": {
"build": "set NODE_ENV=prod && webpack --config config/webpack.prod.js",
"dev": "set NODE_ENV=dev && webpack server --config config/webpack.dev.js NODE_ENV=development"
},
然后在其它腳本中,我們就可以通過(guò)process.env.NODE_ENV來(lái)獲取
為了寫(xiě)一個(gè)腳本配置,適配所有電腦,所以要安裝cross-env解決跨平臺(tái)問(wèn)題:
npm i cross-env -D,這樣,就可以只使用一個(gè)腳本:
"scripts": {
"build": "cross-env NODE_ENV=prod webpack --config config/webpack.prod.js",
"dev": "cross-env NODE_ENV=dev webpack server --config config/webpack.dev.js"
},
然后在webpack.common.js中,打印process.env.NODE_ENV可以獲取到腳本中的設(shè)置值,注意,這個(gè)process.env只有在配置文件中才能獲取到,在其它index.js中是獲取不到的,除非設(shè)置了全局變量
// webpack.common.js
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
})
]
在webpack4之后,上面這些操作,webpack都幫我們內(nèi)置了,所以可以在任何js文件中都能獲取到process.env.NODE_ENV的值,這個(gè)值對(duì)應(yīng)的是webpack配置文件中的mode值,即development或production
這里主要是說(shuō)明怎么接收命令行的參數(shù),并在DefinePlugin設(shè)置全局變量的方法,方便我們?cè)谀K中使用,但注意的是,設(shè)置的對(duì)象需要使用JSON.stringify轉(zhuǎn)換,包括字符串(否則字符串會(huì)被識(shí)別成變量而報(bào)錯(cuò))
開(kāi)發(fā)環(huán)境啟動(dòng)和配置
之前配置了開(kāi)發(fā)環(huán)境腳本,但一直沒(méi)用,現(xiàn)在有了index.html模板文件和打包后的js文件,就可以使用npm run dev啟動(dòng)命令,根據(jù)提示打開(kāi)瀏覽器,訪問(wèn)http://localhost:8080/就可以查看結(jié)果了

跨域配置
在開(kāi)發(fā)環(huán)境最常用的配置是處理跨域問(wèn)題,在webpack.dev.js中設(shè)置devServer,這點(diǎn)和webpack4是一樣的
// webpack.dev.js
const path = require('path')
const commonConfig = require('./webpack.common')
const {merge} = require('webpack-merge')
const devConfig = {
mode: 'development', // 開(kāi)發(fā)環(huán)境
output: {
filename: 'bundle.js', // 輸出文件名
path: path.join(__dirname, '..', 'dist') // 輸出目錄
},
devServer: {
// 設(shè)置代理
proxy: {
// 將本地 /api/xxx 代理到 localhost:6666/api/xxx
// '/api': 'http://localhost:3000',
// 將本地 /api2/xxx 代理到 localhost:6666/xxx,通常用這個(gè),/api2僅作為代理轉(zhuǎn)發(fā)的標(biāo)識(shí)
'/api2': {
target: 'http://localhost:3000',
changeOrigin: true,
pathRewrite: {
'/api2': ''
}
}
}
}
}
module.exports = merge(commonConfig, devConfig)
修改index.js文件,請(qǐng)求跨域的接口
function hello() {
console.log('hello11')
}
fetch('/api2/data').then(res => {
console.log(1111)
})
// 顯示跨域
fetch('http://localhost:3000/data').then(res => {
console.log(2222)
})
hello()
寫(xiě)個(gè)簡(jiǎn)單的express服務(wù)器來(lái)測(cè)試:
const express = require('express')
const app = express()
app.listen(3000, () => {
console.log('server is running in port: 3000');
})
app.get('/data', (req, res) => {
console.log('11111')
res.send('hello')
})
然后啟動(dòng)開(kāi)發(fā)環(huán)境:npm run dev


文件資源處理
在.js文件中導(dǎo)入import './style/index.css'樣式文件,運(yùn)行,發(fā)現(xiàn)會(huì)報(bào)錯(cuò),這是因?yàn)閣ebpack默認(rèn)只認(rèn)識(shí)js文件,其它類型的文件都不識(shí)別。
要使webpack識(shí)別它們,必須引入對(duì)應(yīng)的loader去處理,將其轉(zhuǎn)換成js認(rèn)識(shí)的文件
1. 處理樣式文件
識(shí)別.css文件
- 安裝
npm i css-loader style-loader -D - 在
webpack.common.js中配置module.rules規(guī)則:- css-loade:為了在js中使用import方式導(dǎo)入
css文件 - style-loader:將樣式寫(xiě)在
html文件中head標(biāo)簽內(nèi)的<style>標(biāo)簽中
- css-loade:為了在js中使用import方式導(dǎo)入
module.exports = {
entry: path.join(srcPath, 'index'),
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
]
},
},
識(shí)別.less文件(sass、stylus同理)
要在.js中使用import './src/style/xxx.less'文件:
- 安裝
npm i css-loader style-loader less-loader less -D - 配置
- less-loader:將
.less文件轉(zhuǎn)譯成.css文件
- less-loader:將
module: {
rules: [
{
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
}
]
},
自動(dòng)添加hack前綴
- 安裝
npm i postcss-loader autoprefixer -D - 在
webpack.common.js中配置
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader', 'postcss-loader']
},
{
test: /\.less$/,
use: ['style-loader', 'css-loader','postcss-loader', 'less-loader']
}
]
},
plugins: [
require('autoprefixer')
]
CSS文件抽離
在生產(chǎn)環(huán)境中,我們往往不會(huì)將樣式文件給打包到html文件中,而是單獨(dú)抽離css文件
- 安裝:
npm i mini-css-extract-plugin -D - 在生產(chǎn)環(huán)境配置文件中
webpack.prod.js配置,將前面的style-loader換成mini-css-extract-plugin的loader
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const prodConfig = {
mode: 'production', // 生產(chǎn)環(huán)境
output: {
filename: 'bundle.[chunkhash].js', // 輸出文件名,一般要加上hash
path: path.join(__dirname, '..', 'dist') // 輸出目錄
},
module: {
rules: [
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader']
},
{
test: /\.less$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'less-loader']
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/[name]-[contenthash].css'
})
]
}
- 打包
npm run build
css抽離
2. 圖片資源文件
想在.css中使用url導(dǎo)入圖片
body {
background-color: yellow;
opacity: 0.7;
transform: rotate(45deg);
background: url('../imgs/img002.jpg');
}
或者在.js中使用import導(dǎo)入圖片
import img from './imgs/img002.jpg'
需要借助file-loader或者url-loader,url-loader和file-loader差不多,只不過(guò)增加了一個(gè)設(shè)置文件大小閾值,當(dāng)小于這個(gè)閾值時(shí),使用base64導(dǎo)入文件
- 開(kāi)發(fā)環(huán)境
- 安裝:
npm i file-loader -D - 在開(kāi)發(fā)環(huán)境,因?yàn)椴挥每紤]壓縮問(wèn)題,所以
webpack.dev.js可以配置file-loader
// 處理css樣式文件中的url圖片
{
test: /\.(jpg|png|jpeg|gif)$/,
use: ['file-loader']
}
- 生產(chǎn)環(huán)境
- 安裝:
npm i url-loader -D - 在生產(chǎn)環(huán)境,可以使用
url-loader設(shè)置小圖片使用base64方式寫(xiě)入
// 處理css樣式文件中的url圖片
{
test: /\.(jpg|png|jpeg|gif)$/,
use: {
loader:'url-loader',
options: {
limit: 8192, //限制 8kb 以下使用base64
esMoudle: false,
name: '[name]-[hash:8].[ext]',
// 打包到/images目錄下
outputPath: 'images'
}
}
}
解析ES6+代碼
- 安裝:
npm i babel-loader @babel/core @babel/preset-env -D - 配置:
// webpack.common.js
module: {
rules: [
{
test: /\.js$/,
use: ['babel-loader'], // 1. 開(kāi)啟緩存
include: srcPath, // 2. 縮小適合范圍(寫(xiě)include或exclude)
exclude: /node_modules/
}
]
}
// 根目錄創(chuàng)建,.babelrc
{
"presets": ["@babel/preset-env"], // 一般使用@babel/preset-env就夠了
"plugins": []
}
// 如果是高版本的babel,比如v7.8.0 或更高版本的babel等
// .babelrc 換成根目錄創(chuàng)建 babel.config.json
{
"presets": [
[
"@babel/env",
{
"targets": {
"edge": "17",
"firefox": "60",
"chrome": "67",
"safari": "11.1"
},
"useBuiltIns": "usage",
"corejs": "3.6.5"
}
]
]
}
總的來(lái)說(shuō),webpack5對(duì)比webpack4來(lái)說(shuō),改動(dòng)不算太多,還算是比較平穩(wěn)過(guò)渡,最后,借用網(wǎng)上一張圖,說(shuō)明webpack4升級(jí)webpack5的改動(dòng):

參考:
https://blog.csdn.net/xiaolinlife/article/details/107032533
https://www.imooc.com/article/287156#comment
