一、安装
安装命令
npm install webpack webpack-cli
基础打包命令
webpack 入口文件 --mode=development #开发模式
webpack 入口文件 --mode=production #生产模式
二、webpack 配置文件
在项目根目录新建 webpack.config.js
配置核心概念有 entry(入口),output(输出),loader(加载器),plugins(插件),mode(模式)
基础配置举例:
const path = require("path")
module.exports = {
// 入口
entry:"./src/main.js",//相对路径
// 输出
output:{
// 文件的输出路径
path:path.resolve(__dirname,"dist")//绝对路径
// 文件名
filename:"static/js/main.js"
},
// 加载器
module:{
rules:[
// loader的配置
]
},
// 插件
plugins:[
// 插件的配置
],
// 开发模式
mode:"development"
}
配置完成后就可以直接使用webpack
直接打包,无需再像上面那样麻烦
三、处理样式资源 + loader 的使用
webpack 默认只打包 js 资源,样式资源不会打包,如果引入了样式资源会报错,所以需要安装相应的 loader 进行配置后才会被打包
在上面官方文档中的 loader 里面可以看到很多 loader
添加 css-loader 举例:
官方文档其实是有一些问题的,因为在这个地方需要添加两个 loader,style-loader 和 css-loader,但是安装时只给提示安装一个,这里应该两个都安装
另外有时会该使用 use 的地方给写成了 loader,这两个是有区别的,use 可以使用多个 loader,是一个列表形式,loader 只能使用一个 loader
安装
npm install --save-dev css-loader style-loader
在webpack.config.js中添加配置
module: {
rules: [
// 如果有其他的可以继续添加,rules是一个列表形式
{
test: /\.css$/, //只检测符合条件的文件
use: [
// 执行顺序:从左到右,从下到上
'style-loader',
'css-loader'
]
},
]
}
然后在入口文件引入需要使用的 css 文件即可
四、处理图片资源
之前是使用 file-loader 和 url-loader,没有没太了解过,webpack5 是内置了的,不用配置会自行打包图片资源,但是有时图片资源比较小,为了优化减少请求次数可以将小图片资源打包时转为 base64,或者需要配置打包后生成的图片资源名,或者打包后的输出路径等等,可以进行配置
举例,也是写在 module 的 rules 里面,但是不用安装 loader 了,只需要配置开启:
module: {
rules: [
{
test: /\.(png|jpe?g|gif|webp|svg)$/,
type: "asset",
parser: {
dataUrlCondition: {
// 小于15kb的图片转base64
// 优点:减少请求数量
// 缺点:体积会更大
maxSize: 15 * 1024,
},
},
generator: {
// 输出图片名称
// hash指根据图片内容生成的唯一值
// [hash:8]指hash值取前8位
// ext为扩展名
filename: "static/images/[hash:8][ext]",
},
},
]
}
五、自动清空上次打包的内容
在每次打包时,之前打包的文件需要手动删除,很麻烦很乱,在 webpack4 的时候需要装一个插件才可以自动清除后打包,webpack5 给内置了,只需在 output 里面配置一个 clean 即可
output:{
// 自动清空上次打包的内容
// 原理:在打包前,将path整个目录内容清空,再进行打包
clean:true
}
六、处理其他资源
与处理图片相同,不同的是音视频或字体等不需要处理成 base64,所以不用 parser 配置,修改 type,asset/resource 会原封不动的打包出来,generator 修改输出路径
举例:
{
test: /\.(ttf|woff2|mp3|mp4|avi)$/,
type: "asset/resource",
generator: {
filename: "static/media/[hash:8][ext]",
},
},
七、使用 eslint
在 webpack4 的时候,eslint 在 webpack 使用是作为 loader 使用,在 webpack5 是作为插件来使用的
按照官网,需要安装 eslint-webpack-plugin 和 eslint
npm install eslint-webpack-plugin --save-dev
npm install eslint --save-dev
安装完成后需要引入,然后在 plugins 里面 new
举例:
const ESLintPlugin = require("eslint-webpack-plugin");
plugins: [
new ESLintPlugin({
// 检测src目录下的文件
context: path.resolve(__dirname, "src"),
}),
],
在根目录下新建.eslintrc.js 文件,配置内容可参考eslint 官网,举例
module.exports = {
// 继承Eslint规则
extends: ["eslint:recommended"],
env: {
node: true, // 启用node中全局变量
browser: true, // 启用浏览器中全局变量
},
parserOptions: {
ecmaVersion: 6, // es6
sourceType: "module", // es module
},
rules: {
"no-var": 2, // 不能使用var定义变量
},
};
最后可以在根目录新建一个.eslintignore 文件,写入 dist,表示排出 dist 文件夹,因为打包后的文件就不要 eslint 检查了
八、使用 babel
webpack 在打包 js 的时候不会处理 es6 的语法,例如…运算或者箭头函数等,所以需要使用 babel 将 es6 语法编写的代码转换为兼容的语法,以便运行在当前或旧版本或其他环境当中
babel 是使用 loader 处理,在官网可以找到进行安装
配置
{
test: /\.js$/,
exclude: /node_modules/, // 排出node_modules中的js文件(这些文件不处理)
use: {
loader: 'babel-loader',
options: {
// 智能预设,能够编译es6语法
presets: ['@babel/preset-env']
}
}
},
也可以在根目录新建 babel.config.js 配置文件,将配置单独提出来写在配置文件中,这样 options 就可以去除了,两种方式都可以,写在外面的好处是后面方便更改
九、处理 html 资源
按上面的处理完成后生成的 js 文件需要手动引入到 html 里面,麻烦,可以借助 webpack 插件 HtmlWebpackPlugin 自动引入
安装
npm install --save-dev html-webpack-plugin
引入
const HtmlWebpackPlugin = require('html-webpack-plugin');
使用举例
plugins: [
new HtmlWebpackPlugin({
// 模板:以public/index.html文件创建新的html文件
// 新的html文件特点:1.结构和原来一致 2.自动引入打包输出的资源
template:path.relative(__dirname,"public/index.html")
})
],
十、配置自动化
每次修改完 src 的文件后都需要手动输命令重新打包,麻烦,可以使用 webpack-dev-server 来配置自动化打包
安装
npm i webpack-dev-server -D
配置
module.exports = {
// 开发服务器
devServer: {
host: "localhost", // 启动服务器域名
port: "3000", // 启动服务器端口号
open: true, // 是否自动打开浏览器
},
}
配置完成后需要使用webpack server
启动
十一、提取 css 成单独文件
css 文件前面都是在 js 里面引入的,会在 js 加载时创建 style 标签来生成样式,对于网站来说会出现闪屏现象,对用户体验不好,应该单独提取 css 文件,使用 link 引入
使用 webpack 的 MiniCssExtractPlugin 插件
安装
npm install --save-dev mini-css-extract-plugin
引入
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
使用
plugins: [
new MiniCssExtractPlugin({
// 指定输出目录
filename: "static/css/[hash:8].css",
}),
],
在官网看到,前面使用了style-loader
的地方需要替换为MiniCssExtractPlugin.loader
再打包时,就可以看到有 css 文件了,并且在打包后的 html 文件里面也是已经引入了的
十二、css 兼容性处理
有些样式有兼容性问题,例如 ie 或 Chrome 等等的浏览器样式有的带-ms-、-webkit-、-moz-这样,使用 postcss-loader、postcss、postcss-preset-env 处理
安装
npm install postcss-loader postcss postcss-preset-env -D
配置,写在 css-loader 的后面
如果配置了其他例如 less-loader、sass-loader,也是要写在 css-loader 的后面,例如
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env", // 能解决大多数样式兼容性问题
],
},
},
},
在 package.json 中新增浏览器兼容程度,解释:1.所有浏览器最后两个版本;2 覆盖 99%的浏览器;3.不要已经死亡的浏览器;
"browserslist": [
"last 2 version",
"> 1%",
"not dead"
]
十三、封装样式 loader 函数
在使用时可能要配置很多关于样式的 loader,例如 css,less,sass,scss,styl 等
在写 loader 的时候大部分都是相同的,为了方便维护,使代码更美观,因此可以封装 loader 函数
// 用来获取处理样式的loader
function getStyleLoader(pre) {
return [
//执行顺序,从右到左,从下到上
MiniCssExtractPlugin.loader, //将js中的css通过创建style标签添加html文件中生效
"css-loader", // 将css资源变异成CommonJS的模块到js中
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env", // 能解决大多数样式兼容性问题
],
},
},
},
pre,
].filter(Boolean);
}
在使用时可以直接传入需要使用的 loader
十四、CSS 压缩
将打包的 css 代码压缩到一行,使用 CssMinimizerWebpackPlugin 插件,html 和 js 文件如果开启生产模式默认压缩
安装
npm install css-minimizer-webpack-plugin --save-dev
引入
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
使用
new CssMinimizerPlugin()
压缩前
压缩后
十五、使用 SourceMap(源代码映射)提升开发体验
一般来说程序写好后,打包完成执行出错,查看错误时提示的行数或错误点都是已经打包后的,如果是大型项目找这些错误很麻烦,因此用这个技术生成源代码与构建后的代码映射关系文件(.map 文件),在出错时浏览器会自动识别源代码出错的位置
在官网的配置---devtool
可以找到
实际开发时只需要使用
在开发模式下使用cheap-module-source-map
,打包编译速度快,只包含行映射,不包含列映射
在生产模式下使用source-map
,打包编译速度慢,包含列和行映射
使用时只需增加一条配置即可
十六、提升打包构建速度
在打包时 webpack 默认是重新打包所有的代码,即使只改了一处,所以在大型项目会比较费时,因此使用模块热替换(hot module replacement)
这个在 webpack5 中是默认开启的,不可用于生产环境,在开发环境的开发服务器中配置 hot 即可
但是这个只开启 css 模块热替换,js 资源不会开启模块热替换,因此需要在入口文件进行判断使用
xxx.js为引入的其他js资源,这样写在修改xxx.js时就会开启模块热替换功能
后面可以跟一个函数,如果文件被更改了就会调用后面的函数
if (module.hot) {
// 判断是否支持热模块替换功能
module.hot.accept("xxx1.js"[,函数]);
module.hot.accept("xxx2.js");
}
十七、oneOf 优化
在配置文件中会配置很个 loader 进行资源处理,但是这个运行的模式是会从上到下依次查看 loader 是否能处理资源,即使已经配置了正则表达式过滤,即使上面的 loader 已经可以处理,还是会往下找,因此使用 OneOf 处理
在配置的 loader 外使用 oneOf 包裹起来即可,例如之前使用
module:{
rules:[
{
test: /\.css$/, //只检测.css文件
use: [
//执行顺序,从右到左,从下到上
"style-loader", //将js中的css通过创建style标签添加html文件中生效
"css-loader", // 将css资源变异成CommonJS的模块到js中
],
},
{
test: /\.less$/, //只检测.css文件
use: [
//执行顺序,从右到左,从下到上
"style-loader", //将js中的css通过创建style标签添加html文件中生效
"css-loader", // 将css资源变异成CommonJS的模块到js中
"less-loader",
],
},
]
}
使用 oneOf
module:{
rules:[
{
oneOf:[
{
test: /\.css$/, //只检测.css文件
use: [
//执行顺序,从右到左,从下到上
"style-loader", //将js中的css通过创建style标签添加html文件中生效
"css-loader", // 将css资源变异成CommonJS的模块到js中
],
},
{
test: /\.less$/, //只检测.css文件
use: [
//执行顺序,从右到左,从下到上
"style-loader", //将js中的css通过创建style标签添加html文件中生效
"css-loader", // 将css资源变异成CommonJS的模块到js中
"less-loader",
],
},
]
}
]
}
十八、exclude 和 include 优化
在第八个使用 babel-loader 处理 js 资源时使用过 exclude,排出 node_modules 文件夹里的东西,因为里面是下载的第三方依赖包可以直接使用,另外有 include,为包含,例如写 src 目录就是只处理 src 目录的文件,不处理其他文件
十九、cache 缓存优化
每次打包时,都要经过 eslint 检查和 babel 编译,速度比较慢,可以缓存之前 eslint 检查和 babel 编译的结果,仅检查和编译修改的文件,这样二次打包就会变快了
处理 js 资源 babel-loader 配置,增加 options 配置项
{
test: /\.js$/,
include: path.resolve(__dirname, "../src"), // 只处理src下的文件,其他文件不处理
use:[
loader: "babel-loader",
options: {
cacheDirectory: true, // 开启babel缓存
cacheCompression: false, // 关闭缓存文件压缩
},
]
},
插件 eslint 配置 cache,增加 cache 和 cacheLocation(缓存路径)配置项
new ESLintPlugin({
// 检测哪些文件
context: "src",
exclude: "node_modules",
cache: true,
cacheLocation: path.resolve(__dirname, "../node_modules/.cache/eslintcache"),
}),
二十、多线程打包
为了加快打包速度,可以开启多线程打包,使用 thread-loader
安装
npm i thread-loader -D
一般打包慢的是 js,所以针对 js 资源做处理
// 前面使用nodejs的os获取cpu核数
const os = require("os");
const threads = os.cpus().length; // CPU核数
// 下面修改js的loader配置,配置thread-loader
{
test: /\.js$/,
include: path.resolve(__dirname, "../src"), // 只处理src下的文件,其他文件不处理
use: [
{
loader: "thread-loader", // 开启多线程
options: {
works: threads, // 线程数量
},
},
{
loader: "babel-loader",
options: {
cacheDirectory: true, // 开启babel缓存
cacheCompression: false, // 关闭缓存文件压缩
},
},
],
},
同样 eslint 也可以做多线程处理,只需要增加threads
即可
new ESLintPlugin({
// 检测哪些文件
context: "src",
exclude: "node_modules",
cache: true,
cacheLocation: path.resolve(__dirname, "../node_modules/.cache/eslintcache"),
threads, // 开启多线程和线程数量
}),
多线程压缩 js,引入 terser-webpack-plugin 插件
const TerserWebpackPlugin = require("terser-webpack-plugin");
使用
new TerserWebpackPlugin({
parallel: threads,
}),
在 webpack5 中,官方推荐将压缩的插件单独抽出来写
plugins:[],
optimization: {
minimizer: [
// 压缩css
new CssMinimizerPlugin(),
// 压缩js
new TerserWebpackPlugin({
parallel: threads,
}),
],
},
二十一、使用@babel/plugin-transform-runtime 插件配置 babel-loader 减少代码体积
安装
npm i @babel/plugin-transform-runtime -D
使用,在 babel-loader 的 options 配置里增加 plugibs 配置即可
{
test: /\.js$/,
include: path.resolve(__dirname, "../src"), // 只处理src下的文件,其他文件不处理
use: [
{
loader: "babel-loader",
options: {
cacheDirectory: true, // 开启babel缓存
cacheCompression: false, // 关闭缓存文件压缩
plugins: ["@babel/plugin-transform-runtime"],
},
},
],
},
二十二、压缩本地静态图片体积
使用ImageMinimizerWebpackPlugin插件
下载一直报错,先不说了。。。。。