Webpack4实战教程
尚硅谷新版Webpack4实战教程(从入门到精通) https://www.bilibili.com/video/BV1e7411j7T5
尚硅谷前端Webpack4教程(高级进阶篇) https://www.bilibili.com/video/BV1cv411C74F
笔记分享: https://lab.puji.design/webpack-getting-started-manual/
课件地址webpack从入门到精通
- 下载地址:https://pan.baidu.com/s/1JxvXF8EyG9TSNLqkc98YzQ 提取码:i5qc
- 备用地址:https://pan.baidu.com/s/1T2g37SpIQRjF6fjFDl_YwA 密码:uw5q
目录
- 课程简介
- Webpack简介
- Webpack初体验
- Webpack开发环境基本配置
- Webpack生产环境基本配置
- Webpack优化配置
- Webpack原理分析
- Webpack5介绍
1、课程简介
1.1、知识点
- webpack5
- dll
- production
- development
- eslint
- babel
- pwa
- optimization
- resolve
- HMR
- loader
- plugin
- devtool
- 性能优化
- tree shaking
- code split
- caching
- lazy loading
- library
- shimming
1.2、环境配置
Node.js >= 10
webpack >= 4.26
1.3、预备知识
- Node.js
- NPM
- ES6
2、webpack简介
2.1、webpack是什么
Webpack:
- 一种前端资源构建工具;
- 一个静态模块打包器(module bundler).
在webpack看来,前端的所有资源文件(js/json/css/img/less/...)都会作为模块处理 它根据模块的依赖关系进行静态分析,打包生成对应的静态资源(bundle)
2.2、webpack五个核心概念
entry: 入口
output: 输出
loader:处理非js文件,翻译工作
plugins 插件,执行范围更广的任务,打包优化,压缩,定义环境中的变量等
mode 模式
- development
- 本地调试
- 会将process.env.NODE_ENV的值设置为development
- 启用NamedChunksPlugin
- 启用NamedModulesPlugin
- production
- 上线运行
- 会将process.env.NODE_ENV的值设置为production
- 启用FlagDependencyUsagePlug
- 启用FlagDependencyUsagePlugin
- 启用FlagIncludedChunksPlugin
- 启用ModuleConcatenationPlugin
- 启用NoEmitOnErrorsPlugin
- 启用TerserPlugin
3、webpack初体验
3.1、初始化项目
mkdir webpack-demo
cd webpack-demo
# 初始化项目目录
npm init -y
# 安装webpack
cnpm i webpack webpack-cli -D
项目目录
$ tree
.
├── package.json
└── src
└── index.js
src/index.js
function add(x, y){
return x + y;
}
console.log(add(1, 2));
依赖 package.json
{
"devDependencies": {
"webpack": "^5.72.1",
"webpack-cli": "^4.9.2"
}
}
打包
# 开发环境
$ npx webpack ./src/index.js -o ./dist --mode=development
asset main.js 1.25 KiB [emitted] (name: main)
./src/index.js 64 bytes [built] [code generated]
webpack 5.72.1 compiled successfully in 74 ms
# 生产环境
$ npx webpack ./src/index.js -o ./dist --mode=production
asset main.js 15 bytes [emitted] [minimized] (name: main)
./src/index.js 64 bytes [built] [code generated]
webpack 5.72.1 compiled successfully in 201 ms
3.2、导入json资源
src
├── data.json
└── index.js
data.json
{
"name": "Tom",
"age": 23
}
index.js
import data from './data.json';
function add(x, y){
return x + y;
}
console.log(add(1, 2));
console.log(data);
运行打包后的代码
$ node dist/main.js
3
{ name: 'Tom', age: 23 }
3.3、结论
- webpack能处理js、json资源,不能处理css、img等其他资源
- 生产环境和开发环境将ES6模块化编译成浏览器能识别的模块化
- 生产环境比开发环境多了一部压缩js代码
3.4、webpack配置文件
构建工具基于node.js环境运行,模块化采用commonjs
一个基本的配置
webpack.config.js
// 用来处理路径
const path = require('path');
// webpack配置
module.exports = {
// 入口文件
entry: './src/index.js',
// 输出
output: {
// 输出文件名
filename: 'bundle.js',
// 输出路径 __dirname node.js变量,当前文件的目录绝对路径
path: path.resolve(__dirname, 'dist'),
},
// loader配置
module: {
rules: [],
},
// 插件配置
plugins: [],
// 模式
mode: 'development',
// mode: 'production',
};
3.5、打包样式资源-css文件
安装处理css的loader
$ cnpm i style-loader css-loader -D
项目结构
$ tree -I "node_modules"
.
├── dist
│ ├── bundle.js
│ └── index.html
├── package.json
├── src
│ ├── index.css
│ └── index.js
└── webpack.config.js
src/index.js
// 引入样式资源
import './index.css';
src/index.css
html,
body {
padding: 0;
margin: 0;
height: 100%;
background-color: pink;
}
webpack.config.js
// 用来处理路径
const path = require('path');
// webpack配置
module.exports = {
// 入口文件
entry: './src/index.js',
// 输出
output: {
// 输出文件名
filename: 'bundle.js',
// 输出路径 __dirname node.js变量,当前文件的目录绝对路径
path: path.resolve(__dirname, 'dist'),
},
// loader配置
module: {
rules: [
{
// 正则匹配文件名
test: /\.css$/,
// 处理文件的loader
// 执行顺序:从右到左,从下到上
use: [
// 创建style标签,插入到head中
'style-loader',
// 加载css文件,变成commonjs模块,内容是样式字符串
'css-loader',
],
},
],
},
// 插件配置
plugins: [],
// 模式
mode: 'development',
// mode: 'production',
};
index.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="./bundle.js"></script>
</body>
</html>
执行打包命令
$ npx webpack
打开index.html 文件,可以看到css样式已经生效(右键->检查元素)
js动态生成了style标签
<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>
<style>html,
body {
padding: 0;
margin: 0;
height: 100%;
background-color: pink;
}
</style></head>
<body>
<script src="./bundle.js"></script>
</body></html>
3.6、打包样式资源-less文件
$ cnpm i less less-loader -D
src/index.js
// 引入less样式资源
import './index.less';
src/index.less
html,
body {
padding: 0;
margin: 0;
height: 100%;
background-color: pink;
}
新增配置 webpack.config.js
// webpack.config.js
// 用来处理路径
const path = require('path');
// webpack配置
module.exports = {
// 入口文件
entry: './src/index.js',
// 输出
output: {
// 输出文件名
filename: 'bundle.js',
// 输出路径 __dirname node.js变量,当前文件的目录绝对路径
path: path.resolve(__dirname, 'dist'),
},
// loader配置
module: {
rules: [
// 处理less文件
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
// 将less编译成css
'less-loader',
],
},
],
},
// 插件配置
plugins: [],
// 模式
mode: 'development',
// mode: 'production',
};
执行打包命令
$ npx webpack
3.7、打包Html资源
- loader: 1. 下载; 2.使用(配置loader)
- plugins: 1. 下载; 2.引入;3.使用
cnpm i html-webpack-plugin -D
默认创建一个空的HTML文件,自动引入打包输出的所有资源(js/css)
默认输出的HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Webpack App</title>
<meta name="viewport" content="width=device-width, initial-scale=1"><script defer src="bundle.js"></script></head>
<body>
</body>
</html>
自定义HTML
// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
// webpack配置
module.exports = {
// 入口文件
entry: './src/index.js',
// 输出
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
// loader配置
module: {},
// 插件配置
plugins: [
// 复制一份HTML文件,并自动引入打包资源(js/css)
new HtmlWebpackPlugin({
template: './src/index.html',
}),
],
// 模式
mode: 'development',
// mode: 'production',
};
src/index.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>Webpack</title>
</head>
<body>
</body>
</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>Webpack</title>
<script defer src="bundle.js"></script></head>
<body>
</body>
</html>
3.8、打包图片资源
安装依赖
cnpm i html-loader -D
项目结构
$ tree -I node_modules
.
├── package.json
├── src
│ ├── index.html
│ ├── index.js
│ ├── index.less
│ └── weibo.png
└── webpack.config.js
src/index.js
// 引入less样式资源
import './index.less';
// js引入图片资源
import weibo from './weibo.png';
console.log(weibo);
// http://127.0.0.1:5500/dist/images/7f1a8e356f.png
src/index.less
html,
body {
padding: 0;
margin: 0;
height: 100%;
// background-color: pink;
}
.box {
width: 100px;
height: 100px;
// css引入图片资源
background-image: url('./weibo.png');
// 替换为:background-image: url(/dist/images/7f1a8e356f.png);
background-size: 100% 100%;
background-repeat: no-repeat;
}
src/index.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>Webpack</title>
</head>
<body>
<div class="box"></div>
<!-- html引入图片资源 -->
<img src="./weibo.png" alt="">
<!-- 替换为:<img src="images/7f1a8e356f.png" alt=""> -->
</body>
</html>
配置文件 webpack.config.js
webpack5默认会处理图片资源,webpack4需要单独配置
webpack5 | webpack4 | 说明 |
---|---|---|
asset/resource | file-loader | 发送一个单独的文件并导出 URL |
asset/inline | url-loader | 导出一个资源的 data URI |
asset/source | raw-loader | 导出资源的源代码 |
asset | url-loader | 在导出一个 data URI 和发送一个单独的文件之间自动选择。 |
webpack4 配置
{
module: {
rules: [
// 默认无法处理HTML中的图片
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
// 使用一个loader,如果使用多个loader用use
loader: 'url-loader',
options: {
// 图片大小小于8kb,就会被base64编码
// 优点:减少请求数量,减轻服务器压力
// 缺点:js体积会更大, 文件请求速度更慢
limit: 8 * 1024,
// 问题:url-loader默认使用es6模块解析,而html-loader引入图片是commonjs
// 解析时会出现[object Module]
// 解决:关闭url-loader的es6模块化,使用commonjs解析
esModule: false,
// 自定义命名 取hash前10位
name: '[hash:10].[ext]'
}
},
// 处理html中的图片, 引入img,让后续loader解析
{
test: /\.html$/i,
loader: 'html-loader',
},
]
}
}
package.json
{
"devDependencies": {
"css-loader": "^6.7.1",
"html-loader": "^3.1.0",
"html-webpack-plugin": "^5.5.0",
"less": "^4.1.2",
"less-loader": "^11.0.0",
"style-loader": "^3.3.1",
"webpack": "^5.72.1",
"webpack-cli": "^4.9.2"
}
}
webpack5配置
// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
// webpack配置
module.exports = {
// 入口文件
entry: './src/index.js',
// 输出
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
// 自定义资源文件名
assetModuleFilename: 'images/[hash:10][ext][query]',
},
// loader配置
module: {
rules: [
// 处理less文件
{
test: /\.less$/i,
use: ['style-loader', 'css-loader', 'less-loader'],
},
// 处理资源文件
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
// 默认: 小于 8kb 的文件,将会视为 inline 模块类型,否则会被视为 resource 模块类型。
type: 'asset',
},
// 处理html中的图片
{
test: /\.html$/i,
loader: 'html-loader',
},
],
},
// 插件配置
plugins: [
// 复制一份HTML文件,并自动引入打包资源(js/css)
new HtmlWebpackPlugin({
template: './src/index.html',
}),
],
// 模式
mode: 'development',
// mode: 'production',
};
3.9、打包字体资源
可以从iconfont(https://www.iconfont.cn/)网站下载字体文件
打包后的项目结构
$ tree -I node_modules
.
├── dist
│ ├── bundle.js
│ ├── images
│ │ ├── 5b0edd384b.ttf
│ │ ├── 969b5fedf8.woff
│ │ └── d79bd05095.woff2
│ └── index.html
├── package.json
├── src
│ ├── iconfont
│ │ ├── iconfont.css
│ │ ├── iconfont.js
│ │ ├── iconfont.json
│ │ ├── iconfont.ttf
│ │ ├── iconfont.woff
│ │ └── iconfont.woff2
│ ├── index.html
│ ├── index.js
└── webpack.config.js
src/index.js
// 引入css样式资源
import './iconfont/iconfont.css';
src/index.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>Webpack</title>
</head>
<body>
<span class="iconfont icon-home"></span>
</body>
</html>
webpack.config.js
webpack4
{
// 排除资源
exclude: /\.(js|less|html)$/i,
type: 'file-loader',
options: {
// 自定义命名 取hash前10位
name: '[hash:10].[ext]'
}
},
webpack5
// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
// webpack配置
module.exports = {
// 入口文件
entry: './src/index.js',
// 输出
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
// 自定义资源文件名
assetModuleFilename: 'images/[hash:10][ext][query]',
},
// loader配置
module: {
rules: [
// 处理css文件
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
// 处理less文件
{
test: /\.less$/i,
use: ['style-loader', 'css-loader', 'less-loader'],
},
// 处理资源文件
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset',
},
// 处理html文件,加载其中的图片
{
test: /\.html$/i,
loader: 'html-loader',
},
// 处理字体文件
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/resource',
},
],
},
// 插件配置
plugins: [
// 复制一份HTML文件,并自动引入打包资源(js/css)
new HtmlWebpackPlugin({
template: './src/index.html',
}),
],
// 模式
mode: 'development',
// mode: 'production',
};
4、开发环境基本配置
4.1、devServer
开发服务器,自动化开发(自动编译,自动打开浏览器,自动刷新浏览器)
特点:只会在内存中编译打包,不会有任何输出
npm install webpack-dev-server --save-dev
webpack4配置
module.exports = {
devServer: {
// 项目构建后路径
contentBase: resolve(__dirname, 'dist'),
// 启动gzip压缩
compress: true,
// 端口号
port: 3000,
// 自动打开浏览器
open: true
}
}
webpack5配置
module.exports = {{
// 开发服务器配置
devServer: {
// 从目录提供静态文件
static: {
directory: path.join(__dirname, "public"),
publicPath: "/",
},
// 启动后打开浏览器
open: true,
// 监听请求的端口号
port: 8080,
},
}
为了方便启动,可以配置启动命令
package.json
{
"scripts": {
"dev": "webpack serve",
"build": "webpack"
},
}
启动开发服务器
npm run dev
4.2、webpack开发环境
- 提升开发效率
- 处理js、css、less、图片、字体文件
webpack.config.js 完整配置
// webpack.config.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
// webpack配置
module.exports = {
// 入口文件
entry: "./src/index.js",
// 输出
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "dist"),
// 自定义资源文件名
assetModuleFilename: "images/[hash:10][ext][query]",
},
// 开发服务器配置
devServer: {
// 从目录提供静态文件
static: {
directory: path.join(__dirname, "public"),
publicPath: "/",
},
// 启动后打开浏览器
open: true,
// 监听请求的端口号
port: 8080,
},
// loader配置
module: {
rules: [
// 处理css文件
{
test: /\.css$/i,
use: ["style-loader", "css-loader"],
},
// 处理less文件
{
test: /\.less$/i,
use: ["style-loader", "css-loader", "less-loader"],
},
// 处理资源文件
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: "asset",
},
// 处理html文件,加载其中的图片
{
test: /\.html$/i,
loader: "html-loader",
},
// 处理字体文件
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: "asset/resource",
},
],
},
// 插件配置
plugins: [
// 复制一份HTML文件,并自动引入打包资源(js/css)
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
],
// 模式
mode: "development",
// mode: 'production',
};
5、生产环境基本配置
目前存在的问题
- css通过js动态生成,会出现闪屏现象
- 代码没有压缩
- 浏览器兼容性问题
5.1、提取css成单独的文件
npm i mini-css-extract-plugin -D
完整配置
// webpack.config.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
// webpack配置
module.exports = {
// 入口文件
entry: "./src/index.js",
// 输出
output: {
filename: "[name].js",
path: path.resolve(__dirname, "dist"),
// 自定义资源文件名
assetModuleFilename: "images/[hash:10][ext][query]",
// 在生成文件之前清空 output 目录
clean: true,
},
// 开发服务器配置
devServer: {
// 从目录提供静态文件
static: {
directory: path.join(__dirname, "public"),
publicPath: "/",
},
// 启动后打开浏览器
open: true,
// 监听请求的端口号
port: 8080,
},
// loader配置
module: {
rules: [
// 处理css文件
{
test: /\.css$/i,
use: [
// 创建style标签,将样式放入style标签中
// "style-loader",
// 提取js中的css成单独文件
MiniCssExtractPlugin.loader,
// 将css文件整合到js文件中
"css-loader",
],
},
// 处理less文件
{
test: /\.less$/i,
use: [
// "style-loader",
MiniCssExtractPlugin.loader,
"css-loader",
"less-loader",
],
},
// 处理资源文件
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: "asset",
},
// 处理html文件,加载其中的图片
{
test: /\.html$/i,
loader: "html-loader",
},
// 处理字体文件
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: "asset/resource",
},
],
},
// 插件配置
plugins: [
// 复制一份HTML文件,并自动引入打包资源(js/css)
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
new MiniCssExtractPlugin({
filename: "[name].css",
}),
],
// 模式
mode: "development",
// mode: 'production',
};
5.2、css兼容性处理
npm i postcss postcss-loader postcss-preset-env -D
browserslist: https://github.com/browserslist/browserslist
通过 NODE_ENV 判断环境, 默认生产环境
package.json
{
"browserslist": {
"development": [
"last 1 version"
],
"production": [
"last 1 version",
"> 1%",
"ie 10"
]
}
}
webpack4
// webpack配置
module.exports = {
// loader配置
module: {
rules: [
// 处理css文件
{
test: /\.css$/i,
use: [
// 创建style标签,将样式放入style标签中
// "style-loader",
// 提取js中的css成单独文件
MiniCssExtractPlugin.loader,
// 将css文件整合到js文件中
"css-loader",
// 需要配置 browserlist,配合NODE_ENV使用
{
loader: "postcss-loader",
options: {
ident: 'postcss',
plugins: ()=>[
require('postcss-preset-env')()
]
},
},
},
],
},
],
},
};
webpack5完整配置
// webpack.config.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
// webpack配置
module.exports = {
// 入口文件
entry: "./src/index.js",
// 输出
output: {
filename: "[name].js",
path: path.resolve(__dirname, "dist"),
// 自定义资源文件名
assetModuleFilename: "images/[hash:10][ext][query]",
// 在生成文件之前清空 output 目录
clean: true,
},
// 开发服务器配置
devServer: {
// 从目录提供静态文件
static: {
directory: path.join(__dirname, "public"),
publicPath: "/",
},
// 启动后打开浏览器
open: true,
// 监听请求的端口号
port: 8080,
},
// loader配置
module: {
rules: [
// 处理css文件
{
test: /\.css$/i,
use: [
// 创建style标签,将样式放入style标签中
// "style-loader",
// 提取js中的css成单独文件
MiniCssExtractPlugin.loader,
// 将css文件整合到js文件中
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
[
// postcss-preset-env 帮助postcss找到package.json中`browserslist`里边的配置
"postcss-preset-env",
],
],
},
},
},
],
},
// 处理less文件
{
test: /\.less$/i,
use: [
// "style-loader",
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
[
"postcss-preset-env",
],
],
},
},
},
"less-loader",
],
},
// 处理资源文件
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: "asset",
},
// 处理html文件,加载其中的图片
{
test: /\.html$/i,
loader: "html-loader",
},
// 处理字体文件
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: "asset/resource",
},
],
},
// 插件配置
plugins: [
// 复制一份HTML文件,并自动引入打包资源(js/css)
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
new MiniCssExtractPlugin({
filename: "[name].css",
}),
],
// 模式
mode: "development",
// mode: 'production',
};
5.3、css压缩
webpack4使用 optimize-css-assets-webpack-plugin: https://github.com/NMFR/optimize-css-assets-webpack-plugin
webpack5使用 css-minimizer-webpack-plugin: https://webpack.docschina.org/plugins/css-minimizer-webpack-plugin/
npm install css-minimizer-webpack-plugin --save-dev
完整配置
// webpack.config.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
// webpack配置
module.exports = {
// 入口文件
entry: "./src/index.js",
// 输出
output: {
filename: "[name].js",
path: path.resolve(__dirname, "dist"),
// 自定义资源文件名
assetModuleFilename: "images/[hash:10][ext][query]",
// 在生成文件之前清空 output 目录
clean: true,
},
// 开发服务器配置
devServer: {
// 从目录提供静态文件
static: {
directory: path.join(__dirname, "public"),
publicPath: "/",
},
// 启动后打开浏览器
open: true,
// 监听请求的端口号
port: 8080,
},
// loader配置
module: {
rules: [
// 处理css文件
{
test: /\.css$/i,
use: [
// 创建style标签,将样式放入style标签中
// "style-loader",
// 提取js中的css成单独文件
MiniCssExtractPlugin.loader,
// 将css文件整合到js文件中
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [["postcss-preset-env"]],
},
},
},
],
},
// 处理less文件
{
test: /\.less$/i,
use: [
// "style-loader",
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [["postcss-preset-env"]],
},
},
},
"less-loader",
],
},
// 处理资源文件
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: "asset",
},
// 处理html文件,加载其中的图片
{
test: /\.html$/i,
loader: "html-loader",
},
// 处理字体文件
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: "asset/resource",
},
],
},
// 插件配置
plugins: [
// 复制一份HTML文件,并自动引入打包资源(js/css)
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
new MiniCssExtractPlugin({
filename: "[name].css",
}),
],
optimization: {
// 开发环境下启用 CSS 优化
minimize: true,
minimizer: [
// 使用 cssnano 优化和压缩 CSS
new CssMinimizerPlugin(),
],
},
// 模式
mode: "development",
// mode: 'production',
};
5.4、js语法检查eslint
ESLint:
Airbnb:
Airbnb中文版:https://github.com/lin-123/javascript
npm i eslint eslint-config-airbnb-base eslint-plugin-import -D
设置检查规则
package.json
{
"eslintConfig": {
"extends": "airbnb-base"
}
}
webpack4
cnpm i eslint eslint-loader -D
// webpack.config.js
// webpack配置
module.exports = {
// loader配置
module: {
rules: [
{
test: /\.js$/,
// 注意:只检查自己写的代码,不检查第三方库
exlude: /node_modules/,
loader: 'eslint-loader',
options: {
// 自动修复
fix: true
}
}
]
},
};
webpack5
npm install eslint eslint-webpack-plugin --save-dev
eslint-webpack-plugin:
- 中文文档:https://webpack.docschina.org/plugins/eslint-webpack-plugin/
- github: https://github.com/webpack-contrib/eslint-webpack-plugin
// webpack.config.js
const ESLintPlugin = require("eslint-webpack-plugin");
// webpack配置
module.exports = {
// 插件配置
plugins: [
// 使用eslint对代码检查
new ESLintPlugin({
fix: true,
}),
],
};
// 下一行不进行eslint规则检查
// eslint-disable-next-line
console.log('hi');
5.5、js兼容性处理
处理方案:
- 1、
@babel/preset-env
基本js兼容性处理- 问题:只能转换基本js语法。如,不能转换高级语法Promise(IE不支持)
- 2、
@babel/polyfill
全部js兼容性处理- 问题:将所有兼容性代码全部引入,体积太大
- 3、
core-js
按需加载:只加载需要处理兼容性的语法
方案一:
npm i babel-loader @babel/core @babel/preset-env -D
// webpack.config.js
module.exports = {
module: {
rules: [
{
// js兼容性处理
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
// 预设,提示babel怎么样做兼容性处理
// 基本的兼容性处理,
presets: ['@babel/preset-env']
}
}
]
}
}
方案二:
npm i @babel/polyfill -S
使用方式
// 直接引入即可
import '@babel/polyfill';
方案三:
npm i core-js -D
// webpack.config.js
module.exports = {
module: {
rules: [
{
// js兼容性处理
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
// 预设,提示babel怎么样做兼容性处理
// 基本的兼容性处理,
presets: [[
'@babel/preset-env',
{
// 按需加载
useBuiltIns: 'usage',
// 指定core-js版本
corejs: {
version: 3
},
// 指定兼容性到哪个版本浏览器
targets: {
chrome: '60',
firefox: '60',
ie: '9',
safari: '10',
edge: '17'
}
}
]]
}
}
]
}
}
5.6、压缩html和js
// 生产环境下会自动压缩js代码
mode: 'production'
// 生产环境默认压缩html
new HtmlWebpackPlugin({
template: "./src/index.html",
minify: {
// 移除空格
collapseWhitespace: true,
// 移除注释
removeComments: true,
}
}),
webpack5压缩js
$ npm install terser-webpack-plugin --save-dev
const TerserPlugin = require("terser-webpack-plugin");
module.exports = {
optimization: {
minimize: true,
minimizer: [
// 使用 terser 优化和压缩 JS
new TerserPlugin()
],
},
};
5.7、webpack生产环境
需要处理的资源
- css/less 兼容性处理 单文件提取 压缩优化
- js 兼容性处理 压缩优化
- html 压缩优化
- 图片
- 字体
正常来讲,一个文件只能被一个loader处理
当一个文件要被多个loader处理,一定要指定loader执行的先后顺序
// 优先执行
enforce: 'pre'
完整配置
// webpack.config.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const TerserPlugin = require("terser-webpack-plugin");
const ESLintPlugin = require("eslint-webpack-plugin");
// css 公共loader
const commonCssLoaders = [
// "style-loader",
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
[
// 配合package.json browserlist使用
"postcss-preset-env",
],
],
},
},
},
];
// webpack配置
module.exports = {
// 入口文件
entry: "./src/index.js",
// 输出
output: {
filename: "[name].js",
path: path.resolve(__dirname, "dist"),
// 自定义资源文件名
assetModuleFilename: "images/[hash:10][ext][query]",
// 在生成文件之前清空 output 目录
clean: true,
},
// 开发服务器配置
devServer: {
// 从目录提供静态文件
static: {
directory: path.join(__dirname, "public"),
publicPath: "/",
},
// 启动后打开浏览器
open: true,
// 监听请求的端口号
port: 8080,
},
// loader配置
module: {
rules: [
// 处理css文件
{
test: /\.css$/i,
use: commonCssLoaders,
},
// 处理less文件
{
test: /\.less$/i,
use: [...commonCssLoaders, "less-loader"],
},
// 处理资源文件
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: "asset",
},
// 处理html文件,加载其中的图片
{
test: /\.html$/i,
loader: "html-loader",
},
// 处理字体文件
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: "asset/resource",
},
// js兼容性处理
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
// 预设,提示babel怎么样做兼容性处理
// 基本的兼容性处理,
presets: [
[
"@babel/preset-env",
{
// 按需加载
useBuiltIns: "usage",
// 指定core-js版本
corejs: {
version: 3,
},
// 指定兼容性到哪个版本浏览器
targets: {
chrome: "60",
firefox: "60",
ie: "9",
safari: "10",
edge: "17",
},
},
],
],
},
},
},
],
},
// 插件配置
plugins: [
// 复制一份HTML文件,并自动引入打包资源(js/css)
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
// 提取css文件
new MiniCssExtractPlugin({
filename: "[name].css",
}),
// 使用eslint对代码检查
// package.json eslintConfig airbnb
new ESLintPlugin({
fix: true,
}),
],
optimization: {
// 开发环境下启用 CSS 优化
minimize: true,
minimizer: [
// 使用 cssnano 优化和压缩 CSS
new CssMinimizerPlugin(),
// 使用 terser 优化和压缩 JS
new TerserPlugin(),
],
},
// 模式
// mode: "development",
mode: "production",
};
package.json
{
"scripts": {
"dev": "webpack serve",
"build": "webpack"
},
"devDependencies": {
"@babel/core": "^7.18.0",
"@babel/preset-env": "^7.18.0",
"babel-loader": "^8.2.5",
"core-js": "^3.22.5",
"css-loader": "^6.7.1",
"css-minimizer-webpack-plugin": "^4.0.0",
"eslint": "^8.15.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-plugin-import": "^2.26.0",
"eslint-webpack-plugin": "^3.1.1",
"html-loader": "^3.1.0",
"html-webpack-plugin": "^5.5.0",
"less": "^4.1.2",
"less-loader": "^11.0.0",
"mini-css-extract-plugin": "^2.6.0",
"postcss": "^8.4.14",
"postcss-loader": "^7.0.0",
"postcss-preset-env": "^7.6.0",
"style-loader": "^3.3.1",
"terser-webpack-plugin": "^5.3.1",
"webpack": "^5.72.1",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.9.0"
},
"dependencies": {
"@babel/polyfill": "^7.12.1"
},
"browserslist": {
"development": [
"last 1 version"
],
"production": [
"last 1 version",
"> 1%",
"ie 10"
]
},
"eslintConfig": {
"extends": "airbnb-base"
}
}
6、性能优化
开发环境性能优化
- 优化打包构建速度
- 优化代码调试
生产环境性能优化
- 优化打包构建速度
- 优化代码运行的性能
6.1、HMR 模块热替换
HMR hot module replacement
作用:一个模块发生变化,只会重新打包这一个模块(而不是打包所有模块),提升构建速度
- 样式文件:可以使用HMR功能,style-loader内部实现
- js文件:默认没有HMR
- 注意:只能对非入口文件做HMR
- html文件:默认没有HMR
- 解决:将html文件加入entry入口
devServer: {
// 热模块替换是默认开启的
// 开启HMR功能,修改配置之后需要重启webpack
hot: true,
}
6.2、source map 源码映射
一种提供源代码到构建后代码映射技术
如果构建后的代码出错,可以通过映射关系追踪到源代码出错位置
devtool: 'source-map'
模式
[inline- | hidden- | eval- ][nosources-][cheap-[module-]]source-map
组合值
值 | 说明 | 错误提示 |
---|---|---|
source-map | 外部 | 错误代码的准确信息,源代码的错位位置 |
inline-source-map | 内联 只生成一个内联source-map | 错误代码的准确信息,源代码的错位位置 |
hidden-source-map | 外部 | 错误代码的原因,没有源代码错误位置,只有构建后代码位置 |
eval-source-map | 内联 每个文件都生成对应的source-map,都在eval里 | 错误代码的准确信息,源代码的错位位置 |
nosources-source-map | 外部 | 有错误代码准确信息,没有源代码位置 |
cheap-source-map | 外部 | 有错误代码准确信息,有源代码信息,只能精确到行 |
cheap-module-source-map | 外部 | 错误代码的准确信息,源代码的错位位置 |
内联和外部
- 内联:构建速度快
- 外部:生成单独文件,内联没有
1、开发环境
- 速度快,调试更友好
速度快:
eval > inline > cheap >
eval-cheap-source-map
eval-source-map
调试更友好
source-map
cheap-module-source-map
cheap-source-map
module会将loader的source map加入
eval-source-map / eval-cheap-module-source-map
2、生产环境
- 源代码要不要隐藏,调试要不要更友好
内联会让代码体积变大,所以生产环境不使用内联
nosources-source-map 全部隐藏
hidden-source-map 只会隐藏源代码,会提示构建后代码错误
source-map / cheap-module-source-map
6.3、oneOf
当规则匹配时,只使用第一个匹配规则。
module.exports = {
//...
module: {
rules: [
{
test: /\.css$/,
oneOf: [
{
resourceQuery: /inline/, // foo.css?inline
use: 'url-loader',
},
{
resourceQuery: /external/, // foo.css?external
use: 'file-loader',
},
],
},
],
},
};
6.4、babel-loader缓存
第二次打包构建速度更快
module.exports = {
//...
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
// 预设,提示babel怎么样做兼容性处理
// 基本的兼容性处理,
presets: [
[
"@babel/preset-env",
{
// 按需加载
useBuiltIns: "usage",
// 指定core-js版本
corejs: {
version: 3,
},
// 指定兼容性到哪个版本浏览器
targets: {
chrome: "60",
firefox: "60",
ie: "9",
safari: "10",
edge: "17",
},
},
],
],
// 开启编译缓存
cacheDirectory: true
},
},
},
],
},
};
6.5、文件资源缓存
线上代码缓存优化
1、hash: 每次webpack构建打包,都会生成唯一hash
问题:
因为js和css使用同一个hash值
如果重新打包,会导致所有缓存失效,虽然只改动一个文件
2、chunkhash: 根据chunk生成hash值,如果打包来源于同一个chunk,那么hash值就一样
js和css还是使用同一个hash值
因为css是在js中被引入的,所以属于同一个chunk
3、contenthash: 根据文件的内容生成hash值,不同文件hash值不一样
静态资源服务器
// server.js
// npm i express nodemon -S
// node server.js 或者 nodemon server.js
const express = require("express");
const app = express();
app.use(express.static("dist", { maxAge: 1000 * 3600 }));
app.listen(8002);
完整配置
// webpack.config.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const TerserPlugin = require("terser-webpack-plugin");
const ESLintPlugin = require("eslint-webpack-plugin");
// css 公共loader
const commonCssLoaders = [
// "style-loader",
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
[
// 配合package.json browserlist使用
"postcss-preset-env",
],
],
},
},
},
];
// webpack配置
module.exports = {
// 入口文件
entry: "./src/index.js",
// 输出
output: {
filename: "[name].[contenthash:10].js",
path: path.resolve(__dirname, "dist"),
// 自定义资源文件名
assetModuleFilename: "images/[hash:10][ext][query]",
// 在生成文件之前清空 output 目录
clean: true,
},
// 开发服务器配置
devServer: {
// 从目录提供静态文件
static: {
directory: path.join(__dirname, "public"),
publicPath: "/",
},
// 启动后打开浏览器
open: true,
// 监听请求的端口号
port: 8080,
},
// loader配置
module: {
rules: [
// 处理css文件
{
test: /\.css$/i,
use: commonCssLoaders,
},
// 处理less文件
{
test: /\.less$/i,
use: [...commonCssLoaders, "less-loader"],
},
// 处理资源文件
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: "asset",
},
// 处理html文件,加载其中的图片
{
test: /\.html$/i,
loader: "html-loader",
},
// 处理字体文件
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: "asset/resource",
},
// js兼容性处理
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
// 预设,提示babel怎么样做兼容性处理
// 基本的兼容性处理,
presets: [
[
"@babel/preset-env",
{
// 按需加载
useBuiltIns: "usage",
// 指定core-js版本
corejs: {
version: 3,
},
// 指定兼容性到哪个版本浏览器
targets: {
chrome: "60",
firefox: "60",
ie: "9",
safari: "10",
edge: "17",
},
},
],
],
// 开启编译缓存
cacheDirectory: true
},
},
},
],
},
// 插件配置
plugins: [
// 复制一份HTML文件,并自动引入打包资源(js/css)
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
// 提取css文件
new MiniCssExtractPlugin({
filename: "[name].[contenthash:10].css",
}),
// 使用eslint对代码检查
// package.json eslintConfig airbnb
// new ESLintPlugin({
// fix: true,
// }),
],
optimization: {
// 开发环境下启用 CSS 优化
minimize: true,
minimizer: [
// 使用 cssnano 优化和压缩 CSS
new CssMinimizerPlugin(),
// 使用 terser 优化和压缩 JS
new TerserPlugin(),
],
},
// development
// devtool: "eval-source-map",
// production
devtool: false,
// 模式
mode: "development",
// mode: "production",
};
6.6、tree shaking 树摇
去除无用代码,减少代码体积
前提:
- 必须使用ES6模块化
- 开启production环境
pagekage.json配置
// 所有代码都没有副作用(都可以运行)
sideEffects: false
可能会把css / @babel/polyfill文件干掉
处理方式
// 要保留的文件
sideEffects: ["*.css"]
6.7、code split 代码分割
方式一:入口起点
指定不同的入口
module.exports = {
entry: {
// 多入口
index: './index.js',
home: './home.js',
},
output: {
filename: '[name].[contenthash:4].js'
}
}
方式二 防止重复
作用
将node_modules中的代码单独打包一个chunk最终输出
自动分析多入口chunk中,如果有公共的问题件,会打包成单独一个chunk
module.exports = {
optimization: {
splitChunks: {
chunks: 'all'
}
}
}
方式三 动态导入
import动态引入语法,能将文件单独打包
import(/* webpackChunkName: 'test' */ './test.js').then(()=>{
// 加载成功
}).catch(()=>{
// 加载失败
})
6.8、懒加载和预加载
1、懒加载
当文件需要时才加载
index.html
<button id="btn">点击加载代码</button>
index.js
document.querySelector("#btn").addEventListener("click", function () {
import(/* webpackChunkName: 'print' */ "./print.js")
.then(() => {
// 加载成功
})
.catch(() => {
// 加载失败
});
});
print.js
console.log("print load");
2、预加载
prefetch 会在使用前,提前加载js文件
正常加载可以认为是并行加载(同一时间加载多个文件) 预加载 prefetch:等其他资源加载完毕,浏览器空闲了,再偷偷加载资源
document.querySelector("#btn").addEventListener("click", function () {
import(/* webpackChunkName: 'print', webpackPrefetch: true */ "./print.js")
.then(() => {
// 加载成功
})
.catch(() => {
// 加载失败
});
});
- prefetch(预获取):将来某些导航下可能需要的资源
- preload(预加载):当前导航下可能需要资源
import(/* webpackChunkName: 'print', webpackPrefetch: true */ "./print.js")
import(/* webpackChunkName: 'print', webpackPreload: true */ "./print.js")
6.9、PWA 离线可访问
progressive web application 渐进式网络开发应用程序(离线可访问)
添加 workbox-webpack-plugin 插件
npm install workbox-webpack-plugin --save-dev
webpack.config.js
const WorkboxPlugin = require('workbox-webpack-plugin');
module.exports = {
plugins: [
new WorkboxPlugin.GenerateSW({
// 这些选项帮助快速启用 ServiceWorkers
// 不允许遗留任何“旧的” ServiceWorkers
clientsClaim: true,
skipWaiting: true,
}),
]
};
注册 Service Worker
index.js
// 处理兼容性
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/service-worker.js').then(registration => {
console.log('SW registered: ', registration);
}).catch(registrationError => {
console.log('SW registration failed: ', registrationError);
});
});
}
修改 package.json ESLint配置
让其支持浏览器变量(window、navigator等全局变量)
{
"eslintConfig": {
"extends": "airbnb-base",
"env": {
"browser": true
}
}
}
快速启动一个本地服务器
npm install http-server --save-dev
$ npx http-server dist
# 或者
npm i serve
$ npx serve dist
6.10、多进程打包
npm install --save-dev thread-loader
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.js$/,
include: path.resolve('src'),
use: [
"thread-loader",
// 耗时的 loader (例如 babel-loader)
],
},
],
},
};
6.11、外部扩展(Externals)
从 CDN 引入 jQuery,而不是把它打包
index.html
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
webpack.config.js
module.exports = {
//...
externals: {
jquery: 'jQuery',
},
};
index.js
import $ from 'jquery';
$('.my-element').animate(/* ... */);
6.12、dll
1、将第三方库打包到dll文件
// webpack.dll.config.js
/**
* 使用dll技术,对某些库(第三方库:jQuery,vue, react...)进行单独打包
*/
const path = require("path");
const webpack = require("webpack");
// webpack配置
module.exports = {
// 入口文件
entry: {
vendors: ["jquery"],
},
// 输出
output: {
filename: "[name].dll.js",
path: path.resolve(__dirname, "dll"),
// 打包库对外暴露的名字
library: "[name]_[fullhash:10]",
clean: true,
},
// 插件配置
plugins: [
// 提供映射表
new webpack.DllPlugin({
name: "[name]_[fullhash:10]",
path: path.resolve(__dirname, "[name].manifest.json"),
}),
],
// 模式
mode: "production",
};
$ npx webpack --config webpack.dll.config.js
2、将dll文件引入到html中
$ npm i add-asset-html-webpack-plugin -D
add-asset-html-webpack-plugin: 添加js或css资源到html中 https://github.com/SimenB/add-asset-html-webpack-plugin
// webpack.config.js
const path = require("path");
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');
// webpack配置
module.exports = {
// 入口文件
entry: "./src/index.js",
// 输出
output: {
filename: "[name].[contenthash:10].js",
path: path.resolve(__dirname, "dist"),
publicPath: "/dist/",
// 在生成文件之前清空 output 目录
clean: true,
},
// 插件配置
plugins: [
// 复制一份HTML文件,并自动引入打包资源(js/css)
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
// 告诉webpack 哪些库不参与打包
new webpack.DllReferencePlugin({
context: path.join(__dirname),
manifest: path.resolve(__dirname, "vendors.manifest.json"),
}),
// 将某个文件打包输出,并在HTML文件中引入
new AddAssetHtmlPlugin({
filepath: path.resolve(__dirname, "dll/vendors.dll.js"),
}),
],
// 模式
// mode: "development",
mode: "production",
};
src/index.js
import $ from 'jquery';
console.log($);
$ npx webpack --config webpack.config.js
6.13、性能优化总结
开发环境性能优化
优化打包构建速度
- HMR 模块热替换
优化代码调试
- source-map
生产环境性能优化
优化打包构建速度
- oneOf
- babel缓存
- 多进程打包
优化代码运行的性能
- 缓存(hash chunkhash contenthash)
- tree shaking
- code split
- 多入口
- 单入口
- chunk拆分
- 动态import
- 懒加载/预加载
- pwa
- externals cdn引入
- dll
https://webpack.docschina.org/
7、详细配置
7.1、entry
基本的配置
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'build.js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new HtmlWebpackPlugin()
],
mode: 'development'
}
entry
- string 单入口 输出一个文件,打包chunk默认名:main
entry: './src/index.js'
- array 多入口,最终行成一个chunk, 使用场景:html热更新
entry: ['./src/index.js', './src/add.js']
- object 多入口,有几个入口文件就输出几个chunk,chunk名称是key
entry: {
index: './src/index.js',
add: './src/add.js'
}
entry: {
// 多个入口最终生成一个chunk
index: ['./src/index.js', './src/count.js']
// 生成一个chunk
add: './src/add.js'
}
7.2、output
output: {
// 文件名称(目录 + 名称)
filename: 'js/[name].js',
// 所有资源输出的公共目录
path: path.resolve(__dirname, 'dist'),
// 所有输出资源引入公共路径前缀
publicPath: '/'
// 非入口chunk的名称
chunkFilename: [name]_chunk.js,
// 整个库对外暴露的变量名
library: '[name]',
// 变量名添加到哪个变量上 window(browser), global(node)
libraryTarget: 'window', // 'global'、'commonjs'
},
7.3、module
module: {
rules: [
// loader配置
{
test: /\.css$/,
// 多个loader用use
use: [
'style-loader',
'css-loader'
]
},
{
test: /\.js$/,
// 排除node_modules文件夹下文件
exclude: /node_modules/,
// 只检查src下的js文件
include: path.resolve(__dirname, 'src'),
// 单个loader用loader
loader: 'babel-loader',
// 优先执行
exforce: 'pre',
// 延后执行
// exforce: 'post',
// 参数配置
options: {}
},
// 以下配置只会生效一个
oneOf: []
]
}
7.4、resolve
// 解析模块的规则
resolve: {
// 配置解析模块路径别名,
// 优点:编码时简写路径
// 缺点:没有路径提示
alias: {
'@': path.resolve(__dirname, 'src')
},
// 配置省略文件路径的后缀
extensions: ['.js', '.json', '.css'],
// 告诉webpack解析模块去哪个目录找
modules: ['node_modules']
}
7.5、devServer
devServer: {
// 运行代码的目录
contentBase: resolve(__dirname, 'dist'),
// 监视contentBase目录下文件,一旦变化就reload
watchContentBase: true,
watchOptions: {
// 忽略文件
ignored: /node_modules/
},
// 启动gzip压缩
compress: true,
// 端口号
port: 5000,
// 域名
host: 'localhost',
// 自动打开浏览器
open: true,
// 开启HMR
hot: true,
// 不要显示启动服务器日志信息
clientLogLevel: 'none'
// 除了一些基本启动信息外,其他内容都不要显示
quiet: true,
// 如果出错,不要全屏提示
overlay: false,
// 服务器代理,解决开发环境跨域问题
proxy: {
// 一旦接收 /api 开头的请求,就会把请求转发到另一个服务器
'/api': {
target: 'http://localhost:3000',
// 发送请求时,请求路径重写, 去掉 /api
pathRewrite: {
'^/api': ''
}
}
}
}
7.6、optimization
output: {
chunkFilename: 'js/[name].[contenthash:10]_chunk.js'
}
optimization: {
// 提取公共代码
splitChunks: {
chunks: 'all',
// 一下均为默认值,可以不写
// 分割的chunk最小为30kb
minSize: 30 * 1024,
// 最大没有限制
maxSize: 0,
// 要提取的chunk最少被引用1次
minChunks: 1
// 按需加载时并行加载文件的最大数量
maxAsyncRequests: 5,
// 入口文件最大并行请求数量
maxInitialRequests: 3,
// 名称连接符
automaticNameDelimiter: '~'
// 可以使用命名规则
name: true,
// 分割chunk的组
cacheGroups: {
// node_modules 文件会被打爆到vendors组的chunk中:verdors~xxx.js
// 满足上面的公共规则,如:大小超过30kb,至少被引用1次
verdors: {
test: /[\\/]node_modules[\\/]/,
// 优先级
priority: -10
},
default: {
// 至少被引用2次
minChunks: 2,
// 优先级
priority: -20,
// 如果当前要打包的模块,和之前已经被提取的模块是同一个,就会复用,而不是重新打包模块
reuseExistingChunk: true
}
}
},
// 将当前模块的记录其他模块的hash单独打包为一个文件 runtime
// 解决:修改a文件,导致b文件的contenthash变化,导致缓存失效
runtimeChunk: {
name: entrypoint => `runtime-${entrypoint.name}`
},
// 配置生产环境的压缩方案:js和css
minimizer: [
new TerserWebpackPlugin({
// 开启缓存
cache: true,
// 开启多进程打包
parallel: true,
// 启动source-map
sourceMap: true
})
]
}
math.js
export function add(x, y){
return x + y;
}
index.js
import('./math.js').then(({add})=>{
console.log(add(1, 2));
});
8、webpack5 vs webpack4
@next
未来发布版
- 自动删除Node.js Polyfill: V5不自动加载node.js模块
- chunk和模块ID 添加了新的算法
- chunkID 命名规则优化
- Tree Shaking 能够处理嵌套模块、多模块关系、commonjs
- output V4只输出ES5,V5支持ES5
- SplitChunk js和css大小单独划分
- Caching 磁盘存储
- 监视输出文件 看是否变化再决定要不要输出全部文件
- 添加了默认值
9、总结
五个核心概念
- entry
- output
- loader
- plugins
- mode
开发环境
- 样式 css-loader style-loader less-loader
- HTML html-loader
- 图片
- 其他资源
- devServer
生产环境
- 提取css成单独文件
- css兼容性处理 postcss
- 压缩css
- js语法检查 eslint
- js兼容性处理 babel
- js压缩
优化配置
- HMR
- source-map
- 开发环境:eval-source-map / eval-cheap-module-source-map
- 生产环境:source-map / cheap-module-source-map
- oneOf
- 缓存 hash chunkhash contenthash
- tree shaking
- code split
- 多入口
- 单入口
- import
- lazy loading (import)
- pwa workbox
- 多进程打包 thread-loader
- externals cdn
- dll
详细配置
- entry
- output
- module
- resolve
- devServer porxy
- optimization splitChunks、runtimeChunk、minimizer
2022.05.24 完成学习