1. clean-webpack-plugin
每次打包都清除之前的文件
1.1 安装
npm install --save-dev clean-webpack-plugin
1.2 webpack.config.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
mode: "production", // 设置生产环境,有默认的优化
entry: {
index: "./src/index.js",
},
context: process.cwd(),
output: {
path: path.resolve("dist"),
filename: "main.js",
},
plugins: [
+ new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
],
};
2. copy-webpack-plugin
打包时候拷贝一些开发时用到的静态资源到打包后的生产路径下
2.1 安装
npm install --save-dev copy-webpack-plugin
2.2 webpack.config.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
+ const CopyWebpackPlugin = require("copy-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
mode: "production",
entry: {
index: "./src/index.js",
},
context: process.cwd(),
output: {
path: path.resolve("dist"),
filename: "main.js",
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
+ new CopyWebpackPlugin({
+ patterns: [
+ { from: "public", to: "." }
+ ],
+ }),
],
};
3. 缩小范围
3.1 resolve.extensions
指定 extension 之后可以不用在
require
或是import
的时候加文件扩展名,会依次尝试添加扩展名进行匹配
webapck.config.js
const path = require("path");
module.exports = {
mode: "production",
entry: {
index: "./src/index.js",
},
context: process.cwd(),
output: {
path: path.resolve("dist"),
filename: "[name].[contenthash:8].js?v=[contenthash:8]",
},
resolve: {
+ extensions: [".js", ".ts", ".tsx" ".jsx", ".json", ".css"],
},
};
3.2 resolve.alias
webapck.config.js
const path = require("path");
module.exports = {
mode: "production",
entry: {
index: "./src/index.js",
},
context: process.cwd(),
output: {
path: path.resolve("dist"),
filename: "[name].[contenthash:8].js?v=[contenthash:8]",
},
resolve: {
extensions: [".js", ".ts", ".tsx" ".jsx", ".json", ".css"],
+ alias: {
+ "@": path.resolve("src"),
+ },
},
};
3.3 resolve.modules
指定一些模块的查找路径
webpack.config.js
const path = require("path");
module.exports = {
mode: "production",
entry: {
index: "./src/index.js",
},
context: process.cwd(),
output: {
path: path.resolve("dist"),
filename: "[name].[contenthash:8].js?v=[contenthash:8]",
},
resolve: {
extensions: [".js", ".jsx", ".json"], //指定查找文件名,不指定也可以就是编写代码时写上后缀名 这定义了引入模块是,可以省略的后缀名
alias: { // 指定查找别名
"@": path.resolve(__dirname, "src")
},
+ modules: ["my_modules", node_modules"], // 指定模块查找的目录
+ mainFields: ["module", "main"], // 指定从库的 package.json 中配置的属性查找,默认是 main
+ mainFiles: ["index"] // 如果 mainFields 中的找不到,默认查找库中根目录下的 index.js 文件
},
};
3.4 resolve.mainFields
默认情况下 package.json 文件则按照文件中 main 字段的文件名来查找文件
webpack.config.js
const path = require("path");
module.exports = {
mode: "production",
entry: {
index: "./src/index.js",
},
context: process.cwd(),
output: {
path: path.resolve("dist"),
filename: "[name].[contenthash:8].js?v=[contenthash:8]",
},
resolve: {
// other config ....
// mainFields: 指定从库的 package.json 中配置的属性查找,默认是 main, 可以在package.json 中指定他字段 "xxx": ".../xxx.js"
+ mainFields: ["xxx", "browser", "module", "main"], // 配置 target === "web" 或者 target === "webworker" 时 mainFields 默认值是:['browser', 'module', 'main']
+ mainFields: ["module", "main"], // target 的值为其他时,mainFields 默认值为: ["module", "main"]
},
};
3.5 resolve.mainFiles
当目录下没有 package.json 文件时,我们说会默认使用目录下的 index.js 这个文件,其实这个也是可以配置的
webapck.config.js
{
resovle: {
mainFiles: ["index"]; // 如果 mainFields 中的找不到,默认查找库中根目录下的 index.js 文件
}
}
PS: require("add");
a. 去 node_modules/add 目录中查找
b. 去 node_modules/add 目录中查找 package.json 文件
c. 找到 package.json, 就读取 main 字段对应的文件, 结束
d. 如果找不到 package.json, 就找目录下的 index.js 文件
4. module.noParse
module.noParse
字段,用于配置哪些模块文件的内容不需要进行解析。- 不需要解析依赖(即无依赖) 的第三方类库等,可以提高整体的构建速度。
4.1 webpack.config.js
const path = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
mode: "production",
entry: {
index: "./src/index.js",
},
context: process.cwd(),
output: {
path: path.resolve("dist"),
filename: "[name].[contenthash:8].js?v=[contenthash:8]",
},
module: {
+ noParse: /jquery|lodash/, // 正则表达式
// 或者使用函数
+ noParse(content) {
return /jquery|lodash/.test(content);
},
},
plugins: [new CleanWebpackPlugin()],
};
PS: 使用 noParse 进行忽略的模块文件中不能使用 import、require、define 等导入机制
5. webpack.IgnorePlugin
webpack.IgnorePlugin 用于忽略某些特定的模块,让 webpack 不把这些指定的模块打包进去
5.1 src/index.js
import moment from 'moment';
import 'moment/locale/zh-cn'
console.log(moment().format('MMMM Do YYYY, h:mm:ss a'));
5.2 webpack.config.js
const path = require("path");
+ const webpack = require("webpack");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
mode: "production",
entry: {
index: "./src/index.js",
},
context: process.cwd(),
output: {
path: path.resolve("dist"),
filename: "[name].[contenthash:8].js?v=[contenthash:8]",
},
plugins: [
new CleanWebpackPlugin(),
+ new webpack.IgnorePlugin({
+ contextRegExp: /moment$/, // 匹配引入模块路径的正则表达式
+ resourceRegExp: /^\.\/locale/, // 匹配模块的对应上下文,即所在目录名
+ }),
],
};
6. 打包耗时分析
6.1 安装
npm install --save-dev speed-measure-webpack-plugin
webpack.config.js
const path = require("path");
const webpack = require("webpack");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
+ const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
+ const smp = new SpeedMeasurePlugin();
+ module.exports = smp.wrap({
mode: "production",
entry: {
index: "./src/index.js",
},
context: process.cwd(),
output: {
path: path.resolve("dist"),
filename: "[name].[contenthash:8].js?v=[contenthash:8]",
},
plugins: [
new CleanWebpackPlugin()
],
});
7. 打包体积大小分析
7.1 安装
npm install --save-dev webpack-bundle-analyzer
webpack.config.js
+ const BundleAnalyzerPlugin =
require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
module.exports = {
mode: "production",
// other code ...
plugins: [
new CleanWebpackPlugin(),
+ new BundleAnalyzerPlugin(),
],
};
8. gzip 文件压缩
8.1 安装
npm install --save-dev compression-webpack-plugin
webpack.config.js
const path = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
+ const CompressioWebpackPlugin = require("compression-webpack-plugin");
module.exports = {
mode: "production",
entry: {
index: "./src/index.js",
},
context: process.cwd(),
output: {
path: path.resolve("dist"),
filename: "[name].[contenthash:8].js?v=[contenthash:8]",
},
plugins: [
new CleanWebpackPlugin(),
+ new CompressioWebpackPlugin()
],
};
9. CSS 提取
9.1 安装
npm install mini-css-extract-plugin --save-dev
9.2 webpack.config.js
const path = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
+ const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
mode: "production",
entry: {
index: "./src/index.js",
},
context: process.cwd(),
output: {
path: path.resolve("dist"),
filename: "[name].[contenthash:8].js?v=[contenthash:8]",
},
module: {
rules: [
{
test: /\.(scss|css)$/,
+ use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
},
],
},
plugins: [
new CleanWebpackPlugin()
+ new MiniCssExtractPlugin({
filename: "css/[name].[contenthash:8].css",
}),
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
],
};
10. 压缩 CSS
10.1 安装
npm install --save-dev css-minimizer-webpack-plugin
10.2 webpack.config.js
const path = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
+ const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
module.exports = {
mode: "production",
entry: {
index: "./src/index.js",
},
context: process.cwd(),
output: {
path: path.resolve("dist"),
filename: "[name].[contenthash:8].js?v=[contenthash:8]",
},
+ optimization: {
+ minimizer: [new CssMinimizerPlugin()],
+ },
module: {
rules: [
{
test: /\.(scss|css)$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
},
],
},
plugins: [
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
filename: "css/[name].[contenthash:8].css",
}),
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
],
};
11. 压缩 JS
11.1 安装
npm install --save-dev terser-webpack-plugin
11.2 webpack.config.js
const path = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
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 config = {
mode: "production",
entry: {
index: "./src/index.js",
},
context: process.cwd(),
output: {
path: path.resolve("dist"),
filename: "[name].[contenthash:8].js?v=[contenthash:8]",
},
optimization: {
minimizer: true,
minimizer: [
new CssMinimizerPlugin(),
+ new TerserPlugin()
],
},
module: {
rules: [
{
test: /\.(scss|css)$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
},
],
},
plugins: [
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
filename: "css/[name].[contenthash:8].css",
}),
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
],
};
12. 清理未使用的 css 选择器
12.1 安装
npm install --save-dev purgecss-webpack-plugin
12.2 webpack.config.js
const path = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
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 glob = require("glob");
+ const PurgeCSSPlugin = require("purgecss-webpack-plugin");
+ const PATHS = {
+ src: path.join(__dirname, "src"),
+ };
module.exports = {
mode: "production",
entry: {
index: "./src/index.js",
},
context: process.cwd(),
output: {
path: path.resolve("dist"),
filename: "[name].[contenthash:8].js?v=[contenthash:8]",
},
optimization: {
minimizer: true,
minimizer: [new CssMinimizerPlugin(), new TerserPlugin()],
},
module: {
rules: [
{
test: /\.(scss|css)$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
},
],
},
plugins: [
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
filename: "css/[name].[contenthash:8].css",
}),
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
+ new PurgeCSSPlugin({
+ paths: glob.sync(`${PATHS.src}/**/*`, { nodir: true }),
+ }),
],
};
13. CDN
CDN(内容分发网络),通过把资源部署到某个地方的服务器,用户在访问时按照就近原则从离用户最近的服务器获取资源,从而加速资源的获取速度。
13.1 使用缓存
- HTML文件不缓存,放在自己的服务器上,关闭自己服务器的缓存,静态资源的 URL 变成指向 CDN 服务器的地址。
- 静态的JavaScript、CSS、图片等文件开启 CDN 和缓存,并且文件名带上 HASH 值。
- 为了并行加载不阻塞,把不同的静态资源分配到不同的 CDN 服务器上。
13.2 域名限制
- 同一时刻针对同一个域名的资源并行请求进行限制
- 把这些静态资源分散到不同的 CDN 服务上去
- 多个域名后会增加域名解析时间
- 通过在 HTML HEAD 标签中 加入
<link rel="dns-prefetch" href="http://img.xxx.cn">
去预解析域名,以降低域名解析带来的延迟
13.3 文件指纹
- 打包后输出的文件名和后缀
- hash 一般是结合 CDN 缓存来使用,通过 webpack 构建之后,生成对应文件名自动带上对应的 MD5 值。如果文件内容改变的话,那么对应文件哈希值也会改变,对应的 HTML引用的 URL 地址也会改变,触发 CDN 服务器从源服务器上拉取对应数据,进而更新客户端本地缓存。
指纹占位符
占位符名称 | 含义 |
---|---|
ext | 资源后缀名 |
name | 文件名称 |
path | 文件的相对路径 |
folder | 文件所在的文件夹 |
fullhash | webpack5 该了,之前是 hash,每次 webpack 构建时生成一个唯一的 hash 值 |
chunkhash | 根据 chunk 生成 hash 值,来源于同一个 chunk,则 fullhash 值就一样 |
contenthash | 根据内容生成hash值,文件内容相同hash值就相同 |
webpack.config.js
const path = require("path");
const webpack = require("webpack");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
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 glob = require("glob");
const PurgeCSSPlugin = require("purgecss-webpack-plugin");
const PATHS = {
src: path.join(__dirname, "src"),
};
module.exports = {
mode: "production",
entry: {
index: "./src/index.js",
},
context: process.cwd(),
output: {
path: path.resolve("dist"),
+ filename: "[name].[chunkhash:8].js?v=[chunkhash:8]",
},
optimization: {
minimizer: true,
minimizer: [new CssMinimizerPlugin(), new TerserPlugin()],
},
module: {
rules: [
{
test: /\.(scss|css)$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
},
],
},
plugins: [
new CleanWebpackPlugin(),
new webpack.ProgressPlugin(),
new MiniCssExtractPlugin({
+ filename: "css/[name].[contenthash:8].css?v=[contenthash:8]",
}),
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
new PurgeCSSPlugin({
paths: glob.sync(`${PATHS.src}/**/*`, { nodir: true }),
}),
],
};
14. moduleIds & chunkIds 的优化
- module: 每一个文件可看成一个 module。
- chunk: webpack 打包最终生成的代码块,代码块会生成文件,一个文件对应一个 chunk。
- 在 webpack5 之前,没有从 entry 打包的 chunk 文件,都会以1、2、3...的文件命名方式输出,删除某些文件可能会导致缓存失效。
- 在生产模式下,默认启用这些功能 chunkIds: "deterministic", moduleIds: "deterministic",此算法采用
确定性
的方式将短数字 ID(3 或 4 个字符)短hash值分配给 modules 和 chunks。- chunkId设置为deterministic, webpack5新增,则 output 中 chunkFilename 里的 [name] 会被替换成确定性短数字 ID。
- 虽然 chunkId 不变(不管值是deterministic | natural | named),但更改 chunk 内容,chunkhash 还是会改变的。
可选值 | 含义 | 示例 |
---|---|---|
natural | 按使用顺序的数字ID | 1 |
named | 方便调试的高可读性id | src_main_js.js |
deterministic | 根据模块名称生成简短的hash值 | 375 |
size | 根据模块大小生成的数字id | 0 |
14.1 webpack.config.js
module.exports = {
mode: "production",
entry: {
index: "./src/index.js",
},
context: process.cwd(),
output: {
path: path.resolve("dist"),
filename: "[name].js",
},
optimization: {
minimizer: true,
minimizer: [new CssMinimizerPlugin(), new TerserPlugin()],
+ moduleIds: 'deterministic',
+ chunkIds: 'deterministic'
},
}
src/index.js
import('./one');
import('./two');
import('./three');
会在打包生成文件 output.filename: "[name].js" 将 name 以数字 ID 做为文件的命名。
开发环境: moduleIds: "named",
生产环境:moduleIds: "deterministic",