webpack?5.68.0版本教程示例詳解
起步
版本:"webpack": "^5.68.0"
前言:一定要注意版本,webpack更新太快了。對于一個(gè)前端來說,面試的時(shí)候總是會被問到webpack相關(guān)問題,這里帶大家搭建一個(gè)簡易的Vue/React項(xiàng)目,對webpack有個(gè)初步了解,也會提一些面試被經(jīng)常的問題。碼字不易,點(diǎn)贊支持?。?!
提示:修改了配置文件,要查看效果時(shí),需要重啟項(xiàng)目
GitHub地址:github.com/cwjbjy/webp…
文章根據(jù)評論區(qū)提出的問題,做出了相應(yīng)的更新,并且將webpack的版本升級到5.68.0
1. 基本安裝
(1)創(chuàng)建webpack5文件夾,用vscode打開,通過終端運(yùn)行:
npm init -y npm install -g yarn //如果安裝過yarn就不用運(yùn)行了 yarn add webpack webpack-cli -D
(2)在webpack5目錄下新建 src,dist 文件夾
新建 src/main.js
console.log('Interesting!')
2. 配置出入口
新建build/webpack.common.js
(1)配置入口
可配置多個(gè)入口。但開發(fā)中一般是react或vue,為單頁面web應(yīng)用(SPA),入口一個(gè)即可
//webpack.common.js
const path = require('path')
module.exports = {
entry: path.resolve(__dirname, "../src/main.js"),
}
(2)配置出口
只能有一個(gè)出口,這里指定輸出路徑為'dist'
//webpack.common.js
module.exports = {
output: {
path:path.resolve(__dirname,'../dist'),
filename: '[name].bundle.js',
clean:true //每次構(gòu)建清除dist包
},
}
現(xiàn)在,我們具有了最低配置。在package.json中,我們創(chuàng)建一個(gè)運(yùn)行webpack命令構(gòu)建腳本
"scripts": {
"build":"webpack --config build/webpack.common.js",
}
現(xiàn)在可以運(yùn)行它了:
npm run build
在dist文件夾下會生成main.bundle.js
目錄結(jié)構(gòu):

plugin
插件(Plugins)是用來拓展Webpack功能的,包括:打包優(yōu)化、資源管理、注入環(huán)境變量
插件使用:只需要require()它,然后把它添加到plugins數(shù)組中
1. html-webpack-plugin
html-webpack-plugin將為你生成一個(gè)HTML5文件,在body中使用script標(biāo)簽引入你所有webpack生成的bundle
(1)安裝
yarn add -D html-webpack-plugin
(2)新建 public/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>
<div id="app"><div>123
</div>
</div>
</body>
</html>
(3)配置
//webpack.common.js
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, '../public/index.html'),
filename: 'index.html',
}),
],
}
(4)運(yùn)行
npm run build
可以看到dist下多了index.html文件,并且打包生成的main.bundle.js在index.html中通過script標(biāo)簽被引入
2. progress-bar-webpack-plugin
作用:增加編譯進(jìn)度條
(1)安裝:
yarn add progress-bar-webpack-plugin -D
(2)配置:
//webpack.common.js
const chalk = require("chalk");
const ProgressBarPlugin = require("progress-bar-webpack-plugin");
module.exports = {
plugins: [
// 進(jìn)度條
new ProgressBarPlugin({
format: ` :msg [:bar] ${chalk.green.bold(":percent")} (:elapsed s)`,
}),
],
};
loader
loader 用于對模塊的源代碼進(jìn)行轉(zhuǎn)換
loader都在module下的rules中配置
loader配置項(xiàng)包括:
test 正則校驗(yàn)(必須)
loader 調(diào)用loader的名稱 / use 鏈?zhǔn)秸{(diào)用loader (二選一)
include/exclude 手動添加必修處理的文件/文件夾或屏蔽不需要處理的文件/文件夾(可選)
options 為loaders提供額外的設(shè)置選項(xiàng)(可選)
tip:use鏈?zhǔn)秸{(diào)用,都是從右向左解析,需注意調(diào)用loader的順序。loader要記住,面試經(jīng)常被問到有哪些loader以及其作用
1. css-loader與style-loader
作用:加載css
css-loader:會對@import和url()進(jìn)行處理
style-loader:將CSS注入到JavaScript中,通過DOM操作控制css
(1)安裝
yarn add css-loader style-loader -D
(2)在webpack.common.js中進(jìn)行配置
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader"], //從右向左解析
},
],
},
(3)示例
新建src/assets/styles/style.css
body{
background-color: aqua;
}
在main.js中引入
import './assets/styles/style.css'
重新編譯 npm run build,在瀏覽器中打開 dist/index.html,可以看到css已生效
2. url-loader與file-loader
webpack5內(nèi)置了資源模塊(asset module),代替了file-loader和url-loader
例:加載圖片資源
//在rules下增加
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: "asset",
generator: {
filename: "static/img/[name].[hash:7][ext]",
},
},
3. sass-loader
(1)安裝
yarn add sass-loader node-sass -D
(2)修改原先的css規(guī)則,改為:
{
test: /\.(css|scss|sass)$/,
use: ['style-loader', 'css-loader', 'sass-loader'] //從右往左編譯的
},
(3)新建src/assets/blue.scss文件
$blue: blue;
body{
color: $blue;
}
(4)在main.js中引入blue.scss
import './assets/styles/blue.scss'
重新編譯,打開dist/index.html,可以看到頁面中的123已變成藍(lán)色
4. postcss-loader
作用:處理css的loader
配合autoprefixer,增加廠商前綴(css增加瀏覽器內(nèi)核前綴)
tip:面試的時(shí)候被問到兩次(關(guān)鍵詞:postcss-loader,autoprefixer,browserslist)
(1)安裝:
yarn add -D postcss-loader autoprefixer
(2)修改原先的css規(guī)則:
postcss-loader在css-loader和style-loader之前,在sass-loader或less-loader之后(從右往左解析)
{
test: /\.(css|scss|sass)$/,
use: [
"style-loader",
"css-loader",
{
loader: "postcss-loader",
options:
{
postcssOptions:
{
plugins: ["autoprefixer"], },
},
},
"sass-loader",
],
},
(3)在package.json新增browserslist配置
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
在style.css中增加以下樣式:
/* style.css */
body {
background: #999;
}
#app div{
width: 200px;
margin-top: 50px;
transform: rotate(45deg); /* 這個(gè)屬性會產(chǎn)生瀏覽器內(nèi)核前綴如 -webkit*/
}
重新編譯,打開dist/index.html查看效果
5. babel-loader
作用:解析ES6,JSX
(1)安裝
現(xiàn)在babel已到7的版本,使用@區(qū)分其他非官方包
Babel其實(shí)是幾個(gè)模塊化的包:
@babel/core:babel核心庫
babel-loader:webpack的babel插件,讓我們可以在webpack中運(yùn)行babel
@babel/preset-env:將ES6轉(zhuǎn)換為向后兼容的JavaScript
@babel/plugin-transform-runtime:處理async,await、import()等語法關(guān)鍵字的幫助函數(shù)
運(yùn)行命令:
yarn add @babel/core babel-loader @babel/preset-env @babel/plugin-transform-runtime -D
(2)配置
//webpack.common.js
//在rules下增加配置
{
test: /(\.jsx|\.js)$/,
use: ["babel-loader"],
exclude: /node_modules/,
},
(3)增加babel額外配置項(xiàng)
根目錄新建.babelrc
{
"presets": ["@babel/preset-env"],
"plugins": ["@babel/plugin-transform-runtime"]
}
(4)注意點(diǎn)
babel-loader 8.x 對應(yīng)@babel/core(7.x)
babel-loader 7.x 對應(yīng)babel-core 6.x
(5)測試
public/index.html
使用es6的箭頭語法
<button>按鈕</button>
<script>
document.querySelector("button").onclick = () => {
console.log("es6");
};
</script>
重新編譯,打開dist/index.html。通過點(diǎn)擊可以看到信息被打印出來,說明es6解析成功
搭建環(huán)境
1. 開發(fā)環(huán)境與生產(chǎn)環(huán)境
build下新建webpack.dev.js,webpack.prod.js
(1)安裝webpack-dev-server
yarn add webpack-dev-server -D
(2)安裝webpack-merge
yarn add -D webpack-merge
(3)webpack.dev.js
const { merge } = require("webpack-merge");
const common = require("./webpack.common.js");
const path = require("path");
module.exports = merge(common, {
mode: "development",
devServer: {
hot: true, //熱更新
open: true, //編譯完自動打開瀏覽器
compress: true, //開啟gzip壓縮
port: 3000, //開啟端口號
//托管的靜態(tài)資源文件
//可通過數(shù)組的方式托管多個(gè)靜態(tài)資源文件
static: {
directory: path.join(__dirname, "../public"),
},
},
});
(4)webpack.prod.js
const { merge } = require("webpack-merge");
const common = require("./webpack.common.js");
module.exports = merge(common, {
mode: "production",
});
(5)修改package.json
"scripts": {
"dev": "webpack serve --config build/webpack.dev.js",
"build": "webpack --config build/webpack.prod.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
運(yùn)行npm run dev查看效果,更改index.html內(nèi)容,可以看到頁面進(jìn)行了熱更新
(6)提示
在webpack:5.38.1版本中,如果使用postcss-loader,需配置browserslist,但是配置browserslist后會引起無法熱更新的bug,所以還需增加 target:web(與devServer同級)
在webpack:5.54.0版本中,5.38版本的BUG已修復(fù),無需再配置target:web。但引發(fā)了一個(gè)新問題,就是在Chrome瀏覽器中,如果不打開F12,更改文件內(nèi)容則熱更新(按需更新),但是打開F12控制臺后,更改內(nèi)容會導(dǎo)致每次更新都會重新刷新頁面。在火狐瀏覽器,不管有沒有打開F12,每次更新都會重新刷新頁面
在webpack5.68.0版本中,上述問題已修復(fù)
2. 配置別名
resolve與entry同級:
//webpack.common.js
resolve: {
extensions: [".js", ".jsx", ".json", ".vue"], //省略文件后綴
alias: { //配置別名
"@": path.resolve(__dirname, "../src"),
},
},
代碼分離
1. webpack-bundle-analyzer
它將bundle內(nèi)容展示為一個(gè)便捷的、交互式、可縮放的樹狀圖形式。方便我們更直觀了解代碼的分離
(1)安裝
yarn add webpack-bundle-analyzer -D
(2)配置
//webpack.prod.js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
plugins:[
new BundleAnalyzerPlugin()
]
(3)運(yùn)行 npm run build ,編譯結(jié)束新開一個(gè)頁面,可以看到bundle之間的關(guān)系
2. splitChunks(分離chunks)
作用:拆分chunk
//webpack.prod.js
//與plugins同級
optimization: {
splitChunks: {
chunks: "all",
name: "vendor",
cacheGroups: {
"echarts.vendor": {
name: "echarts.vendor",
priority: 40,
test: /[\\/]node_modules[\\/](echarts|zrender)[\\/]/,
chunks: "all",
},
lodash: {
name: "lodash",
chunks: "async",
test: /[\\/]node_modules[\\/]lodash[\\/]/,
priority: 40,
},
"async-common": {
chunks: "async",
minChunks: 2,
name: "async-commons",
priority: 30,
},
commons: {
name: "commons",
chunks: "all",
minChunks: 2,
priority: 20,
},
},
},
},
(1)chunks:all / async
all:把動態(tài)和非動態(tài)模塊同時(shí)進(jìn)行優(yōu)化打包,所有模塊都扔到vendors.bundle.js里面
async:把動態(tài)模塊打包進(jìn)vender,非動態(tài)模塊保持原樣(不優(yōu)化)
(2)cacheGroups(緩存組)
cacheGroups的作用是將chunks按照cacheGroups中給定的條件分組輸出
(3)test
正則匹配,[\\/] 來表示路徑分隔符的原因,是為了適配window與Linux系統(tǒng)。可通過(antd|@ant-design)匹配多個(gè)文件夾,達(dá)到將特定幾個(gè)文件放入一個(gè)chunk中
(4)priority
優(yōu)先級,默認(rèn)組的優(yōu)先級為負(fù),自定義組的默認(rèn)值為0
(5)非動態(tài)導(dǎo)入(直接通過import引入)
安裝echarts
yarn add echarts -S
新建src/echart.js
import * as echarts from "echarts"
var myChart = echarts.init(document.getElementById('main'));
// 指定圖表的配置項(xiàng)和數(shù)據(jù)
var option = {
title: {
text: 'ECharts 入門示例'
},
tooltip: {},
legend: {
data: ['銷量']
},
xAxis: {
data: ['襯衫', '羊毛衫', '雪紡衫', '褲子', '高跟鞋', '襪子']
},
yAxis: {},
series: [
{
name: '銷量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}
]
};
// 使用剛指定的配置項(xiàng)和數(shù)據(jù)顯示圖表。
myChart.setOption(option);
在main.js中引入
import './echart'
修改public/index.html
<div id="main" style="width: 600px; height: 400px"></div>
運(yùn)行npm run build,在dist下會發(fā)現(xiàn)新增了echarts.vendor.bundle.js。這就是通過splitChunks分離出來echarts包
3. 動態(tài)導(dǎo)入(按需加載chunks)
按需下載資源,如路由懶加載??梢蕴嵘灼良虞d速度
(1)安裝lodash
yarn add lodash -S
(2)通過import()語法實(shí)現(xiàn)動態(tài)導(dǎo)入
//在main.js添加
function getComponent() {
// Lodash, now imported by this script
return import("lodash")
.then(({ default: _ }) => {
const element = document.createElement("div");
element.innerHTML = _.join(["Hello", "webpack"], " ");
return element;
})
.catch((error) => "An error occurred while loading the component");
}
const button = document.createElement("button");
button.innerHTML = "Click me ";
button.onclick = () => {
getComponent().then((component) => {
document.body.appendChild(component);
});
};
document.body.appendChild(button);
(3)在webpack.prod.js中cacheGroups下添加(在上面splitChunks中已經(jīng)加過了)
lodash: {
name: "lodash",
chunks: "async",
test: /[\\/]node_modules[\\/]lodash[\\/]/,
priority: 40,
},
運(yùn)行npm run build,只有點(diǎn)擊按鈕,lodash.bundle.js包才會被加載
4. mini-css-extract-plugin(分離css)
(1)安裝
yarn add -D mini-css-extract-plugin
(2)配置
將webpack.common.js下面的代碼剪貼到webpack.dev.js
//webpack.dev.js
//開發(fā)環(huán)境不需要樣式分離
module: { rules: [ { test: /\.(css|scss|sass)$/, use: [ "style-loader", "css-loader", { loader: "postcss-loader", options: { postcssOptions: { plugins: ["autoprefixer"], }, }, }, "sass-loader", ], }, ], },
修改webpack.prod.js
//webpack.prod.js
//生產(chǎn)環(huán)境進(jìn)行樣式分離
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports={
plugins: [
new MiniCssExtractPlugin({
filename: "static/css/[name].[contenthash:8].css",
})
],
module: { rules: [ { test: /\.(css|scss|sass)$/, use: [ MiniCssExtractPlugin.loader, "css-loader", { loader: "postcss-loader", options: { postcssOptions: { plugins: ["autoprefixer"], }, }, }, "sass-loader", ], }, ], },}
用MiniCssExtractPlugin.loader代替style-loader,配合MiniCssExtractPlugin使用。
(3)拓展:在webpack:5.38.1中,MiniCssExtractPlugin.loader需額外指定publicPath,來引用css資源。因?yàn)閏ss樣式分離到static/css文件夾下,會多兩個(gè)層級目錄,會使css中的背景圖片路徑不對。
在webpack:5.68.0中無需下面的配置了,路徑問題已經(jīng)幫我們解決了
//不再需要進(jìn)行配置
{
test: /\.(css|scss|sass)$/,
use: [{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../../'
}
}, 'css-loader', 'sass-loader']
}
緩存
當(dāng)把打包后dist目錄部署到server上,瀏覽器就能夠訪問此server的網(wǎng)站及其資源。而獲取資源是比較耗費(fèi)時(shí)間的,這就是為什么瀏覽器使用一種名為緩存的技術(shù)??梢酝ㄟ^命中緩存,以降低網(wǎng)絡(luò)流量,使網(wǎng)站加載速度更快,然后,如果我們在部署新版本時(shí)不更改資源的文件名,瀏覽器可能會認(rèn)為它沒有被更新,就會使用它的緩存版本。
所以我們需要將變動后的資源文件更改文件名,沒有變動的資源(node_modules中的第三方文件)不更改包名稱
1. contenthash
[contenthash]將根據(jù)資源內(nèi)容創(chuàng)建出唯一hash。當(dāng)資源內(nèi)容發(fā)生變化時(shí),[contenthash]也會發(fā)生變化。
//webpack.common.js
output: {
path: path.resolve(__dirname, "../dist"),
filename: "[name].[contenthash:8].js",
clean: true, //每次構(gòu)建清除dist包
}
定義全局環(huán)境變量
1. 定義編譯時(shí)全局變量
(1)安裝:
yarn add cross-env -D
(2)配置:
"scripts": {
"dev": "cross-env NODE_ENV=development webpack serve --config build/webpack.dev.js",
"build": "cross-env NODE_ENV=production webpack --config build/webpack.prod.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
//webpack.common.js
console.log('process.env.NODE_ENV',process.env.NODE_ENV)
2. 定義編譯后全局變量
通過DefinePlugin實(shí)現(xiàn)
新建 config/dev.env.js
module.exports = {
NODE_ENV:'"development"',
}
//webpck.dev.js
const env = require("../config/dev.env");
const webpack =require("webpack")
module.exports = merge(common,{
plugins: [
new webpack.DefinePlugin({
"process.env": env,
}),
],
})
//main.js
console.log(process.env)
優(yōu)化打包體積
1. 開啟gzip壓縮
(1)安裝:
yarn add compression-webpack-plugin -D
(2)配置:
//webpack.prod.js
const CompressionPlugin = require("compression-webpack-plugin");
module.exports = {
plugins: [new CompressionPlugin()],
};
2.css-minimizer-webpack-plugin
優(yōu)化和壓縮CSS
(1)安裝:
yarn add css-minimizer-webpack-plugin --save-dev
(2)配置:
//webpack.prod.js
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
optimization: {
minimizer: [`...`, new CssMinimizerPlugin()],
},
3. externals
防止將外部資源包打包到自己的bundle中
示例:從cdn引入jQuery,而不是把它打包
(1)index.html
<script src="https://code.jquery.com/jquery-3.1.0.js" integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk=" crossorigin="anonymous" ></script>
(2)webpack.common.js
module.exports = {
//...
externals: {
jquery: 'jQuery',
},
};
(3)這樣就剝離了那些不需要改動的依賴模塊
import $ from 'jquery';
配置Vue
(1)安裝:
yarn add -D vue-template-compiler@2.6.14 vue-loader@15.9.8
注意 vue和vue-template-compiler版本號一定要一樣,如果要更新vue,vue-template-compiler也要進(jìn)行相應(yīng)的更新
也要注意vue-loader的版本,這里使用vue2,安裝15.9.8版本
vue-loader,用于解析.vue文件
vue-template-compiler,用于模板編譯
(2)配置:
webpack.common.js
const {VueLoaderPlugin} = require('vue-loader'); // vue加載器
module.exports={
module:{
rules:[
{
test: /\.vue$/,
loader: 'vue-loader',
include: [path.resolve(__dirname, '../src')]
},
]
},
plugins:[
new VueLoaderPlugin(),
]
}
vue-loader要放在匹配規(guī)則的第一個(gè),否則會報(bào)錯
(3)配置externals
// index.html
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.min.js"></script> <script src="https://cdn.bootcdn.net/ajax/libs/vue-router/3.5.3/vue-router.min.js"></script>
// webpack.common.js
externals: {
'vue': 'Vue',
'vue-router':'VueRouter'
}
(4)使用
新建src/App.vue
<template>
<div class="app">
<router-link to="/">home</router-link>
<router-link to="/about">about</router-link>
<router-view/>
</div>
</template>
<script>export default { name: "App"}</script>
<style scoped>.app { font-size: 14px; color: aquamarine;}</style>
新建src/views/about.vue
<template>
<div> about頁面 </div>
</template>
新建src/views/home.vue
<template>
<div> Home頁面 </div>
</template>
新建router/index.js
Vue.use(VueRouter);const Home = () => import( /* webpackChunkName: "Home" */ '@/views/home.vue')const About = () => import( /* webpackChunkName: "About" */ '@/views/about.vue')const routes = [{ path: '/', component: Home}, { path: '/about', component: About}]const router = new VueRouter({ routes})export default router
修改main.js
import App from './App.vue';
import router from './router';
Vue.config.productionTip = false;
new Vue({
router,
render: (h) => h(App)
}).$mount('#app');
重啟項(xiàng)目,查看運(yùn)行效果
配置React
安裝其他所必須的babel外,還需安裝@babel/preset-react
1. 安裝 babel解析JSX
yarn add -D @babel/preset-react
2. 配置
//webpack.common.js
entry: {
main:path.resolve(__dirname, "../src/main.js"), //vue入口
index:path.resolve(__dirname, "../src/index.js") //react入口
},
//.babelrc
{
"presets": ["@babel/preset-env", "@babel/preset-react"],
"plugins": ["@babel/plugin-transform-runtime"]
}
3. 安裝react
yarn add react react-dom -S
4. 使用
修改index.html,增加
<div id="root"></div>
新建src/hello.js
import React, {Component} from 'react';
let name = 'Alan';
export default class Hello extends Component{
render() {
return (
{name}
);
}
}
新建src/index.js
import React from 'react';
import {render} from 'react-dom';
import Hello from './hello'; // 可省略.js后綴名
render(, document.getElementById('root'));
重啟項(xiàng)目,可看到運(yùn)行結(jié)果
以上就是webpack 5.68.0版本教程示例詳解的詳細(xì)內(nèi)容,更多關(guān)于webpack 5.68.0版本教程的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
js 變量類型轉(zhuǎn)換常用函數(shù)與代碼[比較全]
腳本之家收集了一些 數(shù)字與字符之間的轉(zhuǎn)換,數(shù)組轉(zhuǎn)為字符等函數(shù)代碼。2009-12-12
js函數(shù)獲取html中className所在的內(nèi)容并去除標(biāo)簽
本文為大家介紹下如何使用js函數(shù)獲取html中className所在的內(nèi)容,具體實(shí)現(xiàn)思路如下,喜歡的朋友可以參考下2013-09-09
JavaScript中實(shí)現(xiàn)new的兩種方式引發(fā)的探究
眾所周知JS中new的作用是通過構(gòu)造函數(shù)來創(chuàng)建一個(gè)實(shí)例對象,這篇文章主要給大家介紹了關(guān)于JavaScript中實(shí)現(xiàn)new的兩種方式引發(fā)的相關(guān)資料,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05

