准备:node.js 16以上版本
按照webpack webpack-cli
webpack 官方网站
一. 基本示例
打包入口js
webpack ./1.demo/main.js --mode=development
打包结果
二. webpack五大核心
1. entry 入口
2. output 输出
3. loader 加载器
4. plugins 插件
5. mode 模式
三. 简单配置
const path = require("path")
module.exports={
//入口
entry:"./main.js",
//出口
output:{
path:path.resolve(__dirname,"dist"),
filename:"main.js"
},
//加载器
module:{
rules:[
//loader的配置
]
},
//插件
plugins:[],
//模式
mode:"development"
}
四. 不同模式的区别
1. 开发模式:完成两个目的
(1)编译代码
(2)代码质量检测,树立代码规范
2. 生产模式
(1)编译代码
(2)压缩代码
五. 功能实现(开发模式)
1. 样式处理
(1)css
安装对应的loader
npm install --save-dev style-loader css-loader
配置
const path = require("path")
module.exports = {
//入口
entry: "./main.js",
//出口
output: {
path: path.resolve(__dirname, "dist"),
filename: "main.js"
},
//加载器
module: {
rules: [
//loader的配置
//css处理
{
test: /\.css$/i,
//从右到左
use: ["style-loader", "css-loader"],
}
]
},
//插件
plugins: [],
//模式
mode: "development"
}
直接webpack打包
会被直接打包到js里
(2)less(其他同理)
npm i -D less-loader
配置
const path = require("path")
module.exports = {
//入口
entry: "./main.js",
//出口
output: {
path: path.resolve(__dirname, "dist"),
filename: "main.js"
},
//加载器
module: {
rules: [
//loader的配置
//css处理
{
test: /\.css$/i,
//从右到左
use: ["style-loader", "css-loader"],
},
{
test: /\.less$/i,
//从右到左
use: ["style-loader", "css-loader","less-loader"],
}
]
},
//插件
plugins: [],
//模式
mode: "development"
}
2. 图片资源处理
webpack4需要下载两个loader,webpack5已经将他俩内置。
将图片引入到样式中或者其他方式引用
@testColor: red;
.demo1 {
width: 100px;
height: 100px;
background-color: @testColor;
}
.demo2 {
width: 100px;
height: 100px;
background: url("../assets//imgs/demo.png");
background-size: cover;
}
打包发现输出为原封不动的输出
使用loader进行处理。
例如转base64 减少服务器请求数量 但是体积会更大。
loader中配置
{
//图片处理
test:/\.(png|jpe?g|gif|webp|svg)$/,
type:"asset",
parser:{
dataUrlCondition:{
//小于10kb转换格式
maxSize:10*1024,//10kb
}
}
}
转换效果
3. 控制输出路径。
js改变和图片改变写法有不同
const path = require("path")
module.exports = {
//入口
entry: "./main.js",
//出口
output: {
path: path.resolve(__dirname, "dist"),
filename: "js/main.js",
clean:true
},
//加载器
module: {
rules: [
//loader的配置
//css处理
{
test: /\.css$/i,
//从右到左
use: ["style-loader", "css-loader"],
},
{
test: /\.less$/i,
//从右到左
use: ["style-loader", "css-loader","less-loader"],
},
{
//图片处理
test:/\.(png|jpe?g|gif|webp|svg)$/,
type:"asset",
parser:{
dataUrlCondition:{
//小于10kb转换格式
maxSize:10*1024,//10kb
}
},
generator:{
//hash文件唯一id ext 扩展名 query 携带请求参数
filename:'static/imgs/[hash:10][ext][query]'
}
}
]
},
//插件
plugins: [],
//模式
mode: "development"
}
4. 处理其他资源
都是只需要原封不动输出,只是修改路径。原封不动输出
type设置为asset/resource
5. 处理js
处理格式和兼容性
主要用两个 eslint和babel
eslint我不想用,不写了
babel:中文文档 Babel 是什么? · Babel 中文网
安装
npm install -D babel-loader @babel/core @babel/preset-env
6. 处理html资源
无需手动引用js
使用插件 HtmlWebpackPlugin | webpack 中文文档
npm install --save-dev html-webpack-plugin
使用
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
entry: 'index.js',
output: {
path: path.resolve(__dirname, './dist'),
filename: 'index_bundle.js',
},
plugins: [new HtmlWebpackPlugin()],
};
效果
但是之前的结构会消失,要让他依照我们之前的为模板
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "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>
<script defer src="js/main.js"></script></head>
<body>
<div class="demo1"></div>
<div class="demo2"></div>
<div class="demo3"></div>
</body>
</html>
7. 开发服务器devServer
安装
npm i -D webpack-dev-server
使用,直接加在与plugins同级就好
devServer: {
static: {
directory: path.join(__dirname, 'public'),
},
compress: true,
port: 9000,
open: true
},
使用命令
webpack serve打开开发服务器
六. 功能实现(生产模式)
1. 首先将生产模式与开发模式的js配置分开
两者如下
开发模式
const path = require("path")
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
//入口
entry: "./main.js",
//出口
output: {
path: undefined, //开发模式无输出
filename: "js/main.js",
clean: true
},
//加载器
module: {
rules: [
//loader的配置
//css处理
{
test: /\.css$/i,
//从右到左
use: ["style-loader", "css-loader"],
},
{
test: /\.less$/i,
//从右到左
use: ["style-loader", "css-loader", "less-loader"],
},
{
//图片处理
test: /\.(png|jpe?g|gif|webp|svg)$/,
//asset转base64 asset/resource 原封不动
type: "asset",
parser: {
dataUrlCondition: {
//小于10kb转换格式
maxSize: 10 * 1024,//10kb
}
},
generator: {
//hash文件唯一id ext 扩展名 query 携带请求参数
filename: 'static/imgs/[hash:10][ext][query]'
}
},
{
//babel
test: /\.m?js$/,
//排除哪些不处理
exclude: /(node_modules|bower_components)/,
loader: 'babel-loader',
//下面的单独写在babel.config.js中
// options: {
// presets: ['@babel/preset-env']
// }
}
]
},
//插件
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../public/index.html")
}),
],
devServer: {
static: {
directory: path.join(__dirname, '../public'),
},
compress: true,
port: 9000,
open: true
},
//模式
mode: "development"
}
生产模式
const path = require("path")
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
//入口
entry: "./main.js",
//出口
output: {
path: path.resolve(__dirname,"../dist"), //生产模式有输出
filename: "static/js/main.js",
clean: true
},
//加载器
module: {
rules: [
//loader的配置
//css处理
{
test: /\.css$/i,
//从右到左
use: ["style-loader", "css-loader"],
},
{
test: /\.less$/i,
//从右到左
use: ["style-loader", "css-loader", "less-loader"],
},
{
//图片处理
test: /\.(png|jpe?g|gif|webp|svg)$/,
//asset转base64 asset/resource 原封不动
type: "asset",
parser: {
dataUrlCondition: {
//小于10kb转换格式
maxSize: 10 * 1024,//10kb
}
},
generator: {
//hash文件唯一id ext 扩展名 query 携带请求参数
filename: 'static/imgs/[hash:10][ext][query]'
}
},
{
//babel
test: /\.m?js$/,
//排除哪些不处理
exclude: /(node_modules|bower_components)/,
loader: 'babel-loader',
//下面的单独写在babel.config.js中
// options: {
// presets: ['@babel/preset-env']
// }
}
]
},
//插件
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../public/index.html")
}),
],
//模式
mode: "production"
}
使用方式
webpack --config ./config/webpack.prod.js
因为指令太长 可以提前在package.json中配置
接下来就和脚手架一样了,只需要npm run dev/build
2. 单独提取css
原因一个是文件单独提取利于维护查看,另一个是以style的方式加入会影响html的解析,出现白屏闪屏的现象,用link标签则不会。
使用插件 MiniCssExtractPlugin | webpack 中文文档
npm install --save-dev mini-css-extract-plugin
这个就不写例子了直接看文档就行。
3. 样式兼容
npm i postcss-loader postcss postcss-preset-env -D
设置兼容的程度 这里是ie8
使用
在cssloader之后
const path = require("path")
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
//入口
entry: "./main.js",
//出口
output: {
path: path.resolve(__dirname, "../dist"), //生产模式有输出
filename: "static/js/main.js",
clean: true
},
//加载器
module: {
rules: [
//loader的配置
//css处理
{
test: /\.css$/i,
//从右到左
use: [MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env" //解决大多数样式兼容性问题
]
}
}
}
],
},
{
test: /\.less$/i,
//从右到左
use: [MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env" //解决大多数样式兼容性问题
]
}
}
},
"less-loader"],
},
{
//图片处理
test: /\.(png|jpe?g|gif|webp|svg)$/,
//asset转base64 asset/resource 原封不动
type: "asset",
parser: {
dataUrlCondition: {
//小于10kb转换格式
maxSize: 10 * 1024,//10kb
}
},
generator: {
//hash文件唯一id ext 扩展名 query 携带请求参数
filename: 'static/imgs/[hash:10][ext][query]'
}
},
{
//babel
test: /\.m?js$/,
//排除哪些不处理
exclude: /(node_modules|bower_components)/,
loader: 'babel-loader',
//下面的单独写在babel.config.js中
// options: {
// presets: ['@babel/preset-env']
// }
}
]
},
//插件
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../public/index.html")
}),
new MiniCssExtractPlugin({
filename: "static/style/main.css"
})
],
//模式
mode: "production"
}
打包后的效果
实际工作一般用不到这么离谱的兼容,何况ie已经亡了
一般是这个配置
"browserslist":[
"last 2 version",
"> 1%",
"not dead"
]
4. css压缩
CssMinimizerWebpackPlugin | webpack 中文文档
直接看文档
使用不用看文档太复杂了
直接
效果
5. 生产模式下的基本功能配置汇总
const path = require("path")
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
module.exports = {
//入口
entry: "./main.js",
//出口
output: {
path: path.resolve(__dirname, "../dist"), //生产模式有输出
filename: "static/js/main.js",
clean: true
},
//加载器
module: {
rules: [
//loader的配置
//css处理
{
test: /\.css$/i,
//从右到左
use: [MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env" //解决大多数样式兼容性问题
]
}
}
}
],
},
{
test: /\.less$/i,
//从右到左
use: [MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env" //解决大多数样式兼容性问题
]
}
}
},
"less-loader"],
},
{
//图片处理
test: /\.(png|jpe?g|gif|webp|svg)$/,
//asset转base64 asset/resource 原封不动
type: "asset",
parser: {
dataUrlCondition: {
//小于10kb转换格式
maxSize: 10 * 1024,//10kb
}
},
generator: {
//hash文件唯一id ext 扩展名 query 携带请求参数
filename: 'static/imgs/[hash:10][ext][query]'
}
},
{
//babel
test: /\.m?js$/,
//排除哪些不处理
exclude: /(node_modules|bower_components)/,
loader: 'babel-loader',
//下面的单独写在babel.config.js中
// options: {
// presets: ['@babel/preset-env']
// }
}
]
},
//插件
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../public/index.html")
}),
new MiniCssExtractPlugin({
filename: "static/style/main.css"
}),
new CssMinimizerPlugin()
],
//模式
mode: "production"
}
七. 高级功能
1. sourceMap(源代码映射)
在开发模式下,如果我们去调试webpack devServer生成的js,会与原来的文件有很大差异。使用sourceMap就会和源文件映射。
Devtool | webpack 中文文档 不同的映射模式
里面有一堆,但是我们实际开发只用两者
开发模式:cheap-module-source-map 行映射 打包快
生产模式: source-map 行 列都映射 打包慢一些相对
2. 提升打包构建速度(HMR)
模块热替换(hot module replacement) | webpack 中文文档
按需更新,部分更新。
使用就是在devServe中加上
webpack5 这是默认开启。
3. oneOf
默认会使用所有的loader过一遍,但是我们希望它得到一个就停。
4. exclude include 排除什么文件/排除什么文件
5. 缓存eslint和babel的缓存,不需要每次都经过他俩扫描
6. 多线程打包
这个要注意文件体积小的话反而会更慢,因为线程的启动需要时间。如果文件体积很大可以使用。
7. 减少代码体积
Tree Shaking 移除js没有用到的代码。
已经默认配置了。
8. 减少babel插入辅助代码
安装
npm i @babel/plugin-transform-runtime -D
使用 babel.config.json
{
"presets": [
[
"@babel/env",
{
"targets": {
"edge": "17",
"firefox": "60",
"chrome": "67",
"safari": "11.1"
}
}
]
],
"plugins": ["@babel/plugin-transform-runtime"]
}
9. 压缩图片
ImageMinimizerWebpackPlugin | webpack 中文文档
这里使用里面的无损压缩
(但是说实话,如果做简单的页面应用其实webpack自动压缩图片是可以的,如果本地图片非常多且非常大其实并不合适让其自动压缩,因为太太耗时了!!!)
这是我网上看到的评价,所以该功能慎用。
10. code split
代码分割,因为代码打包后在一个js中,这样不管打开哪个页面都会加载全部的js。所以要进行分割。
目的:分割代码,按需加载。
方案1:
最简单的,多入口打包
const path = require("path")
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
main1: "./main1",
main2: "./main2"
},
output: {
path: path.resolve(__dirname, "dist"),
filename: "js/[name].js",
clean: true
},
module: {
rules: [
]
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "public/index.html")
})
],
mode: "development"
}
优化方案:提取代码中的公共部分,避免重复打包main1和main2中的重复部分。
const path = require("path")
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
main1: "./main1",
main2: "./main2"
},
output: {
path: path.resolve(__dirname, "dist"),
filename: "js/[name].js",
clean: true
},
module: {
rules: [
]
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "public/index.html")
})
],
mode: "production",
// 优化代码配置
optimization: {
//代码分割配置
splitChunks:{
chunks:"all" //对所有模块都分割
}
}
}
方案2:
单文件入口,多chunks,并且chunks自定义命名。
export default function setBtnClick() {
document.getElementById("test").onclick = function () {
import(/*webpackChunkName:"btnTest"*/"./hello").then(({ sayHello }) => {
sayHello()
})
}
}
注意import里的注释是用来配置chunk的名字的。
const path = require('path')
const HtmlWebpackPlugin = require("html-webpack-plugin")
module.exports = {
entry: "./main.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "js/[name].js",
chunkFilename: "js/[name].js",
clean: true
},
module: {
rules: [
]
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "public/index.html")
})
],
optimization: {
splitChunks: {
chunks: "all"
}
},
mode: "production"
}
11. preload和prefetch
preload 立即加载资源
prefetch 空闲加载
特点是 只加载,不执行。
缺点是 兼容性差
使用插件进行配置
@vue/preload-webpack-plugin - npm
里面提示的安装指令有误:用下面的
npm i -D @vue/preload-webpack-plugin
12. Network cache
先说场景
例如 main.js 引入 了 a.js 打包后生产【hash1】.js 和 【hash2.js】, 当我们改变【hash2】.js,该js文件的hash值会发生改变,可能是hash3,那么我们的【hash1】.js 也要发生改变因为里面有引入
import .. from hash2.js
为了不造成这种一个改变,所有的引入js都改变的情况,需要生成一个runtime来专门保存已经被引入的js的地址。
配置方式就是在代码分割下面加上一段配置。
optimization: {
splitChunks: {
chunks: "all"
},
runtimeChunk:{
name:(entrypoint)=> `runtime~${entrypoint.name}.js`
}
},
13. core.js
用来解决js兼容性问题,仅仅使用babel不能处理类似于promise asyn awit这些高版本语言,使用core.js进行转译。core就是babel的补充。
npm i core-js -D
安装
在main js中引入
import "core-js"
打包后会生成对应的js
当然上面只是全局引入的方式,我们也可以在Babel中配置让它自动按需引入。
安装babel和其他插件
npm install babel-loader @babel/core @babel/preset-env -D
webpack中使用
module: {
rules: [{
test: /\.js$/,
use: {
loader: "babel-loader"
},
exclude: /node_modules/
}]
},
babel中配置按需加载core
const presets = [
[
"@babel/preset-env",
{
targets: {
chrome: "58",
ie: "11"
},
useBuiltIns: "usage",
corejs: 3
}
]
];
const plugins = [];
module.exports = {
plugins,
presets
};
14. PWA
给项目提供离线访问状态。
安装workbox插件
npm install workbox-webpack-plugin --save-dev
完全按文档来就好,最后serviceworker可能会获取失败是因为我们的路劲是dist下,可以用serve dist运行html。