webpack 简介
webpack 是一个静态模块打包工具,也内置本地开发服务器。不仅能编译打包各类型的模块,而且插件种类、可定制化的配置项非常丰富,是当前比较主流的构建打包工具,类似的还有 Rollup、Snowpack、Vite 等。
webpack 4.x 和 webpack 5.x 是当下使用最多的 webpack 版本,自己也在大小项目中实战过,结合最近做的 webpack 5.x 性能优化,讲解下 webpack 5.x 的常用配置和高性能的构建优化配置。
打包原理
在项目构建时,他会递归地构建一个依赖关系图,其中包含应用需要的各个模块,然后将模块打包成一个或多个 bundle。
- 识别入口文件
- 通过逐层识别模块依赖。(Commonjs、amd 或者 es6 的 import,webpack 都会对其进行分析。来获取代码的依赖)
- webpack 做的就是分析代码。转换代码,编译代码,输出代码
- 最终形成打包后的代码
打包配置项介绍
module.exports = {
mode: "development" | "production" | "none", // 默认值为 production
entry: string | object, // 入口
output: {
publicPath: string, // 网站baseUrl
filename: string, // 打包后输出的文件名称
chunkFilename: string, // 间接引用的文件会走这个配置
path: string, // 打包后产物的根目录
},
module: object, // 对各类模块识别和转换规则的定义
plugins: array, // 做loader以外更多的工作,如打包优化、资源管理、注入环境变量等
optimization: object, // 性能优化、分包策略的定义
cache: string | object, // 是否启用构建缓存
};
上面列举了一些常用的构建配置项,定义合理的构建配置项,很大程度上能提高应用的开发体验、页面性能和用户体验。提高页面性能的配置内容主要体现在 module、plugins、optimization、cache 这四大块上。
构建的基础配置
module 配置的定义
1. 处理样式模块
主要包含style-loader
、css-loader
、less-loader
、·和 postcss-loader
的使用
-
使用 css-loader 必须要配合使用 style-loader
-
css-loader
的作用是帮我们分析出各个 css 文件之间的关系,把 各个 css 文件合并成一段 css -
style-loader
的作用是将 css-loader 生成的 css 代码挂载 到页面的 header 部分 -
多个 loader 配合使用时,处理顺序是:
从下到上,从右到左
的顺序; -
postcss-loader
负责进一步处理 CSS 文件,比如添加浏览器前缀,压缩 CSS,px 转 rem 等 -
less-loader
负责将 less 模块转换为浏览器可识别的 css 模块 -
sass-loader
负责将 sass 模块转换为浏览器可识别的 css 模块
以使用 less 项目为范例的样式 module 定义
需要安装以下 loader 模块
npm i -D style-loader css-loader postcss-loader mini-css-extract-plugin
Dev 模式(启用
sourceMap
,开发调试可定位到源文件)
[
{
test: /\.css$/, //寻找css文件
use: ["style-loader", "css-loader", "postcss-loader"], //不提取时使用这种方式
},
{
/**less的配置 */
test: /\.less$/, //寻找less文件
exclude: /node_modules/, //忽略
use: [
{ loader: "style-loader" },
{
loader: "css-loader",
options: {
modules: { localIdentName: "[local]___[hash:base64:5]" },
importLoaders: 2,
sourceMap: true,
},
},
{
loader: "postcss-loader",
options: {
sourceMap: true,
},
},
{
loader: "less-loader",
options: {
sourceMap: true,
},
},
],
},
];
Prod 模式(提取 css 样式到文件中,以 Link 外链方式引用)
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); //想要分开打包我们的css文件,需要使用mini-css-extract-plugin这个插件,
[
{
test: /\.css$/, //寻找css文件
use: [MiniCssExtractPlugin.loader, "css-loader", "postcss-loader"], //使用MiniCssExtractPlugin.loader,css-loader,postcss-loader
},
{
/**less的配置 */
test: /\.less$/, //寻找less文件
exclude: /node_modules/, //忽略
use: [
"style-loader",
{
loader: "css-loader",
options: {
modules: { localIdentName: "[local]___[hash:base64:5]" },
importLoaders: 2,
},
},
{
loader: "postcss-loader",
},
{
loader: "less-loader",
},
],
},
];
2. 处理 js 模块
编译 JS 用的Babel
babel 是 JavaScript 的编译器
它主要的作用是以下三点:
转换语法
为目标环境中缺失的语法提供垫片(Polyfill)
源码转换(模块代码)
涉及到的主要模块分别是 babel-loader、@babel/core 和@babel/preset-env
babel-loader
: 依赖@babel/core, 允许使用 babel 和 webpack 编译 JavaScript 文件@babel/core
: 把 js 代码分析成 ast(Abstract Syntax Tree,抽象语法树) ,方便各个插件分析语法进行相应的处理。有些新语法在低版本 js 中是不存在的,如箭头函数,rest 参数,函数默认值等,这种语言层面的不兼容只能通过将代码转为 ast,分析其语法后再转为低版本 js。@babel/preset-env
:智能预设,它使你可以使用最新的 JavaScript,而无需微观管理目标环境所需的语法转换(以及可选的浏览器 polyfill)
需要安装以下 loader 模块
npm i -D babel-loader @babel/core @babel/preset-env
工程根目录下放置文件.babelrc
{
"presets": [
[
"@babel/preset-env",
{
// 将es6的语法翻译成es5语法
"targets": {
//兼容目标浏览器
//"chrome": "67", //指定浏览器版本
//"browsers": ["last 2 versions", "safari >= 7"], //支持每个浏览器最后两个版本和safari大于等于7版本所需的polyfill代码转换
"browsers": "> 5%", //支持市场份额超过5%的浏览器
"node": "current" //如果通过Babel编译Node.js代码的话,可以设置 "target.node" 是 'current', 含义是 支持的是当前运行版本的nodejs。
},
"useBuiltIns": "usage", // 做@babel/polyfill补充时,按需补充,用到什么才补充什么,例:只转换用到的es6语法.
"corejs": "3" //声明corejs版本
}
],
"@babel/preset-react" //转换react JSX
]
}
Rule 定义如下:
const path = require("path");
[
{
/**js的配置 */
test: /\.(js|jsx)$/,
include: path.resolve(__dirname, "../src"), // 表示只解析以下目录,减少loader处理范围
exclude: /node_modules/, // 排除node_modules中的代码
use: [
{
loader: "babel-loader", // 只是babel和webpack之间的桥梁,并不会将代码转译
options: {
cacheDirectory: true,
},
},
],
},
];
3. 处理图片、字体模块
主要用到 url-loader、file-loader 加载器。
url-loader 允许你有条件地将文件转换为内联的 base-64 URL (当文件小于给定的阈值),这会减少小文件的 HTTP 请求数
。 如果文件大于该阈值,会自动的交给 file-loader 处理。 这个问题可以通过 url-loader 解决。 url-loader 会将引入的图片编码,生成 dataURl
需要安装以下 loader 模块
npm i -D url-loader file-loader
const path = require("path");
[
/**图标和图片的处理配置 */
{
test: /\.(png|jpe?g|svg|gif|webp)$/i,
include: path.resolve(__dirname, "../src"), // 表示只解析以下目录,减少loader处理范围
use: [
{
loader: "url-loader",
options: {
name: "[name].[hash:8].[ext]", // placeholder 占位符
outputPath: "assets/", // 打包文件名
limit: 1024 * 5, // 小于5KB则打包到js文件里,大于则使用file-loader的打包方式打包到assets里
esModule: false, // 支持img标签使用require动态指定图片
},
},
],
},
/**字体的处理配置 */
{
test: /\.(eot|woff2?|ttf|otf)$/,
include: path.resolve(__dirname, "../src"), // 表示只解析以下目录,减少loader处理范围
use: {
loader: "file-loader",
options: {
name: "[name]-[hash:8].min.[ext]", // 和上面同理
outputPath: "fonts/",
limit: 5000,
},
},
},
];
常见 plugins 的配置
clean-webpack-plugin
: 插件默认会清空 webpack 的 output 中配置的 path 指定的文件夹(默认 dist 目录)html-webpack-plugin
: 向 dist 目录中自动添加模版 html,可定义 title、template、favicon 等mini-css-extract-plugin
: 将 CSS 提取到单独的文件中,并且支持 CSS 和 SourceMaps 的按需加载copy-webpack-plugin
: 拷贝静态资源到 build 目录中webpack.DefinePlugin
: 对外暴露环境变量
需要安装以下模块
npm i -D clean-webpack-plugin html-webpack-plugin mini-css-extract-plugin copy-webpack-plugin
配置范例如下:
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
[
(new CleanWebpackPlugin(), // 打包前先清除dist文件,先于HtmlWebpackPlugin运行
new HtmlWebpackPlugin({
template: "public/index.html",
favicon: "public/favicon.ico",
}),
new MiniCssExtractPlugin({
ignoreOrder: true,
filename: "static/css/[name].[contenthash:5].css",
chunkFilename: "static/css/[name].[contenthash:5].css",
}),
new webpack.DefinePlugin({
"process.env.PUBLIC_URL": JSON.stringify(process.env.PUBLIC_URL),
}),
new CopyWebpackPlugin({
patterns: [
{
from: path.join(__dirname, "../mock"),
to: path.join(__dirname, "../dist/mock"),
},
{
from: path.join(__dirname, "../server/mockServer.js"),
to: path.join(__dirname, "../dist/server"),
},
],
})),
];
以上是本次提供的 webpack 5.x 打包入门简介和常用基础配置介绍,附上的代码范例都已经过实践验证,大可放心使用,如有问题请及时指出。