這篇文件主要介紹以下基本配置:
- 拆分不同環(huán)境的配置文件:
webpack-merge
- 自動生成模板文件:
html-webpack-plugin
- 自動刪除以前的打包文件:
clean-webpack-plugin
- 定義全局變量:
- 使用
cross-env
設(shè)置命令行參數(shù),并在配置文件中獲取process.env.xxx
陌选,這個只能在腳本配置文件中獲取 - 使用
webpack.DefinePlugin
設(shè)置模塊中可以使用的全局變量公般,注意要使用JSON.stringify
封裝變量
- 使用
- 開發(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:將資源文件抽離出來埃篓,打包到指定位置
- 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)建一個文件
index.js
慧脱,作為文件入口
// index.js
function hello() {
console.log('hello')
}
hello() // 注意要調(diào)用這個函數(shù),不然會被默認(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"
},
- 啟動打包:
npm run build
會在dist/bundle.js
打包出以下結(jié)果贺喝,可以看出來webpack5的tree-shaking
已經(jīng)非常強(qiáng)大菱鸥,無用的代碼不再被保留
console.log("hello");
區(qū)分 開發(fā)環(huán)境dev 和 生產(chǎn)環(huán)境prod
在大項(xiàng)目中近尚,我們往往需要根據(jù)不同的環(huán)境來進(jìn)行不同的配置挎塌,所以需要拆分webpack
配置文件
- 創(chuàng)建一個
config
目錄,用來區(qū)分不同環(huán)境的配置文件:-
webpack.common.js
:用來配置公共的webpack配置 -
webpack.dev.js
:用來配置開發(fā)環(huán)境專有的webpack配置 -
webpack.prod.js
:用來配置生產(chǎn)環(huán)境專有的webpack配置
-
- 在不同環(huán)境的配置文件中督勺,使用
webpack-merge
中的merge
來合并公共的webpack
配置文件(webpack4
中是通過smart
來合并的)
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', // 開發(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)境的啟動命令
先要安裝:npm install webpack-dev-server -D
PS:在webpack4
中開發(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 自動創(chuàng)建index.html
文件
打包的js
文件贸呢,需要我們有一個載體來查看結(jié)果,也就是我們一般說的模板文件index.html
- 手動創(chuàng)建一個
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>
使用瀏覽器打開拢军,可以看到正常輸出的結(jié)果
這個載體文件楞陷,不單單是開發(fā)環(huán)境需要,生產(chǎn)環(huán)境也是需要的茉唉,但是生產(chǎn)環(huán)境我們往往會生成不同的hash
值來防止資源緩存固蛾,所以每次生成的文件名都是不同的,手動引入入口文件往往不太現(xiàn)實(shí)度陆,所以需要借助html-webpack-plugin
插件來自動生成項(xiàng)目中的html頁面艾凯,并實(shí)現(xiàn)自動導(dǎo)入對應(yīng)腳本
- html-webpack-plugin 自動創(chuàng)建
index.html
文件
- 安裝:
npm i html-webpack-plugin -D
- 在
plugins
中使用,因?yàn)槭枪玫亩詫懺?code>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文件作為模板來自動生成dist/index.html文件
// 注意趾诗,這里是相對根目錄而言的,因?yàn)槟_本的上下文是在根目錄下
template: 'index.html'
// inject: 'head', // 腳本注入的位置蹬蚁,可以是head, body恃泪,或者為 false默認(rèn)
// 在這里還可以自定義參數(shù),在模板中犀斋,使用ejs方式 <%= htmlWebpackPlugin.options %>獲取自定義屬性
title: 'webpack demo',
// webpack5默認(rèn)開啟壓縮屬性贝乎,webpack4要手動設(shè)置
// minify: {
// removeComments: true, // 刪除注釋
// collapseWhitespace: true // 刪除空格
// }
})
]
}
- 刪除根目錄下
index.html
模板中手動導(dǎo)入的語句,并接收自在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ǎo)入了打包后的文件
b. 顯示了自定義參數(shù)的title
標(biāo)題
c. 默認(rèn)開啟了壓縮览效,刪除了注釋和空格
<!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)打包新的文件時,之前生成的打包文件每次都會存在朽肥,所以我們往往配合clean-html-plugin
禁筏,在每次生成新的打包文件之前,會先刪除之前的打包文件
- 安裝
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寫法
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
module.exports = {
entry: path.join(srcPath, 'index'),
plugins: [
new CleanWebpackPlugin(), // 清除之前的打包文件
new htmlWebpackPlugin({
// 以根目錄中的index.html文件作為模板來自動生成dist/index.html文件
// 注意衡招,這里是相對根目錄而言的篱昔,因?yàn)槟_本的上下文是在根目錄下
template: 'index.html'
})
]
}
PS:webpack4
中導(dǎo)入插件的寫法為const CleanWebpackPlugin = require('clean-webpack-plugin')
- 再次打包時,就發(fā)現(xiàn)之前的包被清除了
定義全局變量
我們通常會有個配置文件始腾,需要根據(jù)環(huán)境的不同州刽,配置不同的接口地址,這時一般就會用到全局變量浪箭,webpack
可以使用DefinePlugin
插件來設(shè)置全局變量
我們一般在package.json
文件運(yùn)行腳本中穗椅,會自定義一個環(huán)境變量NODE_ENV
(,這個變量其實(shí)是自定義的奶栖,但前端約定俗成用這個變量名):
// 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"
},
然后在其它腳本中匹表,我們就可以通過process.env.NODE_ENV
來獲取
為了寫一個腳本配置,適配所有電腦宣鄙,所以要安裝cross-env
解決跨平臺問題:
npm i cross-env -D
袍镀,這樣,就可以只使用一個腳本:
"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è)置值苇羡,注意,這個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
的值,這個值對應(yīng)的是webpack
配置文件中的mode
值撑刺,即development
或production
這里主要是說明怎么接收命令行的參數(shù)鹉胖,并在DefinePlugin
設(shè)置全局變量的方法握玛,方便我們在模塊中使用够傍,但注意的是,設(shè)置的對象需要使用JSON.stringify
轉(zhuǎn)換挠铲,包括字符串(否則字符串會被識別成變量而報錯)
開發(fā)環(huán)境啟動和配置
之前配置了開發(fā)環(huán)境腳本冕屯,但一直沒用,現(xiàn)在有了index.html
模板文件和打包后的js
文件拂苹,就可以使用npm run dev
啟動命令安聘,根據(jù)提示打開瀏覽器,訪問http://localhost:8080/
就可以查看結(jié)果了
跨域配置
在開發(fā)環(huá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', // 開發(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丘喻,通常用這個,/api2僅作為代理轉(zhuǎn)發(fā)的標(biāo)識
'/api2': {
target: 'http://localhost:3000',
changeOrigin: true,
pathRewrite: {
'/api2': ''
}
}
}
}
}
module.exports = merge(commonConfig, devConfig)
修改index.js
文件念颈,請求跨域的接口
function hello() {
console.log('hello11')
}
fetch('/api2/data').then(res => {
console.log(1111)
})
// 顯示跨域
fetch('http://localhost:3000/data').then(res => {
console.log(2222)
})
hello()
寫個簡單的express
服務(wù)器來測試:
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')
})
然后啟動開發(fā)環(huán)境:npm run dev
文件資源處理
在.js
文件中導(dǎo)入import './style/index.css'
樣式文件泉粉,運(yùn)行,發(fā)現(xiàn)會報錯榴芳,這是因?yàn)閣ebpack默認(rèn)只認(rèn)識js
文件嗡靡,其它類型的文件都不識別。
要使webpack
識別它們窟感,必須引入對應(yīng)的loader
去處理讨彼,將其轉(zhuǎn)換成js
認(rèn)識的文件
1. 處理樣式文件
識別.css文件
- 安裝
npm i css-loader style-loader -D
- 在
webpack.common.js
中配置module.rules
規(guī)則:- css-loade:為了在js中使用import方式導(dǎo)入
css
文件 - style-loader:將樣式寫在
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']
},
]
},
},
識別.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']
}
]
},
自動添加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)境中柿祈,我們往往不會將樣式文件給打包到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
差不多,只不過增加了一個設(shè)置文件大小閾值紧索,當(dāng)小于這個閾值時袁辈,使用base64
導(dǎo)入文件
- 開發(fā)環(huán)境
- 安裝:
npm i file-loader -D
- 在開發(fā)環(huán)境,因?yà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
方式寫入
// 處理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. 開啟緩存
include: srcPath, // 2. 縮小適合范圍(寫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"
}
]
]
}
總的來說荞彼,webpack5
對比webpack4
來說,改動不算太多待笑,還算是比較平穩(wěn)過渡鸣皂,最后,借用網(wǎng)上一張圖暮蹂,說明webpack4
升級webpack5
的改動:
參考:
https://blog.csdn.net/xiaolinlife/article/details/107032533
https://www.imooc.com/article/287156#comment